feat(generate): insert links/tags sections at the cursor line too
Extend the cursor-line insertion from :NuwikiTOC to the other buffer list generators: :NuwikiGenerateLinks and :NuwikiGenerateTagLinks. They appended at end-of-file; a fresh section now goes at the cursor line (with a leading blank), matching :NuwikiTOC. An existing section is still refreshed in place, and the auto_generate_*-on-save hooks are unaffected (they only ever replace). Shared section_insert() helper computes the insert position/block for all three (cursor line clamped to the document, else the per-command fallback: top of file for TOC, EOF for links/tags). Clients send the 0-based cursor line; handlers parse it via parse_uri_line_arg and thread it through links_edit / tag_links_edit. Rebuild variants pass None. Tests: links_edit_inserts_at_cursor_line + tag_links_edit_inserts_at_cursor_line. 577 passed, clippy clean, keymap harnesses green. Docs updated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -348,6 +348,7 @@ fn nuwiki_generate_links_lists_all_pages_excluding_current() {
|
||||
"Generated Links",
|
||||
1,
|
||||
0,
|
||||
None,
|
||||
None
|
||||
)
|
||||
.is_some());
|
||||
@@ -430,7 +431,8 @@ fn nuwiki_generate_tag_links_builds_section() {
|
||||
true,
|
||||
"Generated Tags",
|
||||
1,
|
||||
0
|
||||
0,
|
||||
None
|
||||
)
|
||||
.is_some());
|
||||
}
|
||||
|
||||
@@ -255,6 +255,7 @@ fn tag_links_edit_inserts_when_section_missing() {
|
||||
"Generated Tags",
|
||||
1,
|
||||
0,
|
||||
None,
|
||||
)
|
||||
.expect("got an edit");
|
||||
let te = &edit.changes.unwrap()[&uri][0];
|
||||
@@ -264,6 +265,37 @@ fn tag_links_edit_inserts_when_section_missing() {
|
||||
assert!(te.new_text.contains("[[Alpha]]"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tag_links_edit_inserts_at_cursor_line() {
|
||||
// A fresh tags section goes at the cursor line, not the EOF.
|
||||
let src = "= Notes =\nbody\nmore\n";
|
||||
let ast = parse(src);
|
||||
let uri = Url::parse("file:///tmp/p.wiki").unwrap();
|
||||
let mut snap = BTreeMap::new();
|
||||
snap.insert("release".to_string(), vec!["Alpha".into()]);
|
||||
let edit = ops::tag_links_edit(
|
||||
src,
|
||||
&ast,
|
||||
&uri,
|
||||
Some("release"),
|
||||
&snap,
|
||||
true,
|
||||
"Generated Tags",
|
||||
1,
|
||||
0,
|
||||
Some(1),
|
||||
)
|
||||
.expect("edit");
|
||||
let te = &edit.changes.unwrap()[&uri][0];
|
||||
assert_eq!(te.range.start.line, 1);
|
||||
assert_eq!(te.range.start.character, 0);
|
||||
assert!(
|
||||
te.new_text.starts_with("\n= Tag: release ="),
|
||||
"got: {:?}",
|
||||
te.new_text
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tag_links_edit_replaces_existing_section() {
|
||||
let src = "= Tag: release =\n- [[Stale]]\n\n= Other =\n";
|
||||
@@ -281,6 +313,7 @@ fn tag_links_edit_replaces_existing_section() {
|
||||
"Generated Tags",
|
||||
1,
|
||||
0,
|
||||
None,
|
||||
)
|
||||
.expect("edit");
|
||||
let te = &edit.changes.unwrap()[&uri][0];
|
||||
@@ -296,8 +329,19 @@ fn tag_links_edit_full_index_replaces_existing_tags_section() {
|
||||
let uri = Url::parse("file:///tmp/p.wiki").unwrap();
|
||||
let mut snap = BTreeMap::new();
|
||||
snap.insert("alpha".to_string(), vec!["P".into()]);
|
||||
let edit = ops::tag_links_edit(src, &ast, &uri, None, &snap, true, "Generated Tags", 1, 0)
|
||||
.expect("edit");
|
||||
let edit = ops::tag_links_edit(
|
||||
src,
|
||||
&ast,
|
||||
&uri,
|
||||
None,
|
||||
&snap,
|
||||
true,
|
||||
"Generated Tags",
|
||||
1,
|
||||
0,
|
||||
None,
|
||||
)
|
||||
.expect("edit");
|
||||
let te = &edit.changes.unwrap()[&uri][0];
|
||||
assert!(te.new_text.contains("== alpha =="));
|
||||
assert!(!te.new_text.contains("[[old]]"));
|
||||
@@ -352,7 +396,8 @@ fn tag_links_edit_returns_none_for_unknown_tag() {
|
||||
true,
|
||||
"Generated Tags",
|
||||
1,
|
||||
0
|
||||
0,
|
||||
None
|
||||
)
|
||||
.is_none());
|
||||
}
|
||||
|
||||
@@ -597,6 +597,7 @@ fn links_edit_inserts_when_section_absent() {
|
||||
1,
|
||||
0,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.expect("edit");
|
||||
let te = &edit.changes.unwrap()[&uri][0];
|
||||
@@ -605,6 +606,37 @@ fn links_edit_inserts_when_section_absent() {
|
||||
assert!(!te.new_text.contains("[[Home]]"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn links_edit_inserts_at_cursor_line() {
|
||||
// A fresh Generated Links section goes at the cursor line, not the EOF.
|
||||
let src = "= Home =\nbody\nmore\n";
|
||||
let ast = parse(src);
|
||||
let uri = Url::parse("file:///tmp/page.wiki").unwrap();
|
||||
let pages = vec!["A".into()];
|
||||
let edit = ops::links_edit(
|
||||
src,
|
||||
&ast,
|
||||
&uri,
|
||||
"Home",
|
||||
&pages,
|
||||
true,
|
||||
"Generated Links",
|
||||
1,
|
||||
0,
|
||||
None,
|
||||
Some(1),
|
||||
)
|
||||
.expect("edit");
|
||||
let te = &edit.changes.unwrap()[&uri][0];
|
||||
assert_eq!(te.range.start.line, 1);
|
||||
assert_eq!(te.range.start.character, 0);
|
||||
assert!(
|
||||
te.new_text.starts_with("\n= Generated Links ="),
|
||||
"got: {:?}",
|
||||
te.new_text
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn links_edit_replaces_when_section_present() {
|
||||
let src = "= Generated Links =\n- [[Stale]]\n\n= Real =\n";
|
||||
@@ -622,6 +654,7 @@ fn links_edit_replaces_when_section_present() {
|
||||
1,
|
||||
0,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.expect("edit");
|
||||
let te = &edit.changes.unwrap()[&uri][0];
|
||||
@@ -645,6 +678,7 @@ fn links_edit_returns_none_for_empty_page_list() {
|
||||
"Generated Links",
|
||||
1,
|
||||
0,
|
||||
None,
|
||||
None
|
||||
)
|
||||
.is_none());
|
||||
|
||||
Reference in New Issue
Block a user