fix: TOC header class, numbering config, and Lua defaults
CI / cargo fmt --check (push) Successful in 31s
CI / cargo clippy (push) Successful in 31s
CI / cargo test (push) Successful in 36s
Release / build x86_64-unknown-linux-gnu (push) Successful in 53s
Release / build aarch64-unknown-linux-musl (push) Successful in 1m6s
Release / build x86_64-unknown-linux-musl (push) Successful in 1m8s
Release / build aarch64-unknown-linux-gnu (push) Successful in 1m47s
Release / gitea release (push) Successful in 28s
CI / editor keymaps (push) Successful in 1m39s

- Add class='toc' to TOC heading in HTML export by detecting the
  configured toc_header value in render_heading()
- Add toc_header field to HtmlRenderer and wire it through
  render_page_html()
- Add toc_header, toc_header_level, html_header_numbering, and
  html_header_numbering_sym to Lua config defaults so users can
  discover and set them
This commit is contained in:
2026-06-04 00:37:07 -03:00
parent bd729d513d
commit f3d8af5f23
4 changed files with 50 additions and 8 deletions
+32 -8
View File
@@ -59,6 +59,10 @@ pub struct HtmlRenderer {
/// vimwiki `html_header_numbering_sym`: a symbol appended after the
/// section number (e.g. `.` → `1.2. Heading`). Empty by default.
header_numbering_sym: String,
/// vimwiki `toc_header`: the heading text that identifies the TOC
/// section. When a heading matches this value (case-insensitive), it
/// gets `class="toc"` in HTML export.
toc_header: String,
/// vimwiki `valid_html_tags`: inline HTML tag names passed through to
/// export verbatim (instead of escaping `<`/`>`). Empty = escape all.
/// `span` is always allowed so colour spans render.
@@ -90,6 +94,7 @@ impl HtmlRenderer {
color_template: "<span style=\"__STYLE__\">__CONTENT__</span>".to_string(),
header_numbering: 0,
header_numbering_sym: String::new(),
toc_header: String::new(),
valid_html_tags: Vec::new(),
emoji_enable: false,
text_ignore_newline: true,
@@ -183,6 +188,13 @@ impl HtmlRenderer {
self.header_numbering_sym = sym.into();
self
}
/// Set the vimwiki TOC heading text. When a heading matches this value
/// (case-insensitive) it gets `class="toc"` in HTML export.
pub fn with_toc_header(mut self, header: impl Into<String>) -> Self {
self.toc_header = header.into();
self
}
}
/// Running state for vimwiki-style HTML section numbering
@@ -314,15 +326,27 @@ impl HtmlRenderer {
/// pass `""` for no numbering.
fn render_heading(&self, n: &HeadingNode, number: &str, w: &mut dyn Write) -> io::Result<()> {
let level = n.level.clamp(1, 6);
let class = if n.centered {
" class=\"centered\""
} else {
""
};
// `id` is the heading's plain text (vimwiki's anchor scheme), so
// `[[Page#Heading]]` and TOC `#Heading` links land here. Matches the
// anchor text the LSP validates and the resolver emits.
let anchor = crate::ast::inline_text(&n.children);
let is_toc = self
.toc_header
.as_bytes()
.iter()
.zip(anchor.as_bytes())
.all(|(a, b)| a.eq_ignore_ascii_case(b))
&& !self.toc_header.is_empty()
&& self.toc_header.len() == anchor.len();
let mut classes = Vec::new();
if is_toc {
classes.push("toc");
}
if n.centered {
classes.push("centered");
}
let class = if classes.is_empty() {
String::new()
} else {
format!(" class=\"{}\"", classes.join(" "))
};
write!(w, "<h{level}{class} id=\"")?;
write_escaped(&anchor, w)?;
write!(w, "\">")?;