Switch to = for headings once again

This commit is contained in:
Laurenz 2021-07-08 20:03:13 +02:00
parent f85e5aac64
commit 5c327e249e
15 changed files with 55 additions and 57 deletions

View File

@ -102,14 +102,12 @@ fn node(p: &mut Parser, at_start: &mut bool) -> Option<Node> {
Token::Star => Node::Strong(span), Token::Star => Node::Strong(span),
Token::Underscore => Node::Emph(span), Token::Underscore => Node::Emph(span),
Token::Raw(t) => raw(p, t), 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::Hyph if *at_start => return Some(list_item(p)),
Token::Numbering(number) if *at_start => return Some(enum_item(p, number)), 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. // Line-based markup that is not currently at the start of the line.
Token::Hashtag | Token::Hyph | Token::Numbering(_) => { Token::Eq | Token::Hyph | Token::Numbering(_) => Node::Text(p.peek_src().into()),
Node::Text(p.peek_src().into())
}
// Hashtag + keyword / identifier. // Hashtag + keyword / identifier.
Token::Ident(_) Token::Ident(_)
@ -183,11 +181,11 @@ fn raw(p: &mut Parser, token: RawToken) -> Node {
/// Parse a heading. /// Parse a heading.
fn heading(p: &mut Parser) -> Node { fn heading(p: &mut Parser) -> Node {
let start = p.next_start(); let start = p.next_start();
p.assert(Token::Hashtag); p.assert(Token::Eq);
// Count depth. // Count depth.
let mut level: usize = 1; let mut level: usize = 1;
while p.eat_if(Token::Hashtag) { while p.eat_if(Token::Eq) {
level += 1; level += 1;
} }

View File

@ -88,12 +88,12 @@ impl<'s> Scanner<'s> {
/// Checks whether the next char fulfills a condition. /// Checks whether the next char fulfills a condition.
/// ///
/// Returns `false` if there is no next char. /// Returns `default` if there is no next char.
pub fn check<F>(&self, f: F) -> bool pub fn check_or<F>(&self, default: bool, f: F) -> bool
where where
F: FnOnce(char) -> bool, F: FnOnce(char) -> bool,
{ {
self.peek().map(f).unwrap_or(false) self.peek().map_or(default, f)
} }
/// The previous index in the source string. /// The previous index in the source string.

View File

@ -89,19 +89,22 @@ impl<'s> Iterator for Tokens<'s> {
impl<'s> Tokens<'s> { impl<'s> Tokens<'s> {
fn markup(&mut self, start: usize, c: char) -> Token<'s> { fn markup(&mut self, start: usize, c: char) -> Token<'s> {
match c { match c {
// Escape sequences.
'\\' => self.backslash(),
// Keywords and identifiers.
'#' => self.hash(),
// Markup. // Markup.
'~' => Token::Tilde, '~' => Token::Tilde,
'*' => Token::Star, '*' => Token::Star,
'_' => Token::Underscore, '_' => Token::Underscore,
'\\' => self.backslash(),
'`' => self.raw(), '`' => self.raw(),
'$' => self.math(), '$' => self.math(),
'-' => self.hyph(start), '-' => 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), c if c == '.' || c.is_ascii_digit() => self.numbering(start, c),
// Headings, keywords and identifiers.
'#' => self.hash(start),
// Plain text. // Plain text.
_ => self.text(start), _ => self.text(start),
} }
@ -143,7 +146,7 @@ impl<'s> Tokens<'s> {
// Numbers. // Numbers.
c if c.is_ascii_digit() 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) self.number(start, c)
} }
@ -157,7 +160,7 @@ impl<'s> Tokens<'s> {
fn whitespace(&mut self, first: char) -> Token<'s> { fn whitespace(&mut self, first: char) -> Token<'s> {
// Fast path for just a single space // 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) Token::Space(0)
} else { } else {
self.s.uneat(); self.s.uneat();
@ -188,8 +191,10 @@ impl<'s> Tokens<'s> {
'/' => true, '/' => true,
// Parentheses. // Parentheses.
'[' | ']' | '{' | '}' => true, '[' | ']' | '{' | '}' => true,
// Code.
'#' => true,
// Markup. // Markup.
'#' | '~' | '*' | '_' | '`' | '$' | '-' => true, '~' | '*' | '_' | '`' | '$' | '-' => true,
// Escaping. // Escaping.
'\\' => true, '\\' => true,
// Just text. // Just text.
@ -233,18 +238,16 @@ impl<'s> Tokens<'s> {
} }
} }
fn hash(&mut self, start: usize) -> Token<'s> { fn hash(&mut self) -> Token<'s> {
if self.s.check(is_id_start) { if self.s.check_or(false, is_id_start) {
let read = self.s.eat_while(is_id_continue); let read = self.s.eat_while(is_id_continue);
if let Some(keyword) = keyword(read) { if let Some(keyword) = keyword(read) {
keyword keyword
} else { } else {
Token::Ident(read) Token::Ident(read)
} }
} else if self.s.check(|c| c != '#' && !c.is_whitespace()) {
Token::Text(self.s.eaten_from(start))
} else { } else {
Token::Hashtag Token::Invalid("#")
} }
} }
@ -255,10 +258,10 @@ impl<'s> Tokens<'s> {
} else { } else {
Token::HyphHyph Token::HyphHyph
} }
} else if self.s.check(|c| !c.is_whitespace()) { } else if self.s.check_or(true, char::is_whitespace) {
Token::Text(self.s.eaten_from(start))
} else {
Token::Hyph Token::Hyph
} else {
Token::Text(self.s.eaten_from(start))
} }
} }
@ -274,11 +277,11 @@ impl<'s> Tokens<'s> {
None None
}; };
if self.s.check(|c| !c.is_whitespace()) { if self.s.check_or(true, char::is_whitespace) {
return Token::Text(self.s.eaten_from(start)); Token::Numbering(number)
} else {
Token::Text(self.s.eaten_from(start))
} }
Token::Numbering(number)
} }
fn raw(&mut self) -> Token<'s> { fn raw(&mut self) -> Token<'s> {
@ -663,8 +666,8 @@ mod tests {
// Test code symbols in text. // Test code symbols in text.
t!(Markup[" /"]: "a():\"b" => Text("a():\"b")); t!(Markup[" /"]: "a():\"b" => Text("a():\"b"));
t!(Markup[" /"]: ";:,|/+" => Text(";:,|"), Text("/+")); t!(Markup[" /"]: ";:,|/+" => Text(";:,|"), Text("/+"));
t!(Markup[" /"]: "#-a" => Text("#"), Text("-"), Text("a")); t!(Markup[" /"]: "=-a" => Text("="), Text("-"), Text("a"));
t!(Markup[" "]: "#123" => Text("#"), Text("123")); t!(Markup[" "]: "#123" => Invalid("#"), Text("123"));
// Test text ends. // Test text ends.
t!(Markup[""]: "hello " => Text("hello"), Space(0)); t!(Markup[""]: "hello " => Text("hello"), Space(0));
@ -712,8 +715,8 @@ mod tests {
// Test markup tokens. // Test markup tokens.
t!(Markup[" a1"]: "*" => Star); t!(Markup[" a1"]: "*" => Star);
t!(Markup: "_" => Underscore); t!(Markup: "_" => Underscore);
t!(Markup[""]: "###" => Hashtag, Hashtag, Hashtag); t!(Markup[""]: "===" => Eq, Eq, Eq);
t!(Markup["a1/"]: "# " => Hashtag, Space(0)); t!(Markup["a1/"]: "= " => Eq, Space(0));
t!(Markup: "~" => Tilde); t!(Markup: "~" => Tilde);
t!(Markup[" "]: r"\" => Backslash); t!(Markup[" "]: r"\" => Backslash);
t!(Markup["a "]: r"a--" => Text("a"), HyphHyph); t!(Markup["a "]: r"a--" => Text("a"), HyphHyph);
@ -776,7 +779,7 @@ mod tests {
for &(s, t) in &list { for &(s, t) in &list {
t!(Markup[" "]: format!("#{}", s) => t); t!(Markup[" "]: format!("#{}", s) => t);
t!(Markup[" "]: format!("#{0}#{0}", s) => t, 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 { for &(s, t) in &list {

View File

@ -169,7 +169,7 @@ impl Pretty for RawNode {
impl Pretty for HeadingNode { impl Pretty for HeadingNode {
fn pretty(&self, p: &mut Printer) { fn pretty(&self, p: &mut Printer) {
for _ in 0 .. self.level { for _ in 0 .. self.level {
p.push('#'); p.push('=');
} }
p.push(' '); p.push(' ');
self.body.pretty(p); self.body.pretty(p);
@ -653,7 +653,7 @@ mod tests {
roundtrip("\\ "); roundtrip("\\ ");
roundtrip("\n\n"); roundtrip("\n\n");
roundtrip("hi"); roundtrip("hi");
roundtrip("# *Ok*"); roundtrip("= *Ok*");
roundtrip("- Ok"); roundtrip("- Ok");
// Raw. // Raw.

View File

@ -19,8 +19,6 @@ pub enum Token<'s> {
Star, Star,
/// An underscore: `_`. /// An underscore: `_`.
Underscore, Underscore,
/// A single hashtag: `#`.
Hashtag,
/// A tilde: `~`. /// A tilde: `~`.
Tilde, Tilde,
/// Two hyphens: `--`. /// Two hyphens: `--`.
@ -215,7 +213,6 @@ impl<'s> Token<'s> {
Self::RightParen => "closing paren", Self::RightParen => "closing paren",
Self::Star => "star", Self::Star => "star",
Self::Underscore => "underscore", Self::Underscore => "underscore",
Self::Hashtag => "hashtag",
Self::Tilde => "tilde", Self::Tilde => "tilde",
Self::HyphHyph => "en dash", Self::HyphHyph => "en dash",
Self::HyphHyphHyph => "em dash", Self::HyphHyphHyph => "em dash",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

@ -7,7 +7,7 @@
--- ---
// Test in heading. // Test in heading.
# A #align!(right) B = A #align!(right) B
C C
--- ---

View File

@ -2,7 +2,7 @@
#let name = "Klaus" #let name = "Klaus"
## Chapter 1 == Chapter 1
#name stood in a field of wheat. There was nothing of particular interest about #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 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 totally ruin his semi-new outdorsy jacket but then again, most of us spend

View File

@ -2,7 +2,7 @@
#let name = "Klaus" #let name = "Klaus"
## Chapter 2 == Chapter 2
Their motivations, however, were pretty descript, so to speak. #name had not yet Their motivations, however, were pretty descript, so to speak. #name had not yet
conceptualized their consequences, but that should change pretty quickly. #name 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 approached the center of the field and picked up a 4-foot long disk made from

View File

@ -1,7 +1,7 @@
// Test include statements. // Test include statements.
--- ---
# Document = Document
// Include a file // Include a file
#include "importable/chap1.typ" #include "importable/chap1.typ"

View File

@ -79,6 +79,6 @@ Three
// Error: 9 expected expression // Error: 9 expected expression
#let v = #let v =
// Should output `= 1`. // Should output a heading `1`.
// Error: 6-9 expected identifier, found string // Error: 6-9 expected identifier, found string
#let "v" = 1 #let "v" = 1

View File

@ -30,7 +30,7 @@
// the parentheses. // the parentheses.
#align(center)[ #align(center)[
// Markdown-like syntax for headings. // 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) *Abgabe: 03.05.2019* (bis 10:10 Uhr in MA 001) #v(4mm)
*Alle Antworten sind zu beweisen.* *Alle Antworten sind zu beweisen.*
] ]

View File

@ -4,39 +4,39 @@
// Different number of hashtags. // Different number of hashtags.
// Valid levels. // Valid levels.
# Level 1 = Level 1
### Level 2 === Level 2
###### Level 6 ====== Level 6
// Too many hashtags. // Too many hashtags.
// Warning: 1-8 should not exceed depth 6 // Warning: 1-8 should not exceed depth 6
####### Level 7 ======= Level 7
--- ---
// Heading vs. no heading. // Heading vs. no heading.
// Parsed as headings if at start of the context. // Parsed as headings if at start of the context.
/**/ # Level 1 /**/ = Level 1
{[## Level 2]} {[== Level 2]}
#box[### Level 3] #box[=== Level 3]
// Not at the start of the context. // Not at the start of the context.
No # heading No = heading
// Escaped. // Escaped.
\# No heading \= No heading
--- ---
// While indented at least as much as the start, the heading continues. // While indented at least as much as the start, the heading continues.
# This = This
is is
indented. indented.
# This = This
is not. is not.
// Code blocks continue heading. // Code blocks continue heading.
# A { = A {
"B" "B"
} }

View File

@ -75,7 +75,7 @@
{ {
"name": "markup.heading.typst", "name": "markup.heading.typst",
"contentName": "entity.name.section.typst", "contentName": "entity.name.section.typst",
"begin": "^\\s*#{1,6}\\s+", "begin": "^\\s*={1,6}\\s+",
"end": "\n", "end": "\n",
"beginCaptures": { "0": { "name": "punctuation.definition.heading.typst" } }, "beginCaptures": { "0": { "name": "punctuation.definition.heading.typst" } },
"patterns": [{ "include": "#markup" }] "patterns": [{ "include": "#markup" }]