fix(elements): returning the correct offset

This commit is contained in:
PoiScript 2019-01-21 22:34:28 +08:00
parent 3105470cee
commit 64535641c1
4 changed files with 113 additions and 129 deletions

View file

@ -9,7 +9,7 @@ impl Keyword {
starts_with!(src, "#+"); 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 // includes the eol character
let end = src.find('\n').map(|i| i + 1).unwrap_or_else(|| src.len()); let end = src.find('\n').map(|i| i + 1).unwrap_or_else(|| src.len());

View file

@ -1,6 +1,3 @@
use memchr::memchr_iter;
use std::iter::once;
pub struct List; pub struct List;
macro_rules! ident { macro_rules! ident {
@ -56,23 +53,16 @@ impl List {
// TODO: handle nested list // TODO: handle nested list
pub fn parse_item(src: &str, ident: usize) -> (usize, usize) { pub fn parse_item(src: &str, ident: usize) -> (usize, usize) {
let beg = src[ident..].find(' ').map(|i| ident + i + 1).unwrap(); let beg = src[ident..].find(' ').map(|i| ident + i + 1).unwrap();
let mut pos = match src.find('\n') { let mut lines = lines!(src);
Some(i) => i + 1, // skip first line
None => return (beg, src.len()), let mut pos = lines.next().unwrap();
}; for line_end in lines {
while let Some(line_end) = src[pos..].find('\n').map(|i| i + pos + 1).or_else(|| { let line = &src[pos..line_end];
if pos < src.len() { if !line.trim().is_empty() && ident!(line) == ident {
Some(src.len())
} else {
None
}
}) {
if ident!(src[pos..]) == ident {
break; break;
} }
pos = line_end; pos = line_end;
} }
(beg, pos) (beg, pos)
} }
@ -191,26 +181,26 @@ fn parse() {
); );
assert_eq!( assert_eq!(
List::parse( 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, - Nulla et dolor vitae elit placerat sagittis. Aliquam a lobortis massa,
aliquam efficitur arcu. 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, - Proin condimentum id orci vitae lobortis. Nunc sollicitudin risus neque,
dapibus malesuada sem faucibus vitae. 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 - Nulla faucibus, metus ut porta hendrerit, urna lorem porta metus, in tempus
nibh orci sed sapien. 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] #[test]
fn parse_item() { fn parse_item() {
assert_eq!(List::parse_item("+ Item1\n+ Item2", 0), (2, 8)); 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!( assert_eq!(
List::parse_item( List::parse_item(
r"+ item1 r"+ item1
@ -271,4 +261,28 @@ fn parse_item() {
), ),
(3, 119) (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)
);
} }

View file

@ -134,16 +134,25 @@ impl<'a> Element<'a> {
|| bytes[pos] == b'*' || bytes[pos] == b'*'
|| (bytes[pos] >= b'0' && bytes[pos] <= b'9') || (bytes[pos] >= b'0' && bytes[pos] <= b'9')
{ {
if let Some((ident, ordered, cont_end, end)) = List::parse(&src[end..]) { if let Some((ident, ordered, cont_end, list_end)) = List::parse(&src[end..]) {
ret!( let list = Element::List {
Element::List { ident,
ident, ordered,
ordered, cont_end,
cont_end, end: list_end,
end };
}, return if pos == start {
0 (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)) = if let Some((name, args, contents_beg, cont_end, end)) =
Block::parse(&src[pos..]) Block::parse(&src[pos..])
{ {
let cont = &src[pos + contents_beg + 1..pos + cont_end - 1];
match name.to_uppercase().as_str() { match name.to_uppercase().as_str() {
"COMMENT" => ret!( "COMMENT" => ret!(Element::CommentBlock { args, cont }, pos + end),
Element::CommentBlock { "EXAMPLE" => ret!(Element::ExampleBlock { args, cont }, pos + end),
args, "EXPORT" => ret!(Element::ExportBlock { args, cont }, pos + end),
cont: &src[pos + contents_beg + 1..pos + cont_end - 1], "SRC" => ret!(Element::SrcBlock { args, cont }, pos + end),
}, "VERSE" => ret!(Element::VerseBlock { args, cont }, pos + end),
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
),
"CENTER" => ret!( "CENTER" => ret!(
Element::CtrBlock { Element::CtrBlock {
args, args,

View file

@ -249,8 +249,26 @@ impl<'a> Parser<'a> {
}), }),
_ => (), _ => (),
} }
self.off += off; 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 { } else {
self.off += off; self.off += off;
self.end() self.end()
@ -282,7 +300,24 @@ impl<'a> Parser<'a> {
self.off += off; 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> { fn next_list_item(&mut self, end: usize, ident: usize) -> Event<'a> {
@ -325,18 +360,18 @@ impl<'a> Parser<'a> {
| Strike { end } | Strike { end }
| Bold { end } | Bold { end }
| Underline { end } => { | Underline { end } => {
assert!(self.off <= end); debug_assert!(self.off <= end);
} }
Paragraph { cont_end, end } => { Paragraph { cont_end, end } => {
assert!(self.off <= end); debug_assert!(self.off <= end);
assert!(self.off <= cont_end); debug_assert!(self.off <= cont_end);
} }
CtrBlock { cont_end, end } CtrBlock { cont_end, end }
| QteBlock { cont_end, end } | QteBlock { cont_end, end }
| SplBlock { cont_end, end } | SplBlock { cont_end, end }
| DynBlock { cont_end, end } => { | DynBlock { cont_end, end } => {
assert!(self.off <= cont_end); debug_assert!(self.off <= cont_end);
assert!(self.off <= end); debug_assert!(self.off <= end);
} }
} }
} }
@ -391,7 +426,7 @@ impl<'a> Iterator for Parser<'a> {
self.off = end; self.off = end;
self.end() self.end()
} else { } else {
self.next_list_item(end, ident) self.next_list_item(cont_end, ident)
} }
} }
Container::ListItem { end } => { Container::ListItem { end } => {
@ -399,7 +434,7 @@ impl<'a> Iterator for Parser<'a> {
self.end() self.end()
} else { } else {
// TODO: handle nested list // TODO: handle nested list
self.next_obj(end) self.next_ele(end)
} }
} }
Container::Section { end } => { Container::Section { end } => {
@ -433,51 +468,6 @@ impl<'a> Iterator for Parser<'a> {
} }
} }
impl<'a> From<Object<'a>> 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<Element<'a>> 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] #[test]
fn parse() { fn parse() {
use self::Event::*; use self::Event::*;