summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorLeedehai <18319900+Leedehai@users.noreply.github.com>2024-04-03 05:01:50 -0400
committerGitHub <noreply@github.com>2024-04-03 09:01:50 +0000
commit0619ae98a86ee5179663aad4ef0575e6b4a284cc (patch)
treefc2e86ee3b38c42503ab0d628c1dd79d9fd626ff /crates
parent0b9878ed318d23e96a853ef025ea6b036673c2a8 (diff)
Fix newline parsing behavior in code mode (#3780)
Diffstat (limited to 'crates')
-rw-r--r--crates/typst-syntax/src/lexer.rs7
-rw-r--r--crates/typst-syntax/src/parser.rs14
2 files changed, 18 insertions, 3 deletions
diff --git a/crates/typst-syntax/src/lexer.rs b/crates/typst-syntax/src/lexer.rs
index aacbee62..f1d29fb3 100644
--- a/crates/typst-syntax/src/lexer.rs
+++ b/crates/typst-syntax/src/lexer.rs
@@ -88,8 +88,10 @@ impl Lexer<'_> {
}
}
-/// Shared.
+/// Shared methods with all [`LexMode`].
impl Lexer<'_> {
+ /// Proceed to the next token and return its [`SyntaxKind`]. Note the
+ /// token could be a [trivia](SyntaxKind::is_trivia).
pub fn next(&mut self) -> SyntaxKind {
if self.mode == LexMode::Raw {
let Some((kind, end)) = self.raw.pop() else {
@@ -121,6 +123,7 @@ impl Lexer<'_> {
}
}
+ /// Eat whitespace characters greedily.
fn whitespace(&mut self, start: usize, c: char) -> SyntaxKind {
let more = self.s.eat_while(|c| is_space(c, self.mode));
let newlines = match c {
@@ -760,7 +763,7 @@ impl ScannerExt for Scanner<'_> {
}
}
-/// Whether a character will become a Space token in Typst
+/// Whether a character will become a [`SyntaxKind::Space`] token.
#[inline]
fn is_space(character: char, mode: LexMode) -> bool {
match mode {
diff --git a/crates/typst-syntax/src/parser.rs b/crates/typst-syntax/src/parser.rs
index 50032898..17f08153 100644
--- a/crates/typst-syntax/src/parser.rs
+++ b/crates/typst-syntax/src/parser.rs
@@ -1748,15 +1748,27 @@ impl<'s> Parser<'s> {
}
}
+ fn next_non_trivia(lexer: &mut Lexer<'s>) -> SyntaxKind {
+ loop {
+ let next = lexer.next();
+ // Loop is terminatable, because SyntaxKind::Eof is not a trivia.
+ if !next.is_trivia() {
+ break next;
+ }
+ }
+ }
+
fn lex(&mut self) {
self.current_start = self.lexer.cursor();
self.current = self.lexer.next();
+
+ // Special cases to handle newlines in code mode.
if self.lexer.mode() == LexMode::Code
&& self.lexer.newline()
&& match self.newline_modes.last() {
Some(NewlineMode::Continue) => false,
Some(NewlineMode::Contextual) => !matches!(
- self.lexer.clone().next(),
+ Self::next_non_trivia(&mut self.lexer.clone()),
SyntaxKind::Else | SyntaxKind::Dot
),
Some(NewlineMode::Stop) => true,