18. Restore list indent behavior

This commit is contained in:
Ian Wrzesinski 2024-11-03 20:35:21 -05:00
parent 9d9a1b1e33
commit 2c9728f53b
3 changed files with 67 additions and 27 deletions

View File

@ -69,9 +69,11 @@ impl<'s> Lexer<'s> {
self.newline self.newline
} }
/// The number of characters until the most recent newline. /// The number of characters until the most recent newline from an index.
pub fn column(&self) -> usize { pub fn column(&self, index: usize) -> usize {
self.s.before().chars().rev().take_while(|&c| !is_newline(c)).count() 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()
} }
} }

View File

@ -1545,11 +1545,7 @@ struct Token {
/// Information about a newline if present (currently only relevant in Markup). /// Information about a newline if present (currently only relevant in Markup).
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
struct Newline { struct Newline {
/// The column of our token in its line. /// The column of the start 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.
column: Option<usize>, column: Option<usize>,
/// Whether any of our newlines were paragraph breaks. /// Whether any of our newlines were paragraph breaks.
parbreak: bool, parbreak: bool,
@ -1684,10 +1680,6 @@ impl<'s> Parser<'s> {
/// The number of characters until the most recent newline from the current /// The number of characters until the most recent newline from the current
/// token, or 0 if it did not follow a newline. /// 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 { fn current_column(&self) -> usize {
self.token.newline.and_then(|newline| newline.column).unwrap_or(0) 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 kind, mut node) = lexer.next();
let mut n_trivia = 0; let mut n_trivia = 0;
let mut had_newline = false; let mut had_newline = false;
let mut newline = Newline { column: None, parbreak: false }; let mut parbreak = false;
while kind.is_trivia() { while kind.is_trivia() {
if lexer.newline() { had_newline |= lexer.newline(); // Newlines are always trivia.
// Newlines are always trivia. parbreak |= kind == SyntaxKind::Parbreak;
had_newline = true;
newline.parbreak |= kind == SyntaxKind::Parbreak;
if lexer.mode() == LexMode::Markup {
newline.column = Some(lexer.column());
}
}
n_trivia += 1; n_trivia += 1;
nodes.push(node); nodes.push(node);
start = lexer.cursor(); start = lexer.cursor();
(kind, node) = lexer.next(); (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 } Token { kind, node, n_trivia, newline, start, prev_end }
} }
} }

View File

@ -34,6 +34,51 @@ _Shopping list_
- C - C
- D - 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 --- --- list-tabs ---
// This works because tabs are used consistently. // This works because tabs are used consistently.
- A with 1 tab - A with 1 tab