fix(export): render vimwiki-compatible HTML for templates, links, and tasks
Stock vimwiki templates and stylesheets rendered broken pages because the
HTML output diverged from vimwiki conventions on three fronts:
- Templates: the renderer only substituted nuwiki's `{{key}}` placeholders,
so vimwiki's `%title%`/`%content%`/`%root_path%`/`%date%`/`%wiki_css%`
passed through literally — dropping the body and breaking asset links.
Both delimiter styles are now recognised; `%wiki_css%` aliases the css var.
- Links: `[[todo.wiki]]` exported to `todo.wiki.html`. render_page_html now
takes the wiki file extension and strips it from wiki/interwiki targets
(via index::strip_wiki_extension) before the `.html` URL is built, matching
in-editor navigation. file:/local: links keep their literal extension.
- Tasks: checkbox items used bespoke `task-*` classes plus an `<input>`,
which double-rendered against vimwiki stylesheets. Emit `done0..done4`
(`[ ] [.] [o] [O] [X]`) and `rejected` (`[-]`) classes with no input — the
stylesheet draws the box.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -18,7 +18,7 @@
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use nuwiki_core::ast::{BlockNode, DocumentNode, HeadingNode, InlineNode};
|
||||
use nuwiki_core::ast::{BlockNode, DocumentNode, HeadingNode, InlineNode, LinkKind};
|
||||
use nuwiki_core::date::DiaryDate;
|
||||
use nuwiki_core::render::{HtmlRenderer, Renderer};
|
||||
|
||||
@@ -188,12 +188,18 @@ pub fn is_excluded(patterns: &[String], name: &str) -> bool {
|
||||
/// Pure HTML render pass. The caller has already loaded the template
|
||||
/// (or falls back). Wires up `{{date}}`, `{{root_path}}`, `{{toc}}`
|
||||
/// plus arbitrary extras passed via `extra_vars`.
|
||||
///
|
||||
/// `wiki_extension` is the wiki's source file extension (e.g. `".wiki"`).
|
||||
/// When set, it is stripped from wiki/interwiki link targets so a link
|
||||
/// written with the extension (`[[todo.wiki]]`) exports to `todo.html`,
|
||||
/// matching how the LSP resolves the same link for in-editor navigation.
|
||||
pub fn render_page_html(
|
||||
doc: &DocumentNode,
|
||||
template: Option<String>,
|
||||
name: &str,
|
||||
today: DiaryDate,
|
||||
cfg: &HtmlConfig,
|
||||
wiki_extension: Option<&str>,
|
||||
extra_vars: HashMap<String, String>,
|
||||
) -> std::io::Result<String> {
|
||||
let date_str = match doc.metadata.date.as_deref() {
|
||||
@@ -211,11 +217,30 @@ pub fn render_page_html(
|
||||
vars.insert("root_path".into(), root_path);
|
||||
vars.insert("toc".into(), toc);
|
||||
vars.insert("css".into(), cfg.css_name.clone());
|
||||
// vimwiki names the stylesheet placeholder `%wiki_css%`; alias it so stock
|
||||
// templates resolve. nuwiki's own templates use `{{css}}`.
|
||||
vars.insert("wiki_css".into(), cfg.css_name.clone());
|
||||
for (k, v) in extra_vars {
|
||||
vars.insert(k, v);
|
||||
}
|
||||
|
||||
let mut r = HtmlRenderer::new();
|
||||
if let Some(ext) = wiki_extension.filter(|e| !e.trim_start_matches('.').is_empty()) {
|
||||
// Strip the wiki extension from page links before the default resolver
|
||||
// turns them into `.html` URLs, so `[[todo.wiki]]` → `todo.html` rather
|
||||
// than `todo.wiki.html`. Only wiki/interwiki targets are touched;
|
||||
// file:/local: paths keep their literal extension.
|
||||
let ext = ext.to_string();
|
||||
r = r.with_link_resolver(move |target| {
|
||||
let mut t = target.clone();
|
||||
if matches!(t.kind, LinkKind::Wiki | LinkKind::Interwiki) {
|
||||
if let Some(p) = t.path.take() {
|
||||
t.path = Some(crate::index::strip_wiki_extension(&p, Some(&ext)).to_string());
|
||||
}
|
||||
}
|
||||
nuwiki_core::render::html::default_link_resolver(&t)
|
||||
});
|
||||
}
|
||||
if let Some(t) = template {
|
||||
r = r.with_template(t);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user