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!(),