fix(parity): close the 2026-06-02 re-audit config/command findings
CI / cargo fmt --check (push) Successful in 19s
CI / cargo clippy (push) Successful in 37s
CI / cargo test (push) Successful in 29s
CI / editor keymaps (push) Successful in 1m36s

Implements the remaining fourth-pass findings (gap doc updated):

- list_margin: rework to upstream's buffer-side meaning. Drop the
  nuwiki-only HTML em-margin (renderer field/method + render_page_html
  param removed) and prepend max(0, list_margin) leading spaces to every
  generated bullet in build_toc_text / build_links_text /
  build_tag_links_text / diary::build_index_body; headings stay at col 0.
  From<RawWiki> derives 0 for markdown wikis when unset. Negatives can't
  resolve 'shiftwidth' server-side, so they collapse to zero indent
  (documented divergence).

- diary_months: per-wiki Vec<String> (default 12 English names), threaded
  into the diary-index month labels; missing/empty slots fall back to the
  English name.

- diary_caption_level: widen u8 -> i8 so vimwiki's -1 (min: -1) parses;
  build_index_body clamps < 0 to base tree level 0.

- VimwikiRemoveDone: regain upstream's -range. All four defs are now
  -bang -range, dispatched via remove_done(bang, range, l1, l2) in both
  clients: ! -> whole buffer, explicit range -> new list_remove_done_range
  ({range:[l1-1,l2-1]}), else current list. Server remove_done_edit gained
  an Option<(u32,u32)> range that filters whole-doc victims by start line.

markdown_header_style is deferred: the generators emit vimwiki syntax only
(caption_line never writes markdown headers), so there's no markdown header
to attach the style to. Logged as the "generated-content is vimwiki-only"
intentional divergence pending a later markdown generated-content effort.

Tests: list_margin indent, markdown list_margin-0 default, diary_months
custom + fallback, negative caption_level clamp/parse, ranged remove-done
(server + both keymap harnesses). 553 lsp/core tests pass; clippy clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-02 10:50:38 +00:00
parent 079e7246ac
commit 9441fe918c
19 changed files with 603 additions and 202 deletions
+56 -8
View File
@@ -49,13 +49,21 @@ pub struct WikiConfig {
/// Weekday the diary week begins on (`monday`..`sunday`, vimwiki's
/// `diary_start_week_day`). Used only when `diary_weekly_style = date`.
pub diary_start_week_day: String,
/// Caption level for the diary index page headings (1 = h1).
pub diary_caption_level: u8,
/// Caption level for the diary index page headings (1 = h1). vimwiki's
/// `diary_caption_level` (`min: -1`). nuwiki uses it as the base level of
/// the year/month index tree; values `< 0` clamp to `0` (upstream's `-1`
/// "read no per-page captions" mode isn't modelled — nuwiki builds the
/// tree from dates, not page headers).
pub diary_caption_level: i8,
/// Newest-first (`desc`) or oldest-first (`asc`) in the diary
/// index.
pub diary_sort: String,
/// H1 text for the diary index page.
pub diary_header: String,
/// vimwiki `diary_months`: month-number → display name for the diary
/// index tree. Twelve entries (January..December) by default; a custom
/// list falls back to the English name for any missing/out-of-range slot.
pub diary_months: Vec<String>,
/// Vimwiki's `g:vimwiki_listsyms`. A progression of checkbox glyphs
/// from "empty" (first) to "done" (last); the lexer recognises these
/// glyphs and the toggle/cycle commands walk them. Any length ≥ 2 is
@@ -66,8 +74,12 @@ pub struct WikiConfig {
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
/// that many extra columns. Layout hint for the renderer.
/// vimwiki `list_margin`: number of leading spaces before bullets in
/// **buffer-side generated lists** — `:VimwikiGenerateLinks`, the TOC, the
/// tags index, and the diary index. `>= 0` indents by that many spaces;
/// `< 0` means "no margin" (default `-1`; `0` for markdown wikis).
/// Divergence: upstream resolves `< 0` to the buffer's `'shiftwidth'`,
/// which the server can't observe, so negatives collapse to zero indent.
pub list_margin: i32,
/// Character used in place of literal spaces inside wikilink
/// targets when writing to disk (a single space `" "` by default,
@@ -229,6 +241,7 @@ impl WikiConfig {
diary_caption_level: d.diary_caption_level,
diary_sort: d.diary_sort,
diary_header: d.diary_header,
diary_months: d.diary_months,
listsyms: d.listsyms,
listsym_rejected: d.listsym_rejected,
listsyms_propagate: d.listsyms_propagate,
@@ -268,6 +281,7 @@ impl WikiConfig {
diary_caption_level: d.diary_caption_level,
diary_sort: d.diary_sort,
diary_header: d.diary_header,
diary_months: d.diary_months,
listsyms: d.listsyms,
listsym_rejected: d.listsym_rejected,
listsyms_propagate: d.listsyms_propagate,
@@ -371,6 +385,27 @@ fn default_diary_header() -> String {
"Diary".to_string()
}
/// vimwiki's default `diary_months` — the English month names, January..December.
fn default_diary_months() -> Vec<String> {
[
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
]
.iter()
.map(|s| s.to_string())
.collect()
}
fn default_listsyms() -> String {
" .oOX".to_string()
}
@@ -411,6 +446,7 @@ fn wiki_defaults() -> WikiDefaults {
diary_caption_level: 0,
diary_sort: default_diary_sort(),
diary_header: default_diary_header(),
diary_months: default_diary_months(),
listsyms: default_listsyms(),
listsym_rejected: default_listsym_rejected(),
listsyms_propagate: true,
@@ -436,9 +472,10 @@ struct WikiDefaults {
diary_frequency: String,
diary_weekly_style: String,
diary_start_week_day: String,
diary_caption_level: u8,
diary_caption_level: i8,
diary_sort: String,
diary_header: String,
diary_months: Vec<String>,
listsyms: String,
listsym_rejected: String,
listsyms_propagate: bool,
@@ -673,12 +710,14 @@ struct RawWiki {
#[serde(default)]
diary_start_week_day: Option<String>,
#[serde(default)]
diary_caption_level: Option<u8>,
diary_caption_level: Option<i8>,
#[serde(default)]
diary_sort: Option<String>,
#[serde(default)]
diary_header: Option<String>,
#[serde(default)]
diary_months: Option<Vec<String>>,
#[serde(default)]
listsyms: Option<String>,
#[serde(default)]
listsym_rejected: Option<String>,
@@ -764,11 +803,19 @@ impl From<RawWiki> for WikiConfig {
html.html_header_numbering_sym = s;
}
let d = wiki_defaults();
let syntax = r.syntax.unwrap_or_else(|| "vimwiki".into());
// vimwiki derives `list_margin = 0` for markdown wikis when the key is
// unset (vars.vim:651); other syntaxes keep the `-1` default.
let list_margin = r.list_margin.unwrap_or(if syntax == "markdown" {
0
} else {
d.list_margin
});
WikiConfig {
name: r.name.unwrap_or(derived_name),
root,
file_extension: r.file_extension.unwrap_or_else(|| ".wiki".into()),
syntax: r.syntax.unwrap_or_else(|| "vimwiki".into()),
syntax,
index: r.index.unwrap_or(d.index),
diary_rel_path: r.diary_rel_path.unwrap_or(d.diary_rel_path),
diary_index: r.diary_index.unwrap_or(d.diary_index),
@@ -778,10 +825,11 @@ impl From<RawWiki> for WikiConfig {
diary_caption_level: r.diary_caption_level.unwrap_or(d.diary_caption_level),
diary_sort: r.diary_sort.unwrap_or(d.diary_sort),
diary_header: r.diary_header.unwrap_or(d.diary_header),
diary_months: r.diary_months.unwrap_or(d.diary_months),
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),
list_margin,
links_space_char: r.links_space_char.unwrap_or(d.links_space_char),
auto_toc: r.auto_toc.unwrap_or(d.auto_toc),
auto_generate_links: r.auto_generate_links.unwrap_or(d.auto_generate_links),