diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 5bda818f..4c935579 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -61,7 +61,7 @@ fn node(p: &mut Parser, at_start: &mut bool) -> Option { // Markup. Token::Star => Node::Strong(span), Token::Underscore => Node::Emph(span), - Token::Eq => { + Token::Hashtag => { if *at_start { return Some(heading(p)); } else { @@ -128,11 +128,11 @@ fn node(p: &mut Parser, at_start: &mut bool) -> Option { /// Parse a heading. fn heading(p: &mut Parser) -> Node { let start = p.start(); - p.assert(Token::Eq); + p.assert(Token::Hashtag); // Count depth. let mut level: usize = 1; - while p.eat_if(Token::Eq) { + while p.eat_if(Token::Hashtag) { level += 1; } diff --git a/src/parse/tokens.rs b/src/parse/tokens.rs index 62d2e68e..fa86d2f1 100644 --- a/src/parse/tokens.rs +++ b/src/parse/tokens.rs @@ -73,7 +73,7 @@ impl<'s> Iterator for Tokens<'s> { '{' => Token::LeftBrace, '}' => Token::RightBrace, - // Keywords, variables, functions, colors. + // Headings, keywords, identifiers, colors. '#' => self.hash(start), // Whitespace. @@ -93,7 +93,6 @@ impl<'s> Iterator for Tokens<'s> { // Markup. '*' => Token::Star, '_' => Token::Underscore, - '=' => Token::Eq, '~' => Token::Tilde, '`' => self.raw(), '$' => self.math(), @@ -157,6 +156,10 @@ impl<'s> Tokens<'s> { match self.mode { TokenMode::Markup => { + if read.is_empty() { + return Token::Hashtag; + } + if let Some(token) = keyword(read) { return token; } @@ -607,8 +610,8 @@ mod tests { // Test markup tokens. t!(Markup[" a1"]: "*" => Star); t!(Markup: "_" => Underscore); - t!(Markup[""]: "===" => Eq, Eq, Eq); - t!(Markup["a1/"]: "= " => Eq, Space(0)); + t!(Markup[""]: "###" => Hashtag, Hashtag, Hashtag); + t!(Markup["a1/"]: "# " => Hashtag, Space(0)); t!(Markup: "~" => Tilde); t!(Markup[" "]: r"\" => Backslash); } @@ -666,7 +669,7 @@ mod tests { for &(s, t) in &keywords { t!(Markup[" "]: format!("#{}", s) => t); t!(Markup[" "]: format!("#{0}#{0}", s) => t, t); - t!(Markup[" /"]: format!("# {}", s) => Token::Invalid("#"), Space(0), Text(s)); + t!(Markup[" /"]: format!("# {}", s) => Token::Hashtag, Space(0), Text(s)); } for &(s, t) in &keywords { diff --git a/src/pretty.rs b/src/pretty.rs index 397bbc38..49f6fd82 100644 --- a/src/pretty.rs +++ b/src/pretty.rs @@ -141,7 +141,7 @@ impl PrettyWithMap for Node { impl PrettyWithMap for HeadingNode { fn pretty_with_map(&self, p: &mut Printer, map: Option<&NodeMap>) { for _ in 0 .. self.level { - p.push('='); + p.push('#'); } self.contents.pretty_with_map(p, map); } @@ -666,7 +666,7 @@ mod tests { roundtrip("hi"); // Heading. - roundtrip("= *Ok*"); + roundtrip("# *Ok*"); // Raw. roundtrip("``"); diff --git a/src/syntax/token.rs b/src/syntax/token.rs index 3484536d..538d81b7 100644 --- a/src/syntax/token.rs +++ b/src/syntax/token.rs @@ -20,8 +20,8 @@ pub enum Token<'s> { Star, /// An underscore: `_`. Underscore, - /// A single equals sign: `=`. - Eq, + /// A single hashtag: `#`. + Hashtag, /// A tilde: `~`. Tilde, /// A backslash followed by nothing or whitespace: `\`. @@ -38,6 +38,8 @@ pub enum Token<'s> { Hyph, /// A slash: `/`. Slash, + /// A single equals sign: `=`. + Eq, /// Two equals signs: `==`. EqEq, /// An exclamation mark followed by an equals sign: `!=`. @@ -200,6 +202,7 @@ impl<'s> Token<'s> { Self::RightParen => "closing paren", Self::Star => "star", Self::Underscore => "underscore", + Self::Hashtag => "hashtag", Self::Tilde => "tilde", Self::Backslash => "backslash", Self::Comma => "comma", diff --git a/tests/ref/code/call-invalid.png b/tests/ref/code/call-invalid.png index f2f90f09..e024e6ce 100644 Binary files a/tests/ref/code/call-invalid.png and b/tests/ref/code/call-invalid.png differ diff --git a/tests/ref/markup/heading.png b/tests/ref/markup/heading.png index 46b5b637..825b4007 100644 Binary files a/tests/ref/markup/heading.png and b/tests/ref/markup/heading.png differ diff --git a/tests/typ/code/call-invalid.typ b/tests/typ/code/call-invalid.typ index 0ed5246f..a2c43abc 100644 --- a/tests/typ/code/call-invalid.typ +++ b/tests/typ/code/call-invalid.typ @@ -1,9 +1,5 @@ // Test invalid function calls. ---- -// Error: 1-2 unexpected invalid token -# - --- // Error: 7-8 expected expression, found colon #args(:) diff --git a/tests/typ/code/importable/chap1.typ b/tests/typ/code/importable/chap1.typ index 06a4c1a1..a0f38d0d 100644 --- a/tests/typ/code/importable/chap1.typ +++ b/tests/typ/code/importable/chap1.typ @@ -2,7 +2,7 @@ #let name = "Klaus" -== Chapter 1 +## Chapter 1 #name stood in a field of wheat. There was nothing of particular interest about the field #name just casually surveyed for any paths on which the corn would not totally ruin his semi-new outdorsy jacket but then again, most of us spend diff --git a/tests/typ/code/importable/chap2.typ b/tests/typ/code/importable/chap2.typ index d4aedc60..51e116aa 100644 --- a/tests/typ/code/importable/chap2.typ +++ b/tests/typ/code/importable/chap2.typ @@ -2,7 +2,7 @@ #let name = "Klaus" -== Chapter 2 +## Chapter 2 Their motivations, however, were pretty descript, so to speak. #name had not yet conceptualized their consequences, but that should change pretty quickly. #name approached the center of the field and picked up a 4-foot long disk made from diff --git a/tests/typ/code/include.typ b/tests/typ/code/include.typ index 9fd028f9..945a041d 100644 --- a/tests/typ/code/include.typ +++ b/tests/typ/code/include.typ @@ -1,7 +1,7 @@ // Test include statements. --- -= Document +# Document // Include a file #include "importable/chap1.typ" diff --git a/tests/typ/full/coma.typ b/tests/typ/full/coma.typ index 4941fb71..78a703a9 100644 --- a/tests/typ/full/coma.typ +++ b/tests/typ/full/coma.typ @@ -30,7 +30,7 @@ // the parentheses. #align(center)[ // Markdown-like syntax for headings. - ==== 3. Übungsblatt Computerorientierte Mathematik II #v(4mm) + #### 3. Übungsblatt Computerorientierte Mathematik II #v(4mm) *Abgabe: 03.05.2019* (bis 10:10 Uhr in MA 001) #v(4mm) *Alle Antworten sind zu beweisen.* ] diff --git a/tests/typ/markup/heading.typ b/tests/typ/markup/heading.typ index 9bbe3415..56f48bae 100644 --- a/tests/typ/markup/heading.typ +++ b/tests/typ/markup/heading.typ @@ -4,44 +4,44 @@ // Different number of hashtags. // Valid levels. -=1 -===2 -======6 +# 1 +### 2 +###### 6 // Too many hashtags. // Warning: 1-8 should not exceed depth 6 -=======7 +####### 7 --- // Heading continuation over linebreak. // Code blocks continue heading. -= A{ +# A{ "B" } // Function call continues heading. -= #rect[ +# #rect[ A ] B // Without some kind of block, headings end at a line break. -= A +# A B --- // Heading vs. no heading. // Parsed as headings if at start of the context. -/**/ = Ok -{[== Ok]} -#rect[=== Ok] +/**/ # Ok +{[## Ok]} +#rect[### Ok] // Not at the start of the context. -No = heading +No # heading // Escaped. -\= No heading +\# No heading --- // Make small, but double heading. @@ -49,4 +49,4 @@ No = heading // The new heading's argument list doesn't contain `level`. // Error: 1-11 unexpected argument -=== Twice. +### Twice. diff --git a/tools/support/typst.tmLanguage.json b/tools/support/typst.tmLanguage.json index 3375a07d..48ef26b8 100644 --- a/tools/support/typst.tmLanguage.json +++ b/tools/support/typst.tmLanguage.json @@ -75,18 +75,17 @@ { "name": "markup.heading.typst", "contentName": "entity.name.section.typst", - "begin": "^\\s*={1,6}", + "begin": "^\\s*#{1,6}\\s+", "end": "\n", "beginCaptures": { "0": { "name": "punctuation.definition.heading.typst" } }, "patterns": [{ "include": "#markup" }] }, { "name": "punctuation.definition.list.unnumbered.typst", - "match": "^\\s*-" + "match": "^\\s*-\\s+" }, { "name": "punctuation.definition.list.numbered.typst", - "match": "^\\s*[0-9]*\\." }, { "name": "string.other.math.block.typst", @@ -111,6 +110,7 @@ "begin": "`", "end": "`", "captures": { "0": { "name": "punctuation.definition.raw.typst" } } + "match": "^\\s*[0-9]*\\.\\s+" }, { "name": "keyword.control.typst",