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:
@@ -168,37 +168,78 @@ fn period_first_day(p: &DiaryPeriod) -> DiaryDate {
|
||||
p.first_day()
|
||||
}
|
||||
|
||||
/// Generate the body of the diary index page — a flat newest-first list
|
||||
/// of `[[diary/YYYY-MM-DD]]` wikilinks, grouped under year and month
|
||||
/// Ordering of entries in the diary index page.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum DiarySort {
|
||||
/// Newest first (vimwiki default).
|
||||
Desc,
|
||||
/// Oldest first.
|
||||
Asc,
|
||||
}
|
||||
|
||||
impl DiarySort {
|
||||
/// Parse a wiki's `diary_sort` field. Anything other than `asc`
|
||||
/// (case-insensitive) is treated as the default `desc`.
|
||||
pub fn parse(s: &str) -> Self {
|
||||
if s.trim().eq_ignore_ascii_case("asc") {
|
||||
Self::Asc
|
||||
} else {
|
||||
Self::Desc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Render a heading line at `level` (1 = `= … =`). Clamped to vimwiki's
|
||||
/// 1..=6 range so a stray config value can't emit a 200-equals heading.
|
||||
fn heading(level: u8, text: &str) -> String {
|
||||
let n = level.clamp(1, 6) as usize;
|
||||
let eq = "=".repeat(n);
|
||||
format!("{eq} {text} {eq}")
|
||||
}
|
||||
|
||||
/// Generate the body of the diary index page — a flat list of
|
||||
/// `[[diary/YYYY-MM-DD]]` wikilinks, grouped under year and month
|
||||
/// subheadings so the rendered page mirrors `:VimwikiDiaryGenerateLinks`.
|
||||
///
|
||||
/// `caption_level` sets the level of the top caption; the year and month
|
||||
/// subheadings nest one and two levels below it. `sort` controls whether
|
||||
/// the flat list runs newest- or oldest-first.
|
||||
pub fn build_index_body(
|
||||
entries: &[DiaryEntry],
|
||||
diary_rel_path: &str,
|
||||
index_heading: &str,
|
||||
sort: DiarySort,
|
||||
caption_level: u8,
|
||||
) -> String {
|
||||
let mut out = String::new();
|
||||
out.push_str("= ");
|
||||
out.push_str(index_heading);
|
||||
out.push_str(" =\n");
|
||||
out.push_str(&heading(caption_level, index_heading));
|
||||
out.push('\n');
|
||||
|
||||
if entries.is_empty() {
|
||||
return out;
|
||||
}
|
||||
|
||||
// Sort descending by date — newest first matches vimwiki.
|
||||
let mut sorted: Vec<&DiaryEntry> = entries.iter().collect();
|
||||
sorted.sort_by(|a, b| b.date.cmp(&a.date));
|
||||
sorted.sort_by(|a, b| match sort {
|
||||
DiarySort::Desc => b.date.cmp(&a.date),
|
||||
DiarySort::Asc => a.date.cmp(&b.date),
|
||||
});
|
||||
|
||||
let year_level = caption_level.saturating_add(1);
|
||||
let month_level = caption_level.saturating_add(2);
|
||||
let mut current_year: Option<i32> = None;
|
||||
let mut current_month: Option<u8> = None;
|
||||
for e in sorted {
|
||||
if current_year != Some(e.date.year) {
|
||||
out.push_str(&format!("\n== {} ==\n", e.date.year));
|
||||
out.push('\n');
|
||||
out.push_str(&heading(year_level, &e.date.year.to_string()));
|
||||
out.push('\n');
|
||||
current_year = Some(e.date.year);
|
||||
current_month = None;
|
||||
}
|
||||
if current_month != Some(e.date.month) {
|
||||
out.push_str(&format!("=== {} ===\n", month_name(e.date.month)));
|
||||
out.push_str(&heading(month_level, month_name(e.date.month)));
|
||||
out.push('\n');
|
||||
current_month = Some(e.date.month);
|
||||
}
|
||||
out.push_str(&format!(
|
||||
@@ -211,9 +252,16 @@ pub fn build_index_body(
|
||||
}
|
||||
|
||||
/// Render the diary-index body for the given wiki's currently-indexed
|
||||
/// entries. Convenience wrapper around [`build_index_body`].
|
||||
/// entries. Convenience wrapper around [`build_index_body`] that honours
|
||||
/// the wiki's `diary_header`, `diary_sort`, and `diary_caption_level`.
|
||||
pub fn render_index_body(cfg: &WikiConfig, index: &WorkspaceIndex) -> String {
|
||||
build_index_body(&list_entries(index), &cfg.diary_rel_path, "Diary")
|
||||
build_index_body(
|
||||
&list_entries(index),
|
||||
&cfg.diary_rel_path,
|
||||
&cfg.diary_header,
|
||||
DiarySort::parse(&cfg.diary_sort),
|
||||
cfg.diary_caption_level,
|
||||
)
|
||||
}
|
||||
|
||||
/// Cheap "is this path under the diary subdir of this wiki" check —
|
||||
|
||||
Reference in New Issue
Block a user