Merge pull request #17 from Trivernis/develop

Changes and fixes to whitespace behaviour
pull/20/head v0.33.0
Trivernis 4 years ago committed by GitHub
commit ccad1547ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

6
Cargo.lock generated

@ -235,9 +235,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "charred" name = "charred"
version = "0.3.5" version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed9759715d56a062d5636cd0cbc71f2aa8a978afe08c572a69e65e8cf53418f5" checksum = "4163b788273102d5de1aaf35a76b1c0e347844842f5278d4d738ad08170e0ea8"
[[package]] [[package]]
name = "chrono" name = "chrono"
@ -2315,7 +2315,7 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]] [[package]]
name = "snekdown" name = "snekdown"
version = "0.32.2" version = "0.33.0"
dependencies = [ dependencies = [
"asciimath-rs", "asciimath-rs",
"base64 0.12.3", "base64 0.12.3",

@ -1,6 +1,6 @@
[package] [package]
name = "snekdown" name = "snekdown"
version = "0.32.2" version = "0.33.0"
authors = ["trivernis <trivernis@protonmail.com>"] authors = ["trivernis <trivernis@protonmail.com>"]
edition = "2018" edition = "2018"
license-file = "LICENSE" license-file = "LICENSE"
@ -21,7 +21,7 @@ path = "src/main.rs"
pdf = ["headless_chrome", "failure"] pdf = ["headless_chrome", "failure"]
[dependencies] [dependencies]
charred = "0.3.5" charred = "0.3.6"
asciimath-rs = "0.5.7" asciimath-rs = "0.5.7"
bibliographix = "0.6.0" bibliographix = "0.6.0"
crossbeam-utils = "0.7.2" crossbeam-utils = "0.7.2"

@ -665,6 +665,15 @@ impl Quote {
pub fn add_text(&mut self, text: TextLine) { pub fn add_text(&mut self, text: TextLine) {
self.text.push(text) self.text.push(text)
} }
/// Strips a single linebreak from the end of the quote
pub fn strip_linebreak(&mut self) {
if let Some(last) = self.text.last_mut() {
if let Some(Inline::LineBreak) = last.subtext.last() {
last.subtext.pop();
}
}
}
} }
impl ImportAnchor { impl ImportAnchor {

@ -99,6 +99,8 @@ table tr td:first-child, table tr th:first-child {
blockquote { blockquote {
margin-left: 0; margin-left: 0;
padding-top: 0.2em;
padding-bottom: 0.2em;
background-color: rgba(0, 0, 0, 0); background-color: rgba(0, 0, 0, 0);
} }

@ -251,7 +251,7 @@ impl ToHtml for Paragraph {
} }
if self.elements.len() > 1 { if self.elements.len() > 1 {
for element in &self.elements[1..] { for element in &self.elements[1..] {
writer.write("<br/>".to_string())?; writer.write(" ".to_string())?;
element.to_html(writer)?; element.to_html(writer)?;
} }
} }

@ -10,7 +10,7 @@ use snekdown::settings::Settings;
use snekdown::utils::caching::CacheStorage; use snekdown::utils::caching::CacheStorage;
use snekdown::Parser; use snekdown::Parser;
use std::fs::{File, OpenOptions}; use std::fs::{File, OpenOptions};
use std::io::{BufWriter, Write}; use std::io::{stdout, BufWriter, Write};
use std::path::PathBuf; use std::path::PathBuf;
use std::process::exit; use std::process::exit;
use std::sync::mpsc::channel; use std::sync::mpsc::channel;
@ -48,7 +48,11 @@ struct RenderOptions {
/// Path for the output file /// Path for the output file
#[structopt(parse(from_os_str))] #[structopt(parse(from_os_str))]
output: PathBuf, output: Option<PathBuf>,
/// If the output should be written to stdout instead of the output file
#[structopt(long = "stdout")]
stdout: bool,
/// the output format /// the output format
#[structopt(short, long, default_value = "html")] #[structopt(short, long, default_value = "html")]
@ -165,6 +169,7 @@ fn render(opt: &RenderOptions) -> Parser {
exit(1) exit(1)
} }
let start = Instant::now(); let start = Instant::now();
let mut parser = Parser::with_defaults(ParserOptions::default().add_path(opt.input.clone())); let mut parser = Parser::with_defaults(ParserOptions::default().add_path(opt.input.clone()));
@ -173,16 +178,24 @@ fn render(opt: &RenderOptions) -> Parser {
log::info!("Parsing + Processing took: {:?}", start.elapsed()); log::info!("Parsing + Processing took: {:?}", start.elapsed());
let start_render = Instant::now(); let start_render = Instant::now();
if let Some(output) = &opt.output {
let file = OpenOptions::new() let file = OpenOptions::new()
.read(true) .read(true)
.write(true) .write(true)
.truncate(true) .truncate(true)
.create(true) .create(true)
.open(&opt.output) .open(output)
.unwrap(); .unwrap();
let writer = BufWriter::new(file);
render_format(opt, document, writer); render_format(opt, document, BufWriter::new(file));
} else {
if !opt.stdout {
log::error!("No output file specified");
exit(1)
}
render_format(opt, document, BufWriter::new(stdout()));
}
log::info!("Rendering took: {:?}", start_render.elapsed()); log::info!("Rendering took: {:?}", start_render.elapsed());
log::info!("Total: {:?}", start.elapsed()); log::info!("Total: {:?}", start.elapsed());
@ -190,7 +203,7 @@ fn render(opt: &RenderOptions) -> Parser {
} }
#[cfg(not(feature = "pdf"))] #[cfg(not(feature = "pdf"))]
fn render_format(opt: &RenderOptions, document: Document, writer: BufWriter<File>) { fn render_format<W: Write + 'static>(opt: &RenderOptions, document: Document, writer: W) {
match opt.format.as_str() { match opt.format.as_str() {
"html" => render_html(document, writer), "html" => render_html(document, writer),
_ => log::error!("Unknown format {}", opt.format), _ => log::error!("Unknown format {}", opt.format),
@ -198,7 +211,7 @@ fn render_format(opt: &RenderOptions, document: Document, writer: BufWriter<File
} }
#[cfg(feature = "pdf")] #[cfg(feature = "pdf")]
fn render_format(opt: &RenderOptions, document: Document, writer: BufWriter<File>) { fn render_format<W: Write + 'static>(opt: &RenderOptions, document: Document, writer: W) {
match opt.format.as_str() { match opt.format.as_str() {
"html" => render_html(document, writer), "html" => render_html(document, writer),
"pdf" => render_pdf(document, writer), "pdf" => render_pdf(document, writer),
@ -206,14 +219,14 @@ fn render_format(opt: &RenderOptions, document: Document, writer: BufWriter<File
} }
} }
fn render_html(document: Document, writer: BufWriter<File>) { fn render_html<W: Write + 'static>(document: Document, writer: W) {
let mut writer = HTMLWriter::new(Box::new(writer), document.config.lock().style.theme.clone()); let mut writer = HTMLWriter::new(Box::new(writer), document.config.lock().style.theme.clone());
document.to_html(&mut writer).unwrap(); document.to_html(&mut writer).unwrap();
writer.flush().unwrap(); writer.flush().unwrap();
} }
#[cfg(feature = "pdf")] #[cfg(feature = "pdf")]
fn render_pdf(document: Document, mut writer: BufWriter<File>) { fn render_pdf<W: Write + 'static>(document: Document, mut writer: W) {
use snekdown::format::chromium_pdf::render_to_pdf; use snekdown::format::chromium_pdf::render_to_pdf;
let result = render_to_pdf(document).expect("Failed to render pdf!"); let result = render_to_pdf(document).expect("Failed to render pdf!");

@ -165,6 +165,7 @@ impl ParseBlock for Parser {
fn parse_quote(&mut self) -> ParseResult<Quote> { fn parse_quote(&mut self) -> ParseResult<Quote> {
let start_index = self.ctm.get_index(); let start_index = self.ctm.get_index();
self.ctm.seek_whitespace(); self.ctm.seek_whitespace();
let metadata = if let Ok(meta) = self.parse_inline_metadata() { let metadata = if let Ok(meta) = self.parse_inline_metadata() {
Some(meta) Some(meta)
} else { } else {
@ -190,6 +191,8 @@ impl ParseBlock for Parser {
break; break;
} }
} }
quote.strip_linebreak();
if quote.text.len() == 0 { if quote.text.len() == 0 {
return Err(self.ctm.rewind_with_error(start_index).into()); return Err(self.ctm.rewind_with_error(start_index).into());
} }
@ -199,11 +202,12 @@ impl ParseBlock for Parser {
/// Parses a paragraph /// Parses a paragraph
fn parse_paragraph(&mut self) -> ParseResult<Paragraph> { fn parse_paragraph(&mut self) -> ParseResult<Paragraph> {
self.ctm.seek_whitespace();
let mut paragraph = Paragraph::new(); 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(); let start_index = self.ctm.get_index();
if self.ctm.check_any_sequence(&BLOCK_SPECIAL_CHARS) if self.ctm.check_any_sequence(&BLOCK_SPECIAL_CHARS)
|| self.ctm.check_any(&self.block_break_at) || self.ctm.check_any(&self.block_break_at)
{ {

@ -1,7 +1,8 @@
use super::ParseResult; use super::ParseResult;
use crate::elements::tokens::*; use crate::elements::tokens::*;
use crate::elements::Inline::LineBreak;
use crate::elements::{BibEntry, Metadata}; 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::inline::ParseInline;
use crate::Parser; use crate::Parser;
use bibliographix::bibliography::bibliography_entry::BibliographyEntry; use bibliographix::bibliography::bibliography_entry::BibliographyEntry;
@ -16,6 +17,7 @@ pub(crate) trait ParseLine {
fn parse_row(&mut self) -> ParseResult<Row>; fn parse_row(&mut self) -> ParseResult<Row>;
fn parse_centered(&mut self) -> ParseResult<Centered>; fn parse_centered(&mut self) -> ParseResult<Centered>;
fn parse_ruler(&mut self) -> ParseResult<Ruler>; fn parse_ruler(&mut self) -> ParseResult<Ruler>;
fn parse_paragraph_break(&mut self) -> ParseResult<TextLine>;
fn parse_text_line(&mut self) -> ParseResult<TextLine>; fn parse_text_line(&mut self) -> ParseResult<TextLine>;
fn parse_bib_entry(&mut self) -> ParseResult<BibEntry>; fn parse_bib_entry(&mut self) -> ParseResult<BibEntry>;
} }
@ -36,6 +38,9 @@ impl ParseLine for Parser {
} else if let Ok(bib) = self.parse_bib_entry() { } else if let Ok(bib) = self.parse_bib_entry() {
log::trace!("Line::BibEntry"); log::trace!("Line::BibEntry");
Ok(Line::BibEntry(bib)) 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() { } else if let Ok(text) = self.parse_text_line() {
log::trace!("Line::Text"); log::trace!("Line::Text");
Ok(Line::Text(text)) Ok(Line::Text(text))
@ -166,6 +171,8 @@ impl ParseLine for Parser {
/// Parses a line of text /// Parses a line of text
fn parse_text_line(&mut self) -> ParseResult<TextLine> { fn parse_text_line(&mut self) -> ParseResult<TextLine> {
let mut text = TextLine::new(); let mut text = TextLine::new();
let start_index = self.ctm.get_index();
while let Ok(subtext) = self.parse_inline() { while let Ok(subtext) = self.parse_inline() {
text.add_subtext(subtext); text.add_subtext(subtext);
if self.ctm.check_eof() || self.ctm.check_any(&self.inline_break_at) { 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 self.ctm.check_char(&LB) {
if let Ok(_) = self.ctm.seek_one() { self.ctm.try_seek();
if self.ctm.check_char(&LB) { if self.ctm.check_char(&LB) {
text.add_subtext(Inline::LineBreak) text.add_subtext(LineBreak);
}
self.ctm.try_seek();
} }
} }
if text.subtext.len() > 0 { if text.subtext.len() > 0 {
Ok(text) Ok(text)
} else { } 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<TextLine> {
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<BibEntry> { fn parse_bib_entry(&mut self) -> ParseResult<BibEntry> {
let start_index = self.ctm.get_index(); let start_index = self.ctm.get_index();
self.ctm.seek_any(&INLINE_WHITESPACE)?; self.ctm.seek_any(&INLINE_WHITESPACE)?;
@ -239,6 +261,7 @@ impl ParseLine for Parser {
} }
} }
}; };
self.ctm.seek_whitespace();
self.options self.options
.document .document

@ -136,6 +136,11 @@ impl Parser {
/// Returns a string of the current position in the file /// Returns a string of the current position in the file
pub(crate) fn get_position_string(&self) -> String { pub(crate) fn get_position_string(&self) -> String {
let char_index = self.ctm.get_index(); 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 text = self.ctm.get_text();
let mut text_unil = text[..char_index].to_vec(); let mut text_unil = text[..char_index].to_vec();
let line_number = text_unil.iter().filter(|c| c == &&LB).count(); 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 = Arc::new(RwLock::new(ImportAnchor::new()));
let anchor_clone = Arc::clone(&anchor); let anchor_clone = Arc::clone(&anchor);
let wg = self.wg.clone(); 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 _ = thread::spawn(move || {
let document = chid_parser.parse(); let document = child_parser.parse();
anchor_clone.write().unwrap().set_document(document); anchor_clone.write().unwrap().set_document(document);
drop(wg); drop(wg);
@ -332,7 +337,18 @@ impl Parser {
if self.ctm.check_eof() { if self.ctm.check_eof() {
break; 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; break;
} }
} }

Loading…
Cancel
Save