fix(review): close all 2026-06-03 codebase-review findings (R1-R18)
Resolves the 18 findings from the parallel codebase review, tracked in development/vimwiki-gap.md. Correctness / perf: - Wiki.config -> Arc<WikiConfig> so cloning a Wiki is a refcount bump (R5) - WorkspaceIndex::remove is no longer O(n^2): a per-source contributions map limits the scan to buckets the source actually wrote into (R6) - render_color now expands color_tag_template (__STYLE__/__CONTENT__), consuming the previously-dead field; ColorNode documented as an extension point; 3 renderer tests added (R3/R4) - wiki_root_for returns empty/nil on no-match instead of falling back to the first wiki (R2); auto_header honours links_space_char (R7) Cleanup / dedup: - Remove dead #[allow(dead_code)] stubs + uncalled pub helpers, narrow imports (R10/R11) - Dedup span_of_inline x3 -> InlineNode::span() (R12) - diary_step single read lock; page_captions single pass (R13) - Lua auto_header loop -> wiki_list(); detect_current_symbol cleanup (R14/R18) Client / docs: - :VimwikiNormalizeLink Vim cmds -> <q-args> (R17); ftplugin header fix (R16); vars.vim multi-wiki limitation documented (R15) - Document 19 config options in README.md + doc/nuwiki.txt; fix list_margin/shiftwidth doc and stale comments (R1/R9) - R8 investigated, confirmed not a real bug (documented) Verified: Neovim harness 307, Vim harness 301/18/21, Rust suite 568, all 0 failed; clippy clean; fresh parallel-agent audit found no regressions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -46,6 +46,11 @@ pub struct HtmlRenderer {
|
||||
/// names fall through to the default `class="color-<name>"`
|
||||
/// rendering. Matches vimwiki's `color_dic`.
|
||||
colors: HashMap<String, String>,
|
||||
/// vimwiki `color_tag_template`: the HTML emitted for a colour span whose
|
||||
/// name resolves in `colors`. `__STYLE__` expands to the inline style
|
||||
/// (`color:<css>`) and `__CONTENT__` to the rendered inner HTML. The
|
||||
/// default matches upstream's `<span style="…">…</span>`.
|
||||
color_template: String,
|
||||
/// vimwiki `html_header_numbering`: the heading level at which automatic
|
||||
/// section numbering begins (`0` = off, the default). When `>= 1`, every
|
||||
/// heading at that level or deeper is prefixed with a dotted section
|
||||
@@ -82,6 +87,7 @@ impl HtmlRenderer {
|
||||
template: None,
|
||||
vars: HashMap::new(),
|
||||
colors: HashMap::new(),
|
||||
color_template: "<span style=\"__STYLE__\">__CONTENT__</span>".to_string(),
|
||||
header_numbering: 0,
|
||||
header_numbering_sym: String::new(),
|
||||
valid_html_tags: Vec::new(),
|
||||
@@ -156,6 +162,18 @@ impl HtmlRenderer {
|
||||
self
|
||||
}
|
||||
|
||||
/// Override the colour-span template (vimwiki `color_tag_template`).
|
||||
/// `__STYLE__` is replaced with the resolved `color:<css>` style and
|
||||
/// `__CONTENT__` with the rendered inner HTML. An empty string keeps the
|
||||
/// built-in default.
|
||||
pub fn with_color_template(mut self, template: impl Into<String>) -> Self {
|
||||
let template = template.into();
|
||||
if !template.is_empty() {
|
||||
self.color_template = template;
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Enable vimwiki-style HTML section numbering. `level` is the heading
|
||||
/// level at which numbering starts (`0` disables it); `sym` is appended
|
||||
/// after the number. Mirrors `html_header_numbering` /
|
||||
@@ -311,7 +329,11 @@ impl HtmlRenderer {
|
||||
|
||||
fn render_paragraph(&self, n: &ParagraphNode, w: &mut dyn Write) -> io::Result<()> {
|
||||
w.write_all(b"<p>")?;
|
||||
let sb = if self.text_ignore_newline { " " } else { "<br />" };
|
||||
let sb = if self.text_ignore_newline {
|
||||
" "
|
||||
} else {
|
||||
"<br />"
|
||||
};
|
||||
self.render_inlines_break(&n.children, sb, w)?;
|
||||
w.write_all(b"</p>\n")
|
||||
}
|
||||
@@ -389,7 +411,11 @@ impl HtmlRenderer {
|
||||
}
|
||||
None => w.write_all(b"<li>")?,
|
||||
}
|
||||
let sb = if self.list_ignore_newline { " " } else { "<br />" };
|
||||
let sb = if self.list_ignore_newline {
|
||||
" "
|
||||
} else {
|
||||
"<br />"
|
||||
};
|
||||
self.render_inlines_break(&n.children, sb, w)?;
|
||||
if let Some(sublist) = &n.sublist {
|
||||
w.write_all(b"\n")?;
|
||||
@@ -664,17 +690,32 @@ impl HtmlRenderer {
|
||||
}
|
||||
|
||||
fn render_color(&self, n: &ColorNode, w: &mut dyn Write) -> io::Result<()> {
|
||||
// Render the inner content up front so it can be slotted into the
|
||||
// colour template.
|
||||
let mut content = Vec::new();
|
||||
self.render_inlines(&n.children, &mut content)?;
|
||||
let content = String::from_utf8_lossy(&content);
|
||||
|
||||
if let Some(css) = self.colors.get(&n.color) {
|
||||
w.write_all(b"<span style=\"color:")?;
|
||||
write_escaped(css, w)?;
|
||||
w.write_all(b"\">")?;
|
||||
// Known colour name: expand `color_tag_template` with the resolved
|
||||
// inline style and rendered content.
|
||||
let mut style = b"color:".to_vec();
|
||||
write_escaped(css, &mut style)?;
|
||||
let style = String::from_utf8_lossy(&style);
|
||||
let html = self
|
||||
.color_template
|
||||
.replace("__STYLE__", &style)
|
||||
.replace("__CONTENT__", &content);
|
||||
w.write_all(html.as_bytes())
|
||||
} else {
|
||||
// Unknown name: fall back to a class hook the stylesheet can target
|
||||
// (the template only models the inline-style case).
|
||||
w.write_all(b"<span class=\"color-")?;
|
||||
write_escaped(&n.color, w)?;
|
||||
w.write_all(b"\">")?;
|
||||
w.write_all(content.as_bytes())?;
|
||||
w.write_all(b"</span>")
|
||||
}
|
||||
self.render_inlines(&n.children, w)?;
|
||||
w.write_all(b"</span>")
|
||||
}
|
||||
|
||||
fn render_wikilink(&self, n: &WikiLinkNode, w: &mut dyn Write) -> io::Result<()> {
|
||||
|
||||
Reference in New Issue
Block a user