From 12bee6fb6bd6ff57c604b662fb265390cc7e77e7 Mon Sep 17 00:00:00 2001 From: PoiScript Date: Sat, 18 Nov 2023 22:37:47 +0800 Subject: [PATCH] refactor: remove HeadlineTitle, ListItemTag, ListItemContent --- examples/html-slugify.rs | 38 ++++++----- src/ast/generate.js | 2 - src/ast/generated.rs | 137 --------------------------------------- src/ast/headline.rs | 36 ++++++++-- src/ast/list.rs | 134 ++++++++++++++++++++++++-------------- src/export/forward.rs | 134 ++++++++++++++++++-------------------- src/export/html.rs | 78 ++++++++++------------ src/export/traverse.rs | 27 +++----- 8 files changed, 240 insertions(+), 346 deletions(-) diff --git a/examples/html-slugify.rs b/examples/html-slugify.rs index 672ac09..5909731 100644 --- a/examples/html-slugify.rs +++ b/examples/html-slugify.rs @@ -3,12 +3,13 @@ //! ``` use orgize::{ - ast::HeadlineTitle, + ast::Headline, export::{HtmlExport, TraversalContext, Traverser}, forward_handler, - rowan::{ast::AstNode, WalkEvent}, + rowan::WalkEvent, Org, }; +use rowan::NodeOrToken; use slugify::slugify; use std::cmp::min; use std::env::args; @@ -24,30 +25,31 @@ impl AsMut for MyHtmlHandler { } impl Traverser for MyHtmlHandler { - fn headline_title(&mut self, event: WalkEvent<&HeadlineTitle>, _ctx: &mut TraversalContext) { - match event { - WalkEvent::Enter(title) => { - let level = title.headline().map(|h| min(h.level(), 6)).unwrap_or(1); - let raw = title.syntax().to_string(); - self.0.push_str(format!( - "", - slugify!(&raw) - )); - } - WalkEvent::Leave(title) => { - let level = title.headline().map(|h| min(h.level(), 6)).unwrap_or(1); - self.0.push_str(format!("")); + 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::(); + self.0.push_str(format!( + "", + slugify!(&title) + )); + for elem in headline.title() { + match elem { + NodeOrToken::Node(node) => self.node(node, ctx), + NodeOrToken::Token(token) => self.token(token, ctx), + } } + self.0.push_str(format!("")); } } forward_handler! { HtmlExport, - link text document headline paragraph section rule comment - inline_src inline_call code bold verbatim italic strike underline list list_item list_item_tag + 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 list_item_content + snippet timestamp target fixed_width org_table org_table_row org_table_cell } } diff --git a/src/ast/generate.js b/src/ast/generate.js index 8aca5bd..bd9ff54 100644 --- a/src/ast/generate.js +++ b/src/ast/generate.js @@ -25,7 +25,6 @@ const nodes = [ struct: "Headline", kind: ["HEADLINE"], first_child: [ - ["title", "HeadlineTitle"], ["section", "Section"], ["planning", "Planning"], ], @@ -74,7 +73,6 @@ const nodes = [ { struct: "ListItem", kind: ["LIST_ITEM"], - first_child: [["content", "ListItemContent"]], }, { struct: "Drawer", diff --git a/src/ast/generated.rs b/src/ast/generated.rs index 90c2554..68c796d 100644 --- a/src/ast/generated.rs +++ b/src/ast/generated.rs @@ -157,9 +157,6 @@ impl Headline { pub fn keyword(&self) -> Option { support::token(&self.syntax, HEADLINE_KEYWORD) } - pub fn title(&self) -> Option { - support::child(&self.syntax) - } pub fn section(&self) -> Option
{ support::child(&self.syntax) } @@ -449,115 +446,6 @@ impl ListItem { pub fn end(&self) -> u32 { self.syntax.text_range().end().into() } - pub fn indent(&self) -> Option { - support::token(&self.syntax, LIST_ITEM_INDENT) - } - pub fn bullet(&self) -> Option { - support::token(&self.syntax, LIST_ITEM_BULLET) - } - pub fn content(&self) -> Option { - support::child(&self.syntax) - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ListItemIndent { - pub(crate) syntax: SyntaxNode, -} -impl AstNode for ListItemIndent { - type Language = OrgLanguage; - fn can_cast(kind: SyntaxKind) -> bool { - kind == LIST_ITEM_INDENT - } - fn cast(node: SyntaxNode) -> Option { - Self::can_cast(node.kind()).then(|| ListItemIndent { syntax: node }) - } - fn syntax(&self) -> &SyntaxNode { - &self.syntax - } -} -impl ListItemIndent { - pub fn begin(&self) -> u32 { - self.syntax.text_range().start().into() - } - pub fn end(&self) -> u32 { - self.syntax.text_range().end().into() - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ListItemTag { - pub(crate) syntax: SyntaxNode, -} -impl AstNode for ListItemTag { - type Language = OrgLanguage; - fn can_cast(kind: SyntaxKind) -> bool { - kind == LIST_ITEM_TAG - } - fn cast(node: SyntaxNode) -> Option { - Self::can_cast(node.kind()).then(|| ListItemTag { syntax: node }) - } - fn syntax(&self) -> &SyntaxNode { - &self.syntax - } -} -impl ListItemTag { - pub fn begin(&self) -> u32 { - self.syntax.text_range().start().into() - } - pub fn end(&self) -> u32 { - self.syntax.text_range().end().into() - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ListItemBullet { - pub(crate) syntax: SyntaxNode, -} -impl AstNode for ListItemBullet { - type Language = OrgLanguage; - fn can_cast(kind: SyntaxKind) -> bool { - kind == LIST_ITEM_BULLET - } - fn cast(node: SyntaxNode) -> Option { - Self::can_cast(node.kind()).then(|| ListItemBullet { syntax: node }) - } - fn syntax(&self) -> &SyntaxNode { - &self.syntax - } -} -impl ListItemBullet { - pub fn begin(&self) -> u32 { - self.syntax.text_range().start().into() - } - pub fn end(&self) -> u32 { - self.syntax.text_range().end().into() - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ListItemContent { - pub(crate) syntax: SyntaxNode, -} -impl AstNode for ListItemContent { - type Language = OrgLanguage; - fn can_cast(kind: SyntaxKind) -> bool { - kind == LIST_ITEM_CONTENT - } - fn cast(node: SyntaxNode) -> Option { - Self::can_cast(node.kind()).then(|| ListItemContent { syntax: node }) - } - fn syntax(&self) -> &SyntaxNode { - &self.syntax - } -} -impl ListItemContent { - pub fn begin(&self) -> u32 { - self.syntax.text_range().start().into() - } - pub fn end(&self) -> u32 { - self.syntax.text_range().end().into() - } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -1452,31 +1340,6 @@ impl FnRef { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct LatexEnvironment { - pub(crate) syntax: SyntaxNode, -} -impl AstNode for LatexEnvironment { - type Language = OrgLanguage; - fn can_cast(kind: SyntaxKind) -> bool { - kind == LATEX_ENVIRONMENT - } - fn cast(node: SyntaxNode) -> Option { - Self::can_cast(node.kind()).then(|| LatexEnvironment { syntax: node }) - } - fn syntax(&self) -> &SyntaxNode { - &self.syntax - } -} -impl LatexEnvironment { - pub fn begin(&self) -> u32 { - self.syntax.text_range().start().into() - } - pub fn end(&self) -> u32 { - self.syntax.text_range().end().into() - } -} - #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Macros { pub(crate) syntax: SyntaxNode, diff --git a/src/ast/headline.rs b/src/ast/headline.rs index cc274ed..296f699 100644 --- a/src/ast/headline.rs +++ b/src/ast/headline.rs @@ -1,4 +1,7 @@ -use crate::syntax::{SyntaxKind, SyntaxToken}; +use crate::{ + syntax::{SyntaxKind, SyntaxToken}, + SyntaxElement, +}; use super::{filter_token, Headline, Timestamp}; @@ -24,6 +27,21 @@ impl Headline { }) } + /// ```rust + /// use orgize::{Org, ast::Headline}; + /// + /// let hdl = Org::parse("*** abc *abc* /abc/ :tag:").first_node::().unwrap(); + /// let title = hdl.title().map(|n| n.to_string()).collect::(); + /// assert_eq!(title, "abc *abc* /abc/ "); + /// ``` + pub fn title(&self) -> impl Iterator { + self.syntax + .children() + .find(|n| n.kind() == SyntaxKind::HEADLINE_TITLE) + .into_iter() + .flat_map(|n| n.children_with_tokens()) + } + /// Return `true` if this headline contains a COMMENT keyword /// /// ```rust @@ -38,12 +56,16 @@ impl Headline { /// ``` pub fn is_commented(&self) -> bool { self.title() - .and_then(|title| title.syntax.first_token()) - .map(|title| { - let text = title.text(); - title.kind() == SyntaxKind::TEXT - && text.starts_with("COMMENT") - && (text.len() == 7 || text[7..].starts_with(char::is_whitespace)) + .next() + .map(|first| { + if let Some(t) = first.as_token() { + let text = t.text(); + t.kind() == SyntaxKind::TEXT + && text.starts_with("COMMENT") + && (text.len() == 7 || text[7..].starts_with(char::is_whitespace)) + } else { + false + } }) .unwrap_or_default() } diff --git a/src/ast/list.rs b/src/ast/list.rs index 5a694c7..24e8258 100644 --- a/src/ast/list.rs +++ b/src/ast/list.rs @@ -1,55 +1,7 @@ -use super::{filter_token, List}; +use super::{filter_token, List, ListItem}; use crate::{syntax::SyntaxKind, SyntaxElement, SyntaxToken}; impl List { - pub fn indent(&self) -> usize { - self.syntax - .children_with_tokens() - .find_map(filter_token(SyntaxKind::LIST_ITEM_INDENT)) - .map(|t| t.text().len()) - .unwrap_or_else(|| { - debug_assert!(false, "list must contains indent token"); - 0 - }) - } - - pub fn bullet(&self) -> Option { - self.syntax - .children_with_tokens() - .find_map(filter_token(SyntaxKind::LIST_ITEM_BULLET)) - } - - pub fn checkbox(&self) -> Option { - self.syntax - .children() - .find(|n| n.kind() == SyntaxKind::LIST_ITEM_CHECK_BOX) - .and_then(|n| { - n.children_with_tokens() - .find_map(filter_token(SyntaxKind::TEXT)) - }) - } - - pub fn counter(&self) -> Option { - self.syntax - .children() - .find(|n| n.kind() == SyntaxKind::LIST_ITEM_COUNTER) - .and_then(|n| { - n.children_with_tokens() - .find_map(filter_token(SyntaxKind::TEXT)) - }) - } - - pub fn tag(&self) -> impl Iterator { - self.syntax - .children() - .find(|n| n.kind() == SyntaxKind::LIST_ITEM_TAG) - .into_iter() - .flat_map(|n| { - n.children_with_tokens() - .filter(|n| n.kind() != SyntaxKind::COLON2) - }) - } - /// Returns `true` if this list is an ordered link /// /// ```rust @@ -93,3 +45,87 @@ impl List { .unwrap_or_default() } } + +impl ListItem { + /// ```rust + /// use orgize::{Org, ast::ListItem}; + /// + /// let item = Org::parse("- 1").first_node::().unwrap(); + /// assert_eq!(item.indent(), 0); + /// let item = Org::parse(" \t * 2").first_node::().unwrap(); + /// assert_eq!(item.indent(), 3); + /// ``` + pub fn indent(&self) -> usize { + self.syntax + .children_with_tokens() + .find_map(filter_token(SyntaxKind::LIST_ITEM_INDENT)) + .map(|t| t.text().len()) + .unwrap_or_else(|| { + debug_assert!(false, "list must contains indent token"); + 0 + }) + } + + /// ```rust + /// use orgize::{Org, ast::ListItem}; + /// + /// let item = Org::parse("- some tag").first_node::().unwrap(); + /// assert_eq!(item.bullet().unwrap().text(), "- "); + /// let item = Org::parse("2. [X] item 2").first_node::().unwrap(); + /// assert_eq!(item.bullet().unwrap().text(), "2. "); + /// ``` + pub fn bullet(&self) -> Option { + self.syntax + .children_with_tokens() + .find_map(filter_token(SyntaxKind::LIST_ITEM_BULLET)) + } + + /// ```rust + /// use orgize::{Org, ast::ListItem}; + /// + /// let item = Org::parse("- [-] item 1").first_node::().unwrap(); + /// assert_eq!(item.checkbox().unwrap().text(), "-"); + /// let item = Org::parse("2. [X] item 2").first_node::().unwrap(); + /// assert_eq!(item.checkbox().unwrap().text(), "X"); + /// let item = Org::parse("3) [ ] item 3").first_node::().unwrap(); + /// assert_eq!(item.checkbox().unwrap().text(), " "); + /// ``` + pub fn checkbox(&self) -> Option { + self.syntax + .children() + .find(|n| n.kind() == SyntaxKind::LIST_ITEM_CHECK_BOX) + .and_then(|n| { + n.children_with_tokens() + .find_map(filter_token(SyntaxKind::TEXT)) + }) + } + + pub fn counter(&self) -> Option { + self.syntax + .children() + .find(|n| n.kind() == SyntaxKind::LIST_ITEM_COUNTER) + .and_then(|n| { + n.children_with_tokens() + .find_map(filter_token(SyntaxKind::TEXT)) + }) + } + + /// ```rust + /// use orgize::{Org, ast::ListItem}; + /// + /// let item = Org::parse("+ this is *TAG* :: item1").first_node::().unwrap(); + /// let tag = item.tag().map(|n| n.to_string()).collect::(); + /// assert_eq!(tag, "this is *TAG* "); + /// ``` + pub fn tag(&self) -> impl Iterator { + self.syntax + .children() + .find(|n| n.kind() == SyntaxKind::LIST_ITEM_TAG) + .into_iter() + .flat_map(|n| { + n.children_with_tokens().filter(|n| { + n.kind() != SyntaxKind::WHITESPACE && n.kind() != SyntaxKind::COLON2 + }) + }) + } +} diff --git a/src/export/forward.rs b/src/export/forward.rs index cfe87fc..4711ece 100644 --- a/src/export/forward.rs +++ b/src/export/forward.rs @@ -1,14 +1,13 @@ -/// Forward handler method implement to other handler +/// Forward traverser method implement to other /// -/// This macros is commonly used if you want to extend -/// some builtin handlers like HtmlExport. +/// Used to "extend" some builtin traverser like `HtmlExport`. /// /// ```rust /// use orgize::{ -/// ast::HeadlineTitle, +/// ast::Headline, /// export::{HtmlExport, TraversalContext, Traverser}, /// forward_handler, -/// rowan::{ast::AstNode, WalkEvent}, +/// rowan::{ast::AstNode, WalkEvent, NodeOrToken}, /// Org, /// }; /// use slugify::slugify; @@ -25,27 +24,31 @@ /// } /// /// impl Traverser for SlugifyTitleHandler { -/// fn headline_title(&mut self, event: WalkEvent<&HeadlineTitle>, _ctx: &mut TraversalContext) { -/// match event { -/// WalkEvent::Enter(title) => { -/// let level = title.headline().map(|h| min(h.level(), 6)).unwrap_or(1); -/// let raw = title.syntax().to_string(); -/// self.0.push_str(format!("", slugify!(&raw))); -/// } -/// WalkEvent::Leave(title) => { -/// let level = title.headline().map(|h| min(h.level(), 6)).unwrap_or(1); -/// self.0.push_str(format!("")); +/// 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::(); +/// self.0.push_str(format!( +/// "", +/// slugify!(&title) +/// )); +/// for elem in headline.title() { +/// match elem { +/// NodeOrToken::Node(node) => self.node(node, ctx), +/// NodeOrToken::Token(token) => self.token(token, ctx), +/// } /// } +/// self.0.push_str(format!("")); /// } /// } /// /// forward_handler! { /// HtmlExport, -/// link text document headline paragraph section rule comment -/// inline_src inline_call code bold verbatim italic strike underline list list_item list_item_tag +/// 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 list_item_content +/// snippet timestamp target fixed_width org_table org_table_row org_table_cell /// } /// } /// @@ -62,146 +65,137 @@ macro_rules! forward_handler { }; (@method $handler:ty, text) => { - forward_handler!(@method $handler, text, ::orgize::SyntaxToken); + forward_handler!(@method $handler, text, $crate::SyntaxToken); }; (@method $handler:ty, document) => { - forward_handler!(@method $handler, document, WalkEvent<&::orgize::ast::Document>); + forward_handler!(@method $handler, document, WalkEvent<&$crate::ast::Document>); }; (@method $handler:ty, headline) => { - forward_handler!(@method $handler, headline, WalkEvent<&::orgize::ast::Headline>); + forward_handler!(@method $handler, headline, WalkEvent<&$crate::ast::Headline>); }; (@method $handler:ty, paragraph) => { - forward_handler!(@method $handler, paragraph, WalkEvent<&::orgize::ast::Paragraph>); + forward_handler!(@method $handler, paragraph, WalkEvent<&$crate::ast::Paragraph>); }; (@method $handler:ty, section) => { - forward_handler!(@method $handler, section, WalkEvent<&::orgize::ast::Section>); + forward_handler!(@method $handler, section, WalkEvent<&$crate::ast::Section>); }; (@method $handler:ty, rule) => { - forward_handler!(@method $handler, rule, WalkEvent<&::orgize::ast::Rule>); + forward_handler!(@method $handler, rule, WalkEvent<&$crate::ast::Rule>); }; (@method $handler:ty, comment) => { - forward_handler!(@method $handler, comment, WalkEvent<&::orgize::ast::Comment>); + forward_handler!(@method $handler, comment, WalkEvent<&$crate::ast::Comment>); }; (@method $handler:ty, inline_src) => { - forward_handler!(@method $handler, inline_src, WalkEvent<&::orgize::ast::InlineSrc>); + forward_handler!(@method $handler, inline_src, WalkEvent<&$crate::ast::InlineSrc>); }; (@method $handler:ty, inline_call) => { - forward_handler!(@method $handler, inline_call, WalkEvent<&::orgize::ast::InlineCall>); + forward_handler!(@method $handler, inline_call, WalkEvent<&$crate::ast::InlineCall>); }; (@method $handler:ty, code) => { - forward_handler!(@method $handler, code, WalkEvent<&::orgize::ast::Code>); + forward_handler!(@method $handler, code, WalkEvent<&$crate::ast::Code>); }; (@method $handler:ty, bold) => { - forward_handler!(@method $handler, bold, WalkEvent<&::orgize::ast::Bold>); + forward_handler!(@method $handler, bold, WalkEvent<&$crate::ast::Bold>); }; (@method $handler:ty, verbatim) => { - forward_handler!(@method $handler, verbatim, WalkEvent<&::orgize::ast::Verbatim>); + forward_handler!(@method $handler, verbatim, WalkEvent<&$crate::ast::Verbatim>); }; (@method $handler:ty, italic) => { - forward_handler!(@method $handler, italic, WalkEvent<&::orgize::ast::Italic>); + forward_handler!(@method $handler, italic, WalkEvent<&$crate::ast::Italic>); }; (@method $handler:ty, strike) => { - forward_handler!(@method $handler, strike, WalkEvent<&::orgize::ast::Strike>); + forward_handler!(@method $handler, strike, WalkEvent<&$crate::ast::Strike>); }; (@method $handler:ty, underline) => { - forward_handler!(@method $handler, underline, WalkEvent<&::orgize::ast::Underline>); + forward_handler!(@method $handler, underline, WalkEvent<&$crate::ast::Underline>); }; (@method $handler:ty, list) => { - forward_handler!(@method $handler, list, WalkEvent<&::orgize::ast::List>); + forward_handler!(@method $handler, list, WalkEvent<&$crate::ast::List>); }; (@method $handler:ty, list_item) => { - forward_handler!(@method $handler, list_item, WalkEvent<&::orgize::ast::ListItem>); - }; - (@method $handler:ty, list_item_tag) => { - forward_handler!(@method $handler, list_item_tag, WalkEvent<&::orgize::ast::ListItemTag>); - }; - (@method $handler:ty, list_item_content) => { - forward_handler!(@method $handler, list_item_content, WalkEvent<&::orgize::ast::ListItemContent>); + forward_handler!(@method $handler, list_item, WalkEvent<&$crate::ast::ListItem>); }; (@method $handler:ty, special_block) => { - forward_handler!(@method $handler, special_block, WalkEvent<&::orgize::ast::SpecialBlock>); + forward_handler!(@method $handler, special_block, WalkEvent<&$crate::ast::SpecialBlock>); }; (@method $handler:ty, quote_block) => { - forward_handler!(@method $handler, quote_block, WalkEvent<&::orgize::ast::QuoteBlock>); + forward_handler!(@method $handler, quote_block, WalkEvent<&$crate::ast::QuoteBlock>); }; (@method $handler:ty, center_block) => { - forward_handler!(@method $handler, center_block, WalkEvent<&::orgize::ast::CenterBlock>); + forward_handler!(@method $handler, center_block, WalkEvent<&$crate::ast::CenterBlock>); }; (@method $handler:ty, verse_block) => { - forward_handler!(@method $handler, verse_block, WalkEvent<&::orgize::ast::VerseBlock>); + forward_handler!(@method $handler, verse_block, WalkEvent<&$crate::ast::VerseBlock>); }; (@method $handler:ty, comment_block) => { - forward_handler!(@method $handler, comment_block, WalkEvent<&::orgize::ast::CommentBlock>); + forward_handler!(@method $handler, comment_block, WalkEvent<&$crate::ast::CommentBlock>); }; (@method $handler:ty, example_block) => { - forward_handler!(@method $handler, example_block, WalkEvent<&::orgize::ast::ExampleBlock>); + forward_handler!(@method $handler, example_block, WalkEvent<&$crate::ast::ExampleBlock>); }; (@method $handler:ty, export_block) => { - forward_handler!(@method $handler, export_block, WalkEvent<&::orgize::ast::ExportBlock>); + forward_handler!(@method $handler, export_block, WalkEvent<&$crate::ast::ExportBlock>); }; (@method $handler:ty, source_block) => { - forward_handler!(@method $handler, source_block, WalkEvent<&::orgize::ast::SourceBlock>); + forward_handler!(@method $handler, source_block, WalkEvent<&$crate::ast::SourceBlock>); }; (@method $handler:ty, babel_call) => { - forward_handler!(@method $handler, babel_call, WalkEvent<&::orgize::ast::BabelCall>); + forward_handler!(@method $handler, babel_call, WalkEvent<&$crate::ast::BabelCall>); }; (@method $handler:ty, clock) => { - forward_handler!(@method $handler, clock, WalkEvent<&::orgize::ast::Clock>); + forward_handler!(@method $handler, clock, WalkEvent<&$crate::ast::Clock>); }; (@method $handler:ty, cookie) => { - forward_handler!(@method $handler, cookie, WalkEvent<&::orgize::ast::Cookie>); + forward_handler!(@method $handler, cookie, WalkEvent<&$crate::ast::Cookie>); }; (@method $handler:ty, radio_target) => { - forward_handler!(@method $handler, radio_target, WalkEvent<&::orgize::ast::RadioTarget>); + forward_handler!(@method $handler, radio_target, WalkEvent<&$crate::ast::RadioTarget>); }; (@method $handler:ty, drawer) => { - forward_handler!(@method $handler, drawer, WalkEvent<&::orgize::ast::Drawer>); + forward_handler!(@method $handler, drawer, WalkEvent<&$crate::ast::Drawer>); }; (@method $handler:ty, dyn_block) => { - forward_handler!(@method $handler, dyn_block, WalkEvent<&::orgize::ast::DynBlock>); + forward_handler!(@method $handler, dyn_block, WalkEvent<&$crate::ast::DynBlock>); }; (@method $handler:ty, fn_def) => { - forward_handler!(@method $handler, fn_def, WalkEvent<&::orgize::ast::FnDef>); + forward_handler!(@method $handler, fn_def, WalkEvent<&$crate::ast::FnDef>); }; (@method $handler:ty, fn_ref) => { - forward_handler!(@method $handler, fn_ref, WalkEvent<&::orgize::ast::FnRef>); + forward_handler!(@method $handler, fn_ref, WalkEvent<&$crate::ast::FnRef>); }; (@method $handler:ty, macros) => { - forward_handler!(@method $handler, macros, WalkEvent<&::orgize::ast::Macros>); + forward_handler!(@method $handler, macros, WalkEvent<&$crate::ast::Macros>); }; (@method $handler:ty, snippet) => { - forward_handler!(@method $handler, snippet, WalkEvent<&::orgize::ast::Snippet>); + forward_handler!(@method $handler, snippet, WalkEvent<&$crate::ast::Snippet>); }; (@method $handler:ty, timestamp) => { - forward_handler!(@method $handler, timestamp, WalkEvent<&::orgize::ast::Timestamp>); + forward_handler!(@method $handler, timestamp, WalkEvent<&$crate::ast::Timestamp>); }; (@method $handler:ty, target) => { - forward_handler!(@method $handler, target, WalkEvent<&::orgize::ast::Target>); + forward_handler!(@method $handler, target, WalkEvent<&$crate::ast::Target>); }; (@method $handler:ty, fixed_width) => { - forward_handler!(@method $handler, fixed_width, WalkEvent<&::orgize::ast::FixedWidth>); - }; - (@method $handler:ty, headline_title) => { - forward_handler!(@method $handler, headline_title, WalkEvent<&::orgize::ast::HeadlineTitle>); + forward_handler!(@method $handler, fixed_width, WalkEvent<&$crate::ast::FixedWidth>); }; (@method $handler:ty, org_table) => { - forward_handler!(@method $handler, org_table, WalkEvent<&::orgize::ast::OrgTable>); + forward_handler!(@method $handler, org_table, WalkEvent<&$crate::ast::OrgTable>); }; (@method $handler:ty, org_table_row) => { - forward_handler!(@method $handler, org_table_row, WalkEvent<&::orgize::ast::OrgTableRow>); + 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<&::orgize::ast::OrgTableCell>); + forward_handler!(@method $handler, org_table_cell, WalkEvent<&$crate::ast::OrgTableCell>); }; (@method $handler:ty, link) => { - forward_handler!(@method $handler, link, WalkEvent<&::orgize::ast::Link>); + forward_handler!(@method $handler, link, WalkEvent<&$crate::ast::Link>); }; (@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 ::orgize::export::TraversalContext) { + fn $name(&mut self, item: $type, ctx: &mut $crate::export::TraversalContext) { >::as_mut(self).$name(item, ctx) } }; diff --git a/src/export/html.rs b/src/export/html.rs index df894f7..5efba73 100644 --- a/src/export/html.rs +++ b/src/export/html.rs @@ -1,4 +1,4 @@ -use rowan::WalkEvent; +use rowan::{NodeOrToken, WalkEvent}; use std::cmp::min; use std::fmt; @@ -116,36 +116,26 @@ impl Traverser for HtmlExport { }; } - #[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() { - self.output += match event { - WalkEvent::Enter(_) => "
  • ", - WalkEvent::Leave(_) => "
  • ", - }; - } - } - - #[tracing::instrument(skip(self, _ctx))] - fn list_item_content( - &mut self, - event: WalkEvent<&ListItemContent>, - _ctx: &mut TraversalContext, - ) { + #[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() { - self.output += match event { - WalkEvent::Enter(_) => "
    ", - WalkEvent::Leave(_) => "
    ", + match event { + WalkEvent::Enter(item) => { + self.output += "
    "; + for elem in item.tag() { + match elem { + NodeOrToken::Node(n) => self.node(n, ctx), + NodeOrToken::Token(t) => self.token(t, ctx), + } + } + self.output += "
    "; + } + WalkEvent::Leave(_) => self.output += "
    ", }; - } - } - - #[tracing::instrument(skip(self, _ctx))] - fn list_item_tag(&mut self, event: WalkEvent<&ListItemTag>, _ctx: &mut TraversalContext) { - if self.in_descriptive_list.last().copied().unwrap_or_default() { - self.output += match event { - WalkEvent::Enter(_) => "
    ", - WalkEvent::Leave(_) => "
    ", + } else { + match event { + WalkEvent::Enter(_) => self.output += "
  • ", + WalkEvent::Leave(_) => self.output += "
  • ", }; } } @@ -185,20 +175,6 @@ impl Traverser for HtmlExport { }; } - #[tracing::instrument(skip(self, _ctx))] - fn headline_title(&mut self, event: WalkEvent<&HeadlineTitle>, _ctx: &mut TraversalContext) { - self.output += &match event { - WalkEvent::Enter(title) => { - let level = title.headline().map(|h| min(h.level(), 6)).unwrap_or(1); - format!("") - } - WalkEvent::Leave(title) => { - let level = title.headline().map(|h| min(h.level(), 6)).unwrap_or(1); - format!("") - } - }; - } - #[tracing::instrument(skip(self, _ctx))] fn italic(&mut self, event: WalkEvent<&Italic>, _ctx: &mut TraversalContext) { self.output += match event { @@ -403,8 +379,20 @@ impl Traverser for HtmlExport { }; } - #[tracing::instrument(skip(self, _ctx))] - fn headline(&mut self, _event: WalkEvent<&Headline>, _ctx: &mut TraversalContext) {} + #[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); + self.output += &format!(""); + for elem in headline.title() { + match elem { + NodeOrToken::Node(node) => self.node(node, ctx), + NodeOrToken::Token(token) => self.token(token, ctx), + } + } + self.output += &format!(""); + } + } #[tracing::instrument(skip(self, _ctx))] fn inline_src(&mut self, _event: WalkEvent<&InlineSrc>, _ctx: &mut TraversalContext) {} diff --git a/src/export/traverse.rs b/src/export/traverse.rs index 9c035b2..3956d0c 100644 --- a/src/export/traverse.rs +++ b/src/export/traverse.rs @@ -63,15 +63,19 @@ impl TraversalContext { /// /// Each handle method can returns a `TraversalControl` to control the traversal. pub trait Traverser { + fn element(&mut self, element: SyntaxElement, ctx: &mut TraversalContext) { + match element { + SyntaxElement::Node(node) => self.node(node, ctx), + SyntaxElement::Token(token) => self.token(token, ctx), + }; + } + /// 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() { - match child { - SyntaxElement::Node(node) => self.node(node, ctx), - SyntaxElement::Token(token) => self.token(token, ctx), - }; + self.element(child, ctx); take_control!(ctx); } }}; @@ -100,8 +104,6 @@ pub trait Traverser { UNDERLINE => traverse!(Underline, underline), LIST => traverse!(List, list), LIST_ITEM => traverse!(ListItem, list_item), - LIST_ITEM_CONTENT => traverse!(ListItemContent, list_item_content), - LIST_ITEM_TAG => traverse!(ListItemTag, list_item_tag), CODE => traverse!(Code, code), INLINE_CALL => traverse!(InlineCall, inline_call), INLINE_SRC => traverse!(InlineSrc, inline_src), @@ -131,13 +133,12 @@ pub trait Traverser { TARGET => traverse!(Target, target), COMMENT => traverse!(Comment, comment), FIXED_WIDTH => traverse!(FixedWidth, fixed_width), - HEADLINE_TITLE => traverse!(HeadlineTitle, headline_title), 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), - BLOCK_CONTENT => traverse_children!(node), + BLOCK_CONTENT | LIST_ITEM_CONTENT => traverse_children!(node), _ => {} } @@ -185,14 +186,6 @@ pub trait Traverser { 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 `ListItemTag` node - fn list_item_tag(&mut self, _event: WalkEvent<&ListItemTag>, _ctx: &mut TraversalContext); - /// Called when entering or leaving `ListItemContent` node - fn list_item_content( - &mut self, - _event: WalkEvent<&ListItemContent>, - _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 @@ -235,8 +228,6 @@ pub trait Traverser { 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 `HeadlineTitle` node - fn headline_title(&mut self, _event: WalkEvent<&HeadlineTitle>, _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