From d5df0b6f05f0540554d3012de6805ba8444010cb Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 23 Jan 2021 10:44:14 +0100 Subject: [PATCH] Change whitespace behaviour A single linebreak will be ignored in plain text while a double line break will be converted to a single linebreak. All following linebreaks are taken as-is and rendered as normal linebreaks. (Fixes #13) Signed-off-by: trivernis --- Cargo.lock | 6 +++--- Cargo.toml | 4 ++-- src/format/html/to_html.rs | 2 +- src/parser/block.rs | 8 +++++--- src/parser/line.rs | 35 +++++++++++++++++++++++++++++------ src/parser/mod.rs | 22 +++++++++++++++++++--- 6 files changed, 59 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9263c19..4e4e7db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -235,9 +235,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "charred" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9759715d56a062d5636cd0cbc71f2aa8a978afe08c572a69e65e8cf53418f5" +checksum = "4163b788273102d5de1aaf35a76b1c0e347844842f5278d4d738ad08170e0ea8" [[package]] name = "chrono" @@ -2315,7 +2315,7 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "snekdown" -version = "0.32.3" +version = "0.33.0" dependencies = [ "asciimath-rs", "base64 0.12.3", diff --git a/Cargo.toml b/Cargo.toml index 3d310ae..8bd57fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "snekdown" -version = "0.32.3" +version = "0.33.0" authors = ["trivernis "] edition = "2018" license-file = "LICENSE" @@ -21,7 +21,7 @@ path = "src/main.rs" pdf = ["headless_chrome", "failure"] [dependencies] -charred = "0.3.5" +charred = "0.3.6" asciimath-rs = "0.5.7" bibliographix = "0.6.0" crossbeam-utils = "0.7.2" diff --git a/src/format/html/to_html.rs b/src/format/html/to_html.rs index 52f7e0f..88489fd 100644 --- a/src/format/html/to_html.rs +++ b/src/format/html/to_html.rs @@ -251,7 +251,7 @@ impl ToHtml for Paragraph { } if self.elements.len() > 1 { for element in &self.elements[1..] { - writer.write("
".to_string())?; + writer.write(" ".to_string())?; element.to_html(writer)?; } } diff --git a/src/parser/block.rs b/src/parser/block.rs index 6ed9576..2bc35e6 100644 --- a/src/parser/block.rs +++ b/src/parser/block.rs @@ -165,6 +165,7 @@ impl ParseBlock for Parser { fn parse_quote(&mut self) -> ParseResult { let start_index = self.ctm.get_index(); self.ctm.seek_whitespace(); + let metadata = if let Ok(meta) = self.parse_inline_metadata() { Some(meta) } else { @@ -199,11 +200,12 @@ impl ParseBlock for Parser { /// Parses a paragraph fn parse_paragraph(&mut self) -> ParseResult { - self.ctm.seek_whitespace(); let mut paragraph = Paragraph::new(); - while let Ok(token) = self.parse_line() { - paragraph.add_element(token); + + while let Ok(element) = self.parse_line() { + paragraph.add_element(element); let start_index = self.ctm.get_index(); + if self.ctm.check_any_sequence(&BLOCK_SPECIAL_CHARS) || self.ctm.check_any(&self.block_break_at) { diff --git a/src/parser/line.rs b/src/parser/line.rs index 13cdeef..4078c15 100644 --- a/src/parser/line.rs +++ b/src/parser/line.rs @@ -1,7 +1,8 @@ use super::ParseResult; use crate::elements::tokens::*; +use crate::elements::Inline::LineBreak; use crate::elements::{BibEntry, Metadata}; -use crate::elements::{Cell, Centered, Header, Inline, Line, ListItem, Row, Ruler, TextLine}; +use crate::elements::{Cell, Centered, Header, Line, ListItem, Row, Ruler, TextLine}; use crate::parser::inline::ParseInline; use crate::Parser; use bibliographix::bibliography::bibliography_entry::BibliographyEntry; @@ -16,6 +17,7 @@ pub(crate) trait ParseLine { fn parse_row(&mut self) -> ParseResult; fn parse_centered(&mut self) -> ParseResult; fn parse_ruler(&mut self) -> ParseResult; + fn parse_paragraph_break(&mut self) -> ParseResult; fn parse_text_line(&mut self) -> ParseResult; fn parse_bib_entry(&mut self) -> ParseResult; } @@ -36,6 +38,9 @@ impl ParseLine for Parser { } else if let Ok(bib) = self.parse_bib_entry() { log::trace!("Line::BibEntry"); Ok(Line::BibEntry(bib)) + } else if let Ok(text) = self.parse_paragraph_break() { + log::trace!("Line::LineBreak"); + Ok(Line::Text(text)) } else if let Ok(text) = self.parse_text_line() { log::trace!("Line::Text"); Ok(Line::Text(text)) @@ -166,6 +171,8 @@ impl ParseLine for Parser { /// Parses a line of text fn parse_text_line(&mut self) -> ParseResult { let mut text = TextLine::new(); + let start_index = self.ctm.get_index(); + while let Ok(subtext) = self.parse_inline() { text.add_subtext(subtext); if self.ctm.check_eof() || self.ctm.check_any(&self.inline_break_at) { @@ -173,21 +180,36 @@ impl ParseLine for Parser { } } + // add a linebreak when encountering \n\n if self.ctm.check_char(&LB) { - if let Ok(_) = self.ctm.seek_one() { - if self.ctm.check_char(&LB) { - text.add_subtext(Inline::LineBreak) - } + self.ctm.try_seek(); + + if self.ctm.check_char(&LB) { + text.add_subtext(LineBreak); + + self.ctm.try_seek(); } } if text.subtext.len() > 0 { Ok(text) } else { - Err(self.ctm.err().into()) + Err(self.ctm.rewind_with_error(start_index).into()) } } + /// Parses a paragraph break + fn parse_paragraph_break(&mut self) -> ParseResult { + let start_index = self.ctm.get_index(); + self.ctm.assert_char(&LB, Some(start_index))?; + self.ctm.seek_one()?; + + let mut line = TextLine::new(); + line.subtext.push(LineBreak); + + Ok(line) + } + fn parse_bib_entry(&mut self) -> ParseResult { let start_index = self.ctm.get_index(); self.ctm.seek_any(&INLINE_WHITESPACE)?; @@ -239,6 +261,7 @@ impl ParseLine for Parser { } } }; + self.ctm.seek_whitespace(); self.options .document diff --git a/src/parser/mod.rs b/src/parser/mod.rs index a05d390..39ee5ad 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -136,6 +136,11 @@ impl Parser { /// Returns a string of the current position in the file pub(crate) fn get_position_string(&self) -> String { let char_index = self.ctm.get_index(); + self.get_position_string_for_index(char_index) + } + + /// Returns a string of the given index position in the file + fn get_position_string_for_index(&self, char_index: usize) -> String { let text = self.ctm.get_text(); let mut text_unil = text[..char_index].to_vec(); let line_number = text_unil.iter().filter(|c| c == &&LB).count(); @@ -180,10 +185,10 @@ impl Parser { let anchor = Arc::new(RwLock::new(ImportAnchor::new())); let anchor_clone = Arc::clone(&anchor); let wg = self.wg.clone(); - let mut chid_parser = self.create_child(path.clone()); + let mut child_parser = self.create_child(path.clone()); let _ = thread::spawn(move || { - let document = chid_parser.parse(); + let document = child_parser.parse(); anchor_clone.write().unwrap().set_document(document); drop(wg); @@ -332,7 +337,18 @@ impl Parser { if self.ctm.check_eof() { break; } - eprintln!("{}", err); + match err { + ParseError::TapeError(t) => { + log::error!( + "Parse Error: {}\n\t--> {}\n", + t, + self.get_position_string_for_index(t.get_index()) + ) + } + _ => { + log::error!("{}", err) + } + } break; } }