From b5f16ae6ef202c2c6e76bcf6da06c6657f826cdf Mon Sep 17 00:00:00 2001 From: Manuel Hatzl <49341624+mhatzl@users.noreply.github.com> Date: Sun, 19 Nov 2023 20:26:49 +0100 Subject: [PATCH] feat: add textbox & hyperlink rendering --- inline/src/element/textbox/mod.rs | 1 + inline/src/parser.rs | 2 +- inline/tests/spec/markup/textbox.yml | 16 ++++++ .../parser/textbox/simple-textbox.snap | 17 ++++++ render/src/html/render.rs | 55 ++++++++++++++++++- render/src/html/tag.rs | 2 + render/src/render.rs | 31 +++++++++-- 7 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 inline/tests/spec/markup/textbox.yml create mode 100644 inline/tests/spec/snapshots/parser/textbox/simple-textbox.snap diff --git a/inline/src/element/textbox/mod.rs b/inline/src/element/textbox/mod.rs index 3710ea7d..a5ccc6d8 100644 --- a/inline/src/element/textbox/mod.rs +++ b/inline/src/element/textbox/mod.rs @@ -87,6 +87,7 @@ pub(crate) fn parse<'slice, 'input>( } None => { scoped_parser.iter.rollback(checkpoint); + scoped_parser.iter.next(); // Consume open bracket } } diff --git a/inline/src/parser.rs b/inline/src/parser.rs index 742468fe..5f188f61 100644 --- a/inline/src/parser.rs +++ b/inline/src/parser.rs @@ -218,7 +218,7 @@ mod test { #[test] fn dummy_for_debugging() { - let tokens = unimarkup_commons::lexer::token::lex_str("**bold *+italic*** plain"); + let tokens = unimarkup_commons::lexer::token::lex_str("[Simple textbox]"); let mut inline_parser = InlineParser { iter: InlineTokenIterator::from(TokenIterator::from(&*tokens)), context: InlineContext::default(), diff --git a/inline/tests/spec/markup/textbox.yml b/inline/tests/spec/markup/textbox.yml new file mode 100644 index 00000000..af01a400 --- /dev/null +++ b/inline/tests/spec/markup/textbox.yml @@ -0,0 +1,16 @@ +# Unimarkup specification version +spec: "0.0.1" + +name: textbox +description: Contains tests for the textbox element. + +tests: + - name: simple-textbox + description: | + Parse a simple textbox. + + input: | + [Simple textbox] + + html: | + Simple textbox diff --git a/inline/tests/spec/snapshots/parser/textbox/simple-textbox.snap b/inline/tests/spec/snapshots/parser/textbox/simple-textbox.snap new file mode 100644 index 00000000..4a308774 --- /dev/null +++ b/inline/tests/spec/snapshots/parser/textbox/simple-textbox.snap @@ -0,0 +1,17 @@ +--- +source: inline/tests/parser/mod.rs +info: "Test 'simple-textbox' from 'markup\\textbox.yml'" +--- +TextBox @ (1:1)->(1:17) ( + Plain @ (1:2)->(1:16) ( + Simple textbox + ^^^^^^^^^^^^^^ + ) +) + +--- +With input: + +[Simple textbox] + + diff --git a/render/src/html/render.rs b/render/src/html/render.rs index bbdb4626..2bad88d7 100644 --- a/render/src/html/render.rs +++ b/render/src/html/render.rs @@ -2,9 +2,10 @@ use unimarkup_commons::lexer::{span::Span, symbol::SymbolKind, token::TokenKind} use unimarkup_inline::element::{ base::{EscapedNewline, EscapedPlain, EscapedWhitespace, Newline, Plain}, formatting::{ - Bold, Highlight, Italic, Overline, Quote, Strikethrough, Subscript, Superscript, Underline, - Verbatim, + Bold, Highlight, Italic, Math, Overline, Quote, Strikethrough, Subscript, Superscript, + Underline, Verbatim, }, + textbox::{hyperlink::Hyperlink, TextBox}, InlineElement, }; use unimarkup_parser::elements::indents::{BulletList, BulletListEntry}; @@ -128,6 +129,41 @@ impl Renderer for HtmlRenderer { Ok(html) } + fn render_textbox( + &mut self, + textbox: &TextBox, + context: &Context, + ) -> Result { + let inner = self.render_nested_inline(textbox.inner(), context)?; + + Ok(Html::nested( + HtmlTag::Span, + HtmlAttributes::default(), + inner, + )) + } + + fn render_hyperlink( + &mut self, + hyperlink: &Hyperlink, + context: &Context, + ) -> Result { + let inner = self.render_nested_inline(hyperlink.inner(), context)?; + let mut attributes = vec![HtmlAttribute { + name: "href".to_string(), + value: Some(hyperlink.link().to_string()), + }]; + + if let Some(link_text) = hyperlink.link_text() { + attributes.push(HtmlAttribute { + name: "title".to_string(), + value: Some(link_text.to_string()), + }) + } + + Ok(Html::nested(HtmlTag::A, HtmlAttributes(attributes), inner)) + } + fn render_bold( &mut self, bold: &Bold, @@ -255,6 +291,21 @@ impl Renderer for HtmlRenderer { Ok(html) } + fn render_inline_math( + &mut self, + math: &Math, + context: &Context, + ) -> Result { + // TODO: use proper math rendering once supported + let inner = self.render_nested_inline(math.inner(), context)?; + + Ok(Html::nested( + HtmlTag::Span, + HtmlAttributes::default(), + inner, + )) + } + fn render_plain( &mut self, plain: &Plain, diff --git a/render/src/html/tag.rs b/render/src/html/tag.rs index 69b1ad8a..308a4a25 100644 --- a/render/src/html/tag.rs +++ b/render/src/html/tag.rs @@ -29,6 +29,7 @@ pub enum HtmlTag { Br, Ul, Li, + A, } impl HtmlTag { @@ -57,6 +58,7 @@ impl HtmlTag { HtmlTag::Br => "br", HtmlTag::Ul => "ul", HtmlTag::Li => "li", + HtmlTag::A => "a", } } } diff --git a/render/src/render.rs b/render/src/render.rs index 14184bce..7368f662 100644 --- a/render/src/render.rs +++ b/render/src/render.rs @@ -4,9 +4,10 @@ use unimarkup_commons::{config::icu_locid::Locale, lexer::span::Span}; use unimarkup_inline::element::{ base::{EscapedNewline, EscapedPlain, EscapedWhitespace, Newline, Plain}, formatting::{ - Bold, Highlight, Italic, Overline, Quote, Strikethrough, Subscript, Superscript, Underline, - Verbatim, + Bold, Highlight, Italic, Math, Overline, Quote, Strikethrough, Subscript, Superscript, + Underline, Verbatim, }, + textbox::{hyperlink::Hyperlink, TextBox}, Inline, }; use unimarkup_parser::{ @@ -107,6 +108,20 @@ pub trait Renderer { //--------------------------------- INLINES --------------------------------- + /// Render a [`TextBox`] to the output format `T`. + fn render_textbox(&mut self, _textbox: &TextBox, _context: &Context) -> Result { + Err(RenderError::Unimplemented) + } + + /// Render a [`Hyperlink`] to the output format `T`. + fn render_hyperlink( + &mut self, + _hyperlink: &Hyperlink, + _context: &Context, + ) -> Result { + Err(RenderError::Unimplemented) + } + /// Render a [`Bold` formatting](unimarkup_inline::inlines::Inline) to the output format `T`. fn render_bold(&mut self, _bold: &Bold, _context: &Context) -> Result { Err(RenderError::Unimplemented) @@ -185,6 +200,11 @@ pub trait Renderer { Err(RenderError::Unimplemented) } + /// Render a [`Math`] to the output format `T`. + fn render_inline_math(&mut self, _math: &Math, _context: &Context) -> Result { + Err(RenderError::Unimplemented) + } + /// Render [`Plain` content](unimarkup_inline::inlines::Inline) to the output format `T`. fn render_plain(&mut self, _plain: &Plain, _context: &Context) -> Result { Err(RenderError::Unimplemented) @@ -330,9 +350,10 @@ pub trait Renderer { Inline::ImplicitNewline(implicit_newline) => { self.render_implicit_newline(implicit_newline, context) } - Inline::Math(_) => todo!(), - Inline::TextBox(_) => todo!(), - Inline::Hyperlink(_) => todo!(), + Inline::Math(math) => self.render_inline_math(math, context), + Inline::TextBox(textbox) => self.render_textbox(textbox, context), + Inline::Hyperlink(hyperlink) => self.render_hyperlink(hyperlink, context), + Inline::NamedSubstitution(_) => todo!(), Inline::ImplicitSubstitution(_) => todo!(), Inline::DirectUri(_) => todo!(),