feat(core): make checkbox lexing honor a configurable listsyms palette
Add a ListSyms type (vimwiki's g:vimwiki_listsyms) and thread it through the lexer so checkbox glyphs are recognized from the configured palette rather than the hardcoded ' .oOX'. Glyphs map to the existing five-bucket CheckboxState, so the HTML renderer and AST consumers are unchanged. VimwikiSyntax::parse_with_listsyms opts into a custom palette; the trait parse() keeps the default. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::ast::{CheckboxState, Keyword, ListSymbol, Position, Span};
|
||||
use crate::listsyms::ListSyms;
|
||||
use crate::syntax::{Lexer, TokenStream};
|
||||
|
||||
/// A single vimwiki token. The `kind` carries the variant, `span` carries
|
||||
@@ -134,11 +135,20 @@ pub enum VimwikiTokenKind {
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct VimwikiLexer;
|
||||
pub struct VimwikiLexer {
|
||||
listsyms: ListSyms,
|
||||
}
|
||||
|
||||
impl VimwikiLexer {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Recognise checkbox glyphs from a custom palette
|
||||
/// (vimwiki's `g:vimwiki_listsyms`) instead of the default `" .oOX"`.
|
||||
pub fn with_listsyms(mut self, listsyms: ListSyms) -> Self {
|
||||
self.listsyms = listsyms;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +156,7 @@ impl Lexer for VimwikiLexer {
|
||||
type Token = VimwikiToken;
|
||||
|
||||
fn lex(&self, text: &str) -> TokenStream<VimwikiToken> {
|
||||
let mut state = LexState::new(text);
|
||||
let mut state = LexState::new(text, &self.listsyms);
|
||||
state.run();
|
||||
TokenStream::from_vec(state.tokens)
|
||||
}
|
||||
@@ -170,16 +180,18 @@ struct LexState<'src> {
|
||||
line: u32,
|
||||
tokens: Vec<VimwikiToken>,
|
||||
mode: BlockMode,
|
||||
listsyms: &'src ListSyms,
|
||||
}
|
||||
|
||||
impl<'src> LexState<'src> {
|
||||
fn new(src: &'src str) -> Self {
|
||||
fn new(src: &'src str, listsyms: &'src ListSyms) -> Self {
|
||||
Self {
|
||||
src,
|
||||
line_start_offset: 0,
|
||||
line: 0,
|
||||
tokens: Vec::new(),
|
||||
mode: BlockMode::Normal,
|
||||
listsyms,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -704,7 +716,7 @@ impl<'src> LexState<'src> {
|
||||
|
||||
// Optional checkbox `[ ]` / `[.]` / `[o]` / `[O]` / `[X]` / `[-]`,
|
||||
// followed by a space.
|
||||
if let Some((cb, cb_len)) = checkbox_at(after) {
|
||||
if let Some((cb, cb_len)) = checkbox_at(after, self.listsyms) {
|
||||
let cb_start = indent + cursor as u32;
|
||||
let cb_end = cb_start + cb_len as u32;
|
||||
self.emit(VimwikiTokenKind::Checkbox(cb), cb_start, cb_end);
|
||||
@@ -1230,19 +1242,18 @@ fn parse_sep_alignment(cell: &str) -> crate::ast::TableAlign {
|
||||
}
|
||||
}
|
||||
|
||||
fn checkbox_at(s: &str) -> Option<(CheckboxState, usize)> {
|
||||
let b = s.as_bytes();
|
||||
if b.len() < 3 || b[0] != b'[' || b[2] != b']' {
|
||||
/// Recognise a `[g]` checkbox at the start of `s`, where `g` is a single
|
||||
/// glyph drawn from `listsyms` (or the rejected marker). Returns the bucketed
|
||||
/// state and the byte length consumed (including the brackets).
|
||||
fn checkbox_at(s: &str, listsyms: &ListSyms) -> Option<(CheckboxState, usize)> {
|
||||
let rest = s.strip_prefix('[')?;
|
||||
let mut chars = rest.char_indices();
|
||||
let (_, glyph) = chars.next()?;
|
||||
let (close_off, ']') = chars.next()? else {
|
||||
return None;
|
||||
}
|
||||
let cb = match b[1] {
|
||||
b' ' => CheckboxState::Empty,
|
||||
b'.' => CheckboxState::Quarter,
|
||||
b'o' => CheckboxState::Half,
|
||||
b'O' => CheckboxState::ThreeQuarters,
|
||||
b'X' => CheckboxState::Done,
|
||||
b'-' => CheckboxState::Rejected,
|
||||
_ => return None,
|
||||
};
|
||||
Some((cb, 3))
|
||||
let state = listsyms.state_of(glyph)?;
|
||||
// `[` + glyph + `]`: 1 + glyph.len_utf8() + 1, i.e. the close bracket
|
||||
// offset within `rest` plus one for the opening bracket and one for `]`.
|
||||
Some((state, 1 + close_off + 1))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user