diff --git a/.gitignore b/.gitignore index 78c3ae5..7215f18 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,5 @@ **/*.rs.bk .idea .ast -test +test-files perf.data \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index ac1ac8c..5f80dc0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -566,7 +566,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "snekdown" -version = "0.12.3" +version = "0.12.4" dependencies = [ "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 79bd153..0a8a782 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "snekdown" -version = "0.12.3" +version = "0.12.4" authors = ["trivernis "] edition = "2018" license-file = "LICENSE" @@ -16,6 +16,8 @@ crate-type = ["lib"] name = "snekdown" path = "src/main.rs" +[tests] + [dependencies] crossbeam-utils = "0.7.2" structopt = "0.3.14" diff --git a/src/lib.rs b/src/lib.rs index 4abc7c8..4b64b10 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ pub mod format; pub mod parsing; pub use parsing::parser::Parser; +pub use parsing::utils; diff --git a/src/parsing/elements.rs b/src/parsing/elements.rs index ec55e8b..aef72e7 100644 --- a/src/parsing/elements.rs +++ b/src/parsing/elements.rs @@ -50,7 +50,7 @@ pub enum Line { #[derive(Clone, Debug)] pub struct Document { - pub(crate) elements: Vec, + pub elements: Vec, pub(crate) is_root: bool, pub(crate) path: Option, pub(crate) placeholders: Vec>>, @@ -80,7 +80,7 @@ pub struct Paragraph { #[derive(Clone, Debug)] pub struct List { pub(crate) ordered: bool, - pub(crate) items: Vec, + pub items: Vec, } #[derive(Clone, Debug)] diff --git a/src/parsing/mod.rs b/src/parsing/mod.rs index 0d02b89..f43efbf 100644 --- a/src/parsing/mod.rs +++ b/src/parsing/mod.rs @@ -4,4 +4,5 @@ pub mod inline; pub mod parser; pub mod placeholders; pub mod tokens; -pub(crate) mod utils; +#[macro_use] +pub mod utils; diff --git a/src/parsing/parser.rs b/src/parsing/parser.rs index fb73845..2fd063e 100644 --- a/src/parsing/parser.rs +++ b/src/parsing/parser.rs @@ -50,7 +50,11 @@ impl Parser { is_child: bool, ) -> Self { let text: Vec = text.chars().collect(); - let current_char = text.get(0).unwrap().clone(); + let current_char = if text.len() > 0 { + text.get(0).unwrap().clone() + } else { + ' ' + }; if let Some(path) = path.clone() { let path_info = Path::new(&path); paths @@ -463,7 +467,9 @@ impl Parser { self.revert_to(start_index)?; break; } - self.revert_to(start_index)?; + if !self.check_eof() { + self.revert_to(start_index)?; + } } if paragraph.elements.len() > 0 { diff --git a/src/parsing/utils.rs b/src/parsing/utils.rs index 507a7e9..a819077 100644 --- a/src/parsing/utils.rs +++ b/src/parsing/utils.rs @@ -3,6 +3,13 @@ use std::error::Error; use std::fmt; use std::fmt::{Display, Formatter}; +#[macro_export] +macro_rules! parse { + ($str:expr) => { + Parser::new($str.to_string(), None).parse() + }; +} + pub type ParseResult = Result; #[derive(Debug)] diff --git a/tests/parsing_tests.rs b/tests/parsing_tests.rs new file mode 100644 index 0000000..f917464 --- /dev/null +++ b/tests/parsing_tests.rs @@ -0,0 +1,97 @@ +use snekdown::parse; +use snekdown::parsing::elements::Block; +use snekdown::Parser; + +macro_rules! count_block_elements { + ($document:expr, $filter:expr) => { + $document + .elements + .iter() + .filter($filter) + .collect::>() + .len() + }; +} + +#[test] +fn it_inits() { + let _ = Parser::new("".to_string(), None); +} + +#[test] +fn it_parses_sections() { + let document = parse!("# Section\n## Subsection\n# Section"); + assert_eq!( + count_block_elements!(document, |e| if let Block::Section(_) = e { + true + } else { + false + }), + 2 + ) +} + +#[test] +fn it_parses_tables() { + let document = parse!("|header|header|\n|---|---|\n|col|col|"); + assert_eq!( + count_block_elements!(document, |e| if let Block::Table(_) = e { + true + } else { + false + }), + 1 + ) +} + +#[test] +fn it_parses_paragraphs() { + let document = parse!("**Bold***Italic*_Underline_`Monospace`^super^~strike~"); + assert_eq!( + count_block_elements!(document, |e| if let Block::Paragraph(_) = e { + true + } else { + false + }), + 1 + ) +} + +#[test] +fn it_parses_lists() { + let document = parse!("- item1\n- item2\n\n* item\n+ item\n\no item\n1. item"); + assert_eq!( + count_block_elements!(document, |e| if let Block::List(l) = e { + l.items.len() == 2 + } else { + false + }), + 3 + ) +} + +#[test] +fn it_parses_code_blocks() { + let document = parse!("```\ncode\n```\n```rust\ncode\n``````"); + assert_eq!( + count_block_elements!(document, |e| if let Block::CodeBlock(_) = e { + true + } else { + false + }), + 2 + ) +} + +#[test] +fn it_parses_quotes() { + let document = parse!("> quote\n\n[meta]> quote\n>hm"); + assert_eq!( + count_block_elements!(document, |e| if let Block::Quote(_) = e { + true + } else { + false + }), + 2 + ) +}