feat: simpify Traverser trait

This commit is contained in:
PoiScript 2023-12-05 17:32:05 +08:00
parent fd098f0cf1
commit 19c62979f0
No known key found for this signature in database
GPG key ID: 22C2B1249D99985E
7 changed files with 439 additions and 885 deletions

View file

@ -3,10 +3,7 @@
//! ```
use orgize::{
ast::Headline,
export::{HtmlExport, TraversalContext, Traverser},
forward_handler,
rowan::WalkEvent,
export::{Container, Event, HtmlExport, TraversalContext, Traverser},
Org,
};
use slugify::slugify;
@ -16,16 +13,9 @@ use std::env::args;
#[derive(Default)]
struct MyHtmlHandler(pub HtmlExport);
// AsMut trait is required for using forward_handler macros
impl AsMut<HtmlExport> for MyHtmlHandler {
fn as_mut(&mut self) -> &mut HtmlExport {
&mut self.0
}
}
impl Traverser for MyHtmlHandler {
fn headline(&mut self, event: WalkEvent<&Headline>, ctx: &mut TraversalContext) {
if let WalkEvent::Enter(headline) = event {
fn event(&mut self, event: Event, ctx: &mut TraversalContext) {
if let Event::Enter(Container::Headline(headline)) = event {
let level = min(headline.level(), 6);
let title = headline.title().map(|e| e.to_string()).collect::<String>();
self.0.push_str(format!(
@ -36,18 +26,11 @@ impl Traverser for MyHtmlHandler {
self.element(elem, ctx);
}
self.0.push_str(format!("</a></h{level}>"));
} else {
// forwrad to default html export
self.0.event(event, ctx);
}
}
forward_handler! {
HtmlExport,
link text document paragraph section rule comment
inline_src inline_call code bold verbatim italic strike underline list list_item
special_block quote_block center_block verse_block comment_block example_block export_block
source_block babel_call clock cookie radio_target drawer dyn_block fn_def fn_ref macros
snippet timestamp target fixed_width org_table org_table_row org_table_cell latex_fragment
latex_environment entity line_break superscript subscript keyword property_drawer
}
}
fn main() {

70
src/export/event.rs Normal file
View file

@ -0,0 +1,70 @@
use crate::{ast::*, SyntaxToken};
#[non_exhaustive]
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Container {
Document(Document),
Section(Section),
Paragraph(Paragraph),
Headline(Headline),
OrgTable(OrgTable),
OrgTableRow(OrgTableRow),
OrgTableCell(OrgTableCell),
TableEl(TableEl),
List(List),
ListItem(ListItem),
Drawer(Drawer),
DynBlock(DynBlock),
FnDef(FnDef),
Comment(Comment),
FixedWidth(FixedWidth),
SpecialBlock(SpecialBlock),
QuoteBlock(QuoteBlock),
CenterBlock(CenterBlock),
VerseBlock(VerseBlock),
CommentBlock(CommentBlock),
ExampleBlock(ExampleBlock),
ExportBlock(ExportBlock),
SourceBlock(SourceBlock),
Link(Link),
RadioTarget(RadioTarget),
FnRef(FnRef),
Target(Target),
Bold(Bold),
Strike(Strike),
Italic(Italic),
Underline(Underline),
Verbatim(Verbatim),
Code(Code),
Superscript(Superscript),
Subscript(Subscript),
BabelCall(BabelCall),
PropertyDrawer(PropertyDrawer),
AffiliatedKeyword(AffiliatedKeyword),
Keyword(Keyword),
}
#[non_exhaustive]
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Event {
Enter(Container),
Leave(Container),
Text(SyntaxToken),
Macros(Macros),
Cookie(Cookie),
InlineCall(InlineCall),
InlineSrc(InlineSrc),
Clock(Clock),
LineBreak(LineBreak),
Snippet(Snippet),
Rule(Rule),
Timestamp(Timestamp),
LatexFragment(LatexFragment),
LatexEnvironment(LatexEnvironment),
Entity(Entity),
}

View file

@ -1,224 +0,0 @@
/// Forward traverser method implement to other
///
/// Used to "extend" some builtin traverser like `HtmlExport`.
///
/// ```rust
/// use orgize::{
/// ast::Headline,
/// export::{HtmlExport, TraversalContext, Traverser},
/// forward_handler,
/// rowan::{ast::AstNode, WalkEvent},
/// Org,
/// };
/// use slugify::slugify;
/// use std::cmp::min;
///
/// #[derive(Default)]
/// struct SlugifyTitleHandler(pub HtmlExport);
///
/// // AsMut trait is required
/// impl AsMut<HtmlExport> for SlugifyTitleHandler {
/// fn as_mut(&mut self) -> &mut HtmlExport {
/// &mut self.0
/// }
/// }
///
/// impl Traverser for SlugifyTitleHandler {
/// fn headline(&mut self, event: WalkEvent<&Headline>, ctx: &mut TraversalContext) {
/// if let WalkEvent::Enter(headline) = event {
/// let level = min(headline.level(), 6);
/// let title = headline.title().map(|e| e.to_string()).collect::<String>();
/// self.0.push_str(format!(
/// "<h{level}><a id=\"{0}\" href=\"#{0}\">",
/// slugify!(&title)
/// ));
/// for elem in headline.title() {
/// self.element(elem, ctx);
/// }
/// self.0.push_str(format!("</a></h{level}>"));
/// }
/// }
///
/// forward_handler! {
/// HtmlExport,
/// link text document paragraph section rule comment
/// inline_src inline_call code bold verbatim italic strike underline list list_item
/// special_block quote_block center_block verse_block comment_block example_block export_block
/// source_block babel_call clock cookie radio_target drawer dyn_block fn_def fn_ref macros
/// snippet timestamp target fixed_width org_table org_table_row org_table_cell latex_fragment
/// latex_environment entity line_break superscript subscript keyword property_drawer
/// }
/// }
///
/// let mut handler = SlugifyTitleHandler::default();
/// Org::parse("* hello world!").traverse(&mut handler);
/// assert_eq!(handler.0.finish(), r##"<main><h1><a id="hello-world" href="#hello-world">hello world!</a></h1></main>"##);
/// ```
#[macro_export(local_inner_macros)]
macro_rules! forward_handler {
($handler:ty, $($func:ident)*) => {
$(
forward_handler!(@method $handler, $func);
)*
};
(@method $handler:ty, text) => {
forward_handler!(@method $handler, text, $crate::SyntaxToken);
};
(@method $handler:ty, document) => {
forward_handler!(@method $handler, document, WalkEvent<&$crate::ast::Document>);
};
(@method $handler:ty, headline) => {
forward_handler!(@method $handler, headline, WalkEvent<&$crate::ast::Headline>);
};
(@method $handler:ty, paragraph) => {
forward_handler!(@method $handler, paragraph, WalkEvent<&$crate::ast::Paragraph>);
};
(@method $handler:ty, section) => {
forward_handler!(@method $handler, section, WalkEvent<&$crate::ast::Section>);
};
(@method $handler:ty, rule) => {
forward_handler!(@method $handler, rule, WalkEvent<&$crate::ast::Rule>);
};
(@method $handler:ty, comment) => {
forward_handler!(@method $handler, comment, WalkEvent<&$crate::ast::Comment>);
};
(@method $handler:ty, inline_src) => {
forward_handler!(@method $handler, inline_src, WalkEvent<&$crate::ast::InlineSrc>);
};
(@method $handler:ty, inline_call) => {
forward_handler!(@method $handler, inline_call, WalkEvent<&$crate::ast::InlineCall>);
};
(@method $handler:ty, code) => {
forward_handler!(@method $handler, code, WalkEvent<&$crate::ast::Code>);
};
(@method $handler:ty, bold) => {
forward_handler!(@method $handler, bold, WalkEvent<&$crate::ast::Bold>);
};
(@method $handler:ty, verbatim) => {
forward_handler!(@method $handler, verbatim, WalkEvent<&$crate::ast::Verbatim>);
};
(@method $handler:ty, italic) => {
forward_handler!(@method $handler, italic, WalkEvent<&$crate::ast::Italic>);
};
(@method $handler:ty, strike) => {
forward_handler!(@method $handler, strike, WalkEvent<&$crate::ast::Strike>);
};
(@method $handler:ty, underline) => {
forward_handler!(@method $handler, underline, WalkEvent<&$crate::ast::Underline>);
};
(@method $handler:ty, list) => {
forward_handler!(@method $handler, list, WalkEvent<&$crate::ast::List>);
};
(@method $handler:ty, list_item) => {
forward_handler!(@method $handler, list_item, WalkEvent<&$crate::ast::ListItem>);
};
(@method $handler:ty, special_block) => {
forward_handler!(@method $handler, special_block, WalkEvent<&$crate::ast::SpecialBlock>);
};
(@method $handler:ty, quote_block) => {
forward_handler!(@method $handler, quote_block, WalkEvent<&$crate::ast::QuoteBlock>);
};
(@method $handler:ty, center_block) => {
forward_handler!(@method $handler, center_block, WalkEvent<&$crate::ast::CenterBlock>);
};
(@method $handler:ty, verse_block) => {
forward_handler!(@method $handler, verse_block, WalkEvent<&$crate::ast::VerseBlock>);
};
(@method $handler:ty, comment_block) => {
forward_handler!(@method $handler, comment_block, WalkEvent<&$crate::ast::CommentBlock>);
};
(@method $handler:ty, example_block) => {
forward_handler!(@method $handler, example_block, WalkEvent<&$crate::ast::ExampleBlock>);
};
(@method $handler:ty, export_block) => {
forward_handler!(@method $handler, export_block, WalkEvent<&$crate::ast::ExportBlock>);
};
(@method $handler:ty, source_block) => {
forward_handler!(@method $handler, source_block, WalkEvent<&$crate::ast::SourceBlock>);
};
(@method $handler:ty, babel_call) => {
forward_handler!(@method $handler, babel_call, WalkEvent<&$crate::ast::BabelCall>);
};
(@method $handler:ty, clock) => {
forward_handler!(@method $handler, clock, WalkEvent<&$crate::ast::Clock>);
};
(@method $handler:ty, cookie) => {
forward_handler!(@method $handler, cookie, WalkEvent<&$crate::ast::Cookie>);
};
(@method $handler:ty, radio_target) => {
forward_handler!(@method $handler, radio_target, WalkEvent<&$crate::ast::RadioTarget>);
};
(@method $handler:ty, drawer) => {
forward_handler!(@method $handler, drawer, WalkEvent<&$crate::ast::Drawer>);
};
(@method $handler:ty, dyn_block) => {
forward_handler!(@method $handler, dyn_block, WalkEvent<&$crate::ast::DynBlock>);
};
(@method $handler:ty, fn_def) => {
forward_handler!(@method $handler, fn_def, WalkEvent<&$crate::ast::FnDef>);
};
(@method $handler:ty, fn_ref) => {
forward_handler!(@method $handler, fn_ref, WalkEvent<&$crate::ast::FnRef>);
};
(@method $handler:ty, macros) => {
forward_handler!(@method $handler, macros, WalkEvent<&$crate::ast::Macros>);
};
(@method $handler:ty, snippet) => {
forward_handler!(@method $handler, snippet, WalkEvent<&$crate::ast::Snippet>);
};
(@method $handler:ty, timestamp) => {
forward_handler!(@method $handler, timestamp, WalkEvent<&$crate::ast::Timestamp>);
};
(@method $handler:ty, target) => {
forward_handler!(@method $handler, target, WalkEvent<&$crate::ast::Target>);
};
(@method $handler:ty, fixed_width) => {
forward_handler!(@method $handler, fixed_width, WalkEvent<&$crate::ast::FixedWidth>);
};
(@method $handler:ty, org_table) => {
forward_handler!(@method $handler, org_table, WalkEvent<&$crate::ast::OrgTable>);
};
(@method $handler:ty, org_table_row) => {
forward_handler!(@method $handler, org_table_row, WalkEvent<&$crate::ast::OrgTableRow>);
};
(@method $handler:ty, org_table_cell) => {
forward_handler!(@method $handler, org_table_cell, WalkEvent<&$crate::ast::OrgTableCell>);
};
(@method $handler:ty, link) => {
forward_handler!(@method $handler, link, WalkEvent<&$crate::ast::Link>);
};
(@method $handler:ty, latex_fragment) => {
forward_handler!(@method $handler, latex_fragment, WalkEvent<&$crate::ast::LatexFragment>);
};
(@method $handler:ty, latex_environment) => {
forward_handler!(@method $handler, latex_environment, WalkEvent<&$crate::ast::LatexEnvironment>);
};
(@method $handler:ty, entity) => {
forward_handler!(@method $handler, entity, WalkEvent<&$crate::ast::Entity>);
};
(@method $handler:ty, line_break) => {
forward_handler!(@method $handler, line_break, WalkEvent<&$crate::ast::LineBreak>);
};
(@method $handler:ty, superscript) => {
forward_handler!(@method $handler, superscript, WalkEvent<&$crate::ast::Superscript>);
};
(@method $handler:ty, subscript) => {
forward_handler!(@method $handler, subscript, WalkEvent<&$crate::ast::Subscript>);
};
(@method $handler:ty, keyword) => {
forward_handler!(@method $handler, keyword, WalkEvent<&$crate::ast::Keyword>);
};
(@method $handler:ty, property_drawer) => {
forward_handler!(@method $handler, property_drawer, WalkEvent<&$crate::ast::PropertyDrawer>);
};
(@method $handler:ty, $x:ident) => {
std::compile_error!(std::concat!(std::stringify!($x), " is not a method"));
};
(@method $handler:ty, $name:ident, $type:ty) => {
fn $name(&mut self, item: $type, ctx: &mut $crate::export::TraversalContext) {
<Self as AsMut<$handler>>::as_mut(self).$name(item, ctx)
}
};
}

View file

@ -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(_) => "<main>",
WalkEvent::Leave(_) => "</main>",
};
}
#[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 += "<main>",
Event::Leave(Container::Document(_)) => self.output += "</main>",
Event::Enter(Container::Headline(headline)) => {
let level = min(headline.level(), 6);
let _ = write!(&mut self.output, "<h{level}>");
for elem in headline.title() {
self.element(elem, ctx);
}
let _ = write!(&mut self.output, "</h{level}>");
}
Event::Leave(Container::Headline(_)) => {}
Event::Enter(Container::Paragraph(_)) => self.output += "<p>",
Event::Leave(Container::Paragraph(_)) => self.output += "</p>",
Event::Enter(Container::Section(_)) => self.output += "<section>",
Event::Leave(Container::Section(_)) => self.output += "</section>",
Event::Enter(Container::Italic(_)) => self.output += "<i>",
Event::Leave(Container::Italic(_)) => self.output += "</i>",
Event::Enter(Container::Bold(_)) => self.output += "<b>",
Event::Leave(Container::Bold(_)) => self.output += "</b>",
Event::Enter(Container::Strike(_)) => self.output += "<s>",
Event::Leave(Container::Strike(_)) => self.output += "</s>",
Event::Enter(Container::Underline(_)) => self.output += "<u>",
Event::Leave(Container::Underline(_)) => self.output += "</u>",
Event::Enter(Container::Verbatim(_)) => self.output += "<code>",
Event::Leave(Container::Verbatim(_)) => self.output += "</code>",
Event::Enter(Container::Code(_)) => self.output += "<code>",
Event::Leave(Container::Code(_)) => self.output += "</code>",
Event::Enter(Container::QuoteBlock(_)) => self.output += "<blockquote>",
Event::Leave(Container::QuoteBlock(_)) => self.output += "</blockquote>",
Event::Enter(Container::VerseBlock(_)) => self.output += "<p class=\"verse\">",
Event::Leave(Container::VerseBlock(_)) => self.output += "</p>",
Event::Enter(Container::ExampleBlock(_)) => self.output += "<pre class=\"example\">",
Event::Leave(Container::ExampleBlock(_)) => self.output += "</pre>",
Event::Enter(Container::CenterBlock(_)) => self.output += "<div class=\"center\">",
Event::Leave(Container::CenterBlock(_)) => self.output += "</div>",
Event::Enter(Container::CommentBlock(_)) => self.output += "<!--",
Event::Leave(Container::CommentBlock(_)) => self.output += "-->",
Event::Enter(Container::Comment(_)) => self.output += "<!--",
Event::Leave(Container::Comment(_)) => self.output += "-->",
Event::Enter(Container::Subscript(_)) => self.output += "<sub>",
Event::Leave(Container::Subscript(_)) => self.output += "</sub>",
Event::Enter(Container::Superscript(_)) => self.output += "<sup>",
Event::Leave(Container::Superscript(_)) => self.output += "</sup>",
Event::Enter(Container::List(list)) => {
self.output += if list.is_ordered() {
self.in_descriptive_list.push(false);
"<ol>"
@ -105,7 +151,7 @@ impl Traverser for HtmlExport {
"<ul>"
};
}
WalkEvent::Leave(list) => {
Event::Leave(Container::List(list)) => {
self.output += if list.is_ordered() {
"</ol>"
} 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 += "<dt>";
for elem in item.tag() {
for elem in list_item.tag() {
self.element(elem, ctx);
}
self.output += "</dt><dd>";
} else {
self.output += "<li>";
}
}
Event::Leave(Container::ListItem(_)) => {
if let Some(&true) = self.in_descriptive_list.last() {
self.output += "</dd>";
} else {
self.output += "</li>";
}
WalkEvent::Leave(_) => self.output += "</dd>",
};
} else {
match event {
WalkEvent::Enter(_) => self.output += "<li>",
WalkEvent::Leave(_) => self.output += "</li>",
};
}
}
#[tracing::instrument(skip(self, _ctx))]
fn paragraph(&mut self, event: WalkEvent<&Paragraph>, _ctx: &mut TraversalContext) {
self.output += match event {
WalkEvent::Enter(_) => "<p>",
WalkEvent::Leave(_) => "</p>",
};
}
#[tracing::instrument(skip(self, _ctx))]
fn section(&mut self, event: WalkEvent<&Section>, _ctx: &mut TraversalContext) {
self.output += match event {
WalkEvent::Enter(_) => "<section>",
WalkEvent::Leave(_) => "</section>",
};
}
#[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(_) => "<i>",
WalkEvent::Leave(_) => "</i>",
};
}
Event::Enter(Container::OrgTable(table)) => {
self.output += "<table>";
self.table_row = if table.has_header() {
TableRow::HeaderRule
} else {
TableRow::BodyRule
}
}
Event::Leave(Container::OrgTable(_)) => {
match self.table_row {
TableRow::Body => self.output += "</tbody>",
TableRow::Header => self.output += "</thead>",
_ => {}
}
self.output += "</table>";
}
Event::Enter(Container::OrgTableRow(row)) => {
if row.is_rule() {
match self.table_row {
TableRow::Body => {
self.output += "</tbody>";
self.table_row = TableRow::BodyRule;
}
TableRow::Header => {
self.output += "</thead>";
self.table_row = TableRow::BodyRule;
}
_ => {}
}
ctx.skip();
} else {
match self.table_row {
TableRow::HeaderRule => {
self.table_row = TableRow::Header;
self.output += "<thead>";
}
TableRow::BodyRule => {
self.table_row = TableRow::Body;
self.output += "<tbody>";
}
_ => {}
}
self.output += "<tr>";
}
}
Event::Leave(Container::OrgTableRow(row)) => {
if row.is_rule() {
match self.table_row {
TableRow::Body => {
self.output += "</tbody>";
self.table_row = TableRow::BodyRule;
}
TableRow::Header => {
self.output += "</thead>";
self.table_row = TableRow::BodyRule;
}
_ => {}
}
ctx.skip();
} else {
self.output += "</tr>";
}
}
Event::Enter(Container::OrgTableCell(_)) => self.output += "<td>",
Event::Leave(Container::OrgTableCell(_)) => self.output += "</td>",
#[tracing::instrument(skip(self, _ctx))]
fn bold(&mut self, event: WalkEvent<&Bold>, _ctx: &mut TraversalContext) {
self.output += match event {
WalkEvent::Enter(_) => "<b>",
WalkEvent::Leave(_) => "</b>",
};
}
#[tracing::instrument(skip(self, _ctx))]
fn strike(&mut self, event: WalkEvent<&Strike>, _ctx: &mut TraversalContext) {
self.output += match event {
WalkEvent::Enter(_) => "<s>",
WalkEvent::Leave(_) => "</s>",
};
}
#[tracing::instrument(skip(self, _ctx))]
fn underline(&mut self, event: WalkEvent<&Underline>, _ctx: &mut TraversalContext) {
self.output += match event {
WalkEvent::Enter(_) => "<u>",
WalkEvent::Leave(_) => "</u>",
};
}
#[tracing::instrument(skip(self, _ctx))]
fn verbatim(&mut self, event: WalkEvent<&Verbatim>, _ctx: &mut TraversalContext) {
self.output += match event {
WalkEvent::Enter(_) => "<code>",
WalkEvent::Leave(_) => "</code>",
};
}
#[tracing::instrument(skip(self, _ctx))]
fn code(&mut self, event: WalkEvent<&Code>, _ctx: &mut TraversalContext) {
self.output += match event {
WalkEvent::Enter(_) => "<code>",
WalkEvent::Leave(_) => "</code>",
};
}
#[tracing::instrument(skip(self, ctx))]
fn rule(&mut self, event: WalkEvent<&Rule>, ctx: &mut TraversalContext) {
if let WalkEvent::Enter(_) = event {
self.output += "<hr/>"
};
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, "{}</a>", HtmlEscape(&path));
return ctx.skip();
ctx.skip();
}
}
WalkEvent::Leave(_) => {
self.output += "</a>";
Event::Leave(Container::Link(_)) => self.output += "</a>",
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(_) => "<blockquote>",
WalkEvent::Leave(_) => "</blockquote>",
};
}
Event::LineBreak(_) => self.output += "<br/>",
#[tracing::instrument(skip(self, _ctx))]
fn verse_block(&mut self, event: WalkEvent<&VerseBlock>, _ctx: &mut TraversalContext) {
self.output += match event {
WalkEvent::Enter(_) => "<p class=\"verse\">",
WalkEvent::Leave(_) => "</p>",
};
}
#[tracing::instrument(skip(self, _ctx))]
fn example_block(&mut self, event: WalkEvent<&ExampleBlock>, _ctx: &mut TraversalContext) {
self.output += match event {
WalkEvent::Enter(_) => "<pre class=\"example\">",
WalkEvent::Leave(_) => "</pre>",
};
}
#[tracing::instrument(skip(self, _ctx))]
fn center_block(&mut self, event: WalkEvent<&CenterBlock>, _ctx: &mut TraversalContext) {
self.output += match event {
WalkEvent::Enter(_) => "<div class=\"center\">",
WalkEvent::Leave(_) => "</div>",
};
}
#[tracing::instrument(skip(self, _ctx))]
fn org_table(&mut self, event: WalkEvent<&OrgTable>, _ctx: &mut TraversalContext) {
match event {
WalkEvent::Enter(table) => {
self.output += "<table>";
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 += "</tbody>",
TableRow::Header => self.output += "</thead>",
_ => {}
}
self.output += "</table>";
}
}
}
#[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 += "</tbody>";
self.table_row = TableRow::BodyRule;
}
TableRow::Header => {
self.output += "</thead>";
self.table_row = TableRow::BodyRule;
}
_ => {}
}
return ctx.skip();
}
Event::Rule(_) => self.output += "<hr/>",
match event {
WalkEvent::Enter(_) => {
match self.table_row {
TableRow::HeaderRule => {
self.table_row = TableRow::Header;
self.output += "<thead>";
Event::Timestamp(timestamp) => {
self.output += r#"<span class="timestamp-wrapper"><span class="timestamp">"#;
for e in timestamp.syntax.children_with_tokens() {
match e {
NodeOrToken::Token(t) if t.kind() == SyntaxKind::MINUS2 => {
self.output += "&#x2013;";
}
NodeOrToken::Token(t) => {
self.output += t.text();
}
_ => {}
}
TableRow::BodyRule => {
self.table_row = TableRow::Body;
self.output += "<tbody>";
}
_ => {}
}
self.output += "<tr>";
self.output += r#"</span></span>"#;
}
WalkEvent::Leave(_) => {
self.output += "</tr>";
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(_) => "<td>",
WalkEvent::Leave(_) => "</td>",
};
}
#[tracing::instrument(skip(self, _ctx))]
fn comment(&mut self, event: WalkEvent<&Comment>, _ctx: &mut TraversalContext) {
self.output += match event {
WalkEvent::Enter(_) => "<!--",
WalkEvent::Leave(_) => "-->",
};
}
#[tracing::instrument(skip(self, _ctx))]
fn comment_block(&mut self, event: WalkEvent<&CommentBlock>, _ctx: &mut TraversalContext) {
self.output += match event {
WalkEvent::Enter(_) => "<!--",
WalkEvent::Leave(_) => "-->",
};
}
#[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, "<h{level}>");
for elem in headline.title() {
self.element(elem, ctx);
Event::LatexEnvironment(latex) => {
let _ = write!(&mut self.output, "{}", &latex.syntax);
}
let _ = write!(&mut self.output, "</h{level}>");
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#"<span class="timestamp-wrapper"><span class="timestamp">"#;
for e in t.syntax.children_with_tokens() {
match e {
NodeOrToken::Token(t) if t.kind() == SyntaxKind::MINUS2 => {
self.output += "&#x2013;";
}
NodeOrToken::Token(t) => {
self.output += t.text();
}
_ => {}
}
}
self.output += r#"</span></span>"#;
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 += "<br/>";
ctx.skip();
}
}
#[tracing::instrument(skip(self, _ctx))]
fn subscript(&mut self, event: WalkEvent<&Subscript>, _ctx: &mut TraversalContext) {
match event {
WalkEvent::Enter(_) => self.output += "<sub>",
WalkEvent::Leave(_) => self.output += "</sub>",
}
}
#[tracing::instrument(skip(self, _ctx))]
fn superscript(&mut self, event: WalkEvent<&Superscript>, _ctx: &mut TraversalContext) {
match event {
WalkEvent::Enter(_) => self.output += "<sup>",
WalkEvent::Leave(_) => self.output += "</sup>",
}
}
#[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()
}
}

View file

@ -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};

View file

@ -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::<String>();
/// self.0.push_str(&format!("<a href='#{}'>", slugify!(&title)));
/// for elem in headline.title() {
/// self.element(elem, ctx);
/// }
/// self.0.push_str("</a>");
/// if headline.headlines().count() > 0 {
/// self.0.push_str("<ul>");
/// }
/// }
/// Event::Leave(Container::Headline(headline)) => {
/// if headline.headlines().count() > 0 {
/// self.0.push_str("</ul>");
/// }
/// }
/// 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(), "\
/// <a href='#heading-1'>heading 1</a>\
/// <ul><a href='#heading-1-1'>heading 1.1</a><a href='#heading-1-2'>heading 1.2</a></ul>\
/// <a href='#heading-2'>heading 2</a>\
/// <a href='#heading-3'>heading 3</a>\
/// <ul><a href='#heading-3-1'>heading 3.1</a></ul>");
/// ```
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);
}

View file

@ -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<T: Traverser>(&self, h: &mut T) {
pub fn traverse<T: Traverser>(&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