From c31eceeb97f20c4261b13e2e3f63697868dbd8a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20=C5=A0ula?= Date: Mon, 10 Jan 2022 12:43:47 +0100 Subject: [PATCH] fix: added suggestions from PR escaped inline formatting, tests for inline formatting, documentation minor grammar changes --- src/backend/inline_formatting.rs | 208 ++++++++++-------- src/backend/mod.rs | 3 +- src/grammar/unimarkup.pest | 4 +- tests/backend/inline_tests.rs | 29 +++ .../test_files/frontend/inline_formatting.um | 5 - tests/tests.rs | 1 + 6 files changed, 157 insertions(+), 93 deletions(-) create mode 100644 tests/backend/inline_tests.rs delete mode 100644 tests/test_files/frontend/inline_formatting.um diff --git a/src/backend/inline_formatting.rs b/src/backend/inline_formatting.rs index a3606c27..65c1e1b4 100644 --- a/src/backend/inline_formatting.rs +++ b/src/backend/inline_formatting.rs @@ -1,121 +1,138 @@ use std::{collections::VecDeque, fmt::Debug}; use pest::iterators::Pair; +use pest::Parser; -use crate::{ - frontend::{ - parser::{Rule}, - }}; +use crate::backend::UmError; +use crate::frontend::parser::{Rule, UnimarkupParser}; use super::Render; +/// [`Plain`] is one of the inline formatting types, which contains the raw text as String. #[derive(Debug)] pub struct Plain { - pub content: String + content: String, } +/// [`Bold`] is one of the inline formatting types #[derive(Debug)] pub struct Bold { - pub content: VecDeque + content: VecDeque, } +/// [`Italic`] is one of the inline formatting types. #[derive(Debug)] pub struct Italic { - pub content: VecDeque + content: VecDeque, } +/// [`Subscript`] is one of the inline formatting types. #[derive(Debug)] pub struct Subscript { - pub content: VecDeque + content: VecDeque, } +/// [`Superscript`] is one of the inline formatting types. #[derive(Debug)] pub struct Superscript { - pub content: VecDeque + content: VecDeque, } +/// [`Verbatim`] is one of the inline formatting types. #[derive(Debug)] pub struct Verbatim { - pub content: String -} -#[derive(Debug)] -pub struct Raw { - pub content: String + content: String, } +/// [`FormatTypes`] is an enum of all the inline formatting types. #[derive(Debug)] pub enum FormatTypes { + /// Represents the [`Bold`] FormatType Bold(Bold), + /// Represents the [`Italic`] FormatType Italic(Italic), + /// Represents the [`Subscript`] FormatType Subscript(Subscript), + /// Represents the [`Superscript`] FormatType Superscript(Superscript), + /// Represents the [`Verbatim`] FormatType Verbatim(Verbatim), + /// Represents the [`Plain`] FormatType Plain(Plain), } -pub fn create_format_types(pair: Pair) -> VecDeque { - get_nested_inline(pair) +/// [`parse_inline`] parses through the content of a [`UnimarkupBlock`] and returns a VecDeque of Formattypes +pub fn parse_inline(source: &str) -> Result, UmError> { + let mut rule_pairs = + UnimarkupParser::parse(Rule::inline_format, source).map_err(|err| UmError::General { + msg: String::from("Could not parse string!"), + error: Box::new(err), + })?; + + let mut inline_format = VecDeque::::new(); + + println!("{:#?}", rule_pairs); + + if let Some(inline) = rule_pairs.next() { + inline_format.append(&mut pair_into_format_types(inline)); + } + + Ok(inline_format) } -fn get_nested_inline(pair: Pair) -> VecDeque { +fn create_format_types(pair: Pair) -> VecDeque { let mut content: VecDeque = VecDeque::::new(); match pair.as_rule() { - - Rule::text => { - let plain = Plain { content: pair.as_str().to_string(),}; + Rule::plain => { + let plain = Plain { + content: pair.as_str().to_string(), + }; content.push_back(FormatTypes::Plain(plain)); - }, - Rule::italic => { - let inner = pair.into_inner(); - let mut vector = VecDeque::new(); - - for pair in inner { - vector.append(&mut get_nested_inline(pair)); - } - let italic = Italic{content: vector}; + } + Rule::italic_inline => { + let italic = Italic { + content: pair_into_format_types(pair), + }; content.push_back(FormatTypes::Italic(italic)); - }, - Rule::subscript => { - let inner = pair.into_inner(); - let mut vector = VecDeque::new(); - - for pair in inner { - vector.append(&mut get_nested_inline(pair)); - } - let subscript = Subscript{content: vector}; + } + Rule::subscript_inline => { + let subscript = Subscript { + content: pair_into_format_types(pair), + }; content.push_back(FormatTypes::Subscript(subscript)); - }, - Rule::superscript => { - let inner = pair.into_inner(); - let mut vector = VecDeque::new(); - - for pair in inner { - vector.append(&mut get_nested_inline(pair)); - } - let superscript = Superscript{content: vector}; + } + Rule::superscript_inline => { + let superscript = Superscript { + content: pair_into_format_types(pair), + }; content.push_back(FormatTypes::Superscript(superscript)); - }, - Rule::bold => { - let inner = pair.into_inner(); - let mut vector = VecDeque::new(); - - for pair in inner { - vector.append(&mut get_nested_inline(pair)); - } - let bold = Bold{content: vector}; + } + Rule::bold_inline => { + let bold = Bold { + content: pair_into_format_types(pair), + }; content.push_back(FormatTypes::Bold(bold)); - }, - Rule::verbatim => { - let verbatim = Verbatim{content: pair.into_inner().as_str().to_string(),}; + } + Rule::verbatim_inline => { + let verbatim = Verbatim { + content: pair.into_inner().as_str().to_string(), + }; content.push_back(FormatTypes::Verbatim(verbatim)); - }, - _ => unreachable!("No other inline types allowed.") + } + _ => unreachable!("No other inline types allowed."), } - + content } +fn pair_into_format_types(pair: Pair) -> VecDeque { + pair.into_inner().flat_map(create_format_types).collect() +} + impl Render for Bold { - fn render_html(&self) -> Result { - + fn render_html(&self) -> Result { let mut html = String::default(); html.push_str(""); for element in &self.content { - html.push_str(&element.render_html().expect("At least one or more formatting types expected")); + html.push_str( + &element + .render_html() + .expect("At least one or more formatting types expected"), + ); } html.push_str(""); Ok(html) @@ -123,44 +140,55 @@ impl Render for Bold { } impl Render for Italic { - fn render_html(&self) -> Result { - + fn render_html(&self) -> Result { let mut html = String::default(); html.push_str(""); for element in &self.content { - html.push_str(&element.render_html().expect("At least one or more formatting types expected")); + html.push_str( + &element + .render_html() + .expect("At least one or more formatting types expected"), + ); } html.push_str(""); Ok(html) } } + impl Render for Subscript { - fn render_html(&self) -> Result { - + fn render_html(&self) -> Result { let mut html = String::default(); html.push_str(""); for element in &self.content { - html.push_str(&element.render_html().expect("At least one or more formatting types expected")); + html.push_str( + &element + .render_html() + .expect("At least one or more formatting types expected"), + ); } html.push_str(""); Ok(html) } } + impl Render for Superscript { - fn render_html(&self) -> Result { - + fn render_html(&self) -> Result { let mut html = String::default(); html.push_str(""); for element in &self.content { - html.push_str(&element.render_html().expect("At least one or more formatting types expected")); + html.push_str( + &element + .render_html() + .expect("At least one or more formatting types expected"), + ); } html.push_str(""); Ok(html) } } + impl Render for Verbatim { - fn render_html(&self) -> Result { - + fn render_html(&self) -> Result { let mut html = String::default(); html.push_str("
");
         html.push_str(&self.content);
@@ -168,16 +196,16 @@ impl Render for Verbatim {
         Ok(html)
     }
 }
+
 impl Render for Plain {
-    fn render_html(&self) -> Result {
-        
-        let mut html = String::default();
-        html.push_str(&self.content);
-        Ok(html)
+    fn render_html(&self) -> Result {
+        println!("{}", self.content);
+        Ok(self.content.clone())
     }
 }
+
 impl Render for FormatTypes {
-    fn render_html(&self) -> Result {
+    fn render_html(&self) -> Result {
         match self {
             FormatTypes::Bold(content) => content.render_html(),
             FormatTypes::Italic(content) => content.render_html(),
@@ -189,9 +217,17 @@ impl Render for FormatTypes {
     }
 }
 
-pub fn render_inline_umblocks(html: &mut String, inline_format:VecDeque) {
+impl Render for VecDeque {
+    fn render_html(&self) -> Result {
+        let mut html = String::default();
 
-    for element in inline_format {
-        html.push_str(&element.render_html().expect("Rendered format types expected"));
+        for element in self {
+            html.push_str(
+                &element
+                    .render_html()
+                    .expect("Rendered format types expected"),
+            );
+        }
+        Ok(html)
     }
-}
\ No newline at end of file
+}
diff --git a/src/backend/mod.rs b/src/backend/mod.rs
index 17a27511..da27b089 100644
--- a/src/backend/mod.rs
+++ b/src/backend/mod.rs
@@ -12,11 +12,12 @@ use log::info;
 use rusqlite::Connection;
 
 mod backend_error;
+mod inline_formatting;
 mod loader;
 mod renderer;
-pub(crate) mod inline_formatting;
 
 pub use backend_error::BackendError;
+pub use inline_formatting::*;
 pub use loader::ParseFromIr;
 pub use renderer::*;
 
diff --git a/src/grammar/unimarkup.pest b/src/grammar/unimarkup.pest
index 6878b438..0c1abe6f 100644
--- a/src/grammar/unimarkup.pest
+++ b/src/grammar/unimarkup.pest
@@ -45,7 +45,9 @@ headings = { heading+ }
 paragraph = { ANY+ }
 
 // ****** INLINE FORMATTING ******
-plain = { (!(inline_delim) ~ ANY)+ }
+escaped = { "\\" }
+escaped_delim = @{ escaped ~ (italic_delim | subscript_delim | superscript_delim | verbatim_delim)}
+plain = @{ ((escaped_delim) | (!(inline_delim) ~ ANY))+ }
 inline_format = { (inline_block | plain)+ }
 inline_block = _{ bold_inline | italic_inline | subscript_inline | superscript_inline | verbatim_inline }
 inline_body = _{ (!(PEEK) ~ (inline_block | plain))+ }
diff --git a/tests/backend/inline_tests.rs b/tests/backend/inline_tests.rs
new file mode 100644
index 00000000..8c51e19f
--- /dev/null
+++ b/tests/backend/inline_tests.rs
@@ -0,0 +1,29 @@
+use unimarkup_rs::{backend::Render, um_elements::ParagraphBlock, um_error::UmError};
+
+#[test]
+
+fn escaped_inline() -> Result<(), UmError> {
+    let id = String::from("paragraph-id");
+    let content = String::from("\\*23\\*3");
+
+    let mut block = ParagraphBlock {
+        id: id.clone(),
+        content,
+        attributes: "{}".into(),
+        line_nr: 0,
+    };
+
+    let mut expected_html = format!("

\\*23\\*3

", id); + + assert_eq!(expected_html, block.render_html()?); + + block.content = "\\ *italic*\\".to_string(); + expected_html = format!("

\\ italic\\

", id); + assert_eq!(expected_html, block.render_html()?); + + block.content = "**\\*only bold\\***".to_string(); + expected_html = format!("

\\*only bold\\*

", id); + assert_eq!(expected_html, block.render_html()?); + + Ok(()) +} diff --git a/tests/test_files/frontend/inline_formatting.um b/tests/test_files/frontend/inline_formatting.um deleted file mode 100644 index f239c2cf..00000000 --- a/tests/test_files/frontend/inline_formatting.um +++ /dev/null @@ -1,5 +0,0 @@ -### Heading with *a very beautiful _formatting_* - -plain text *_nested text with italic & subscript_ only italic ^and italic & superscript^* **only bold** - -`verbatim text` \ No newline at end of file diff --git a/tests/tests.rs b/tests/tests.rs index 59a056f0..06d69392 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -19,4 +19,5 @@ mod um_elements { mod backend { mod backend_run; + mod inline_tests; }