summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-07-08 20:03:13 +0200
committerLaurenz <laurmaedje@gmail.com>2021-07-08 20:03:13 +0200
commit5c327e249e03ac303e7fef40e2df6c6ef834db66 (patch)
tree44e60f7ed494e1e6452f378620baa4afbc755346
parentf85e5aac64784deac75950a1307f2ca802ad6765 (diff)
Switch to = for headings once again
-rw-r--r--src/parse/mod.rs10
-rw-r--r--src/parse/scanner.rs6
-rw-r--r--src/parse/tokens.rs51
-rw-r--r--src/pretty.rs4
-rw-r--r--src/syntax/token.rs3
-rw-r--r--tests/ref/code/let.pngbin2231 -> 2245 bytes
-rw-r--r--tests/ref/markup/heading.pngbin7446 -> 7328 bytes
-rw-r--r--tests/typ/code/call-wide.typ2
-rw-r--r--tests/typ/code/importable/chap1.typ2
-rw-r--r--tests/typ/code/importable/chap2.typ2
-rw-r--r--tests/typ/code/include.typ2
-rw-r--r--tests/typ/code/let.typ2
-rw-r--r--tests/typ/coma.typ2
-rw-r--r--tests/typ/markup/heading.typ24
-rw-r--r--tools/support/typst.tmLanguage.json2
15 files changed, 55 insertions, 57 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index bdecc31f..1d893ad9 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -102,14 +102,12 @@ fn node(p: &mut Parser, at_start: &mut bool) -> Option<Node> {
Token::Star => Node::Strong(span),
Token::Underscore => Node::Emph(span),
Token::Raw(t) => raw(p, t),
- Token::Hashtag if *at_start => return Some(heading(p)),
+ Token::Eq if *at_start => return Some(heading(p)),
Token::Hyph if *at_start => return Some(list_item(p)),
Token::Numbering(number) if *at_start => return Some(enum_item(p, number)),
// Line-based markup that is not currently at the start of the line.
- Token::Hashtag | Token::Hyph | Token::Numbering(_) => {
- Node::Text(p.peek_src().into())
- }
+ Token::Eq | Token::Hyph | Token::Numbering(_) => Node::Text(p.peek_src().into()),
// Hashtag + keyword / identifier.
Token::Ident(_)
@@ -183,11 +181,11 @@ fn raw(p: &mut Parser, token: RawToken) -> Node {
/// Parse a heading.
fn heading(p: &mut Parser) -> Node {
let start = p.next_start();
- p.assert(Token::Hashtag);
+ p.assert(Token::Eq);
// Count depth.
let mut level: usize = 1;
- while p.eat_if(Token::Hashtag) {
+ while p.eat_if(Token::Eq) {
level += 1;
}
diff --git a/src/parse/scanner.rs b/src/parse/scanner.rs
index fad44e89..af88aa68 100644
--- a/src/parse/scanner.rs
+++ b/src/parse/scanner.rs
@@ -88,12 +88,12 @@ impl<'s> Scanner<'s> {
/// Checks whether the next char fulfills a condition.
///
- /// Returns `false` if there is no next char.
- pub fn check<F>(&self, f: F) -> bool
+ /// Returns `default` if there is no next char.
+ pub fn check_or<F>(&self, default: bool, f: F) -> bool
where
F: FnOnce(char) -> bool,
{
- self.peek().map(f).unwrap_or(false)
+ self.peek().map_or(default, f)
}
/// The previous index in the source string.
diff --git a/src/parse/tokens.rs b/src/parse/tokens.rs
index f2196740..aebe7b70 100644
--- a/src/parse/tokens.rs
+++ b/src/parse/tokens.rs
@@ -89,19 +89,22 @@ impl<'s> Iterator for Tokens<'s> {
impl<'s> Tokens<'s> {
fn markup(&mut self, start: usize, c: char) -> Token<'s> {
match c {
+ // Escape sequences.
+ '\\' => self.backslash(),
+
+ // Keywords and identifiers.
+ '#' => self.hash(),
+
// Markup.
'~' => Token::Tilde,
'*' => Token::Star,
'_' => Token::Underscore,
- '\\' => self.backslash(),
'`' => self.raw(),
'$' => self.math(),
'-' => self.hyph(start),
+ '=' if self.s.check_or(true, |c| c == '=' || c.is_whitespace()) => Token::Eq,
c if c == '.' || c.is_ascii_digit() => self.numbering(start, c),
- // Headings, keywords and identifiers.
- '#' => self.hash(start),
-
// Plain text.
_ => self.text(start),
}
@@ -143,7 +146,7 @@ impl<'s> Tokens<'s> {
// Numbers.
c if c.is_ascii_digit()
- || (c == '.' && self.s.check(|n| n.is_ascii_digit())) =>
+ || (c == '.' && self.s.check_or(false, |n| n.is_ascii_digit())) =>
{
self.number(start, c)
}
@@ -157,7 +160,7 @@ impl<'s> Tokens<'s> {
fn whitespace(&mut self, first: char) -> Token<'s> {
// Fast path for just a single space
- if first == ' ' && !self.s.check(char::is_whitespace) {
+ if first == ' ' && self.s.check_or(true, |c| !c.is_whitespace()) {
Token::Space(0)
} else {
self.s.uneat();
@@ -188,8 +191,10 @@ impl<'s> Tokens<'s> {
'/' => true,
// Parentheses.
'[' | ']' | '{' | '}' => true,
+ // Code.
+ '#' => true,
// Markup.
- '#' | '~' | '*' | '_' | '`' | '$' | '-' => true,
+ '~' | '*' | '_' | '`' | '$' | '-' => true,
// Escaping.
'\\' => true,
// Just text.
@@ -233,18 +238,16 @@ impl<'s> Tokens<'s> {
}
}
- fn hash(&mut self, start: usize) -> Token<'s> {
- if self.s.check(is_id_start) {
+ fn hash(&mut self) -> Token<'s> {
+ if self.s.check_or(false, is_id_start) {
let read = self.s.eat_while(is_id_continue);
if let Some(keyword) = keyword(read) {
keyword
} else {
Token::Ident(read)
}
- } else if self.s.check(|c| c != '#' && !c.is_whitespace()) {
- Token::Text(self.s.eaten_from(start))
} else {
- Token::Hashtag
+ Token::Invalid("#")
}
}
@@ -255,10 +258,10 @@ impl<'s> Tokens<'s> {
} else {
Token::HyphHyph
}
- } else if self.s.check(|c| !c.is_whitespace()) {
- Token::Text(self.s.eaten_from(start))
- } else {
+ } else if self.s.check_or(true, char::is_whitespace) {
Token::Hyph
+ } else {
+ Token::Text(self.s.eaten_from(start))
}
}
@@ -274,11 +277,11 @@ impl<'s> Tokens<'s> {
None
};
- if self.s.check(|c| !c.is_whitespace()) {
- return Token::Text(self.s.eaten_from(start));
+ if self.s.check_or(true, char::is_whitespace) {
+ Token::Numbering(number)
+ } else {
+ Token::Text(self.s.eaten_from(start))
}
-
- Token::Numbering(number)
}
fn raw(&mut self) -> Token<'s> {
@@ -663,8 +666,8 @@ mod tests {
// Test code symbols in text.
t!(Markup[" /"]: "a():\"b" => Text("a():\"b"));
t!(Markup[" /"]: ";:,|/+" => Text(";:,|"), Text("/+"));
- t!(Markup[" /"]: "#-a" => Text("#"), Text("-"), Text("a"));
- t!(Markup[" "]: "#123" => Text("#"), Text("123"));
+ t!(Markup[" /"]: "=-a" => Text("="), Text("-"), Text("a"));
+ t!(Markup[" "]: "#123" => Invalid("#"), Text("123"));
// Test text ends.
t!(Markup[""]: "hello " => Text("hello"), Space(0));
@@ -712,8 +715,8 @@ mod tests {
// Test markup tokens.
t!(Markup[" a1"]: "*" => Star);
t!(Markup: "_" => Underscore);
- t!(Markup[""]: "###" => Hashtag, Hashtag, Hashtag);
- t!(Markup["a1/"]: "# " => Hashtag, Space(0));
+ t!(Markup[""]: "===" => Eq, Eq, Eq);
+ t!(Markup["a1/"]: "= " => Eq, Space(0));
t!(Markup: "~" => Tilde);
t!(Markup[" "]: r"\" => Backslash);
t!(Markup["a "]: r"a--" => Text("a"), HyphHyph);
@@ -776,7 +779,7 @@ mod tests {
for &(s, t) in &list {
t!(Markup[" "]: format!("#{}", s) => t);
t!(Markup[" "]: format!("#{0}#{0}", s) => t, t);
- t!(Markup[" /"]: format!("# {}", s) => Token::Hashtag, Space(0), Text(s));
+ t!(Markup[" /"]: format!("# {}", s) => Token::Invalid("#"), Space(0), Text(s));
}
for &(s, t) in &list {
diff --git a/src/pretty.rs b/src/pretty.rs
index 17609cea..ff8841f3 100644
--- a/src/pretty.rs
+++ b/src/pretty.rs
@@ -169,7 +169,7 @@ impl Pretty for RawNode {
impl Pretty for HeadingNode {
fn pretty(&self, p: &mut Printer) {
for _ in 0 .. self.level {
- p.push('#');
+ p.push('=');
}
p.push(' ');
self.body.pretty(p);
@@ -653,7 +653,7 @@ mod tests {
roundtrip("\\ ");
roundtrip("\n\n");
roundtrip("hi");
- roundtrip("# *Ok*");
+ roundtrip("= *Ok*");
roundtrip("- Ok");
// Raw.
diff --git a/src/syntax/token.rs b/src/syntax/token.rs
index 32a14d58..425dac10 100644
--- a/src/syntax/token.rs
+++ b/src/syntax/token.rs
@@ -19,8 +19,6 @@ pub enum Token<'s> {
Star,
/// An underscore: `_`.
Underscore,
- /// A single hashtag: `#`.
- Hashtag,
/// A tilde: `~`.
Tilde,
/// Two hyphens: `--`.
@@ -215,7 +213,6 @@ impl<'s> Token<'s> {
Self::RightParen => "closing paren",
Self::Star => "star",
Self::Underscore => "underscore",
- Self::Hashtag => "hashtag",
Self::Tilde => "tilde",
Self::HyphHyph => "en dash",
Self::HyphHyphHyph => "em dash",
diff --git a/tests/ref/code/let.png b/tests/ref/code/let.png
index ae360b6b..e9c00064 100644
--- a/tests/ref/code/let.png
+++ b/tests/ref/code/let.png
Binary files differ
diff --git a/tests/ref/markup/heading.png b/tests/ref/markup/heading.png
index f69bb887..35a589bd 100644
--- a/tests/ref/markup/heading.png
+++ b/tests/ref/markup/heading.png
Binary files differ
diff --git a/tests/typ/code/call-wide.typ b/tests/typ/code/call-wide.typ
index 54da540b..996a052d 100644
--- a/tests/typ/code/call-wide.typ
+++ b/tests/typ/code/call-wide.typ
@@ -7,7 +7,7 @@
---
// Test in heading.
-# A #align!(right) B
+= A #align!(right) B
C
---
diff --git a/tests/typ/code/importable/chap1.typ b/tests/typ/code/importable/chap1.typ
index a0f38d0d..06a4c1a1 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 51e116aa..d4aedc60 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 8080c6e8..166c3945 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/code/let.typ b/tests/typ/code/let.typ
index 1a0bb10e..d788a563 100644
--- a/tests/typ/code/let.typ
+++ b/tests/typ/code/let.typ
@@ -79,6 +79,6 @@ Three
// Error: 9 expected expression
#let v =
-// Should output `= 1`.
+// Should output a heading `1`.
// Error: 6-9 expected identifier, found string
#let "v" = 1
diff --git a/tests/typ/coma.typ b/tests/typ/coma.typ
index 5074bd9e..161ac832 100644
--- a/tests/typ/coma.typ
+++ b/tests/typ/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 8787d959..e0dbd999 100644
--- a/tests/typ/markup/heading.typ
+++ b/tests/typ/markup/heading.typ
@@ -4,39 +4,39 @@
// Different number of hashtags.
// Valid levels.
-# Level 1
-### Level 2
-###### Level 6
+= Level 1
+=== Level 2
+====== Level 6
// Too many hashtags.
// Warning: 1-8 should not exceed depth 6
-####### Level 7
+======= Level 7
---
// Heading vs. no heading.
// Parsed as headings if at start of the context.
-/**/ # Level 1
-{[## Level 2]}
-#box[### Level 3]
+/**/ = Level 1
+{[== Level 2]}
+#box[=== Level 3]
// Not at the start of the context.
-No # heading
+No = heading
// Escaped.
-\# No heading
+\= No heading
---
// While indented at least as much as the start, the heading continues.
-# This
+= This
is
indented.
-# This
+= This
is not.
// Code blocks continue heading.
-# A {
+= A {
"B"
}
diff --git a/tools/support/typst.tmLanguage.json b/tools/support/typst.tmLanguage.json
index e1f41653..33e4c3db 100644
--- a/tools/support/typst.tmLanguage.json
+++ b/tools/support/typst.tmLanguage.json
@@ -75,7 +75,7 @@
{
"name": "markup.heading.typst",
"contentName": "entity.name.section.typst",
- "begin": "^\\s*#{1,6}\\s+",
+ "begin": "^\\s*={1,6}\\s+",
"end": "\n",
"beginCaptures": { "0": { "name": "punctuation.definition.heading.typst" } },
"patterns": [{ "include": "#markup" }]