diff --git a/autoload/nuwiki/commands.vim b/autoload/nuwiki/commands.vim index 881f42d..ff0cfaa 100644 --- a/autoload/nuwiki/commands.vim +++ b/autoload/nuwiki/commands.vim @@ -855,10 +855,14 @@ function! nuwiki#commands#table_move_right() abort \ }] call s:exec('nuwiki.table.moveColumn', l:args) endfunction -" `:VimwikiColorize {color}` — pure-VimL wrap as inline span tag, -" matching vimwiki's `%s` template. +" `:VimwikiColorize {color}` — wrap text in an inline colour span, matching +" vimwiki's `%s` template. Wraps the visual +" selection when invoked with a range (`:'<,'>VimwikiColorize` / the `x`-mode +" wc mapping), otherwise the word under the cursor. +" a:1 = colour (empty → prompt); a:2 = range count (>0 → use the selection). function! nuwiki#commands#colorize(...) abort let l:color = a:0 >= 1 ? a:1 : '' + let l:visual = a:0 >= 2 && a:2 > 0 if l:color ==# '' let l:color = input('Colour: ') endif @@ -867,6 +871,28 @@ function! nuwiki#commands#colorize(...) abort endif let l:open_tag = '' let l:close_tag = '' + + if l:visual + let l:sp = getpos("'<") + let l:ep = getpos("'>") + if l:sp[1] > 0 && l:sp[1] == l:ep[1] + 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 + let l:new = strpart(l:line, 0, l:sc - 1) + \ . l:open_tag . strpart(l:line, l:sc - 1, l:ec - l:sc + 1) . l:close_tag + \ . strpart(l:line, l:ec) + call setline(l:sp[1], l:new) + return + endif + endif + " Multi-line or empty selection: fall through to the cword. + endif + let l:line = getline('.') let l:col = col('.') " Word boundaries around cursor (1-based). diff --git a/development/tests/test-keymaps-vim.vim b/development/tests/test-keymaps-vim.vim index 5f63144..18ba507 100644 --- a/development/tests/test-keymaps-vim.vim +++ b/development/tests/test-keymaps-vim.vim @@ -477,6 +477,44 @@ call s:record( \ 'ext=' . get(get(s:wl, 1, {}), 'ext', '')) unlet g:nuwiki_wikis +" ===== Colorize (cword, visual selection, ranged command) ===== +" The command is -nargs=1 -range: normal invocation wraps the cword; a visual +" range (`:'<,'>VimwikiColorize` / the x-mode wc map) wraps the +" selection. Run these while still on the vimwiki buffer (the buffer-local +" command must be defined). +call s:set_buf(['word here']) +call cursor(1, 1) +silent VimwikiColorize red +call s:record( + \ getline(1) ==# 'word here' ? 1 : 0, + \ 'colorize.command_wraps_cword', + \ 'got ' . string(getline(1))) + +" Visual selection → wraps the selection (visual flag passed explicitly). +call s:set_buf(['one two three']) +call cursor(1, 5) +call feedkeys("viw\", 'tx') +call nuwiki#commands#colorize('blue', 2) +call s:record( + \ getline(1) ==# 'one two three' ? 1 : 0, + \ 'colorize.visual_wraps_selection', + \ 'got ' . string(getline(1))) + +" Ranged command must not raise E481 and wraps the selection. +call s:set_buf(['alpha beta gamma']) +call cursor(1, 8) +call feedkeys("viw\", 'tx') +let s:cz_err = '' +try + silent '<,'>VimwikiColorize green +catch + let s:cz_err = v:exception +endtry +call s:record( + \ s:cz_err ==# '' && getline(1) ==# 'alpha beta gamma' ? 1 : 0, + \ 'colorize.ranged_command_no_error', + \ 'err=' . s:cz_err . ' 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 diff --git a/development/tests/test-keymaps.lua b/development/tests/test-keymaps.lua index af3fbce..0aaca16 100644 --- a/development/tests/test-keymaps.lua +++ b/development/tests/test-keymaps.lua @@ -761,6 +761,18 @@ vim.defer_fn(function() error('visual colorize did not wrap selection: ' .. got) end end) + -- Invoking the command with a range (`:'<,'>VimwikiColorize`, as Vim builds + -- it when you select then type the command) must not error (-range) and + -- wraps the selection. + tobj_case('cmd.Colorize_range_wraps_selection', function() + set_buf({ 'pick this word' }) + vim.cmd('normal! 0wviw\27') -- select 'this' + vim.cmd("'<,'>VimwikiColorize orange") + local got = vim.api.nvim_get_current_line() + if got ~= 'pick this word' then + error('ranged command 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 diff --git a/development/vimwiki-gap.md b/development/vimwiki-gap.md index 76245d5..a2e27ec 100644 --- a/development/vimwiki-gap.md +++ b/development/vimwiki-gap.md @@ -129,11 +129,17 @@ fix site. bug: `colorize()` inferred visual-vs-normal from `vim.fn.visualmode()`, which returns the *last* session visual mode with stale `'<`/`'>` marks — so the normal-mode command wrapped a leftover selection instead of the cword. - `colorize(color, visual)` now takes an explicit `visual` flag passed only by - the `x`-mode `wc` mapping (`lua/nuwiki/keymaps.lua`); the command and - normal mapping always wrap the cword. Covered by `cmd.VimwikiColorize_uses_arg`, - `cmd.Colorize_ignores_stale_visual_selection`, and - `colorize.visual_wraps_selection` in `development/tests/test-keymaps.lua`. + `colorize(color, visual)` now takes an explicit `visual` flag; the command and + normal mapping always wrap the cword. Third bug: the commands were not + `-range`, so selecting text and running `:VimwikiColorize` (which Vim turns + into `:'<,'>VimwikiColorize`) raised `E481: No range allowed`. All four + command defs are now `-range` and pass the range to the handler — a ranged + (visual) invocation wraps the `'<`/`'>` selection on both clients; the + `x`-mode `wc` mapping passes the visual flag directly. Covered by + `cmd.VimwikiColorize_uses_arg`, `cmd.Colorize_ignores_stale_visual_selection`, + `colorize.visual_wraps_selection`, `cmd.Colorize_range_wraps_selection` in + `test-keymaps.lua` and `colorize.{command_wraps_cword,visual_wraps_selection, + ranged_command_no_error}` in `test-keymaps-vim.vim`. - [ ] **`VimwikiTableMoveColumn{Left,Right}` dispatch to different backing names per client** — Vim branch → `table_move_left/right`; Neovim branch → `table_move_column_left/right`. Harmless today (each name exists in its own diff --git a/ftplugin/vimwiki.vim b/ftplugin/vimwiki.vim index f483a19..ec79ad5 100644 --- a/ftplugin/vimwiki.vim +++ b/ftplugin/vimwiki.vim @@ -103,7 +103,7 @@ if !has('nvim') command! -buffer -nargs=1 VimwikiTable call nuwiki#commands#table_insert() command! -buffer VimwikiTableMoveColumnLeft call nuwiki#commands#table_move_left() command! -buffer VimwikiTableMoveColumnRight call nuwiki#commands#table_move_right() - command! -buffer -nargs=1 VimwikiColorize call nuwiki#commands#colorize() + command! -buffer -nargs=1 -range VimwikiColorize call nuwiki#commands#colorize(, ) command! -buffer VimwikiPasteLink call nuwiki#commands#paste_link() command! -buffer VimwikiPasteUrl call nuwiki#commands#paste_url() command! -buffer VimwikiCatUrl call nuwiki#commands#cat_url() @@ -174,7 +174,7 @@ if !has('nvim') command! -buffer -nargs=1 NuwikiTable call nuwiki#commands#table_insert() command! -buffer NuwikiTableMoveColumnLeft call nuwiki#commands#table_move_left() command! -buffer NuwikiTableMoveColumnRight call nuwiki#commands#table_move_right() - command! -buffer -nargs=1 NuwikiColorize call nuwiki#commands#colorize() + command! -buffer -nargs=1 -range NuwikiColorize call nuwiki#commands#colorize(, ) command! -buffer NuwikiPasteLink call nuwiki#commands#paste_link() command! -buffer NuwikiPasteUrl call nuwiki#commands#paste_url() command! -buffer NuwikiCatUrl call nuwiki#commands#cat_url() @@ -216,7 +216,7 @@ if !has('nvim') nnoremap wd :call nuwiki#commands#delete_file() nnoremap wr :call nuwiki#commands#rename_file() nnoremap wc :call nuwiki#commands#colorize('') - xnoremap wc :call nuwiki#commands#colorize('') + xnoremap wc :call nuwiki#commands#colorize('', 2) endif " Diary nav @@ -442,7 +442,7 @@ command! -buffer -nargs=? VimwikiGenerateTags lua require('nuwiki.commands' command! -buffer -nargs=1 VimwikiTable lua require('nuwiki.commands').table_insert() command! -buffer VimwikiTableMoveColumnLeft lua require('nuwiki.commands').table_move_column_left() command! -buffer VimwikiTableMoveColumnRight lua require('nuwiki.commands').table_move_column_right() -command! -buffer -nargs=1 VimwikiColorize lua require('nuwiki.commands').colorize() +command! -buffer -nargs=1 -range VimwikiColorize lua require('nuwiki.commands').colorize(, > 0) command! -buffer VimwikiPasteLink lua require('nuwiki.commands').paste_link() command! -buffer VimwikiPasteUrl lua require('nuwiki.commands').paste_url() command! -buffer VimwikiCatUrl lua require('nuwiki.commands').cat_url() @@ -514,7 +514,7 @@ command! -buffer NuwikiTableAlign lua require('nuwiki.command command! -buffer -nargs=1 NuwikiTable lua require('nuwiki.commands').table_insert() command! -buffer NuwikiTableMoveColumnLeft lua require('nuwiki.commands').table_move_column_left() command! -buffer NuwikiTableMoveColumnRight lua require('nuwiki.commands').table_move_column_right() -command! -buffer -nargs=1 NuwikiColorize lua require('nuwiki.commands').colorize() +command! -buffer -nargs=1 -range NuwikiColorize lua require('nuwiki.commands').colorize(, > 0) command! -buffer NuwikiPasteLink lua require('nuwiki.commands').paste_link() command! -buffer NuwikiPasteUrl lua require('nuwiki.commands').paste_url() command! -buffer NuwikiCatUrl lua require('nuwiki.commands').cat_url() diff --git a/lua/nuwiki/commands.lua b/lua/nuwiki/commands.lua index 1a159c4..233a292 100644 --- a/lua/nuwiki/commands.lua +++ b/lua/nuwiki/commands.lua @@ -951,9 +951,11 @@ end --- the template is `%s` with `%c` --- replaced by the user-supplied colour and `%s` by the wrapped text. --- Pure-Lua; no server roundtrip needed. +-- Read the last visual selection from the `'<`/`'>` marks. Only meaningful +-- when the caller knows it's acting on a selection (colorize's `visual` flag); +-- we deliberately don't gate on vim.fn.visualmode() here since that reflects +-- session state, not whether the marks are the selection we want right now. local function visual_selection_range() - local mode = vim.fn.visualmode() - if mode == '' then return nil end local s = vim.api.nvim_buf_get_mark(0, '<') local e = vim.api.nvim_buf_get_mark(0, '>') if s[1] == 0 or e[1] == 0 then return nil end