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

@ -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()
}
}