From 64535641c113534490683f0930f60eaf5d7392b4 Mon Sep 17 00:00:00 2001 From: PoiScript Date: Mon, 21 Jan 2019 22:34:28 +0800 Subject: [PATCH] fix(elements): returning the correct offset --- src/elements/keyword.rs | 2 +- src/elements/list.rs | 72 ++++++++++++++++++------------ src/elements/mod.rs | 70 +++++++++++------------------ src/parser.rs | 98 ++++++++++++++++++----------------------- 4 files changed, 113 insertions(+), 129 deletions(-) diff --git a/src/elements/keyword.rs b/src/elements/keyword.rs index 1ee9fd6..592651d 100644 --- a/src/elements/keyword.rs +++ b/src/elements/keyword.rs @@ -9,7 +9,7 @@ impl Keyword { starts_with!(src, "#+"); } - let key = until_while!(src, 2, b':', |c: u8| c.is_ascii_uppercase() || c == b'_')?; + let key = until_while!(src, 2, b':', |c: u8| c.is_ascii_alphabetic() || c == b'_')?; // includes the eol character let end = src.find('\n').map(|i| i + 1).unwrap_or_else(|| src.len()); diff --git a/src/elements/list.rs b/src/elements/list.rs index dad3808..1476f50 100644 --- a/src/elements/list.rs +++ b/src/elements/list.rs @@ -1,6 +1,3 @@ -use memchr::memchr_iter; -use std::iter::once; - pub struct List; macro_rules! ident { @@ -56,23 +53,16 @@ impl List { // TODO: handle nested list pub fn parse_item(src: &str, ident: usize) -> (usize, usize) { let beg = src[ident..].find(' ').map(|i| ident + i + 1).unwrap(); - let mut pos = match src.find('\n') { - Some(i) => i + 1, - None => return (beg, src.len()), - }; - while let Some(line_end) = src[pos..].find('\n').map(|i| i + pos + 1).or_else(|| { - if pos < src.len() { - Some(src.len()) - } else { - None - } - }) { - if ident!(src[pos..]) == ident { + let mut lines = lines!(src); + // skip first line + let mut pos = lines.next().unwrap(); + for line_end in lines { + let line = &src[pos..line_end]; + if !line.trim().is_empty() && ident!(line) == ident { break; } pos = line_end; } - (beg, pos) } @@ -191,26 +181,26 @@ fn parse() { ); assert_eq!( List::parse( - r#" - Lorem ipsum dolor sit amet, consectetur adipiscing elit. + r#"- Lorem ipsum dolor sit amet, consectetur adipiscing elit. - - Nulla et dolor vitae elit placerat sagittis. Aliquam a lobortis massa, - aliquam efficitur arcu. + - Nulla et dolor vitae elit placerat sagittis. Aliquam a lobortis massa, + aliquam efficitur arcu. - - Lorem ipsum dolor sit amet, consectetur adipiscing elit. + - Lorem ipsum dolor sit amet, consectetur adipiscing elit. - - Phasellus auctor lacus a orci imperdiet, ut facilisis neque lobortis. + - Phasellus auctor lacus a orci imperdiet, ut facilisis neque lobortis. - - Proin condimentum id orci vitae lobortis. Nunc sollicitudin risus neque, - dapibus malesuada sem faucibus vitae. + - Proin condimentum id orci vitae lobortis. Nunc sollicitudin risus neque, + dapibus malesuada sem faucibus vitae. - - Sed vitae dolor augue. Phasellus at rhoncus arcu. Suspendisse potenti. +- Sed vitae dolor augue. Phasellus at rhoncus arcu. Suspendisse potenti. - - Nulla faucibus, metus ut porta hendrerit, urna lorem porta metus, in tempus - nibh orci sed sapien. + - Nulla faucibus, metus ut porta hendrerit, urna lorem porta metus, in tempus + nibh orci sed sapien. - - Morbi tortor mi, dapibus vel faucibus a, iaculis sed turpis."# + - Morbi tortor mi, dapibus vel faucibus a, iaculis sed turpis."# ), - Some((1, false, 677, 677)) + Some((0, false, 666, 666)) ); } @@ -232,7 +222,7 @@ fn is_item() { #[test] fn parse_item() { assert_eq!(List::parse_item("+ Item1\n+ Item2", 0), (2, 8)); - assert_eq!(List::parse_item("+ Item1\n\n+ Item2", 0), (2, 8)); + assert_eq!(List::parse_item("+ Item1\n\n+ Item2", 0), (2, 9)); assert_eq!( List::parse_item( r"+ item1 @@ -271,4 +261,28 @@ fn parse_item() { ), (3, 119) ); + assert_eq!( + List::parse_item( + r#"- Lorem ipsum dolor sit amet, consectetur adipiscing elit. + + - Nulla et dolor vitae elit placerat sagittis. Aliquam a lobortis massa, + aliquam efficitur arcu. + + - Lorem ipsum dolor sit amet, consectetur adipiscing elit. + + - Phasellus auctor lacus a orci imperdiet, ut facilisis neque lobortis. + + - Proin condimentum id orci vitae lobortis. Nunc sollicitudin risus neque, + dapibus malesuada sem faucibus vitae. + +- Sed vitae dolor augue. Phasellus at rhoncus arcu. Suspendisse potenti. + + - Nulla faucibus, metus ut porta hendrerit, urna lorem porta metus, in tempus + nibh orci sed sapien. + + - Morbi tortor mi, dapibus vel faucibus a, iaculis sed turpis."#, + 0 + ), + (2, 421) + ); } diff --git a/src/elements/mod.rs b/src/elements/mod.rs index c6f1031..06da443 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -134,16 +134,25 @@ impl<'a> Element<'a> { || bytes[pos] == b'*' || (bytes[pos] >= b'0' && bytes[pos] <= b'9') { - if let Some((ident, ordered, cont_end, end)) = List::parse(&src[end..]) { - ret!( - Element::List { - ident, - ordered, - cont_end, - end - }, - 0 - ); + if let Some((ident, ordered, cont_end, list_end)) = List::parse(&src[end..]) { + let list = Element::List { + ident, + ordered, + cont_end, + end: list_end, + }; + return if pos == start { + (1, Some(list), None) + } else { + ( + start, + Some(Element::Paragraph { + cont_end: end, + end: end, + }), + Some((list, 1)), + ) + }; } } @@ -173,42 +182,13 @@ impl<'a> Element<'a> { if let Some((name, args, contents_beg, cont_end, end)) = Block::parse(&src[pos..]) { + let cont = &src[pos + contents_beg + 1..pos + cont_end - 1]; match name.to_uppercase().as_str() { - "COMMENT" => ret!( - Element::CommentBlock { - args, - cont: &src[pos + contents_beg + 1..pos + cont_end - 1], - }, - pos + end - ), - "EXAMPLE" => ret!( - Element::ExampleBlock { - args, - cont: &src[pos + contents_beg + 1..pos + cont_end - 1], - }, - pos + end - ), - "EXPORT" => ret!( - Element::ExportBlock { - args, - cont: &src[pos + contents_beg + 1..pos + cont_end - 1], - }, - pos + end - ), - "SRC" => ret!( - Element::SrcBlock { - args, - cont: &src[pos + contents_beg + 1..pos + cont_end - 1], - }, - pos + end - ), - "VERSE" => ret!( - Element::VerseBlock { - args, - cont: &src[pos + contents_beg + 1..pos + cont_end - 1], - }, - pos + end - ), + "COMMENT" => ret!(Element::CommentBlock { args, cont }, pos + end), + "EXAMPLE" => ret!(Element::ExampleBlock { args, cont }, pos + end), + "EXPORT" => ret!(Element::ExportBlock { args, cont }, pos + end), + "SRC" => ret!(Element::SrcBlock { args, cont }, pos + end), + "VERSE" => ret!(Element::VerseBlock { args, cont }, pos + end), "CENTER" => ret!( Element::CtrBlock { args, diff --git a/src/parser.rs b/src/parser.rs index b356aca..29e2828 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -249,8 +249,26 @@ impl<'a> Parser<'a> { }), _ => (), } + self.off += off; - ele.into() + + match ele { + Element::Comment(c) => Event::Comment(c), + Element::CommentBlock { args, cont } => Event::CommentBlock { args, cont }, + Element::CtrBlock { .. } => Event::CtrBlockBeg, + Element::DynBlock { name, args, .. } => Event::DynBlockBeg { name, args }, + Element::ExampleBlock { args, cont } => Event::ExampleBlock { args, cont }, + Element::ExportBlock { args, cont } => Event::ExportBlock { args, cont }, + Element::FnDef { label, cont } => Event::FnDef { label, cont }, + Element::Keyword { key, value } => Event::Keyword { key, value }, + Element::List { ordered, .. } => Event::ListBeg { ordered }, + Element::Paragraph { .. } => Event::ParagraphBeg, + Element::QteBlock { .. } => Event::QteBlockBeg, + Element::Rule => Event::Rule, + Element::SplBlock { name, args, .. } => Event::SplBlockBeg { name, args }, + Element::SrcBlock { args, cont } => Event::SrcBlock { args, cont }, + Element::VerseBlock { args, cont } => Event::VerseBlock { args, cont }, + } } else { self.off += off; self.end() @@ -282,7 +300,24 @@ impl<'a> Parser<'a> { self.off += off; - obj.into() + match obj { + Object::Bold { .. } => Event::BoldBeg, + Object::Code(c) => Event::Code(c), + Object::Cookie(c) => Event::Cookie(c), + Object::FnRef(f) => Event::FnRef(f), + Object::InlineCall(i) => Event::InlineCall(i), + Object::InlineSrc(i) => Event::InlineSrc(i), + Object::Italic { .. } => Event::ItalicBeg, + Object::Link(l) => Event::Link(l), + Object::Macros(m) => Event::Macros(m), + Object::RadioTarget(r) => Event::RadioTarget(r), + Object::Snippet(s) => Event::Snippet(s), + Object::Strike { .. } => Event::StrikeBeg, + Object::Target(t) => Event::Target(t), + Object::Text(t) => Event::Text(t), + Object::Underline { .. } => Event::UnderlineBeg, + Object::Verbatim(v) => Event::Verbatim(v), + } } fn next_list_item(&mut self, end: usize, ident: usize) -> Event<'a> { @@ -325,18 +360,18 @@ impl<'a> Parser<'a> { | Strike { end } | Bold { end } | Underline { end } => { - assert!(self.off <= end); + debug_assert!(self.off <= end); } Paragraph { cont_end, end } => { - assert!(self.off <= end); - assert!(self.off <= cont_end); + debug_assert!(self.off <= end); + debug_assert!(self.off <= cont_end); } CtrBlock { cont_end, end } | QteBlock { cont_end, end } | SplBlock { cont_end, end } | DynBlock { cont_end, end } => { - assert!(self.off <= cont_end); - assert!(self.off <= end); + debug_assert!(self.off <= cont_end); + debug_assert!(self.off <= end); } } } @@ -391,7 +426,7 @@ impl<'a> Iterator for Parser<'a> { self.off = end; self.end() } else { - self.next_list_item(end, ident) + self.next_list_item(cont_end, ident) } } Container::ListItem { end } => { @@ -399,7 +434,7 @@ impl<'a> Iterator for Parser<'a> { self.end() } else { // TODO: handle nested list - self.next_obj(end) + self.next_ele(end) } } Container::Section { end } => { @@ -433,51 +468,6 @@ impl<'a> Iterator for Parser<'a> { } } -impl<'a> From> for Event<'a> { - fn from(obj: Object<'a>) -> Self { - match obj { - Object::Bold { .. } => Event::BoldBeg, - Object::Code(c) => Event::Code(c), - Object::Cookie(c) => Event::Cookie(c), - Object::FnRef(f) => Event::FnRef(f), - Object::InlineCall(i) => Event::InlineCall(i), - Object::InlineSrc(i) => Event::InlineSrc(i), - Object::Italic { .. } => Event::ItalicBeg, - Object::Link(l) => Event::Link(l), - Object::Macros(m) => Event::Macros(m), - Object::RadioTarget(r) => Event::RadioTarget(r), - Object::Snippet(s) => Event::Snippet(s), - Object::Strike { .. } => Event::StrikeBeg, - Object::Target(t) => Event::Target(t), - Object::Text(t) => Event::Text(t), - Object::Underline { .. } => Event::UnderlineBeg, - Object::Verbatim(v) => Event::Verbatim(v), - } - } -} - -impl<'a> From> for Event<'a> { - fn from(ele: Element<'a>) -> Self { - match ele { - Element::Comment(c) => Event::Comment(c), - Element::CommentBlock { args, cont } => Event::CommentBlock { args, cont }, - Element::CtrBlock { .. } => Event::CtrBlockBeg, - Element::DynBlock { name, args, .. } => Event::DynBlockBeg { name, args }, - Element::ExampleBlock { args, cont } => Event::ExampleBlock { args, cont }, - Element::ExportBlock { args, cont } => Event::ExportBlock { args, cont }, - Element::FnDef { label, cont } => Event::FnDef { label, cont }, - Element::Keyword { key, value } => Event::Keyword { key, value }, - Element::List { ordered, .. } => Event::ListBeg { ordered }, - Element::Paragraph { .. } => Event::ParagraphBeg, - Element::QteBlock { .. } => Event::QteBlockBeg, - Element::Rule => Event::Rule, - Element::SplBlock { name, args, .. } => Event::SplBlockBeg { name, args }, - Element::SrcBlock { args, cont } => Event::SrcBlock { args, cont }, - Element::VerseBlock { args, cont } => Event::VerseBlock { args, cont }, - } - } -} - #[test] fn parse() { use self::Event::*;