orgize/src/org.rs

194 lines
5.3 KiB
Rust

use indextree::{Arena, NodeEdge, NodeId};
use std::io::{Error, Write};
use std::ops::{Index, IndexMut};
use crate::{
config::{ParseConfig, DEFAULT_CONFIG},
elements::{Element, Keyword},
export::{DefaultHtmlHandler, DefaultOrgHandler, HtmlHandler, OrgHandler},
parsers::{blank_lines_count, parse_container, Container, OwnedArena},
};
pub struct Org<'a> {
pub(crate) arena: Arena<Element<'a>>,
pub(crate) root: NodeId,
}
#[derive(Debug)]
pub enum Event<'a, 'b> {
Start(&'b Element<'a>),
End(&'b Element<'a>),
}
impl<'a> Org<'a> {
/// Creates a new empty `Org` struct.
pub fn new() -> Org<'static> {
let mut arena = Arena::new();
let root = arena.new_node(Element::Document { pre_blank: 0 });
Org { arena, root }
}
/// Parses string `text` into `Org` struct.
pub fn parse(text: &'a str) -> Org<'a> {
Org::parse_custom(text, &DEFAULT_CONFIG)
}
/// Likes `parse`, but accepts `String`.
pub fn parse_string(text: String) -> Org<'static> {
Org::parse_string_custom(text, &DEFAULT_CONFIG)
}
/// Parses string `text` into `Org` struct with custom `ParseConfig`.
pub fn parse_custom(text: &'a str, config: &ParseConfig) -> Org<'a> {
let mut arena = Arena::new();
let (text, pre_blank) = blank_lines_count(text);
let root = arena.new_node(Element::Document { pre_blank });
let mut org = Org { arena, root };
parse_container(
&mut org.arena,
Container::Document {
content: text,
node: org.root,
},
config,
);
org.debug_validate();
org
}
/// Likes `parse_custom`, but accepts `String`.
pub fn parse_string_custom(text: String, config: &ParseConfig) -> Org<'static> {
let mut arena = Arena::new();
let (text, pre_blank) = blank_lines_count(&text);
let root = arena.new_node(Element::Document { pre_blank });
let mut org = Org { arena, root };
parse_container(
&mut OwnedArena::new(&mut org.arena),
Container::Document {
content: text,
node: org.root,
},
config,
);
org.debug_validate();
org
}
/// Returns a reference to the underlay arena.
pub fn arena(&self) -> &Arena<Element<'a>> {
&self.arena
}
/// Returns a mutual reference to the underlay arena.
pub fn arena_mut(&mut self) -> &mut Arena<Element<'a>> {
&mut self.arena
}
/// Returns an iterator of `Event`s.
pub fn iter<'b>(&'b self) -> impl Iterator<Item = Event<'a, 'b>> + 'b {
self.root.traverse(&self.arena).map(move |edge| match edge {
NodeEdge::Start(node) => Event::Start(&self[node]),
NodeEdge::End(node) => Event::End(&self[node]),
})
}
/// Returns an iterator of `Keyword`s.
pub fn keywords(&self) -> impl Iterator<Item = &Keyword<'_>> {
self.root
.descendants(&self.arena)
.skip(1)
.filter_map(move |node| match &self[node] {
Element::Keyword(kw) => Some(kw),
_ => None,
})
}
/// Writes an `Org` struct as html format.
pub fn write_html<W>(&self, writer: W) -> Result<(), Error>
where
W: Write,
{
self.write_html_custom(writer, &mut DefaultHtmlHandler)
}
/// Writes an `Org` struct as html format with custom `HtmlHandler`.
pub fn write_html_custom<W, H, E>(&self, mut writer: W, handler: &mut H) -> Result<(), E>
where
W: Write,
E: From<Error>,
H: HtmlHandler<E>,
{
for event in self.iter() {
match event {
Event::Start(element) => handler.start(&mut writer, element)?,
Event::End(element) => handler.end(&mut writer, element)?,
}
}
Ok(())
}
/// Writes an `Org` struct as org format.
pub fn write_org<W>(&self, writer: W) -> Result<(), Error>
where
W: Write,
{
self.write_org_custom(writer, &mut DefaultOrgHandler)
}
/// Writes an `Org` struct as org format with custom `OrgHandler`.
pub fn write_org_custom<W, H, E>(&self, mut writer: W, handler: &mut H) -> Result<(), E>
where
W: Write,
E: From<Error>,
H: OrgHandler<E>,
{
for event in self.iter() {
match event {
Event::Start(element) => handler.start(&mut writer, element)?,
Event::End(element) => handler.end(&mut writer, element)?,
}
}
Ok(())
}
}
impl Default for Org<'static> {
fn default() -> Self {
Org::new()
}
}
impl<'a> Index<NodeId> for Org<'a> {
type Output = Element<'a>;
fn index(&self, node_id: NodeId) -> &Self::Output {
self.arena[node_id].get()
}
}
impl<'a> IndexMut<NodeId> for Org<'a> {
fn index_mut(&mut self, node_id: NodeId) -> &mut Self::Output {
self.arena[node_id].get_mut()
}
}
#[cfg(feature = "ser")]
use serde::{ser::Serializer, Serialize};
#[cfg(feature = "ser")]
impl Serialize for Org<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use serde_indextree::Node;
serializer.serialize_newtype_struct("Org", &Node::new(self.root, &self.arena))
}
}