parity(7): table cell alignment markers (|:--|--:|:--:|)
The Markdown-style alignment anchors on a table's header-separator row now propagate from the lexer through the parser into the AST, and the HTML renderer emits a `style="text-align: …;"` attribute on each affected `<th>` / `<td>`. |:--| → left |--:| → right |:--:| → center |---| → default (no style attr) Encoding choice: rather than threading the source string into the parser, the lexer now extracts per-cell alignment when it recognises the separator row and carries the `Vec<TableAlign>` inline on the `TableHeaderRow` token. The parser unpacks it into `TableNode`'s new `alignments: Vec<TableAlign>` field. Cells past the end of the vector render with the default alignment. `TableAlign` lives in `nuwiki_core::ast::block` alongside the table nodes and is re-exported via `nuwiki_core::ast`. Tests: 4 new in crates/nuwiki-core/tests/vimwiki_table_alignment.rs covering plain dashes, all three anchor flavours, the HTML output shape, and the no-style-attr case. The existing `vimwiki_lexer::table_header_separator_row` was updated to assert the new payload shape. Gates: 425 Rust / 39 Neovim / 12 Vim. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -68,8 +68,9 @@ pub enum VimwikiTokenKind {
|
||||
// ----- Tables -----
|
||||
/// `|` cell separator.
|
||||
TableSep,
|
||||
/// A header-separator row, e.g. `|---|---|`.
|
||||
TableHeaderRow,
|
||||
/// A header-separator row, e.g. `|---|---|`. Carries per-cell
|
||||
/// Markdown-style alignment markers (`:--`, `--:`, `:--:`).
|
||||
TableHeaderRow(Vec<crate::ast::TableAlign>),
|
||||
/// A cell whose only content is `>`, meaning "merge with cell to the left".
|
||||
TableColSpan,
|
||||
/// A cell whose only content is `\/`, meaning "merge with cell above".
|
||||
@@ -563,14 +564,20 @@ impl<'src> LexState<'src> {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Header separator row: every cell content is dashes (e.g. "|---|---|").
|
||||
// Header separator row: every cell is `-`s (with optional `:`
|
||||
// anchors at one or both ends for alignment) or whitespace.
|
||||
if trimmed
|
||||
.split('|')
|
||||
.filter(|s| !s.is_empty())
|
||||
.all(|cell| cell.chars().all(|c| c == '-' || c == ' ' || c == '\t'))
|
||||
.all(is_sep_cell)
|
||||
{
|
||||
let aligns: Vec<crate::ast::TableAlign> = trimmed
|
||||
.split('|')
|
||||
.filter(|s| !s.is_empty())
|
||||
.map(parse_sep_alignment)
|
||||
.collect();
|
||||
let span = Span::new(self.line_start_pos(), self.line_end_pos(line));
|
||||
self.push(VimwikiTokenKind::TableHeaderRow, span);
|
||||
self.push(VimwikiTokenKind::TableHeaderRow(aligns), span);
|
||||
self.emit_newline(line);
|
||||
return true;
|
||||
}
|
||||
@@ -1199,6 +1206,29 @@ fn looks_like_list_marker(s: &str) -> bool {
|
||||
list_marker_at(s).is_some_and(|(_, len)| s.as_bytes().get(len) == Some(&b' '))
|
||||
}
|
||||
|
||||
/// Is this cell content a valid separator-cell body? Allows leading /
|
||||
/// trailing `:` for alignment and inner runs of `-` plus whitespace.
|
||||
fn is_sep_cell(cell: &str) -> bool {
|
||||
let t = cell.trim();
|
||||
if t.is_empty() {
|
||||
return false;
|
||||
}
|
||||
let body = t.trim_start_matches(':').trim_end_matches(':');
|
||||
!body.is_empty() && body.chars().all(|c| c == '-')
|
||||
}
|
||||
|
||||
fn parse_sep_alignment(cell: &str) -> crate::ast::TableAlign {
|
||||
let t = cell.trim();
|
||||
let l = t.starts_with(':');
|
||||
let r = t.ends_with(':');
|
||||
match (l, r) {
|
||||
(true, true) => crate::ast::TableAlign::Center,
|
||||
(true, false) => crate::ast::TableAlign::Left,
|
||||
(false, true) => crate::ast::TableAlign::Right,
|
||||
_ => crate::ast::TableAlign::Default,
|
||||
}
|
||||
}
|
||||
|
||||
fn checkbox_at(s: &str) -> Option<(CheckboxState, usize)> {
|
||||
let b = s.as_bytes();
|
||||
if b.len() < 3 || b[0] != b'[' || b[2] != b']' {
|
||||
|
||||
Reference in New Issue
Block a user