diff options
| author | Ian Wrzesinski <wrzian@umich.edu> | 2024-11-03 20:35:21 -0500 |
|---|---|---|
| committer | Ian Wrzesinski <wrzian@umich.edu> | 2024-11-03 22:04:06 -0500 |
| commit | 2c9728f53b318a6cae092f30ad0956a536af7ccb (patch) | |
| tree | c30909de62b6d2d87c02393542d38b56ddd4beec | |
| parent | 9d9a1b1e33cdc379200c1d3881c34fe05c496894 (diff) | |
18. Restore list indent behavior
| -rw-r--r-- | crates/typst-syntax/src/lexer.rs | 8 | ||||
| -rw-r--r-- | crates/typst-syntax/src/parser.rs | 41 | ||||
| -rw-r--r-- | tests/suite/model/list.typ | 45 |
3 files changed, 67 insertions, 27 deletions
diff --git a/crates/typst-syntax/src/lexer.rs b/crates/typst-syntax/src/lexer.rs index d09c6f84..1314016f 100644 --- a/crates/typst-syntax/src/lexer.rs +++ b/crates/typst-syntax/src/lexer.rs @@ -69,9 +69,11 @@ impl<'s> Lexer<'s> { self.newline } - /// The number of characters until the most recent newline. - pub fn column(&self) -> usize { - self.s.before().chars().rev().take_while(|&c| !is_newline(c)).count() + /// The number of characters until the most recent newline from an index. + pub fn column(&self, index: usize) -> usize { + let mut s = self.s; // Make a new temporary scanner (cheap). + s.jump(index); + s.before().chars().rev().take_while(|&c| !is_newline(c)).count() } } diff --git a/crates/typst-syntax/src/parser.rs b/crates/typst-syntax/src/parser.rs index b26cc002..5fc621d6 100644 --- a/crates/typst-syntax/src/parser.rs +++ b/crates/typst-syntax/src/parser.rs @@ -1545,11 +1545,7 @@ struct Token { /// Information about a newline if present (currently only relevant in Markup). #[derive(Debug, Clone, Copy)] struct Newline { - /// The column of our token in its line. - /// - /// Note that this is actually the column of the first non-whitespace - /// `SyntaxKind` in the line, so `\n /**/- list` has column 2 (not 6) - /// because the block comment is the first non-space kind. + /// The column of the start of our token in its line. column: Option<usize>, /// Whether any of our newlines were paragraph breaks. parbreak: bool, @@ -1684,10 +1680,6 @@ impl<'s> Parser<'s> { /// The number of characters until the most recent newline from the current /// token, or 0 if it did not follow a newline. - /// - /// Note that this is actually the column of the first non-whitespace - /// `SyntaxKind` in the line, so `\n /**/- list` has column 2 (not 6) - /// because the block comment is the first non-space kind. fn current_column(&self) -> usize { self.token.newline.and_then(|newline| newline.column).unwrap_or(0) } @@ -1852,29 +1844,30 @@ impl<'s> Parser<'s> { let (mut kind, mut node) = lexer.next(); let mut n_trivia = 0; let mut had_newline = false; - let mut newline = Newline { column: None, parbreak: false }; + let mut parbreak = false; while kind.is_trivia() { - if lexer.newline() { - // Newlines are always trivia. - had_newline = true; - newline.parbreak |= kind == SyntaxKind::Parbreak; - if lexer.mode() == LexMode::Markup { - newline.column = Some(lexer.column()); - } - } + had_newline |= lexer.newline(); // Newlines are always trivia. + parbreak |= kind == SyntaxKind::Parbreak; n_trivia += 1; nodes.push(node); start = lexer.cursor(); (kind, node) = lexer.next(); } - if had_newline && nl_mode.stop_at(newline, kind) { - // Insert a temporary `SyntaxKind::End` to halt the parser. - // The actual kind will be restored from `node` later. - kind = SyntaxKind::End; - } - let newline = had_newline.then_some(newline); + let newline = if had_newline { + let column = (lexer.mode() == LexMode::Markup).then(|| lexer.column(start)); + let newline = Newline { column, parbreak }; + if nl_mode.stop_at(newline, kind) { + // Insert a temporary `SyntaxKind::End` to halt the parser. + // The actual kind will be restored from `node` later. + kind = SyntaxKind::End; + } + Some(newline) + } else { + None + }; + Token { kind, node, n_trivia, newline, start, prev_end } } } diff --git a/tests/suite/model/list.typ b/tests/suite/model/list.typ index 46f4621f..c3c123de 100644 --- a/tests/suite/model/list.typ +++ b/tests/suite/model/list.typ @@ -34,6 +34,51 @@ _Shopping list_ - C - D +--- list-indent-trivia-nesting --- +// Test indent nesting behavior with odd trivia (comments and spaces). + +#let indented = [ +- a + /**/- b +/**/ - c + /*spanning + multiple + lines */ - d + - e +/**/ - f +/**/ - g +] +// Current behavior is that list columns are based on the first non-whitespace +// element in their line, so the block comments here determine the column the +// list starts at + +#let item = list.item +#let manual = { + [ ] + item({ + [a] + [ ] + item[b] + [ ]; [ ] + item({ + [c] + [ ]; [ ] + item[d] + }) + [ ] + item({ + [e] + [ ]; [ ] + item[f] + [ ]; [ ] + item[g] + }) + }) + [ ] +} + +#test(indented, manual) + --- list-tabs --- // This works because tabs are used consistently. - A with 1 tab |
