feat: real range/bang/visual handling for the deferred command gaps
CI / cargo fmt --check (push) Successful in 27s
CI / cargo clippy (push) Successful in 22s
CI / cargo test (push) Successful in 53s
CI / editor keymaps (push) Successful in 1m29s

Implements the four items previously left as "needs handler work" — all
fully wired, not cosmetic.

- ToggleListItem / IncrementListItem / DecrementListItem are now -range
  (both clients). The client loops the per-line op over [<line1>,<line2>]
  (toggle_list_item_range / list_cycle_symbol_range). The server's edits are
  version-less single-line WorkspaceEdits, so each line applies independently
  — no server protocol change. `:'<,'>VimwikiToggleListItem` toggles the whole
  selection.
- VimwikiRebuildTags gains -bang: `:…RebuildTags!` passes { all: true } and
  the server (tags_rebuild) re-indexes every configured wiki via
  wikis_snapshot(), not just the current one.
- VimwikiNormalizeLink is -nargs=?: with `1` (upstream's visual flag; the
  x-mode `+` mapping now passes it) it wraps the '< / '> selection as
  [[selection]] (new wrap_visual_as_wikilink in both clients).
- VimwikiCheckLinks is -range: a ranged invocation filters the broken-link
  report to the current buffer's selected lines (client-side filter in
  results_to_qf / check_links).

Tests: cmd.toggle_list_item_range + cmd.normalize_link_visual_wraps_selection
(test-keymaps.lua), normalize.visual_wraps_selection (test-keymaps-vim.vim).
README + doc/nuwiki.txt + gap doc updated. fmt/clippy clean; nvim 274,
vim 266+18, all Rust tests + config-parity green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-31 17:57:03 +00:00
parent 212b300fb4
commit db9c1c5c11
10 changed files with 297 additions and 105 deletions
+4 -4
View File
@@ -429,10 +429,10 @@ available on both the Neovim and plain-Vim paths.
| Nuwiki | Vimwiki | Action |
|---|---|---|
| `:NuwikiNextTask` | `:VimwikiNextTask` | Jump to the next unfinished task |
| `:NuwikiToggleListItem` | `:VimwikiToggleListItem` | Toggle the checkbox under the cursor |
| `:NuwikiToggleListItem` | `:VimwikiToggleListItem` | Toggle the checkbox under the cursor (`-range`: every item in the selection) |
| `:NuwikiToggleRejected` | `:VimwikiToggleRejectedListItem` | Toggle the rejected marker `[-]` |
| `:NuwikiListToggle` | `:VimwikiListToggle` | Toggle a checkbox on the current item (adds `[ ]` if none) |
| `:NuwikiIncrementListItem` / `:NuwikiDecrementListItem` | `:VimwikiIncrementListItem` / `:VimwikiDecrementListItem` | Cycle the list marker to the next / previous symbol |
| `:NuwikiIncrementListItem` / `:NuwikiDecrementListItem` | `:VimwikiIncrementListItem` / `:VimwikiDecrementListItem` | Cycle the list marker to the next / previous symbol (`-range`: every item in the selection) |
| `:NuwikiChangeSymbol {sym}` | `:VimwikiChangeSymbolTo {sym}` (`:VimwikiListChangeSymbolI`) | Set the current item's marker to `{sym}` |
| `:NuwikiChangeSymbolInList {sym}` | `:VimwikiChangeSymbolInListTo {sym}` | Set every item in the list to `{sym}` |
| `:NuwikiRemoveDone[!]` | `:VimwikiRemoveDone[!]` | Remove every completed item from the current list; with `!`, from the whole buffer |
@@ -451,9 +451,9 @@ available on both the Neovim and plain-Vim paths.
|---|---|---|
| `:NuwikiTOC` | `:VimwikiTOC` | Generate / refresh the table of contents on the current page |
| `:NuwikiGenerateLinks` | `:VimwikiGenerateLinks` | Insert a flat list of every page in the wiki |
| `:NuwikiCheckLinks` | `:VimwikiCheckLinks` | Send broken links to the quickfix list |
| `:NuwikiCheckLinks` | `:VimwikiCheckLinks` | Send broken links to the quickfix list (`-range`: limit to the current buffer's selected lines) |
| `:NuwikiFindOrphans` | `:VimwikiFindOrphans` | List pages with no incoming links in the quickfix list |
| `:NuwikiRebuildTags` | `:VimwikiRebuildTags` | Force a full workspace re-index |
| `:NuwikiRebuildTags[!]` | `:VimwikiRebuildTags[!]` | Re-index the current wiki; `!` re-indexes every configured wiki |
| `:NuwikiSearchTags {tag}` | `:VimwikiSearchTags {tag}` | Quickfix listing every occurrence of `:tag:` |
| `:NuwikiGenerateTagLinks [tag]` | `:VimwikiGenerateTagLinks [tag]` (`:VimwikiGenerateTags`) | Insert a section linking every page that has `<tag>` |
| `:NuwikiColorize {color}` | `:VimwikiColorize {color}` | Wrap the word / visual selection in a coloured `<span>` |
+77 -8
View File
@@ -529,6 +529,26 @@ endfunction
function! nuwiki#commands#toggle_list_item() abort
call s:exec_pos('nuwiki.list.toggleCheckbox')
endfunction
" Apply a per-line action across [l1, l2] (visual-range commands). Each call
" sends its own request for its line; the server's edits are version-less and
" single-line, so applying them as they return never conflicts.
function! s:over_range(l1, l2, Fn) abort
let l:save = getcurpos()
for l:ln in range(a:l1, a:l2)
call cursor(l:ln, 1)
call a:Fn()
endfor
call setpos('.', l:save)
endfunction
function! nuwiki#commands#toggle_list_item_range(l1, l2) abort
call s:over_range(a:l1, a:l2, function('nuwiki#commands#toggle_list_item'))
endfunction
function! nuwiki#commands#list_cycle_symbol_range(direction, l1, l2) abort
call s:over_range(a:l1, a:l2, { -> nuwiki#commands#list_cycle_symbol(a:direction) })
endfunction
function! nuwiki#commands#cycle_list_item() abort
call s:exec_pos('nuwiki.list.cycleCheckbox')
endfunction
@@ -573,9 +593,12 @@ endfunction
function! nuwiki#commands#links_generate() abort
call s:exec('nuwiki.links.generate', [{'uri': s:buf_uri()}])
endfunction
function! nuwiki#commands#check_links() abort
function! nuwiki#commands#check_links(...) abort
" a:1 = range count; when >0, restrict the report to the current buffer's
" [a:2, a:3] lines (`:'<,'>VimwikiCheckLinks`). No range → whole workspace.
let l:rng = (a:0 >= 3 && a:1 > 0) ? [a:2, a:3] : []
call s:exec('nuwiki.workspace.checkLinks', [{ 'uri': s:buf_uri() }],
\ {n -> s:results_to_qf(n, 'broken links')})
\ {n -> s:results_to_qf(n, 'broken links', l:rng)})
endfunction
function! nuwiki#commands#find_orphans() abort
@@ -583,7 +606,10 @@ function! nuwiki#commands#find_orphans() abort
\ {n -> s:results_to_qf(n, 'orphans')})
endfunction
function! s:results_to_qf(notification, title) abort
function! s:results_to_qf(notification, title, ...) abort
" Optional a:1 = [line1, line2]: keep only current-buffer rows in that range.
let l:rng = a:0 >= 1 ? a:1 : []
let l:cur = empty(l:rng) ? '' : resolve(expand('%:p'))
let l:rows = get(get(a:notification, 'response', {}), 'result', [])
if type(l:rows) != type([]) || empty(l:rows)
echom 'nuwiki: no ' . a:title
@@ -598,9 +624,18 @@ function! s:results_to_qf(notification, title) abort
let l:lnum = l:row['range']['start']['line'] + 1
let l:col = l:row['range']['start']['character'] + 1
endif
if !empty(l:rng)
if resolve(l:path) !=# l:cur || l:lnum < l:rng[0] || l:lnum > l:rng[1]
continue
endif
endif
let l:text = get(l:row, 'message', get(l:row, 'name', ''))
call add(l:items, { 'filename': l:path, 'lnum': l:lnum, 'col': l:col, 'text': l:text })
endfor
if empty(l:items)
echom 'nuwiki: no ' . a:title
return
endif
call setqflist([], ' ', { 'title': 'nuwiki ' . a:title, 'items': l:items })
copen
endfunction
@@ -624,8 +659,11 @@ function! nuwiki#commands#tags_generate_links(tag) abort
call s:exec('nuwiki.tags.generateLinks', [l:args])
endfunction
function! nuwiki#commands#tags_rebuild() abort
call s:exec('nuwiki.tags.rebuild', [{ 'uri': s:buf_uri() }])
function! nuwiki#commands#tags_rebuild(...) abort
" a:1 (the command's <bang>) → re-index every configured wiki.
let l:all = a:0 >= 1 && a:1
call s:exec('nuwiki.tags.rebuild',
\ [{ 'uri': s:buf_uri(), 'all': l:all ? v:true : v:false }])
endfunction
" ===== HTML export =====
@@ -1205,15 +1243,46 @@ function! nuwiki#commands#smart_shift_tab() abort
return "\<Cmd>call nuwiki#commands#_table_jump_to_cell(" . line('.') . ", " . l:target_idx . ")\<CR>"
endfunction
" `:VimwikiNormalizeLink` — wrap the word at cursor as `[[word]]`
" without following. Pure-VimL.
function! nuwiki#commands#normalize_link() abort
" `:VimwikiNormalizeLink [1]` — wrap text as `[[…]]` without following.
" With a:1 (upstream's visual `1` arg, also the `x`-mode mapping) wrap the
" `'<`/`'>` selection; otherwise the word under the cursor. Pure-VimL.
function! nuwiki#commands#normalize_link(...) abort
let l:visual = a:0 >= 1 && a:1
if l:visual
call s:wrap_visual_as_wikilink()
return
endif
if s:cursor_inside_wikilink()
return
endif
call s:wrap_cword_as_wikilink()
endfunction
" Wrap the single-line `'<`/`'>` visual selection as `[[selection]]`.
function! s:wrap_visual_as_wikilink() abort
let l:sp = getpos("'<")
let l:ep = getpos("'>")
if l:sp[1] <= 0 || l:sp[1] != l:ep[1]
return
endif
let l:line = getline(l:sp[1])
let l:sc = l:sp[2]
let l:ec = l:ep[2]
if l:ec > strlen(l:line)
let l:ec = strlen(l:line)
endif
if l:ec < l:sc
return
endif
let l:sel = strpart(l:line, l:sc - 1, l:ec - l:sc + 1)
" Don't double-wrap if the selection is already a bracketed link.
if l:sel =~# '^\[\[.*\]\]$'
return
endif
let l:new = strpart(l:line, 0, l:sc - 1) . '[[' . l:sel . ']]' . strpart(l:line, l:ec)
call setline(l:sp[1], l:new)
endfunction
function! s:echo_url_from(response, ...) abort
let l:result = get(get(a:response, 'response', {}), 'result', '')
if type(l:result) == type('') && l:result !=# ''
+35 -14
View File
@@ -619,29 +619,44 @@ fn tags_generate_links(
}
fn tags_rebuild(backend: &Backend, args: Vec<Value>) -> Result<Option<Value>, String> {
// `:VimwikiRebuildTags!` passes `{ all: true }` to re-index every
// configured wiki (upstream's bang variant); otherwise just the current.
let all = args
.first()
.and_then(|v| v.get("all"))
.and_then(Value::as_bool)
.unwrap_or(false);
let p = parse_optional_uri_arg(args)?;
let Some(wiki) = resolve_diary_wiki(backend, p.uri.as_ref()) else {
return Ok(None);
};
let registry = std::sync::Arc::clone(&backend.registry);
let root = wiki.config.root.clone();
if root.as_os_str().is_empty() {
return Ok(Some(
serde_json::json!({ "pages": 0, "reason": "no wiki root configured" }),
));
}
let Some(plugin) = registry.get("vimwiki") else {
return Err("vimwiki syntax plugin missing".to_string());
};
let files = crate::index::walk_wiki_files(&root);
let total = files.len();
let targets: Vec<crate::wiki::Wiki> = if all {
backend.wikis_snapshot()
} else {
match resolve_diary_wiki(backend, p.uri.as_ref()) {
Some(w) => vec![w],
None => return Ok(None),
}
};
let mut indexed = 0usize;
let mut total = 0usize;
let mut stale_removed = 0usize;
let mut wikis_done = 0usize;
for wiki in &targets {
let root = wiki.config.root.clone();
if root.as_os_str().is_empty() {
continue;
}
let files = crate::index::walk_wiki_files(&root);
total += files.len();
let mut idx = wiki
.index
.write()
.map_err(|_| "index lock poisoned".to_string())?;
// Drop pages whose files no longer exist. Collect first to avoid mutating
// during iteration.
// Drop pages whose files no longer exist. Collect first to avoid
// mutating during iteration.
let stale: Vec<Url> = idx
.pages_by_uri
.keys()
@@ -654,6 +669,7 @@ fn tags_rebuild(backend: &Backend, args: Vec<Value>) -> Result<Option<Value>, St
for u in &stale {
idx.remove(u);
}
stale_removed += stale.len();
for path in files {
let Ok(text) = std::fs::read_to_string(&path) else {
continue;
@@ -665,10 +681,15 @@ fn tags_rebuild(backend: &Backend, args: Vec<Value>) -> Result<Option<Value>, St
idx.upsert(uri, &ast);
indexed += 1;
}
wikis_done += 1;
}
Ok(Some(serde_json::json!({
"pages": indexed,
"files_seen": total,
"stale_removed": stale.len(),
"stale_removed": stale_removed,
"wikis": wikis_done,
"all": all,
})))
}
+11
View File
@@ -577,6 +577,17 @@ call s:record(
\ 'err=' . s:cz_e . ' real=' . synconcealed(3, 1)[0]
\ . ' rgb=' . synconcealed(2, stridx(getline(2), '<span') + 1)[0])
" ===== NormalizeLink visual wraps the selection (pure-VimL) =====
" `:VimwikiNormalizeLink 1` / the x-mode `+` wrap the `'<`/`'>` selection.
call s:set_buf(['one two three'])
call cursor(1, 5)
call feedkeys("viw\<Esc>", 'tx')
call nuwiki#commands#normalize_link(1)
call s:record(
\ getline(1) ==# 'one [[two]] three' ? 1 : 0,
\ 'normalize.visual_wraps_selection',
\ 'got ' . string(getline(1)))
" ===== Follow-link resolves + opens in the current window (regression) =====
" follow_link_or_create() must resolve the definition itself and `:edit` the
" target in the CURRENT window — including a page that does not exist yet
+28
View File
@@ -792,6 +792,34 @@ vim.defer_fn(function()
end
end)
-- ===== Visual-range list commands + normalize-visual (regression) =====
-- :N,MVimwikiToggleListItem toggles every checkbox in the range (server,
-- one request per line; wait for the edits to land).
tobj_case('cmd.toggle_list_item_range', function()
set_buf({ '- [ ] a', '- [ ] b', '- [ ] c' })
vim.cmd('1,3VimwikiToggleListItem')
local done = vim.wait(2000, function()
for _, l in ipairs(vim.api.nvim_buf_get_lines(0, 0, -1, false)) do
if not l:match('%[[xX]%]') then return false end
end
return true
end, 30)
if not done then
error('range toggle incomplete: ' .. vim.inspect(vim.api.nvim_buf_get_lines(0, 0, -1, false)))
end
end)
-- `:VimwikiNormalizeLink 1` (the arg is upstream's visual flag; the command
-- is -nargs=? not -range, so no `'<,'>`) wraps the last visual selection.
tobj_case('cmd.normalize_link_visual_wraps_selection', function()
set_buf({ 'one two three' })
vim.cmd('normal! 0wviw\27') -- select 'two', leave visual (sets '<,'> marks)
vim.cmd('VimwikiNormalizeLink 1')
local got = vim.api.nvim_get_current_line()
if got ~= 'one [[two]] three' then
error('visual normalize did not wrap selection: ' .. got)
end
end)
-- ===== Wiki picker (config-driven, no LSP) =====
-- The picker must build its list from config so it works from any buffer
-- before the server attaches.
+18 -9
View File
@@ -132,7 +132,10 @@ fix site.
(align) vs `gww` (align w/o resize) distinction lost.
- [ ] `VimwikiTable` is `-nargs=1` vs upstream `-nargs=*` (can't pass cols+rows).
- [ ] `VimwikiListChangeLvl` is `-nargs=?` vs upstream `-range -nargs=+`.
- [ ] `VimwikiRebuildTags` lacks `-bang` ("rebuild all" variant).
- [x] `VimwikiRebuildTags` `-bang` ("rebuild all") — `:…RebuildTags!` now passes
`{ all: true }`; the server (`tags_rebuild`) re-indexes **every** configured
wiki (via `wikis_snapshot()`) instead of just the current one. `-bang` added to
all four command defs.
- [ ] `:VimwikiSearch` / `VWS` uses `lvimgrep`, not vimwiki's search engine.
- [ ] `VimwikiIndex` family is buffer-local in nuwiki (upstream defines globally
in `plugin/`); only `:…UISelect` is a global entry point.
@@ -175,9 +178,12 @@ fix site.
also switched both Neovim `Vimwiki/NuwikiTabIndex` from `vim.v.count` (always 0
in command context) to `<count>`, so a `:NNuwikiTabIndex` count is now actually
honored.
- [ ] **`VimwikiToggleListItem` / `Increment` / `DecrementListItem` lack
`-range`** (both branches) vs upstream's `-range` (`:350`) — no visual-range
checkbox toggle / symbol cycle.
- [x] **`VimwikiToggleListItem` / `Increment` / `DecrementListItem` `-range`** —
all three (both branches) are now `-range`; the client loops the per-line op
over `[<line1>, <line2>]` (`toggle_list_item_range` / `list_cycle_symbol_range`).
The server edits are version-less single-line, so each line's edit applies
independently — no server protocol change needed. Covered by
`cmd.toggle_list_item_range` in `test-keymaps.lua`.
- [ ] **Diary-note family lacks `-count`** _(new, 2026-05-31 re-audit)_ — upstream's
`:Vimwiki{Make,TabMake,MakeYesterday,MakeTomorrow}DiaryNote` carry `-count=0`
(the count selects the wiki number); nuwiki's diary-note commands declare no
@@ -189,11 +195,14 @@ fix site.
(colours), and the tag commands. nuwiki defines none, so `<Tab>` completion of
page / tag / colour names at the `:` line is unavailable. _Fix:_
`ftplugin/vimwiki.vim` (both branches) — VimL completers or LSP-backed.
- [ ] **Minor command-attribute gaps** _(new)_`VimwikiNormalizeLink` lacks
upstream's `-nargs=?`; `VimwikiCheckLinks` lacks `-range`. (`VimwikiColorize`
`-nargs=1``-nargs=*` **done** — all four defs now match upstream, so a bare
`:VimwikiColorize` prompts for the colour.) The remaining two would be
accepted-but-ignored without handler work, so left open.
- [x] **Minor command-attribute gaps** _(new)_all now real, not cosmetic:
`VimwikiNormalizeLink` is `-nargs=?` and with `1` wraps the `'<`/`'>` selection
(`wrap_visual_as_wikilink`, both clients; the `x`-mode `+` passes it too);
`VimwikiCheckLinks` is `-range` and a ranged invocation filters the report to
the current buffer's selected lines; `VimwikiColorize` `-nargs=1``-nargs=*`
(bare `:VimwikiColorize` prompts). Covered by
`normalize.visual_wraps_selection` (vim) /
`cmd.normalize_link_visual_wraps_selection` (nvim).
### Config
- [ ] `auto_header` — auto H1-from-filename on new page (server-side).
+6 -4
View File
@@ -376,8 +376,10 @@ Page generation ~
Insert a flat list of every page in the wiki under the cursor.
*:NuwikiCheckLinks*
:NuwikiCheckLinks
Send every broken link in the workspace to the |quickfix| list.
:[range]NuwikiCheckLinks
Send every broken link in the workspace to the |quickfix| list. With a
range (e.g. `:'<,'>NuwikiCheckLinks`) the report is limited to the current
buffer's selected lines.
Tags ~
@@ -391,8 +393,8 @@ Tags ~
argument, generates a section per tag found in the workspace.
*:NuwikiRebuildTags*
:NuwikiRebuildTags
Force a full workspace re-index.
:NuwikiRebuildTags[!]
Re-index the current wiki. With `!`, re-index every configured wiki.
HTML export ~
+25 -25
View File
@@ -76,11 +76,11 @@ if !has('nvim')
command! -buffer VimwikiRenameFile call nuwiki#commands#rename_file()
command! -buffer VimwikiRenameLink call nuwiki#commands#rename_file()
command! -buffer VimwikiNextTask call nuwiki#commands#next_task()
command! -buffer VimwikiToggleListItem call nuwiki#commands#toggle_list_item()
command! -buffer -range VimwikiToggleListItem call nuwiki#commands#toggle_list_item_range(<line1>, <line2>)
command! -buffer VimwikiToggleRejectedListItem call nuwiki#commands#reject_list_item()
command! -buffer VimwikiListToggle call nuwiki#commands#list_toggle_or_add_checkbox()
command! -buffer VimwikiIncrementListItem call nuwiki#commands#list_cycle_symbol(1)
command! -buffer VimwikiDecrementListItem call nuwiki#commands#list_cycle_symbol(-1)
command! -buffer -range VimwikiIncrementListItem call nuwiki#commands#list_cycle_symbol_range(1, <line1>, <line2>)
command! -buffer -range VimwikiDecrementListItem call nuwiki#commands#list_cycle_symbol_range(-1, <line1>, <line2>)
command! -buffer -nargs=1 VimwikiChangeSymbolTo call nuwiki#commands#list_change_symbol(<q-args>, 0)
command! -buffer -nargs=1 VimwikiListChangeSymbolI call nuwiki#commands#list_change_symbol(<q-args>, 0)
command! -buffer -nargs=1 VimwikiChangeSymbolInListTo call nuwiki#commands#list_change_symbol(<q-args>, 1)
@@ -88,7 +88,7 @@ if !has('nvim')
command! -buffer -range VimwikiRemoveSingleCB call nuwiki#commands#list_remove_checkbox()
command! -buffer VimwikiRemoveCBInList call nuwiki#commands#list_remove_checkbox_in_list()
command! -buffer -nargs=? VimwikiListChangeLvl call nuwiki#commands#list_change_lvl()
command! -buffer VimwikiNormalizeLink call nuwiki#commands#normalize_link()
command! -buffer -nargs=? VimwikiNormalizeLink call nuwiki#commands#normalize_link(<args>)
command! -buffer VimwikiRenumberList call nuwiki#commands#list_renumber()
command! -buffer VimwikiRenumberAllLists call nuwiki#commands#list_renumber_all()
command! -buffer VimwikiTableAlignQ call nuwiki#commands#table_align()
@@ -101,10 +101,10 @@ if !has('nvim')
command! -buffer VimwikiTOC call nuwiki#commands#toc_generate()
command! -buffer VimwikiGenerateLinks call nuwiki#commands#links_generate()
command! -buffer VimwikiCheckLinks call nuwiki#commands#check_links()
command! -buffer -range VimwikiCheckLinks call nuwiki#commands#check_links(<range>, <line1>, <line2>)
command! -buffer VimwikiFindOrphans call nuwiki#commands#find_orphans()
command! -buffer VimwikiRebuildTags call nuwiki#commands#tags_rebuild()
command! -buffer -bang VimwikiRebuildTags call nuwiki#commands#tags_rebuild(<bang>0)
command! -buffer -nargs=? VimwikiSearchTags call nuwiki#commands#tags_search(<q-args>)
command! -buffer -nargs=? VimwikiGenerateTagLinks call nuwiki#commands#tags_generate_links(<q-args>)
command! -buffer -nargs=? VimwikiGenerateTags call nuwiki#commands#tags_generate_links(<q-args>)
@@ -137,7 +137,7 @@ if !has('nvim')
command! -buffer NuwikiDeleteFile call nuwiki#commands#delete_file()
command! -buffer NuwikiRenameFile call nuwiki#commands#rename_file()
command! -buffer NuwikiNextTask call nuwiki#commands#next_task()
command! -buffer NuwikiToggleListItem call nuwiki#commands#toggle_list_item()
command! -buffer -range NuwikiToggleListItem call nuwiki#commands#toggle_list_item_range(<line1>, <line2>)
command! -buffer NuwikiToggleRejected call nuwiki#commands#reject_list_item()
command! -buffer NuwikiExport call nuwiki#commands#export_current()
command! -buffer NuwikiExportBrowse call nuwiki#commands#export_browse()
@@ -145,9 +145,9 @@ if !has('nvim')
command! -buffer NuwikiRss call nuwiki#commands#export_rss()
command! -buffer NuwikiTOC call nuwiki#commands#toc_generate()
command! -buffer NuwikiGenerateLinks call nuwiki#commands#links_generate()
command! -buffer NuwikiCheckLinks call nuwiki#commands#check_links()
command! -buffer -range NuwikiCheckLinks call nuwiki#commands#check_links(<range>, <line1>, <line2>)
command! -buffer NuwikiFindOrphans call nuwiki#commands#find_orphans()
command! -buffer NuwikiRebuildTags call nuwiki#commands#tags_rebuild()
command! -buffer -bang NuwikiRebuildTags call nuwiki#commands#tags_rebuild(<bang>0)
command! -buffer -nargs=? NuwikiSearchTags call nuwiki#commands#tags_search(<q-args>)
command! -buffer -nargs=? NuwikiGenerateTagLinks call nuwiki#commands#tags_generate_links(<q-args>)
command! -buffer -nargs=1 NuwikiGoto call nuwiki#commands#wiki_goto_page(<q-args>)
@@ -173,11 +173,11 @@ if !has('nvim')
command! -buffer NuwikiRemoveCheckboxInList call nuwiki#commands#list_remove_checkbox_in_list()
command! -buffer -nargs=? NuwikiListChangeLvl call nuwiki#commands#list_change_lvl()
command! -buffer NuwikiListToggle call nuwiki#commands#list_toggle_or_add_checkbox()
command! -buffer NuwikiIncrementListItem call nuwiki#commands#list_cycle_symbol(1)
command! -buffer NuwikiDecrementListItem call nuwiki#commands#list_cycle_symbol(-1)
command! -buffer -range NuwikiIncrementListItem call nuwiki#commands#list_cycle_symbol_range(1, <line1>, <line2>)
command! -buffer -range NuwikiDecrementListItem call nuwiki#commands#list_cycle_symbol_range(-1, <line1>, <line2>)
command! -buffer -nargs=1 NuwikiChangeSymbol call nuwiki#commands#list_change_symbol(<q-args>, 0)
command! -buffer -nargs=1 NuwikiChangeSymbolInList call nuwiki#commands#list_change_symbol(<q-args>, 1)
command! -buffer NuwikiNormalizeLink call nuwiki#commands#normalize_link()
command! -buffer -nargs=? NuwikiNormalizeLink call nuwiki#commands#normalize_link(<args>)
command! -buffer NuwikiRenumberList call nuwiki#commands#list_renumber()
command! -buffer NuwikiRenumberAllLists call nuwiki#commands#list_renumber_all()
command! -buffer NuwikiTableAlign call nuwiki#commands#table_align()
@@ -223,7 +223,7 @@ if !has('nvim')
nnoremap <silent><buffer> <Tab> /\[\[<CR>:nohlsearch<CR>
nnoremap <silent><buffer> <S-Tab> ?\[\[<CR>:nohlsearch<CR>
nnoremap <silent><buffer> + :call nuwiki#commands#normalize_link()<CR>
xnoremap <silent><buffer> + :<C-u>call nuwiki#commands#normalize_link()<CR>
xnoremap <silent><buffer> + :<C-u>call nuwiki#commands#normalize_link(1)<CR>
nnoremap <silent><buffer> <Leader>wn :call nuwiki#commands#wiki_goto_page('')<CR>
nnoremap <silent><buffer> <Leader>wd :call nuwiki#commands#delete_file()<CR>
nnoremap <silent><buffer> <Leader>wr :call nuwiki#commands#rename_file()<CR>
@@ -417,11 +417,11 @@ command! -buffer VimwikiRenameFile lua require('nuwiki.commands').rename_
command! -buffer VimwikiRenameLink lua require('nuwiki.commands').rename_file()
command! -buffer VimwikiNextTask lua require('nuwiki.commands').next_task()
command! -buffer VimwikiToggleListItem lua require('nuwiki.commands').toggle_list_item()
command! -buffer -range VimwikiToggleListItem lua require('nuwiki.commands').toggle_list_item_range(<line1>, <line2>)
command! -buffer VimwikiToggleRejectedListItem lua require('nuwiki.commands').reject_list_item()
command! -buffer VimwikiListToggle lua require('nuwiki.commands').list_toggle_or_add_checkbox()
command! -buffer VimwikiIncrementListItem lua require('nuwiki.commands').list_cycle_symbol(1)
command! -buffer VimwikiDecrementListItem lua require('nuwiki.commands').list_cycle_symbol(-1)
command! -buffer -range VimwikiIncrementListItem lua require('nuwiki.commands').list_cycle_symbol_range(1, <line1>, <line2>)
command! -buffer -range VimwikiDecrementListItem lua require('nuwiki.commands').list_cycle_symbol_range(-1, <line1>, <line2>)
command! -buffer -nargs=1 VimwikiChangeSymbolTo lua require('nuwiki.commands').list_change_symbol(<q-args>, false)
command! -buffer -nargs=1 VimwikiListChangeSymbolI lua require('nuwiki.commands').list_change_symbol(<q-args>, false)
command! -buffer -nargs=1 VimwikiChangeSymbolInListTo lua require('nuwiki.commands').list_change_symbol(<q-args>, true)
@@ -429,7 +429,7 @@ command! -buffer -bang VimwikiRemoveDone lua require('nuwiki.command
command! -buffer -range VimwikiRemoveSingleCB lua require('nuwiki.commands').list_remove_checkbox()
command! -buffer VimwikiRemoveCBInList lua require('nuwiki.commands').list_remove_checkbox_in_list()
command! -buffer -nargs=? VimwikiListChangeLvl lua require('nuwiki.commands').list_change_lvl()
command! -buffer VimwikiNormalizeLink lua require('nuwiki.commands').normalize_link()
command! -buffer -nargs=? VimwikiNormalizeLink lua require('nuwiki.commands').normalize_link(<args>)
command! -buffer VimwikiRenumberList lua require('nuwiki.commands').list_renumber()
command! -buffer VimwikiRenumberAllLists lua require('nuwiki.commands').list_renumber_all()
command! -buffer VimwikiTableAlignQ lua require('nuwiki.commands').table_align()
@@ -442,10 +442,10 @@ command! -buffer VimwikiRss lua require('nuwiki.commands').export
command! -buffer VimwikiTOC lua require('nuwiki.commands').toc_generate()
command! -buffer VimwikiGenerateLinks lua require('nuwiki.commands').links_generate()
command! -buffer VimwikiCheckLinks lua require('nuwiki.commands').check_links()
command! -buffer -range VimwikiCheckLinks lua require('nuwiki.commands').check_links(<range>, <line1>, <line2>)
command! -buffer VimwikiFindOrphans lua require('nuwiki.commands').find_orphans()
command! -buffer VimwikiRebuildTags lua require('nuwiki.commands').tags_rebuild()
command! -buffer -bang VimwikiRebuildTags lua require('nuwiki.commands').tags_rebuild('<bang>' == '!')
command! -buffer -nargs=? VimwikiSearchTags lua require('nuwiki.commands').tags_search(<q-args>)
command! -buffer -nargs=? VimwikiGenerateTagLinks lua require('nuwiki.commands').tags_generate_links(<q-args>)
command! -buffer -nargs=? VimwikiGenerateTags lua require('nuwiki.commands').tags_generate_links(<q-args>)
@@ -475,7 +475,7 @@ command! -buffer NuwikiBacklinks lua vim.lsp.buf.references()
command! -buffer NuwikiDeleteFile lua require('nuwiki.commands').delete_file()
command! -buffer NuwikiRenameFile lua require('nuwiki.commands').rename_file()
command! -buffer NuwikiNextTask lua require('nuwiki.commands').next_task()
command! -buffer NuwikiToggleListItem lua require('nuwiki.commands').toggle_list_item()
command! -buffer -range NuwikiToggleListItem lua require('nuwiki.commands').toggle_list_item_range(<line1>, <line2>)
command! -buffer NuwikiToggleRejected lua require('nuwiki.commands').reject_list_item()
command! -buffer NuwikiExport lua require('nuwiki.commands').export_current()
command! -buffer NuwikiExportBrowse lua require('nuwiki.commands').export_browse()
@@ -483,9 +483,9 @@ command! -buffer -bang NuwikiExportAll execute (<bang>0 ? "lua require
command! -buffer NuwikiRss lua require('nuwiki.commands').export_rss()
command! -buffer NuwikiTOC lua require('nuwiki.commands').toc_generate()
command! -buffer NuwikiGenerateLinks lua require('nuwiki.commands').links_generate()
command! -buffer NuwikiCheckLinks lua require('nuwiki.commands').check_links()
command! -buffer -range NuwikiCheckLinks lua require('nuwiki.commands').check_links(<range>, <line1>, <line2>)
command! -buffer NuwikiFindOrphans lua require('nuwiki.commands').find_orphans()
command! -buffer NuwikiRebuildTags lua require('nuwiki.commands').tags_rebuild()
command! -buffer -bang NuwikiRebuildTags lua require('nuwiki.commands').tags_rebuild('<bang>' == '!')
command! -buffer -nargs=? NuwikiSearchTags lua require('nuwiki.commands').tags_search(<q-args>)
command! -buffer -nargs=? NuwikiGenerateTagLinks lua require('nuwiki.commands').tags_generate_links(<q-args>)
command! -buffer -nargs=1 NuwikiGoto lua require('nuwiki.commands').wiki_goto_page(<q-args>)
@@ -515,11 +515,11 @@ command! -buffer -range NuwikiRemoveCheckbox lua require('nuwiki.command
command! -buffer NuwikiRemoveCheckboxInList lua require('nuwiki.commands').list_remove_checkbox_in_list()
command! -buffer -nargs=? NuwikiListChangeLvl lua require('nuwiki.commands').list_change_lvl()
command! -buffer NuwikiListToggle lua require('nuwiki.commands').list_toggle_or_add_checkbox()
command! -buffer NuwikiIncrementListItem lua require('nuwiki.commands').list_cycle_symbol(1)
command! -buffer NuwikiDecrementListItem lua require('nuwiki.commands').list_cycle_symbol(-1)
command! -buffer -range NuwikiIncrementListItem lua require('nuwiki.commands').list_cycle_symbol_range(1, <line1>, <line2>)
command! -buffer -range NuwikiDecrementListItem lua require('nuwiki.commands').list_cycle_symbol_range(-1, <line1>, <line2>)
command! -buffer -nargs=1 NuwikiChangeSymbol lua require('nuwiki.commands').list_change_symbol(<q-args>, false)
command! -buffer -nargs=1 NuwikiChangeSymbolInList lua require('nuwiki.commands').list_change_symbol(<q-args>, true)
command! -buffer NuwikiNormalizeLink lua require('nuwiki.commands').normalize_link()
command! -buffer -nargs=? NuwikiNormalizeLink lua require('nuwiki.commands').normalize_link(<args>)
command! -buffer NuwikiRenumberList lua require('nuwiki.commands').list_renumber()
command! -buffer NuwikiRenumberAllLists lua require('nuwiki.commands').list_renumber_all()
command! -buffer NuwikiTableAlign lua require('nuwiki.commands').table_align()
+62 -11
View File
@@ -361,6 +361,27 @@ function M.cycle_list_item_back()
exec('nuwiki.list.cycleCheckbox', a)
end
M.reject_list_item = _exec_pos('nuwiki.list.rejectCheckbox')
-- Apply a per-line action across [l1, l2] (visual-range commands). Each call
-- targets its own line; the server's version-less single-line edits apply
-- independently as they return, so no conflict.
local function over_range(l1, l2, fn)
local save = vim.api.nvim_win_get_cursor(0)
for ln = l1, l2 do
vim.api.nvim_win_set_cursor(0, { ln, 0 })
fn()
end
pcall(vim.api.nvim_win_set_cursor, 0, save)
end
function M.toggle_list_item_range(l1, l2)
over_range(l1, l2, M.toggle_list_item)
end
function M.list_cycle_symbol_range(direction, l1, l2)
over_range(l1, l2, function() M.list_cycle_symbol(direction) end)
end
M.heading_add_level = _exec_pos('nuwiki.heading.addLevel')
M.heading_remove_level = _exec_pos('nuwiki.heading.removeLevel')
@@ -380,7 +401,11 @@ end
M.toc_generate = function() exec('nuwiki.toc.generate', uri_args()) end
M.links_generate = function() exec('nuwiki.links.generate', uri_args()) end
function M.check_links()
-- range>0 restricts the report to the current buffer's [l1, l2] lines
-- (`:'<,'>VimwikiCheckLinks`); otherwise the whole workspace.
function M.check_links(range, l1, l2)
local filter = type(range) == 'number' and range > 0
local cur = filter and vim.api.nvim_buf_get_name(0) or nil
exec('nuwiki.workspace.checkLinks', uri_args(), function(r)
if type(r) ~= 'table' or #r == 0 then
vim.notify('nuwiki: no broken links')
@@ -388,13 +413,21 @@ function M.check_links()
end
local items = {}
for _, b in ipairs(r) do
local fname = vim.uri_to_fname(b.uri)
local lnum = (b.range and b.range.start and b.range.start.line or 0) + 1
if not filter or (fname == cur and lnum >= l1 and lnum <= l2) then
table.insert(items, {
filename = vim.uri_to_fname(b.uri),
lnum = (b.range and b.range.start and b.range.start.line or 0) + 1,
filename = fname,
lnum = lnum,
col = (b.range and b.range.start and b.range.start.character or 0) + 1,
text = (b.kind or '?') .. ': ' .. (b.message or ''),
})
end
end
if #items == 0 then
vim.notify('nuwiki: no broken links')
return
end
vim.fn.setqflist({}, ' ', { title = 'nuwiki broken links', items = items })
vim.cmd('copen')
end)
@@ -451,10 +484,14 @@ function M.tags_generate_links(tag)
exec('nuwiki.tags.generateLinks', { args })
end
function M.tags_rebuild()
exec('nuwiki.tags.rebuild', uri_args(), function(r)
function M.tags_rebuild(all)
local a = uri_args()
a[1].all = all and true or false
exec('nuwiki.tags.rebuild', a, function(r)
if r and r.pages then
vim.notify(string.format('nuwiki: re-indexed %d page(s)', r.pages))
local scope = (r.all and (r.wikis or 0) ~= 1)
and string.format(' across %d wikis', r.wikis or 0) or ''
vim.notify(string.format('nuwiki: re-indexed %d page(s)%s', r.pages, scope))
end
end)
end
@@ -1027,11 +1064,25 @@ function M.paste_url()
exec('nuwiki.link.pasteUrl', pos_args())
end
--- Vimwiki `:VimwikiNormalizeLink` — wrap the word at cursor as
--- `[[word]]` without following. The `<CR>` two-step does the same
--- thing under the hood; expose it as a standalone command + keymap
--- for users who want to bind it to `+` per vimwiki defaults.
function M.normalize_link()
-- Wrap the single-line `'<`/`'>` visual selection as `[[selection]]`.
local function wrap_visual_as_wikilink()
local sl, sc, el, ec = visual_selection_range()
if not (sl and sl == el) then return end
local line = vim.api.nvim_buf_get_lines(0, sl - 1, sl, false)[1] or ''
local sel = line:sub(sc + 1, ec + 1)
if sel == '' or sel:match('^%[%[.*%]%]$') then return end
local new = line:sub(1, sc) .. '[[' .. sel .. ']]' .. line:sub(ec + 2)
vim.api.nvim_buf_set_lines(0, sl - 1, sl, false, { new })
end
--- Vimwiki `:VimwikiNormalizeLink [1]` — wrap text as `[[…]]` without
--- following. With `visual` (upstream's `1` arg / the `x`-mode `+` mapping)
--- wrap the selection; otherwise the word at the cursor.
function M.normalize_link(visual)
if visual then
wrap_visual_as_wikilink()
return
end
if cursor_inside_wikilink() then return end
wrap_cword_as_wikilink()
end
+2 -1
View File
@@ -174,7 +174,8 @@ function M.attach(bufnr, mappings)
map('n', '<Tab>', link.next, { desc = 'nuwiki: next wikilink' }, bufnr)
map('n', '<S-Tab>', link.prev, { desc = 'nuwiki: prev wikilink' }, bufnr)
map('n', '+', cmd.normalize_link, { desc = 'nuwiki: wrap word as wikilink' }, bufnr)
map('x', '+', cmd.normalize_link, { desc = 'nuwiki: wrap word as wikilink' }, bufnr)
map('x', '+', function() cmd.normalize_link(true) end,
{ desc = 'nuwiki: wrap selection as wikilink' }, bufnr)
map('n', '<Leader>wn', cmd.wiki_goto_page, { desc = 'nuwiki: goto page' }, bufnr)
map('n', '<Leader>wd', cmd.delete_file, { desc = 'nuwiki: delete page' }, bufnr)
map('n', '<Leader>wr', cmd.rename_file, { desc = 'nuwiki: rename page' }, bufnr)