feat(lsp): wire diary/auto_toc/links_space_char/list_margin; drop client-side keys
Consume several per-wiki config keys that the server deserialized but
ignored, and remove keys whose effect is purely client-side:
- diagnostics: re-publish open-doc diagnostics on
didChangeConfiguration so a link_severity change takes effect
immediately; fix the single-key unwrap in apply_change so a minimal
`{ diagnostic: {...} }` payload isn't mistaken for a namespace wrapper.
- auto_toc: rebuild an existing TOC section on save (new
ops::toc_rebuild_edit, no-op when the page has no TOC).
- diary index: honour diary_header, diary_sort and diary_caption_level
when rendering the diary index body.
- links_space_char: apply on rename so spaces in the link target and
the on-disk path become the configured glyph (default " " = verbatim).
- list_margin: thread the per-wiki value into render_page_html.
- remove nested_syntaxes, maxhi and diary_start_week_day from the server
config: nested-syntax and heading highlighting are client-side, and
the weekly diary is ISO-week based so a custom week start has no clean
server-side meaning.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -267,16 +267,13 @@ fn defaults_carry_vimwiki_per_wiki_keys() {
|
||||
let cfg = WikiConfig::empty();
|
||||
assert_eq!(cfg.index, "index");
|
||||
assert_eq!(cfg.diary_frequency, "daily");
|
||||
assert_eq!(cfg.diary_start_week_day, "monday");
|
||||
assert_eq!(cfg.diary_caption_level, 1);
|
||||
assert_eq!(cfg.diary_sort, "desc");
|
||||
assert_eq!(cfg.diary_header, "Diary");
|
||||
assert_eq!(cfg.maxhi, 1);
|
||||
assert_eq!(cfg.listsyms, " .oOX");
|
||||
assert!(cfg.listsyms_propagate);
|
||||
assert_eq!(cfg.list_margin, -1);
|
||||
assert_eq!(cfg.links_space_char, " ");
|
||||
assert!(cfg.nested_syntaxes.is_empty());
|
||||
assert!(!cfg.auto_toc);
|
||||
}
|
||||
|
||||
@@ -287,35 +284,26 @@ fn raw_wiki_parses_every_new_key() {
|
||||
"root": "/tmp/w",
|
||||
"index": "home",
|
||||
"diary_frequency": "weekly",
|
||||
"diary_start_week_day": "sunday",
|
||||
"diary_caption_level": 2,
|
||||
"diary_sort": "asc",
|
||||
"diary_header": "Journal",
|
||||
"maxhi": 6,
|
||||
"listsyms": "abcde",
|
||||
"listsyms_propagate": false,
|
||||
"list_margin": 2,
|
||||
"links_space_char": "_",
|
||||
"nested_syntaxes": { "python": "python", "ruby": "ruby" },
|
||||
"auto_toc": true,
|
||||
}],
|
||||
}));
|
||||
let w = &cfg.wikis[0];
|
||||
assert_eq!(w.index, "home");
|
||||
assert_eq!(w.diary_frequency, "weekly");
|
||||
assert_eq!(w.diary_start_week_day, "sunday");
|
||||
assert_eq!(w.diary_caption_level, 2);
|
||||
assert_eq!(w.diary_sort, "asc");
|
||||
assert_eq!(w.diary_header, "Journal");
|
||||
assert_eq!(w.maxhi, 6);
|
||||
assert_eq!(w.listsyms, "abcde");
|
||||
assert!(!w.listsyms_propagate);
|
||||
assert_eq!(w.list_margin, 2);
|
||||
assert_eq!(w.links_space_char, "_");
|
||||
assert_eq!(
|
||||
w.nested_syntaxes.get("python").map(String::as_str),
|
||||
Some("python")
|
||||
);
|
||||
assert!(w.auto_toc);
|
||||
}
|
||||
|
||||
@@ -367,6 +355,77 @@ fn apply_change_preserves_severity_on_partial_update() {
|
||||
assert_eq!(cfg.diagnostic.link_severity, LinkSeverity::Error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_change_minimal_diagnostic_payload_is_not_unwrapped() {
|
||||
// A lone `{ "diagnostic": { … } }` is a real flat payload, not a
|
||||
// `{ "nuwiki": { … } }` namespace wrapper. The single-key unwrap must
|
||||
// skip it (it's a recognised top-level key) so the severity applies.
|
||||
let mut cfg = config_from_json(json!({ "wiki_root": "/tmp/w" }));
|
||||
assert_eq!(cfg.diagnostic.link_severity, LinkSeverity::Warning);
|
||||
|
||||
cfg.apply_change(&json!({ "diagnostic": { "link_severity": "error" } }));
|
||||
assert_eq!(cfg.diagnostic.link_severity, LinkSeverity::Error);
|
||||
|
||||
// The Neovim namespace wrapper still unwraps correctly.
|
||||
cfg.apply_change(&json!({ "nuwiki": { "diagnostic": { "link_severity": "hint" } } }));
|
||||
assert_eq!(cfg.diagnostic.link_severity, LinkSeverity::Hint);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn severity_change_via_apply_change_is_observable_in_collected_diagnostics() {
|
||||
// Contract behind `did_change_configuration`'s diagnostic re-publish:
|
||||
// once `apply_change` updates the severity, re-running `collect_diagnostics`
|
||||
// (what the handler does for every open doc) must emit broken-link
|
||||
// diagnostics at the *new* severity. Guards the data path the handler
|
||||
// depends on — apply_change writing the severity AND collect_diagnostics
|
||||
// reading it.
|
||||
use nuwiki_core::syntax::vimwiki::VimwikiSyntax;
|
||||
use nuwiki_core::syntax::SyntaxPlugin;
|
||||
use nuwiki_lsp::index::WorkspaceIndex;
|
||||
use tower_lsp::lsp_types::DiagnosticSeverity;
|
||||
|
||||
let root = "/tmp/cfgchange";
|
||||
let src = "[[GhostPage]]\n";
|
||||
let ast = VimwikiSyntax::new().parse(src);
|
||||
let mut idx = WorkspaceIndex::new(Some(PathBuf::from(root)));
|
||||
let uri = Url::from_file_path(format!("{root}/Home.wiki")).unwrap();
|
||||
idx.upsert(uri.clone(), &ast);
|
||||
|
||||
let mut cfg = config_from_json(json!({
|
||||
"wiki_root": root,
|
||||
"diagnostic": { "link_severity": "warn" },
|
||||
}));
|
||||
let warn = collect_diagnostics(
|
||||
&ast,
|
||||
src,
|
||||
Some(&uri),
|
||||
Some(&idx),
|
||||
Some("Home"),
|
||||
&cfg.diagnostic,
|
||||
true,
|
||||
);
|
||||
assert_eq!(warn.len(), 1, "broken link should warn");
|
||||
assert_eq!(warn[0].severity, Some(DiagnosticSeverity::WARNING));
|
||||
|
||||
// Simulate the client raising severity via didChangeConfiguration.
|
||||
cfg.apply_change(&json!({ "diagnostic": { "link_severity": "error" } }));
|
||||
let err = collect_diagnostics(
|
||||
&ast,
|
||||
src,
|
||||
Some(&uri),
|
||||
Some(&idx),
|
||||
Some("Home"),
|
||||
&cfg.diagnostic,
|
||||
true,
|
||||
);
|
||||
assert_eq!(err.len(), 1);
|
||||
assert_eq!(
|
||||
err[0].severity,
|
||||
Some(DiagnosticSeverity::ERROR),
|
||||
"re-collected diagnostics must reflect the new severity"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vim_flat_and_neovim_wrapped_payloads_desugar_identically() {
|
||||
// Parity guard for the two client shapes:
|
||||
|
||||
Reference in New Issue
Block a user