fix(parser): accept spaceless headings (==Heading==) like vimwiki (#7)
CI / cargo clippy (push) Successful in 34s
CI / cargo fmt --check (push) Successful in 39s
CI / cargo test (push) Successful in 1m4s
CI / editor keymaps (push) Successful in 1m12s

The heading lexer required a space after the opening `=`s, so `==Heading==`
fell through to a literal `<p>==Heading==</p>` instead of an `<h2>`. vimwiki
accepts the spaceless form, so a migrated page whose top heading was
`==TODO==` (or `====Progress====`) rendered with no heading at all.

Drop the space-after-marker requirement; the existing title trim already
handles one optional space per side, so both `== H ==` and `==H==` work.
Marker-only (`======`) and unbalanced (`==a==b`, `==> x`) lines still stay
paragraphs (title-present + matching trailing-`=` checks). Regression tests
added at the lexer and renderer levels.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-24 01:09:32 +00:00
parent f1494dd2fc
commit 4a717bcb31
3 changed files with 50 additions and 4 deletions
+26
View File
@@ -85,6 +85,32 @@ fn centered_heading_is_marked_centered() {
assert!(matches!(lexed[2], HeadingClose));
}
#[test]
fn spaceless_heading_is_a_heading() {
// vimwiki accepts `==Heading==` with no spaces around the text.
let lexed = lex("==Plain==\n");
assert_eq!(
lexed,
vec![
HeadingOpen {
level: 2,
centered: false
},
text("Plain"),
HeadingClose,
Newline,
]
);
}
#[test]
fn marker_only_or_unbalanced_lines_are_not_headings() {
// No title between markers, and trailing `=` not at line end → plain text.
assert!(!matches!(lex("======\n")[0], HeadingOpen { .. }));
assert!(!matches!(lex("==> arrow\n")[0], HeadingOpen { .. }));
assert!(!matches!(lex("==a==b\n")[0], HeadingOpen { .. }));
}
#[test]
fn heading_with_inline_bold() {
let lexed = lex("== Hello *world* ==\n");