Spaceless headings (==Heading==) are not parsed as headings (vimwiki accepts them) #7

Closed
opened 2026-06-24 00:52:48 +00:00 by gffranco · 2 comments
Owner

Summary

Headings written without spaces around the text — ==Heading== — are not parsed as headings. nuwiki renders them as a literal ==Heading== paragraph instead of an <h2>. Upstream vimwiki accepts the spaceless form and renders it as a heading.

This is independent of the keyword/badge logic (a plain ==Foo== breaks the same way) and is present in both v0.4.0 and v0.4.1, so it's not a regression from the recent parity work — just a gap.

Environment

  • nuwiki v0.4.1 (also reproduced on v0.4.0) + the release nuwiki-ls-x86_64-unknown-linux-gnu binary, Neovim 0.12
  • Compared against upstream vimwiki (latest master) under Vim 9.2
  • Same minimal wiki + a trivial %content%-only template

Reproduction

index.wiki:

%title htest
== TODO ==

spaced keyword

==TODO==

spaceless keyword

== Plain ==

spaced plain

==Plain==

spaceless plain

Rendered heading element per variant:

Source line vimwiki nuwiki v0.4.0 nuwiki v0.4.1
== TODO == (spaced) <h2 id="TODO"> <h2 id=""> ⚠️ (empty id) <h2 id="TODO">
==TODO== (spaceless) <h2 id="TODO"> <p>==TODO==</p> <p>==TODO==</p>
== Plain == (spaced) <h2 id="Plain"> <h2 id="Plain"> <h2 id="Plain">
==Plain== (spaceless) <h2 id="Plain"> <p>==Plain==</p> <p>==Plain==</p>

So both spaceless rows (==TODO==, ==Plain==) render as paragraphs in nuwiki but as headings in vimwiki. The keyword badge on the broken line is just a consequence of the line being treated as body text.

Expected

Spaceless headings should parse as headings, matching vimwiki — i.e. ==TODO==<h2 id="TODO">…</h2> and ==Plain==<h2 id="Plain">Plain</h2>.

Real-world impact

A real wiki page whose top heading is ==TODO== (and another with ====Progress====) renders with no heading at all — the ==…== shows up as literal text in the body. vimwiki rendered these fine, so the pages regressed on migrating to nuwiki.

Minor side note

In v0.4.0 the spaced keyword heading == TODO == produced an empty id="" (broken anchor); v0.4.1 already fixed that to id="TODO". Only the spaceless-parsing issue remains.

## Summary Headings written **without spaces** around the text — `==Heading==` — are not parsed as headings. nuwiki renders them as a literal `==Heading==` paragraph instead of an `<h2>`. Upstream vimwiki accepts the spaceless form and renders it as a heading. This is independent of the keyword/badge logic (a plain `==Foo==` breaks the same way) and is present in **both v0.4.0 and v0.4.1**, so it's not a regression from the recent parity work — just a gap. ## Environment - nuwiki **v0.4.1** (also reproduced on v0.4.0) + the release `nuwiki-ls-x86_64-unknown-linux-gnu` binary, Neovim 0.12 - Compared against upstream **vimwiki** (latest `master`) under Vim 9.2 - Same minimal wiki + a trivial `%content%`-only template ## Reproduction `index.wiki`: ``` %title htest == TODO == spaced keyword ==TODO== spaceless keyword == Plain == spaced plain ==Plain== spaceless plain ``` Rendered heading element per variant: | Source line | vimwiki | nuwiki v0.4.0 | nuwiki v0.4.1 | |---|---|---|---| | `== TODO ==` (spaced) | `<h2 id="TODO">` ✅ | `<h2 id="">` ⚠️ (empty id) | `<h2 id="TODO">` ✅ | | `==TODO==` (spaceless) | `<h2 id="TODO">` ✅ | `<p>==TODO==</p>` ❌ | `<p>==TODO==</p>` ❌ | | `== Plain ==` (spaced) | `<h2 id="Plain">` ✅ | `<h2 id="Plain">` ✅ | `<h2 id="Plain">` ✅ | | `==Plain==` (spaceless) | `<h2 id="Plain">` ✅ | `<p>==Plain==</p>` ❌ | `<p>==Plain==</p>` ❌ | So both spaceless rows (`==TODO==`, `==Plain==`) render as paragraphs in nuwiki but as headings in vimwiki. The keyword badge on the broken line is just a consequence of the line being treated as body text. ## Expected Spaceless headings should parse as headings, matching vimwiki — i.e. `==TODO==` → `<h2 id="TODO">…</h2>` and `==Plain==` → `<h2 id="Plain">Plain</h2>`. ## Real-world impact A real wiki page whose top heading is `==TODO==` (and another with `====Progress====`) renders with no heading at all — the `==…==` shows up as literal text in the body. vimwiki rendered these fine, so the pages regressed on migrating to nuwiki. ## Minor side note In v0.4.0 the *spaced* keyword heading `== TODO ==` produced an empty `id=""` (broken anchor); v0.4.1 already fixed that to `id="TODO"`. Only the spaceless-parsing issue remains.
Author
Owner

Confirmed and fixed on main (commit 4a717bc) — will ship in the next release.

The heading lexer required a space after the opening =s, so ==Heading== fell through to a literal <p>==Heading==</p>. vimwiki accepts the spaceless form, so I dropped that requirement. The existing title trim already handles one optional space per side, so both == H == and ==H== now parse:

  • ==TODO==<div id="TODO"><h2 id="TODO" class="header"><a href="#TODO">TODO</a></h2></div> (header, not a badge)
  • ==Plain==<h2 id="Plain">…
  • ====Progress====<h4 id="Progress">…

Lines that only look like markers stay paragraphs, as before: ====== (no title), ==a==b (trailing = not at line end), ==> arrow (unbalanced). Added lexer + renderer regression tests.

Good catch on the empty-id note too — that was the inline_text-drops-keyword bug already fixed in v0.4.1.

I'll cut a release with this shortly; once it's published, :NuwikiInstall and re-export.

Confirmed and fixed on `main` (commit 4a717bc) — will ship in the next release. The heading lexer required a space after the opening `=`s, so `==Heading==` fell through to a literal `<p>==Heading==</p>`. vimwiki accepts the spaceless form, so I dropped that requirement. The existing title trim already handles one optional space per side, so both `== H ==` and `==H==` now parse: - `==TODO==` → `<div id="TODO"><h2 id="TODO" class="header"><a href="#TODO">TODO</a></h2></div>` (header, not a badge) - `==Plain==` → `<h2 id="Plain">…` - `====Progress====` → `<h4 id="Progress">…` Lines that only look like markers stay paragraphs, as before: `======` (no title), `==a==b` (trailing `=` not at line end), `==> arrow` (unbalanced). Added lexer + renderer regression tests. Good catch on the empty-`id` note too — that was the `inline_text`-drops-keyword bug already fixed in v0.4.1. I'll cut a release with this shortly; once it's published, `:NuwikiInstall` and re-export.
Author
Owner

Released in v0.4.2 — spaceless headings (==Heading==, ====Progress====) now parse as headings, matching vimwiki. Grab the new binary from the v0.4.2 release (:NuwikiInstall), restart, and re-run the export. Closing — reopen if anything still looks off.

Released in **v0.4.2** — spaceless headings (`==Heading==`, `====Progress====`) now parse as headings, matching vimwiki. Grab the new binary from the [v0.4.2 release](https://code.gfran.co/gffranco/nuwiki/releases/tag/v0.4.2) (`:NuwikiInstall`), restart, and re-run the export. Closing — reopen if anything still looks off.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: gffranco/nuwiki#7