Files
nuwiki-rs/crates/nuwiki-lsp/tests/commands_headings.rs
T
gffranco 29a4efb6bc
CI / cargo fmt --check (push) Successful in 59s
CI / cargo clippy (push) Successful in 1m20s
CI / cargo test (push) Successful in 1m29s
CI / editor keymaps (push) Failing after 33s
feat: initial nuwiki Rust workspace (core, lsp, ls)
2026-06-24 00:01:59 +00:00

84 lines
2.7 KiB
Rust

//! Heading level rewriter — `nuwiki.heading.addLevel` /
//! `nuwiki.heading.removeLevel`.
use nuwiki_core::syntax::vimwiki::VimwikiSyntax;
use nuwiki_core::syntax::SyntaxPlugin;
use nuwiki_lsp::commands::ops;
use tower_lsp::lsp_types::Url;
fn parse(src: &str) -> nuwiki_core::ast::DocumentNode {
VimwikiSyntax::new().parse(src)
}
fn dummy_uri() -> Url {
Url::parse("file:///tmp/note.wiki").unwrap()
}
fn one_text_edit(edit: tower_lsp::lsp_types::WorkspaceEdit) -> tower_lsp::lsp_types::TextEdit {
let changes = edit.changes.expect("expected changes map");
let (_, edits) = changes.into_iter().next().expect("at least one uri");
assert_eq!(edits.len(), 1, "expected exactly one text edit");
edits.into_iter().next().unwrap()
}
#[test]
fn add_heading_level_promotes_h2_to_h3() {
let src = "== Sub ==\n";
let doc = parse(src);
let edit =
ops::heading_change_level(src, &doc, &dummy_uri(), 0, 0, true, 1).expect("add_level edit");
let te = one_text_edit(edit);
assert_eq!(te.new_text, "=== Sub ===");
}
#[test]
fn add_heading_level_caps_at_6() {
let src = "====== Deep ======\n";
let doc = parse(src);
let edit = ops::heading_change_level(src, &doc, &dummy_uri(), 0, 0, true, 1);
// No-op because level 6 is the cap; clamp matched current level.
assert!(edit.is_none());
}
#[test]
fn remove_heading_level_demotes() {
let src = "=== Mid ===\n";
let doc = parse(src);
let edit = ops::heading_change_level(src, &doc, &dummy_uri(), 0, 0, true, -1)
.expect("remove_level edit");
let te = one_text_edit(edit);
assert_eq!(te.new_text, "== Mid ==");
}
#[test]
fn remove_heading_level_at_h1_is_noop() {
let src = "= Top =\n";
let doc = parse(src);
let edit = ops::heading_change_level(src, &doc, &dummy_uri(), 0, 0, true, -1);
assert!(edit.is_none());
}
#[test]
fn heading_change_returns_none_when_cursor_not_on_heading() {
let src = "paragraph\n";
let doc = parse(src);
let edit = ops::heading_change_level(src, &doc, &dummy_uri(), 0, 0, true, 1);
assert!(edit.is_none());
}
#[test]
fn rewrite_heading_with_level_keeps_leading_whitespace_outside_span() {
// The lexer's heading span starts at the first `=`, not the line's
// start, so the leading whitespace that marks a "centered" heading
// lives outside the edit range — preserved automatically. The
// rewriter's output is just the `=...=` portion.
let src = " = Title =\n";
let doc = parse(src);
let h = match &doc.children[0] {
nuwiki_core::ast::BlockNode::Heading(h) => h,
_ => panic!("expected heading"),
};
let new = ops::rewrite_heading_with_level(src, h.span, 2).unwrap();
assert_eq!(new, "== Title ==");
}