feat(html): html_header_numbering section numbering for HTML export
Mirror vimwiki's html_header_numbering / html_header_numbering_sym: top-level headings at or below the start level get a dotted section number (1, 1.1, 1.2, ...) with a configurable trailing symbol. Off by default (level 0). Nested headings in lists/quotes stay unnumbered, matching upstream's document-level-only scan. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -41,6 +41,8 @@ fn html_config_defaults_match_vimwiki() {
|
||||
assert!(!c.auto_export);
|
||||
assert!(!c.html_filename_parameterization);
|
||||
assert!(c.exclude_files.is_empty());
|
||||
assert_eq!(c.html_header_numbering, 0); // upstream default: numbering off
|
||||
assert!(c.html_header_numbering_sym.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -270,6 +272,73 @@ fn render_page_html_uses_metadata_date_when_set() {
|
||||
assert!(html.contains("DATE=2025-01-02"), "got: {html}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_page_html_numbers_headers_when_enabled() {
|
||||
let ast = parse("= Intro =\n== Background ==\n== Methods ==\n= Results =\n");
|
||||
let mut c = cfg("/tmp/x");
|
||||
c.html.html_header_numbering = 1; // number from h1
|
||||
c.html.html_header_numbering_sym = ".".into();
|
||||
let html = export::render_page_html(
|
||||
&ast,
|
||||
None,
|
||||
"Home",
|
||||
DiaryDate::from_ymd(2026, 5, 11).unwrap(),
|
||||
&c.html,
|
||||
None,
|
||||
-1,
|
||||
HashMap::new(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(html.contains("<h1>1. Intro</h1>"), "got: {html}");
|
||||
assert!(html.contains("<h2>1.1. Background</h2>"), "got: {html}");
|
||||
assert!(html.contains("<h2>1.2. Methods</h2>"), "got: {html}");
|
||||
assert!(html.contains("<h1>2. Results</h1>"), "got: {html}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_page_html_numbering_skips_headers_above_start_level() {
|
||||
let ast = parse("= Title =\n== Section ==\n=== Sub ===\n");
|
||||
let mut c = cfg("/tmp/x");
|
||||
c.html.html_header_numbering = 2; // start at h2; h1 stays unnumbered
|
||||
// empty sym → number followed by a bare space
|
||||
let html = export::render_page_html(
|
||||
&ast,
|
||||
None,
|
||||
"Home",
|
||||
DiaryDate::from_ymd(2026, 5, 11).unwrap(),
|
||||
&c.html,
|
||||
None,
|
||||
-1,
|
||||
HashMap::new(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(
|
||||
html.contains("<h1>Title</h1>"),
|
||||
"h1 unnumbered, got: {html}"
|
||||
);
|
||||
assert!(html.contains("<h2>1 Section</h2>"), "got: {html}");
|
||||
assert!(html.contains("<h3>1.1 Sub</h3>"), "got: {html}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_page_html_no_header_numbering_by_default() {
|
||||
let ast = parse("= Intro =\n== Sub ==\n");
|
||||
let c = cfg("/tmp/x");
|
||||
let html = export::render_page_html(
|
||||
&ast,
|
||||
None,
|
||||
"Home",
|
||||
DiaryDate::from_ymd(2026, 5, 11).unwrap(),
|
||||
&c.html,
|
||||
None,
|
||||
-1,
|
||||
HashMap::new(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(html.contains("<h1>Intro</h1>"), "got: {html}");
|
||||
assert!(html.contains("<h2>Sub</h2>"), "got: {html}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_page_html_root_path_for_nested_pages() {
|
||||
let ast = parse("= D =\n");
|
||||
|
||||
Reference in New Issue
Block a user