From 274e008e2c775d9c8c888767a6baeaff9e99de9d Mon Sep 17 00:00:00 2001 From: Laurenz Date: Wed, 13 Jan 2021 16:09:08 +0100 Subject: [PATCH] =?UTF-8?q?Move=20heading=20tests=20to=20integration=20?= =?UTF-8?q?=F0=9F=9A=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/parse/mod.rs | 23 +++++++++------------ src/parse/tests.rs | 45 ----------------------------------------- src/parse/tokens.rs | 1 + tests/ref/headings.png | Bin 0 -> 7991 bytes tests/typ/headings.typ | 40 ++++++++++++++++++++++++++++++++++++ 5 files changed, 50 insertions(+), 59 deletions(-) create mode 100644 tests/ref/headings.png create mode 100644 tests/typ/headings.typ diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 4483ed765..5fdaa4ce0 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -34,11 +34,9 @@ fn tree(p: &mut Parser) -> Tree { let mut at_start = true; let mut tree = vec![]; while !p.eof() { - if let Some(node) = p.span_if(|p| node(p, at_start)) { - match node.v { - Node::Parbreak => at_start = true, - Node::Space => {} - _ => at_start = false, + if let Some(node) = p.span_if(|p| node(p, &mut at_start)) { + if !matches!(node.v, Node::Parbreak | Node::Space) { + at_start = false; } tree.push(node); } @@ -47,7 +45,7 @@ fn tree(p: &mut Parser) -> Tree { } /// Parse a syntax node. -fn node(p: &mut Parser, at_start: bool) -> Option { +fn node(p: &mut Parser, at_start: &mut bool) -> Option { let node = match p.peek()? { // Bracket call. Token::LeftBracket => { @@ -64,7 +62,7 @@ fn node(p: &mut Parser, at_start: bool) -> Option { Token::Underscore => Node::Emph, Token::Tilde => Node::Text("\u{00A0}".into()), Token::Hash => { - if at_start { + if *at_start { return Some(Node::Heading(heading(p))); } else { Node::Text(p.get(p.peek_span()).into()) @@ -72,11 +70,8 @@ fn node(p: &mut Parser, at_start: bool) -> Option { } Token::Backslash => Node::Linebreak, Token::Space(newlines) => { - if newlines < 2 { - Node::Space - } else { - Node::Parbreak - } + *at_start |= newlines > 0; + if newlines < 2 { Node::Space } else { Node::Parbreak } } Token::Text(text) => Node::Text(text.into()), Token::Raw(t) => Node::Raw(raw(p, t)), @@ -122,8 +117,8 @@ fn heading(p: &mut Parser) -> NodeHeading { // Parse the heading contents. let mut contents = vec![]; - while p.check(|t| !matches!(t, Token::Space(n) if n >= 1)) { - if let Some(node) = p.span_if(|p| node(p, false)) { + while p.check(|t| !matches!(t, Token::Space(n) if n > 0)) { + if let Some(node) = p.span_if(|p| node(p, &mut false)) { contents.push(node); } } diff --git a/src/parse/tests.rs b/src/parse/tests.rs index 2e7a2af36..f8b9dcbb1 100644 --- a/src/parse/tests.rs +++ b/src/parse/tests.rs @@ -87,10 +87,6 @@ fn Text(text: &str) -> Node { Node::Text(text.into()) } -fn Heading(level: impl Into>, contents: Tree) -> Node { - Node::Heading(NodeHeading { level: level.into(), contents }) -} - fn Raw(lang: Option<&str>, lines: &[&str], inline: bool) -> Node { Node::Raw(NodeRaw { lang: lang.map(|id| Ident(id.into())), @@ -246,47 +242,6 @@ fn test_parse_simple_nodes() { S(1..2, "unexpected closing brace")]); } -#[test] -fn test_parse_headings() { - // Basics with spans. - t!("# a" - nodes: [S(0..3, Heading(S(0..1, 0), Template![ - @S(1..2, Space), S(2..3, Text("a")) - ]))], - spans: true); - - // Multiple hashtags. - t!("### three" Heading(2, Template![@Space, Text("three")])); - t!("###### six" Heading(5, Template![@Space, Text("six")])); - - // Start of heading. - t!("/**/#" Heading(0, Template![@])); - t!("[f][# ok]" Call!("f", Args![Template![Heading(0, Template![ - @Space, Text("ok") - ])]])); - - // End of heading. - t!("# a\nb" Heading(0, Template![@Space, Text("a")]), Space, Text("b")); - - // Continued heading. - t!("# a{\n1\n}b" Heading(0, Template![ - @Space, Text("a"), Block!(Int(1)), Text("b") - ])); - t!("# a[f][\n\n]d" Heading(0, Template![@ - Space, Text("a"), Call!("f", Args![Template![Parbreak]]), Text("d"), - ])); - - // No heading. - t!(r"\#" Text("#")); - t!("Nr. #1" Text("Nr."), Space, Text("#"), Text("1")); - t!("[v]#" Call!("v"), Text("#")); - - // Too many hashtags. - t!("####### seven" - nodes: [Heading(5, Template![@Space, Text("seven")])], - warnings: [S(0..7, "section depth should not exceed 6")]); -} - #[test] fn test_parse_raw() { // Basic, mostly tested in tokenizer and resolver. diff --git a/src/parse/tokens.rs b/src/parse/tokens.rs index 32cc11d9c..7741d27f8 100644 --- a/src/parse/tokens.rs +++ b/src/parse/tokens.rs @@ -567,6 +567,7 @@ mod tests { // Test markup tokens. t!(Markup[" a1"]: "*" => Star); t!(Markup: "_" => Underscore); + t!(Markup[""]: "###" => Hash, Hash, Hash); t!(Markup["a1/"]: "# " => Hash, Space(0)); t!(Markup: "~" => Tilde); t!(Markup[" "]: r"\" => Backslash); diff --git a/tests/ref/headings.png b/tests/ref/headings.png new file mode 100644 index 0000000000000000000000000000000000000000..b16e38a6bad4b354913343738524a72e20a56b4d GIT binary patch literal 7991 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 literal 0 HcmV?d00001 diff --git a/tests/typ/headings.typ b/tests/typ/headings.typ new file mode 100644 index 000000000..88c76ad38 --- /dev/null +++ b/tests/typ/headings.typ @@ -0,0 +1,40 @@ +// Number of hashtags. +// +// warning: 5:1-5:8 section depth should not exceed 6 + +# One +### Three +###### Six +####### Seven + +--- +// Is a heading. + +/**/ # Heading +{[## Heading]} +[box][### Heading] + +--- +// Is no heading. +// +// error: 4:1-4:6 unexpected invalid token + +\# No heading + +Text with # hashtag + +#nope + +--- +// Heading continues over linebreak. + +# This { + "works" +} + +# [box][ + This +] too + +# This +does not