feat(config): make listsym_rejected configurable (P2)

The rejected/cancelled checkbox glyph was a hardcoded `const REJECTED = '-'`.
ListSyms now carries a `rejected` field (new_with_rejected); a per-wiki
`listsym_rejected` key (default `-`) is added to WikiConfig, and
WikiConfig::list_syms() builds the palette with it. Routed the three
config-driven ListSyms construction sites (parse path in lib.rs + the
toggle/cycle commands) through list_syms(), so a custom rejected glyph both
lexes and round-trips.

Tests: listsyms::custom_rejected_glyph_is_honoured + config round-trip.
README/doc/lua config comment updated. fmt clean; 0 Rust test failures.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-31 18:33:25 +00:00
parent 624bccbe50
commit 2d3db458fb
9 changed files with 76 additions and 17 deletions
+3 -5
View File
@@ -250,7 +250,7 @@ fn list_checkbox(
let wiki = backend.wiki_for_uri(&p.uri);
let syms = wiki
.as_ref()
.map(|w| nuwiki_core::listsyms::ListSyms::new(&w.config.listsyms))
.map(|w| w.config.list_syms())
.unwrap_or_default();
let propagate = wiki.map(|w| w.config.listsyms_propagate).unwrap_or(true);
Ok(ops::checkbox_edit(
@@ -1184,10 +1184,8 @@ fn export_all(backend: &Backend, args: Vec<Value>, force: bool) -> Result<Option
let Ok(text) = std::fs::read_to_string(path) else {
continue;
};
let ast = nuwiki_core::syntax::vimwiki::VimwikiSyntax::new().parse_with_listsyms(
&text,
&nuwiki_core::listsyms::ListSyms::new(&cfg.listsyms),
);
let ast = nuwiki_core::syntax::vimwiki::VimwikiSyntax::new()
.parse_with_listsyms(&text, &cfg.list_syms());
(text, ast)
}
};
+21
View File
@@ -61,6 +61,9 @@ pub struct WikiConfig {
/// glyphs and the toggle/cycle commands walk them. Any length ≥ 2 is
/// honoured. Default: `" .oOX"`.
pub listsyms: String,
/// Vimwiki's `g:vimwiki_listsym_rejected` — the glyph for a cancelled
/// checkbox (`[-]` by default). First character is used.
pub listsym_rejected: String,
/// When toggling a parent list item, also cascade to descendants.
pub listsyms_propagate: bool,
/// `-1` keeps tight lists; positive integers indent list items by
@@ -188,6 +191,7 @@ impl WikiConfig {
diary_sort: d.diary_sort,
diary_header: d.diary_header,
listsyms: d.listsyms,
listsym_rejected: d.listsym_rejected,
listsyms_propagate: d.listsyms_propagate,
list_margin: d.list_margin,
links_space_char: d.links_space_char,
@@ -217,6 +221,7 @@ impl WikiConfig {
diary_sort: d.diary_sort,
diary_header: d.diary_header,
listsyms: d.listsyms,
listsym_rejected: d.listsym_rejected,
listsyms_propagate: d.listsyms_propagate,
list_margin: d.list_margin,
links_space_char: d.links_space_char,
@@ -258,6 +263,13 @@ impl WikiConfig {
nuwiki_core::date::DiaryFrequency::parse(&self.diary_frequency)
}
/// The checkbox palette for this wiki — the `listsyms` progression plus
/// the configured `listsym_rejected` glyph (default `-`).
pub fn list_syms(&self) -> nuwiki_core::listsyms::ListSyms {
let rejected = self.listsym_rejected.chars().next().unwrap_or('-');
nuwiki_core::listsyms::ListSyms::new_with_rejected(&self.listsyms, rejected)
}
/// The diary navigation policy (frequency + weekly naming/week-start),
/// used by the diary commands to compute today / next / prev.
pub fn diary_calendar(&self) -> nuwiki_core::date::DiaryCalendar {
@@ -306,6 +318,10 @@ fn default_listsyms() -> String {
" .oOX".to_string()
}
fn default_listsym_rejected() -> String {
"-".to_string()
}
fn default_links_space_char() -> String {
" ".to_string()
}
@@ -327,6 +343,7 @@ fn wiki_defaults() -> WikiDefaults {
diary_sort: default_diary_sort(),
diary_header: default_diary_header(),
listsyms: default_listsyms(),
listsym_rejected: default_listsym_rejected(),
listsyms_propagate: true,
list_margin: -1,
links_space_char: default_links_space_char(),
@@ -345,6 +362,7 @@ struct WikiDefaults {
diary_sort: String,
diary_header: String,
listsyms: String,
listsym_rejected: String,
listsyms_propagate: bool,
list_margin: i32,
links_space_char: String,
@@ -565,6 +583,8 @@ struct RawWiki {
diary_header: Option<String>,
#[serde(default)]
listsyms: Option<String>,
#[serde(default)]
listsym_rejected: Option<String>,
#[serde(default, deserialize_with = "opt_bool_or_int::deserialize")]
listsyms_propagate: Option<bool>,
#[serde(default)]
@@ -629,6 +649,7 @@ impl From<RawWiki> for WikiConfig {
diary_sort: r.diary_sort.unwrap_or(d.diary_sort),
diary_header: r.diary_header.unwrap_or(d.diary_header),
listsyms: r.listsyms.unwrap_or(d.listsyms),
listsym_rejected: r.listsym_rejected.unwrap_or(d.listsym_rejected),
listsyms_propagate: r.listsyms_propagate.unwrap_or(d.listsyms_propagate),
list_margin: r.list_margin.unwrap_or(d.list_margin),
links_space_char: r.links_space_char.unwrap_or(d.links_space_char),
+1 -1
View File
@@ -193,7 +193,7 @@ impl Backend {
fn parse_for_uri(&self, uri: &Url, text: &str) -> nuwiki_core::ast::DocumentNode {
let syms = self
.wiki_for_uri(uri)
.map(|w| nuwiki_core::listsyms::ListSyms::new(&w.config.listsyms))
.map(|w| w.config.list_syms())
.unwrap_or_default();
nuwiki_core::syntax::vimwiki::VimwikiSyntax::new().parse_with_listsyms(text, &syms)
}