fix(parity): close the 2026-06-02 re-audit config/command findings
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:
@@ -274,7 +274,15 @@ fn build_index_body_is_newest_first_grouped_by_year_month() {
|
||||
&["2025-12-31", "2026-05-11", "2026-05-12", "2026-04-30"],
|
||||
);
|
||||
let entries = diary::list_entries(&idx);
|
||||
let body = diary::build_index_body(&entries, "diary", "Diary", diary::DiarySort::Desc, 1);
|
||||
let body = diary::build_index_body(
|
||||
&entries,
|
||||
"diary",
|
||||
"Diary",
|
||||
diary::DiarySort::Desc,
|
||||
1,
|
||||
&[],
|
||||
0,
|
||||
);
|
||||
let lines: Vec<&str> = body.lines().collect();
|
||||
assert_eq!(lines[0], "= Diary =");
|
||||
// First date in output should be the latest: 2026-05-12
|
||||
@@ -292,7 +300,7 @@ fn build_index_body_is_newest_first_grouped_by_year_month() {
|
||||
|
||||
#[test]
|
||||
fn build_index_body_empty_when_no_entries() {
|
||||
let body = diary::build_index_body(&[], "diary", "Diary", diary::DiarySort::Desc, 1);
|
||||
let body = diary::build_index_body(&[], "diary", "Diary", diary::DiarySort::Desc, 1, &[], 0);
|
||||
assert_eq!(body, "= Diary =\n");
|
||||
}
|
||||
|
||||
@@ -300,7 +308,8 @@ fn build_index_body_empty_when_no_entries() {
|
||||
fn build_index_body_ascending_sort_lists_oldest_first() {
|
||||
let idx = build_index_with_entries("/tmp/diarySort", &["2026-05-11", "2026-05-12"]);
|
||||
let entries = diary::list_entries(&idx);
|
||||
let body = diary::build_index_body(&entries, "diary", "Diary", diary::DiarySort::Asc, 1);
|
||||
let body =
|
||||
diary::build_index_body(&entries, "diary", "Diary", diary::DiarySort::Asc, 1, &[], 0);
|
||||
let older = body.find("2026-05-11").unwrap();
|
||||
let newer = body.find("2026-05-12").unwrap();
|
||||
assert!(older < newer, "ascending sort lists oldest first");
|
||||
@@ -310,7 +319,15 @@ fn build_index_body_ascending_sort_lists_oldest_first() {
|
||||
fn build_index_body_caption_level_shifts_all_headings() {
|
||||
let idx = build_index_with_entries("/tmp/diaryCap", &["2026-05-11"]);
|
||||
let entries = diary::list_entries(&idx);
|
||||
let body = diary::build_index_body(&entries, "diary", "Diary", diary::DiarySort::Desc, 2);
|
||||
let body = diary::build_index_body(
|
||||
&entries,
|
||||
"diary",
|
||||
"Diary",
|
||||
diary::DiarySort::Desc,
|
||||
2,
|
||||
&[],
|
||||
0,
|
||||
);
|
||||
assert!(body.contains("== Diary =="), "caption at level 2");
|
||||
assert!(
|
||||
body.contains("=== 2026 ==="),
|
||||
@@ -327,11 +344,102 @@ fn build_index_body_clamps_caption_level_to_six() {
|
||||
let idx = build_index_with_entries("/tmp/diaryClamp", &["2026-05-11"]);
|
||||
let entries = diary::list_entries(&idx);
|
||||
// caption_level 6 → year/month would be 7/8 but clamp to 6.
|
||||
let body = diary::build_index_body(&entries, "diary", "Diary", diary::DiarySort::Desc, 6);
|
||||
let body = diary::build_index_body(
|
||||
&entries,
|
||||
"diary",
|
||||
"Diary",
|
||||
diary::DiarySort::Desc,
|
||||
6,
|
||||
&[],
|
||||
0,
|
||||
);
|
||||
assert!(body.contains("====== Diary ======"));
|
||||
assert!(!body.contains("======="), "no heading exceeds level 6");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_index_body_uses_custom_diary_months() {
|
||||
let idx = build_index_with_entries("/tmp/diaryMonths", &["2026-05-11", "2026-12-01"]);
|
||||
let entries = diary::list_entries(&idx);
|
||||
// A localized month table (Portuguese) replaces the English labels.
|
||||
let months: Vec<String> = [
|
||||
"Janeiro",
|
||||
"Fevereiro",
|
||||
"Março",
|
||||
"Abril",
|
||||
"Maio",
|
||||
"Junho",
|
||||
"Julho",
|
||||
"Agosto",
|
||||
"Setembro",
|
||||
"Outubro",
|
||||
"Novembro",
|
||||
"Dezembro",
|
||||
]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let body = diary::build_index_body(
|
||||
&entries,
|
||||
"diary",
|
||||
"Diary",
|
||||
diary::DiarySort::Desc,
|
||||
1,
|
||||
&months,
|
||||
0,
|
||||
);
|
||||
assert!(body.contains("=== Maio ==="), "May → Maio: {body}");
|
||||
assert!(
|
||||
body.contains("=== Dezembro ==="),
|
||||
"December → Dezembro: {body}"
|
||||
);
|
||||
assert!(!body.contains("May"), "English label leaked: {body}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_index_body_falls_back_per_missing_month_slot() {
|
||||
let idx = build_index_with_entries("/tmp/diaryShort", &["2026-05-11"]);
|
||||
let entries = diary::list_entries(&idx);
|
||||
// A too-short table only covers Jan–Mar; May falls back to English.
|
||||
let months: Vec<String> = ["Jan", "Feb", "Mar"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let body = diary::build_index_body(
|
||||
&entries,
|
||||
"diary",
|
||||
"Diary",
|
||||
diary::DiarySort::Desc,
|
||||
1,
|
||||
&months,
|
||||
0,
|
||||
);
|
||||
assert!(
|
||||
body.contains("=== May ==="),
|
||||
"missing slot → English: {body}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_index_body_clamps_negative_caption_level_to_zero() {
|
||||
let idx = build_index_with_entries("/tmp/diaryNeg", &["2026-05-11"]);
|
||||
let entries = diary::list_entries(&idx);
|
||||
// vimwiki allows diary_caption_level = -1; nuwiki clamps it to 0 (same as
|
||||
// a caption_level of 0: caption h1, year h1, month h2).
|
||||
let body = diary::build_index_body(
|
||||
&entries,
|
||||
"diary",
|
||||
"Diary",
|
||||
diary::DiarySort::Desc,
|
||||
-1,
|
||||
&[],
|
||||
0,
|
||||
);
|
||||
assert!(body.contains("= Diary ="), "caption at level 1: {body}");
|
||||
assert!(body.contains("= 2026 ="), "year at level 1: {body}");
|
||||
assert!(body.contains("== May =="), "month at level 2: {body}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_index_body_round_trip() {
|
||||
let cfg = wiki_cfg("/tmp/diaryA");
|
||||
|
||||
Reference in New Issue
Block a user