>::as_mut(self).$name(item, ctx)
- }
- };
-}
diff --git a/src/export/html.rs b/src/export/html.rs
index 5a44b70..9ec25e0 100644
--- a/src/export/html.rs
+++ b/src/export/html.rs
@@ -1,12 +1,11 @@
-use rowan::{NodeOrToken, WalkEvent};
+use rowan::NodeOrToken;
use std::cmp::min;
use std::fmt;
use std::fmt::Write as _;
+use super::event::{Container, Event};
use super::TraversalContext;
use super::Traverser;
-use crate::ast::*;
-use crate::syntax::SyntaxToken;
use crate::SyntaxKind;
/// A wrapper for escaping sensitive characters in html.
@@ -77,23 +76,70 @@ impl HtmlExport {
}
impl Traverser for HtmlExport {
- #[tracing::instrument(skip(self, _ctx))]
- fn text(&mut self, token: SyntaxToken, _ctx: &mut TraversalContext) {
- self.output += &HtmlEscape(token.text()).to_string();
- }
-
- #[tracing::instrument(skip(self, _ctx))]
- fn document(&mut self, event: WalkEvent<&Document>, _ctx: &mut TraversalContext) {
- self.output += match event {
- WalkEvent::Enter(_) => "",
- WalkEvent::Leave(_) => "",
- };
- }
-
- #[tracing::instrument(skip(self, _ctx))]
- fn list(&mut self, event: WalkEvent<&List>, _ctx: &mut TraversalContext) {
+ fn event(&mut self, event: Event, ctx: &mut TraversalContext) {
match event {
- WalkEvent::Enter(list) => {
+ Event::Enter(Container::Document(_)) => self.output += "",
+ Event::Leave(Container::Document(_)) => self.output += "",
+
+ Event::Enter(Container::Headline(headline)) => {
+ let level = min(headline.level(), 6);
+ let _ = write!(&mut self.output, "");
+ for elem in headline.title() {
+ self.element(elem, ctx);
+ }
+ let _ = write!(&mut self.output, "");
+ }
+ Event::Leave(Container::Headline(_)) => {}
+
+ Event::Enter(Container::Paragraph(_)) => self.output += "",
+ Event::Leave(Container::Paragraph(_)) => self.output += "
",
+
+ Event::Enter(Container::Section(_)) => self.output += "",
+ Event::Leave(Container::Section(_)) => self.output += "",
+
+ Event::Enter(Container::Italic(_)) => self.output += "",
+ Event::Leave(Container::Italic(_)) => self.output += "",
+
+ Event::Enter(Container::Bold(_)) => self.output += "",
+ Event::Leave(Container::Bold(_)) => self.output += "",
+
+ Event::Enter(Container::Strike(_)) => self.output += "",
+ Event::Leave(Container::Strike(_)) => self.output += "",
+
+ Event::Enter(Container::Underline(_)) => self.output += "",
+ Event::Leave(Container::Underline(_)) => self.output += "",
+
+ Event::Enter(Container::Verbatim(_)) => self.output += "",
+ Event::Leave(Container::Verbatim(_)) => self.output += "",
+
+ Event::Enter(Container::Code(_)) => self.output += "",
+ Event::Leave(Container::Code(_)) => self.output += "",
+
+ Event::Enter(Container::QuoteBlock(_)) => self.output += "",
+ Event::Leave(Container::QuoteBlock(_)) => self.output += "
",
+
+ Event::Enter(Container::VerseBlock(_)) => self.output += "",
+ Event::Leave(Container::VerseBlock(_)) => self.output += "
",
+
+ Event::Enter(Container::ExampleBlock(_)) => self.output += "",
+ Event::Leave(Container::ExampleBlock(_)) => self.output += "
",
+
+ Event::Enter(Container::CenterBlock(_)) => self.output += "",
+ Event::Leave(Container::CenterBlock(_)) => self.output += "
",
+
+ Event::Enter(Container::CommentBlock(_)) => self.output += "",
+
+ Event::Enter(Container::Comment(_)) => self.output += "",
+
+ Event::Enter(Container::Subscript(_)) => self.output += "",
+ Event::Leave(Container::Subscript(_)) => self.output += "",
+
+ Event::Enter(Container::Superscript(_)) => self.output += "",
+ Event::Leave(Container::Superscript(_)) => self.output += "",
+
+ Event::Enter(Container::List(list)) => {
self.output += if list.is_ordered() {
self.in_descriptive_list.push(false);
""
@@ -105,7 +151,7 @@ impl Traverser for HtmlExport {
""
};
}
- WalkEvent::Leave(list) => {
+ Event::Leave(Container::List(list)) => {
self.output += if list.is_ordered() {
"
"
} else if let Some(true) = self.in_descriptive_list.last() {
@@ -115,123 +161,92 @@ impl Traverser for HtmlExport {
};
self.in_descriptive_list.pop();
}
- };
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn list_item(&mut self, event: WalkEvent<&ListItem>, ctx: &mut TraversalContext) {
- if self.in_descriptive_list.last().copied().unwrap_or_default() {
- match event {
- WalkEvent::Enter(item) => {
+ Event::Enter(Container::ListItem(list_item)) => {
+ if let Some(&true) = self.in_descriptive_list.last() {
self.output += "";
- for elem in item.tag() {
+ for elem in list_item.tag() {
self.element(elem, ctx);
}
self.output += "";
+ } else {
+ self.output += "";
+ }
+ }
+ Event::Leave(Container::ListItem(_)) => {
+ if let Some(&true) = self.in_descriptive_list.last() {
+ self.output += "";
+ } else {
+ self.output += "";
}
- WalkEvent::Leave(_) => self.output += "",
- };
- } else {
- match event {
- WalkEvent::Enter(_) => self.output += "",
- WalkEvent::Leave(_) => self.output += "",
- };
- }
- }
-
- #[tracing::instrument(skip(self, _ctx))]
- fn paragraph(&mut self, event: WalkEvent<&Paragraph>, _ctx: &mut TraversalContext) {
- self.output += match event {
- WalkEvent::Enter(_) => "",
- WalkEvent::Leave(_) => "
",
- };
- }
-
- #[tracing::instrument(skip(self, _ctx))]
- fn section(&mut self, event: WalkEvent<&Section>, _ctx: &mut TraversalContext) {
- self.output += match event {
- WalkEvent::Enter(_) => "",
- WalkEvent::Leave(_) => "",
- };
- }
-
- #[tracing::instrument(skip(self, _ctx))]
- fn fixed_width(&mut self, event: WalkEvent<&FixedWidth>, _ctx: &mut TraversalContext) {
- if let WalkEvent::Enter(_f) = event {
- // self.output += f.text();
- };
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn snippet(&mut self, event: WalkEvent<&Snippet>, ctx: &mut TraversalContext) {
- if let WalkEvent::Enter(snippet) = event {
- if snippet.backend().eq_ignore_ascii_case("html") {
- self.output += &snippet.value();
}
- return ctx.skip();
- };
- }
- #[tracing::instrument(skip(self, _ctx))]
- fn italic(&mut self, event: WalkEvent<&Italic>, _ctx: &mut TraversalContext) {
- self.output += match event {
- WalkEvent::Enter(_) => "",
- WalkEvent::Leave(_) => "",
- };
- }
+ Event::Enter(Container::OrgTable(table)) => {
+ self.output += "";
+ self.table_row = if table.has_header() {
+ TableRow::HeaderRule
+ } else {
+ TableRow::BodyRule
+ }
+ }
+ Event::Leave(Container::OrgTable(_)) => {
+ match self.table_row {
+ TableRow::Body => self.output += "",
+ TableRow::Header => self.output += "",
+ _ => {}
+ }
+ self.output += "
";
+ }
+ Event::Enter(Container::OrgTableRow(row)) => {
+ if row.is_rule() {
+ match self.table_row {
+ TableRow::Body => {
+ self.output += "";
+ self.table_row = TableRow::BodyRule;
+ }
+ TableRow::Header => {
+ self.output += "";
+ self.table_row = TableRow::BodyRule;
+ }
+ _ => {}
+ }
+ ctx.skip();
+ } else {
+ match self.table_row {
+ TableRow::HeaderRule => {
+ self.table_row = TableRow::Header;
+ self.output += "";
+ }
+ TableRow::BodyRule => {
+ self.table_row = TableRow::Body;
+ self.output += "";
+ }
+ _ => {}
+ }
+ self.output += "";
+ }
+ }
+ Event::Leave(Container::OrgTableRow(row)) => {
+ if row.is_rule() {
+ match self.table_row {
+ TableRow::Body => {
+ self.output += "
";
+ self.table_row = TableRow::BodyRule;
+ }
+ TableRow::Header => {
+ self.output += "";
+ self.table_row = TableRow::BodyRule;
+ }
+ _ => {}
+ }
+ ctx.skip();
+ } else {
+ self.output += "";
+ }
+ }
+ Event::Enter(Container::OrgTableCell(_)) => self.output += "",
+ Event::Leave(Container::OrgTableCell(_)) => self.output += " | ",
- #[tracing::instrument(skip(self, _ctx))]
- fn bold(&mut self, event: WalkEvent<&Bold>, _ctx: &mut TraversalContext) {
- self.output += match event {
- WalkEvent::Enter(_) => "",
- WalkEvent::Leave(_) => "",
- };
- }
-
- #[tracing::instrument(skip(self, _ctx))]
- fn strike(&mut self, event: WalkEvent<&Strike>, _ctx: &mut TraversalContext) {
- self.output += match event {
- WalkEvent::Enter(_) => "",
- WalkEvent::Leave(_) => "",
- };
- }
-
- #[tracing::instrument(skip(self, _ctx))]
- fn underline(&mut self, event: WalkEvent<&Underline>, _ctx: &mut TraversalContext) {
- self.output += match event {
- WalkEvent::Enter(_) => "",
- WalkEvent::Leave(_) => "",
- };
- }
-
- #[tracing::instrument(skip(self, _ctx))]
- fn verbatim(&mut self, event: WalkEvent<&Verbatim>, _ctx: &mut TraversalContext) {
- self.output += match event {
- WalkEvent::Enter(_) => "",
- WalkEvent::Leave(_) => "",
- };
- }
-
- #[tracing::instrument(skip(self, _ctx))]
- fn code(&mut self, event: WalkEvent<&Code>, _ctx: &mut TraversalContext) {
- self.output += match event {
- WalkEvent::Enter(_) => "",
- WalkEvent::Leave(_) => "",
- };
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn rule(&mut self, event: WalkEvent<&Rule>, ctx: &mut TraversalContext) {
- if let WalkEvent::Enter(_) = event {
- self.output += "
"
- };
- ctx.skip()
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn link(&mut self, event: WalkEvent<&Link>, ctx: &mut TraversalContext) {
- match event {
- WalkEvent::Enter(link) => {
+ Event::Enter(Container::Link(link)) => {
let path = link.path();
if link.is_image() {
@@ -243,299 +258,51 @@ impl Traverser for HtmlExport {
if !link.has_description() {
let _ = write!(&mut self.output, "{}", HtmlEscape(&path));
- return ctx.skip();
+ ctx.skip();
}
}
- WalkEvent::Leave(_) => {
- self.output += "";
+ Event::Leave(Container::Link(_)) => self.output += "",
+
+ Event::Text(text) => {
+ let _ = write!(&mut self.output, "{}", HtmlEscape(text.text()));
}
- }
- }
- #[tracing::instrument(skip(self, _ctx))]
- fn quote_block(&mut self, event: WalkEvent<&QuoteBlock>, _ctx: &mut TraversalContext) {
- self.output += match event {
- WalkEvent::Enter(_) => "",
- WalkEvent::Leave(_) => "
",
- };
- }
+ Event::LineBreak(_) => self.output += "
",
- #[tracing::instrument(skip(self, _ctx))]
- fn verse_block(&mut self, event: WalkEvent<&VerseBlock>, _ctx: &mut TraversalContext) {
- self.output += match event {
- WalkEvent::Enter(_) => "",
- WalkEvent::Leave(_) => "
",
- };
- }
-
- #[tracing::instrument(skip(self, _ctx))]
- fn example_block(&mut self, event: WalkEvent<&ExampleBlock>, _ctx: &mut TraversalContext) {
- self.output += match event {
- WalkEvent::Enter(_) => "",
- WalkEvent::Leave(_) => "
",
- };
- }
-
- #[tracing::instrument(skip(self, _ctx))]
- fn center_block(&mut self, event: WalkEvent<&CenterBlock>, _ctx: &mut TraversalContext) {
- self.output += match event {
- WalkEvent::Enter(_) => "",
- WalkEvent::Leave(_) => "
",
- };
- }
-
- #[tracing::instrument(skip(self, _ctx))]
- fn org_table(&mut self, event: WalkEvent<&OrgTable>, _ctx: &mut TraversalContext) {
- match event {
- WalkEvent::Enter(table) => {
- self.output += "";
- self.table_row = if table.has_header() {
- TableRow::HeaderRule
- } else {
- TableRow::BodyRule
+ Event::Snippet(snippet) => {
+ if snippet.backend().eq_ignore_ascii_case("html") {
+ self.output += &snippet.value();
}
}
- WalkEvent::Leave(_) => {
- match self.table_row {
- TableRow::Body => self.output += "",
- TableRow::Header => self.output += "",
- _ => {}
- }
- self.output += "
";
- }
- }
- }
- #[tracing::instrument(skip(self, ctx))]
- fn org_table_row(&mut self, event: WalkEvent<&OrgTableRow>, ctx: &mut TraversalContext) {
- if match event {
- WalkEvent::Enter(n) | WalkEvent::Leave(n) => n.is_rule(),
- } {
- match self.table_row {
- TableRow::Body => {
- self.output += "";
- self.table_row = TableRow::BodyRule;
- }
- TableRow::Header => {
- self.output += "";
- self.table_row = TableRow::BodyRule;
- }
- _ => {}
- }
- return ctx.skip();
- }
+ Event::Rule(_) => self.output += "
",
- match event {
- WalkEvent::Enter(_) => {
- match self.table_row {
- TableRow::HeaderRule => {
- self.table_row = TableRow::Header;
- self.output += "";
+ Event::Timestamp(timestamp) => {
+ self.output += r#""#;
+ for e in timestamp.syntax.children_with_tokens() {
+ match e {
+ NodeOrToken::Token(t) if t.kind() == SyntaxKind::MINUS2 => {
+ self.output += "–";
+ }
+ NodeOrToken::Token(t) => {
+ self.output += t.text();
+ }
+ _ => {}
}
- TableRow::BodyRule => {
- self.table_row = TableRow::Body;
- self.output += "";
- }
- _ => {}
}
- self.output += "";
+ self.output += r#""#;
}
- WalkEvent::Leave(_) => {
- self.output += "
";
+
+ Event::LatexFragment(latex) => {
+ let _ = write!(&mut self.output, "{}", &latex.syntax);
}
- }
- }
-
- #[tracing::instrument(skip(self, _ctx))]
- fn org_table_cell(&mut self, event: WalkEvent<&OrgTableCell>, _ctx: &mut TraversalContext) {
- self.output += match event {
- WalkEvent::Enter(_) => "",
- WalkEvent::Leave(_) => " | ",
- };
- }
-
- #[tracing::instrument(skip(self, _ctx))]
- fn comment(&mut self, event: WalkEvent<&Comment>, _ctx: &mut TraversalContext) {
- self.output += match event {
- WalkEvent::Enter(_) => "",
- };
- }
-
- #[tracing::instrument(skip(self, _ctx))]
- fn comment_block(&mut self, event: WalkEvent<&CommentBlock>, _ctx: &mut TraversalContext) {
- self.output += match event {
- WalkEvent::Enter(_) => "",
- };
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn headline(&mut self, event: WalkEvent<&Headline>, ctx: &mut TraversalContext) {
- if let WalkEvent::Enter(headline) = event {
- let level = min(headline.level(), 6);
- let _ = write!(&mut self.output, "");
- for elem in headline.title() {
- self.element(elem, ctx);
+ Event::LatexEnvironment(latex) => {
+ let _ = write!(&mut self.output, "{}", &latex.syntax);
}
- let _ = write!(&mut self.output, "");
+
+ Event::Entity(entity) => self.output += entity.html(),
+
+ _ => {}
}
}
-
- #[tracing::instrument(skip(self, ctx))]
- fn inline_src(&mut self, _event: WalkEvent<&InlineSrc>, ctx: &mut TraversalContext) {
- ctx.skip();
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn inline_call(&mut self, _event: WalkEvent<&InlineCall>, ctx: &mut TraversalContext) {
- ctx.skip();
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn special_block(&mut self, _event: WalkEvent<&SpecialBlock>, ctx: &mut TraversalContext) {
- ctx.skip();
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn export_block(&mut self, _event: WalkEvent<&ExportBlock>, ctx: &mut TraversalContext) {
- ctx.skip();
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn source_block(&mut self, _event: WalkEvent<&SourceBlock>, ctx: &mut TraversalContext) {
- ctx.skip();
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn babel_call(&mut self, _event: WalkEvent<&BabelCall>, ctx: &mut TraversalContext) {
- ctx.skip();
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn clock(&mut self, _event: WalkEvent<&Clock>, ctx: &mut TraversalContext) {
- ctx.skip();
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn cookie(&mut self, _event: WalkEvent<&Cookie>, ctx: &mut TraversalContext) {
- ctx.skip();
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn radio_target(&mut self, _event: WalkEvent<&RadioTarget>, ctx: &mut TraversalContext) {
- ctx.skip();
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn drawer(&mut self, _event: WalkEvent<&Drawer>, ctx: &mut TraversalContext) {
- ctx.skip();
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn dyn_block(&mut self, _event: WalkEvent<&DynBlock>, ctx: &mut TraversalContext) {
- ctx.skip();
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn fn_def(&mut self, _event: WalkEvent<&FnDef>, ctx: &mut TraversalContext) {
- ctx.skip();
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn fn_ref(&mut self, _event: WalkEvent<&FnRef>, ctx: &mut TraversalContext) {
- ctx.skip();
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn macros(&mut self, _event: WalkEvent<&Macros>, ctx: &mut TraversalContext) {
- ctx.skip();
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn timestamp(&mut self, event: WalkEvent<&Timestamp>, ctx: &mut TraversalContext) {
- if let WalkEvent::Enter(t) = event {
- self.output += r#""#;
- for e in t.syntax.children_with_tokens() {
- match e {
- NodeOrToken::Token(t) if t.kind() == SyntaxKind::MINUS2 => {
- self.output += "–";
- }
- NodeOrToken::Token(t) => {
- self.output += t.text();
- }
- _ => {}
- }
- }
- self.output += r#""#;
- ctx.skip();
- }
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn target(&mut self, _event: WalkEvent<&Target>, ctx: &mut TraversalContext) {
- ctx.skip();
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn latex_fragment(&mut self, event: WalkEvent<&LatexFragment>, ctx: &mut TraversalContext) {
- if let WalkEvent::Enter(l) = event {
- self.output += &l.syntax.to_string();
- ctx.skip();
- }
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn latex_environment(
- &mut self,
- event: WalkEvent<&LatexEnvironment>,
- ctx: &mut TraversalContext,
- ) {
- if let WalkEvent::Enter(l) = event {
- self.output += &l.syntax.to_string();
- ctx.skip();
- }
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn entity(&mut self, event: WalkEvent<&Entity>, ctx: &mut TraversalContext) {
- if let WalkEvent::Enter(e) = event {
- self.output += e.html();
- ctx.skip();
- }
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn line_break(&mut self, event: WalkEvent<&LineBreak>, ctx: &mut TraversalContext) {
- if let WalkEvent::Enter(_) = event {
- self.output += "
";
- ctx.skip();
- }
- }
-
- #[tracing::instrument(skip(self, _ctx))]
- fn subscript(&mut self, event: WalkEvent<&Subscript>, _ctx: &mut TraversalContext) {
- match event {
- WalkEvent::Enter(_) => self.output += "",
- WalkEvent::Leave(_) => self.output += "",
- }
- }
-
- #[tracing::instrument(skip(self, _ctx))]
- fn superscript(&mut self, event: WalkEvent<&Superscript>, _ctx: &mut TraversalContext) {
- match event {
- WalkEvent::Enter(_) => self.output += "",
- WalkEvent::Leave(_) => self.output += "",
- }
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn keyword(&mut self, _event: WalkEvent<&Keyword>, ctx: &mut TraversalContext) {
- ctx.skip();
- }
-
- #[tracing::instrument(skip(self, ctx))]
- fn property_drawer(&mut self, _event: WalkEvent<&PropertyDrawer>, ctx: &mut TraversalContext) {
- ctx.skip()
- }
}
diff --git a/src/export/mod.rs b/src/export/mod.rs
index 3d3f0bd..b5e4401 100644
--- a/src/export/mod.rs
+++ b/src/export/mod.rs
@@ -1,8 +1,9 @@
//! Export `Org` struct to various formats.
-mod forward;
+mod event;
mod html;
mod traverse;
+pub use event::{Container, Event};
pub use html::{HtmlEscape, HtmlExport};
pub use traverse::{TraversalContext, Traverser};
diff --git a/src/export/traverse.rs b/src/export/traverse.rs
index 4c1464a..42e2c24 100644
--- a/src/export/traverse.rs
+++ b/src/export/traverse.rs
@@ -1,8 +1,10 @@
use crate::ast::*;
-use crate::syntax::{SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken};
-use rowan::{ast::AstNode, WalkEvent};
+use crate::syntax::{SyntaxElement, SyntaxKind};
+use rowan::ast::AstNode;
use SyntaxKind::*;
+use super::event::{Container, Event};
+
#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
enum TraversalControl {
Up,
@@ -12,26 +14,6 @@ enum TraversalControl {
Continue,
}
-macro_rules! take_control {
- ($ctrl:expr) => {
- match $ctrl.control {
- TraversalControl::Stop => {
- $ctrl.control = TraversalControl::Stop;
- return;
- }
- TraversalControl::Up => {
- $ctrl.control = TraversalControl::Skip;
- return;
- }
- TraversalControl::Skip => {
- $ctrl.control = TraversalControl::Continue;
- return;
- }
- TraversalControl::Continue => {}
- }
- };
-}
-
#[derive(Default)]
pub struct TraversalContext {
control: TraversalControl,
@@ -56,216 +38,187 @@ impl TraversalContext {
}
}
-/// Enumerates org syntax tree
+/// A trait for enumerating org syntax tree
///
-/// Traverser enumerates org syntax tree and calls handle method on each
-/// enumerated node and token.
+/// ### `TraversalContext`
///
-/// Each handle method can returns a `TraversalControl` to control the traversal.
+/// `TraversalContext` can be used to control the traversal.
+///
+/// For example, `ctx.skip()` will skips the traversal for current
+/// element and its descendants and improve the traversal performance.
+///
+/// ```rust
+/// use orgize::{
+/// export::{Container, Event, HtmlExport, TraversalContext, Traverser},
+/// Org,
+/// };
+/// use slugify::slugify;
+///
+/// #[derive(Default)]
+/// struct Toc(HtmlExport);
+///
+/// impl Traverser for Toc {
+/// fn event(&mut self, event: Event, ctx: &mut TraversalContext) {
+/// match event {
+/// Event::Enter(Container::Headline(headline)) => {
+/// let title = headline.title().map(|e| e.to_string()).collect::();
+/// self.0.push_str(&format!("", slugify!(&title)));
+/// for elem in headline.title() {
+/// self.element(elem, ctx);
+/// }
+/// self.0.push_str("");
+/// if headline.headlines().count() > 0 {
+/// self.0.push_str("");
+/// }
+/// }
+/// Event::Leave(Container::Headline(headline)) => {
+/// if headline.headlines().count() > 0 {
+/// self.0.push_str("
");
+/// }
+/// }
+/// Event::Enter(Container::Section(_)) | Event::Leave(Container::Section(_)) => ctx.skip(),
+/// Event::Enter(Container::Document(_)) | Event::Leave(Container::Document(_)) => {}
+/// _ => self.0.event(event, ctx),
+/// }
+/// }
+/// }
+///
+/// let org = Org::parse(r#"
+/// * heading 1
+/// section 1
+/// ** heading 1.1
+/// ** heading 1.2
+/// * heading 2
+/// section 2
+/// * heading 3
+/// **** heading 3.1"#);
+/// let mut toc = Toc::default();
+/// org.traverse(&mut toc);
+/// assert_eq!(toc.0.finish(), "\
+/// heading 1\
+/// \
+/// heading 2\
+/// heading 3\
+/// ");
+/// ```
pub trait Traverser {
+ /// Handles traversal event
+ fn event(&mut self, event: Event, ctx: &mut TraversalContext);
+
fn element(&mut self, element: SyntaxElement, ctx: &mut TraversalContext) {
+ macro_rules! take_control {
+ () => {
+ match ctx.control {
+ TraversalControl::Stop => {
+ ctx.control = TraversalControl::Stop;
+ return;
+ }
+ TraversalControl::Up => {
+ ctx.control = TraversalControl::Skip;
+ return;
+ }
+ TraversalControl::Skip => {
+ ctx.control = TraversalControl::Continue;
+ return;
+ }
+ TraversalControl::Continue => {}
+ }
+ };
+ }
+
match element {
- SyntaxElement::Node(node) => self.node(node, ctx),
- SyntaxElement::Token(token) => self.token(token, ctx),
+ SyntaxElement::Node(node) => {
+ macro_rules! walk {
+ ($ast:ident) => {{
+ debug_assert!($ast::can_cast(node.kind()));
+ let node = $ast { syntax: node };
+ self.event(Event::Enter(Container::$ast(node.clone())), ctx);
+ take_control!();
+ for child in node.syntax.children_with_tokens() {
+ self.element(child, ctx);
+ take_control!();
+ }
+ self.event(Event::Leave(Container::$ast(node.clone())), ctx);
+ take_control!();
+ }};
+ (@$ast:ident) => {{
+ debug_assert!($ast::can_cast(node.kind()));
+ let node = $ast { syntax: node };
+ self.event(Event::$ast(node), ctx);
+ take_control!();
+ }};
+ }
+
+ match node.kind() {
+ DOCUMENT => walk!(Document),
+ HEADLINE => walk!(Headline),
+ SECTION => walk!(Section),
+ PARAGRAPH => walk!(Paragraph),
+ BOLD => walk!(Bold),
+ ITALIC => walk!(Italic),
+ STRIKE => walk!(Strike),
+ UNDERLINE => walk!(Underline),
+ LIST => walk!(List),
+ LIST_ITEM => walk!(ListItem),
+ CODE => walk!(Code),
+ INLINE_CALL => walk!(@InlineCall),
+ INLINE_SRC => walk!(@InlineSrc),
+ RULE => walk!(@Rule),
+ VERBATIM => walk!(Verbatim),
+ SPECIAL_BLOCK => walk!(SpecialBlock),
+ QUOTE_BLOCK => walk!(QuoteBlock),
+ CENTER_BLOCK => walk!(CenterBlock),
+ VERSE_BLOCK => walk!(VerseBlock),
+ COMMENT_BLOCK => walk!(CommentBlock),
+ EXAMPLE_BLOCK => walk!(ExampleBlock),
+ EXPORT_BLOCK => walk!(ExportBlock),
+ SOURCE_BLOCK => walk!(SourceBlock),
+ BABEL_CALL => walk!(BabelCall),
+ CLOCK => walk!(@Clock),
+ COOKIE => walk!(@Cookie),
+ RADIO_TARGET => walk!(RadioTarget),
+ DRAWER => walk!(Drawer),
+ DYN_BLOCK => walk!(DynBlock),
+ FN_DEF => walk!(FnDef),
+ FN_REF => walk!(FnRef),
+ MACROS => walk!(@Macros),
+ SNIPPET => walk!(@Snippet),
+ TIMESTAMP_ACTIVE | TIMESTAMP_INACTIVE | TIMESTAMP_DIARY => walk!(@Timestamp),
+ TARGET => walk!(Target),
+ COMMENT => walk!(Comment),
+ FIXED_WIDTH => walk!(FixedWidth),
+ ORG_TABLE => walk!(OrgTable),
+ ORG_TABLE_RULE_ROW | ORG_TABLE_STANDARD_ROW => walk!(OrgTableRow),
+ ORG_TABLE_CELL => walk!(OrgTableCell),
+ LINK => walk!(Link),
+ LATEX_FRAGMENT => walk!(@LatexFragment),
+ LATEX_ENVIRONMENT => walk!(@LatexEnvironment),
+ ENTITY => walk!(@Entity),
+ LINE_BREAK => walk!(@LineBreak),
+ SUPERSCRIPT => walk!(Superscript),
+ SUBSCRIPT => walk!(Subscript),
+ KEYWORD => walk!(Keyword),
+ PROPERTY_DRAWER => walk!(PropertyDrawer),
+ BLOCK_CONTENT | LIST_ITEM_CONTENT => {
+ for child in node.children_with_tokens() {
+ self.element(child, ctx);
+ take_control!();
+ }
+ }
+
+ kind => debug_assert!(
+ !kind.is_element() && !kind.is_object(),
+ "{:?} is not handled",
+ kind
+ ),
+ }
+ }
+ SyntaxElement::Token(token) => {
+ if token.kind() == TEXT {
+ self.event(Event::Text(token), ctx);
+ take_control!();
+ }
+ }
};
}
-
- /// Called when visiting any node
- fn node(&mut self, node: SyntaxNode, ctx: &mut TraversalContext) {
- macro_rules! traverse_children {
- ($node:expr) => {{
- for child in $node.children_with_tokens() {
- self.element(child, ctx);
- take_control!(ctx);
- }
- }};
- }
-
- macro_rules! traverse {
- ($node:ident, $method:ident) => {{
- debug_assert!($node::can_cast(node.kind()));
- let node = $node { syntax: node };
- self.$method(WalkEvent::Enter(&node), ctx);
- take_control!(ctx);
- traverse_children!(&node.syntax);
- self.$method(WalkEvent::Leave(&node), ctx);
- take_control!(ctx);
- }};
- }
-
- match node.kind() {
- DOCUMENT => traverse!(Document, document),
- HEADLINE => traverse!(Headline, headline),
- SECTION => traverse!(Section, section),
- PARAGRAPH => traverse!(Paragraph, paragraph),
- BOLD => traverse!(Bold, bold),
- ITALIC => traverse!(Italic, italic),
- STRIKE => traverse!(Strike, strike),
- UNDERLINE => traverse!(Underline, underline),
- LIST => traverse!(List, list),
- LIST_ITEM => traverse!(ListItem, list_item),
- CODE => traverse!(Code, code),
- INLINE_CALL => traverse!(InlineCall, inline_call),
- INLINE_SRC => traverse!(InlineSrc, inline_src),
- RULE => traverse!(Rule, rule),
- VERBATIM => traverse!(Verbatim, verbatim),
- SPECIAL_BLOCK => traverse!(SpecialBlock, special_block),
- QUOTE_BLOCK => traverse!(QuoteBlock, quote_block),
- CENTER_BLOCK => traverse!(CenterBlock, center_block),
- VERSE_BLOCK => traverse!(VerseBlock, verse_block),
- COMMENT_BLOCK => traverse!(CommentBlock, comment_block),
- EXAMPLE_BLOCK => traverse!(ExampleBlock, example_block),
- EXPORT_BLOCK => traverse!(ExportBlock, export_block),
- SOURCE_BLOCK => traverse!(SourceBlock, source_block),
- BABEL_CALL => traverse!(BabelCall, babel_call),
- CLOCK => traverse!(Clock, clock),
- COOKIE => traverse!(Cookie, cookie),
- RADIO_TARGET => traverse!(RadioTarget, radio_target),
- DRAWER => traverse!(Drawer, drawer),
- DYN_BLOCK => traverse!(DynBlock, dyn_block),
- FN_DEF => traverse!(FnDef, fn_def),
- FN_REF => traverse!(FnRef, fn_ref),
- MACROS => traverse!(Macros, macros),
- SNIPPET => traverse!(Snippet, snippet),
- TIMESTAMP_ACTIVE | TIMESTAMP_INACTIVE | TIMESTAMP_DIARY => {
- traverse!(Timestamp, timestamp)
- }
- TARGET => traverse!(Target, target),
- COMMENT => traverse!(Comment, comment),
- FIXED_WIDTH => traverse!(FixedWidth, fixed_width),
- ORG_TABLE => traverse!(OrgTable, org_table),
- ORG_TABLE_RULE_ROW | ORG_TABLE_STANDARD_ROW => traverse!(OrgTableRow, org_table_row),
- ORG_TABLE_CELL => traverse!(OrgTableCell, org_table_cell),
- LINK => traverse!(Link, link),
- LATEX_FRAGMENT => traverse!(LatexFragment, latex_fragment),
- LATEX_ENVIRONMENT => traverse!(LatexEnvironment, latex_environment),
- ENTITY => traverse!(Entity, entity),
- LINE_BREAK => traverse!(LineBreak, line_break),
- SUPERSCRIPT => traverse!(Superscript, superscript),
- SUBSCRIPT => traverse!(Subscript, subscript),
- KEYWORD => traverse!(Keyword, keyword),
- PROPERTY_DRAWER => traverse!(PropertyDrawer, property_drawer),
-
- BLOCK_CONTENT | LIST_ITEM_CONTENT => traverse_children!(node),
-
- kind => debug_assert!(
- !kind.is_element() && !kind.is_object(),
- "{:?} is not handled",
- kind
- ),
- }
- }
-
- /// Called when visiting any token
- fn token(&mut self, token: SyntaxToken, ctx: &mut TraversalContext) {
- if token.kind() == TEXT {
- self.text(token, ctx);
- }
- take_control!(ctx);
- }
-
- /// Called when visiting `Text` token
- fn text(&mut self, token: SyntaxToken, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Document` node
- fn document(&mut self, event: WalkEvent<&Document>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Headline` node
- fn headline(&mut self, event: WalkEvent<&Headline>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Paragraph` node
- fn paragraph(&mut self, event: WalkEvent<&Paragraph>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Section` node
- fn section(&mut self, event: WalkEvent<&Section>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Rule` node
- fn rule(&mut self, event: WalkEvent<&Rule>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Comment` node
- fn comment(&mut self, event: WalkEvent<&Comment>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `InlineSrc` node
- fn inline_src(&mut self, event: WalkEvent<&InlineSrc>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `InlineCall` node
- fn inline_call(&mut self, event: WalkEvent<&InlineCall>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Code` node
- fn code(&mut self, event: WalkEvent<&Code>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Bold` node
- fn bold(&mut self, event: WalkEvent<&Bold>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Verbatim` node
- fn verbatim(&mut self, event: WalkEvent<&Verbatim>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Italic` node
- fn italic(&mut self, event: WalkEvent<&Italic>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Strike` node
- fn strike(&mut self, event: WalkEvent<&Strike>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Underline` node
- fn underline(&mut self, event: WalkEvent<&Underline>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `List` node
- fn list(&mut self, event: WalkEvent<&List>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `ListItem` node
- fn list_item(&mut self, event: WalkEvent<&ListItem>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `SpecialBlock` node
- fn special_block(&mut self, event: WalkEvent<&SpecialBlock>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `QuoteBlock` node
- fn quote_block(&mut self, event: WalkEvent<&QuoteBlock>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `CenterBlock` node
- fn center_block(&mut self, event: WalkEvent<&CenterBlock>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `VerseBlock` node
- fn verse_block(&mut self, event: WalkEvent<&VerseBlock>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `CommentBlock` node
- fn comment_block(&mut self, event: WalkEvent<&CommentBlock>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `ExampleBlock` node
- fn example_block(&mut self, event: WalkEvent<&ExampleBlock>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `ExportBlock` node
- fn export_block(&mut self, event: WalkEvent<&ExportBlock>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `SourceBlock` node
- fn source_block(&mut self, event: WalkEvent<&SourceBlock>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `BabelCall` node
- fn babel_call(&mut self, event: WalkEvent<&BabelCall>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Clock` node
- fn clock(&mut self, event: WalkEvent<&Clock>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Cookie` node
- fn cookie(&mut self, event: WalkEvent<&Cookie>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `RadioTarget` node
- fn radio_target(&mut self, event: WalkEvent<&RadioTarget>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Drawer` node
- fn drawer(&mut self, event: WalkEvent<&Drawer>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `DynBlock` node
- fn dyn_block(&mut self, event: WalkEvent<&DynBlock>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `FnDef` node
- fn fn_def(&mut self, event: WalkEvent<&FnDef>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `FnRef` node
- fn fn_ref(&mut self, event: WalkEvent<&FnRef>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Macros` node
- fn macros(&mut self, event: WalkEvent<&Macros>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Snippet` node
- fn snippet(&mut self, event: WalkEvent<&Snippet>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Timestamp` node
- fn timestamp(&mut self, event: WalkEvent<&Timestamp>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Target` node
- fn target(&mut self, event: WalkEvent<&Target>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `FixedWidth` node
- fn fixed_width(&mut self, event: WalkEvent<&FixedWidth>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `OrgTable` node
- fn org_table(&mut self, event: WalkEvent<&OrgTable>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `OrgTableRow` node
- fn org_table_row(&mut self, event: WalkEvent<&OrgTableRow>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `OrgTableCell` node
- fn org_table_cell(&mut self, event: WalkEvent<&OrgTableCell>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Link` node
- fn link(&mut self, event: WalkEvent<&Link>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `LatexFragment` node
- fn latex_fragment(&mut self, event: WalkEvent<&LatexFragment>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `LatexEnvironment` node
- fn latex_environment(
- &mut self,
- event: WalkEvent<&LatexEnvironment>,
- ctx: &mut TraversalContext,
- );
- /// Called when entering or leaving `Entity` node
- fn entity(&mut self, event: WalkEvent<&Entity>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `LineBreak` node
- fn line_break(&mut self, event: WalkEvent<&LineBreak>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Superscript` node
- fn superscript(&mut self, event: WalkEvent<&Superscript>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Subscript` node
- fn subscript(&mut self, event: WalkEvent<&Subscript>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `Keyword` node
- fn keyword(&mut self, event: WalkEvent<&Keyword>, ctx: &mut TraversalContext);
- /// Called when entering or leaving `PropertyDrawer` node
- fn property_drawer(&mut self, event: WalkEvent<&PropertyDrawer>, ctx: &mut TraversalContext);
}
diff --git a/src/org.rs b/src/org.rs
index dfd088e..1a3a144 100644
--- a/src/org.rs
+++ b/src/org.rs
@@ -5,6 +5,7 @@ use crate::ast::Document;
use crate::config::ParseConfig;
use crate::export::{HtmlExport, TraversalContext, Traverser};
use crate::syntax::{OrgLanguage, SyntaxNode};
+use crate::SyntaxElement;
#[derive(Debug)]
pub struct Org {
@@ -46,9 +47,12 @@ impl Org {
}
/// Walk through org element tree using given traverser
- pub fn traverse(&self, h: &mut T) {
+ pub fn traverse(&self, t: &mut T) {
let mut ctx = TraversalContext::default();
- h.node(SyntaxNode::new_root(self.green.clone()), &mut ctx);
+ t.element(
+ SyntaxElement::Node(SyntaxNode::new_root(self.green.clone())),
+ &mut ctx,
+ );
}
/// Returns the first node in org element tree in depth first order