From d402a12e88c84d50d88b948dc8a04d09c647e3be Mon Sep 17 00:00:00 2001 From: Tatsuya Kawano Date: Wed, 6 Jan 2021 22:24:02 +0800 Subject: [PATCH] Skip HTML comments in the summary --- src/book/summary.rs | 130 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 122 insertions(+), 8 deletions(-) diff --git a/src/book/summary.rs b/src/book/summary.rs index b909629c..0d6f0c1e 100644 --- a/src/book/summary.rs +++ b/src/book/summary.rs @@ -365,6 +365,8 @@ impl<'a> SummaryParser<'a> { let mut first = true; loop { + let mut html_node = false; + match self.next_event() { Some(ev @ Event::Start(Tag::Paragraph)) => { if !first { @@ -405,6 +407,12 @@ impl<'a> SummaryParser<'a> { items.push(SummaryItem::Separator); } + // A HTML node, such as a comment line... ignore, but set the html_node flag. + Some(Event::Html(html)) => { + trace!("Skipping a HTML node of {:?}", html); + html_node = true; + } + // something else... ignore Some(_) => {} @@ -414,8 +422,10 @@ impl<'a> SummaryParser<'a> { } } - // From now on, we cannot accept any new paragraph opening tags. - first = false; + // If the event was not a HTML node, we no longer accept any new paragraph opening tags. + if !html_node { + first = false; + } } Ok(items) @@ -525,14 +535,19 @@ impl<'a> SummaryParser<'a> { /// Try to parse the title line. fn parse_title(&mut self) -> Option { - match self.next_event() { - Some(Event::Start(Tag::Heading(1))) => { - debug!("Found a h1 in the SUMMARY"); + loop { + match self.next_event() { + Some(Event::Start(Tag::Heading(1))) => { + debug!("Found a h1 in the SUMMARY"); - let tags = collect_events!(self.stream, end Tag::Heading(1)); - Some(stringify_events(tags)) + let tags = collect_events!(self.stream, end Tag::Heading(1)); + return Some(stringify_events(tags)); + } + // Skip a HTML element such as a comment line. + Some(Event::Html(_)) => {} + // Otherwise, no title. + _ => return None, } - _ => None, } } } @@ -973,4 +988,103 @@ mod tests { assert_eq!(got, should_be); } + + #[test] + fn skip_html_comments() { + let src = r#" +# Title - Local + + +[Prefix 00-01 - Local](ch00-01.md) +[Prefix 00-02 - Local](ch00-02.md) + + +## Section Title - Localized + + +- [Ch 01-00 - Local](ch01-00.md) + - [Ch 01-01 - Local](ch01-01.md) + - [Ch 01-02 - Local](ch01-02.md) + + +- [Ch 02-00 - Local](ch02-00.md) + +` +[Appendix A - Local](appendix-01.md) +[Appendix B - Local](appendix-02.md) +"#; + + let mut parser = SummaryParser::new(src); + + // ---- Title ---- + let title = parser.parse_title(); + assert_eq!(title, Some(String::from("Title - Local"))); + + // ---- Prefix Chapters ---- + + let new_affix_item = |name, location| { + SummaryItem::Link(Link { + name: String::from(name), + location: Some(PathBuf::from(location)), + ..Default::default() + }) + }; + + let should_be = vec![ + new_affix_item("Prefix 00-01 - Local", "ch00-01.md"), + new_affix_item("Prefix 00-02 - Local", "ch00-02.md"), + ]; + + let got = parser.parse_affix(true).unwrap(); + assert_eq!(got, should_be); + + // ---- Numbered Chapters ---- + + let new_numbered_item = |name, location, numbers: &[u32], nested_items| { + SummaryItem::Link(Link { + name: String::from(name), + location: Some(PathBuf::from(location)), + number: Some(SectionNumber(numbers.to_vec())), + nested_items, + }) + }; + + let ch01_nested = vec![ + new_numbered_item("Ch 01-01 - Local", "ch01-01.md", &[1, 1], vec![]), + new_numbered_item("Ch 01-02 - Local", "ch01-02.md", &[1, 2], vec![]), + ]; + + let should_be = vec![ + new_numbered_item("Ch 01-00 - Local", "ch01-00.md", &[1], ch01_nested), + new_numbered_item("Ch 02-00 - Local", "ch02-00.md", &[2], vec![]), + ]; + let got = parser.parse_parts().unwrap(); + assert_eq!(got, should_be); + + // ---- Suffix Chapters ---- + + let should_be = vec![ + new_affix_item("Appendix A - Local", "appendix-01.md"), + new_affix_item("Appendix B - Local", "appendix-02.md"), + ]; + + let got = parser.parse_affix(false).unwrap(); + assert_eq!(got, should_be); + } }