fix(keymap): C-Space toggle fires across all terminal byte spellings
User reported Ctrl+Space didn't toggle list items. Three things contributed: 1. **Terminal byte ambiguity.** Different terminals encode Ctrl+Space differently — GUI / kitty protocol sends `<C-Space>`, xterm and most legacy terms send NUL which Vim sees as `<C-@>` (or, in some Neovim builds, `<Nul>` in keymap.lhs). The previous keymap registered only `<C-Space>` + `<C-@>`. Added the `<Nul>` alias too (both Lua and VimL paths) so the binding fires regardless of what byte the user's terminal produces. 2. **Deprecated `vim.lsp.util.make_position_params`.** Neovim 0.12 requires `position_encoding` explicitly. The old no-arg call now prints a deprecation warning, and in stricter setups returns nil — which made the command's `arguments` malformed and the `executeCommand` request silently fail. `position_params()` now pulls `offset_encoding` from the resolved client and passes both args, with a `pcall`-guarded fallback to the no-arg form for Neovim < 0.10. 3. **Deprecated `client.request(...)` dot-call.** Same Neovim 0.12 change — `Client:request()` is the method form. Use the colon call now; both arities are preserved for back-compat. Verified end-to-end: feeding all three of `<C-Space>` / `<C-@>` / `<Nul>` via `nvim_feedkeys` toggles the checkbox; `:messages` no longer carries the deprecation warnings. 381 tests still pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -146,6 +146,8 @@ if !has('nvim')
|
|||||||
xnoremap <silent><buffer> <C-Space> :<C-u>call nuwiki#commands#toggle_list_item()<CR>
|
xnoremap <silent><buffer> <C-Space> :<C-u>call nuwiki#commands#toggle_list_item()<CR>
|
||||||
nnoremap <silent><buffer> <C-@> :call nuwiki#commands#toggle_list_item()<CR>
|
nnoremap <silent><buffer> <C-@> :call nuwiki#commands#toggle_list_item()<CR>
|
||||||
xnoremap <silent><buffer> <C-@> :<C-u>call nuwiki#commands#toggle_list_item()<CR>
|
xnoremap <silent><buffer> <C-@> :<C-u>call nuwiki#commands#toggle_list_item()<CR>
|
||||||
|
nnoremap <silent><buffer> <Nul> :call nuwiki#commands#toggle_list_item()<CR>
|
||||||
|
xnoremap <silent><buffer> <Nul> :<C-u>call nuwiki#commands#toggle_list_item()<CR>
|
||||||
nnoremap <silent><buffer> gnt :call nuwiki#commands#next_task()<CR>
|
nnoremap <silent><buffer> gnt :call nuwiki#commands#next_task()<CR>
|
||||||
nnoremap <silent><buffer> gln :call nuwiki#commands#cycle_list_item()<CR>
|
nnoremap <silent><buffer> gln :call nuwiki#commands#cycle_list_item()<CR>
|
||||||
xnoremap <silent><buffer> gln :<C-u>call nuwiki#commands#cycle_list_item()<CR>
|
xnoremap <silent><buffer> gln :<C-u>call nuwiki#commands#cycle_list_item()<CR>
|
||||||
|
|||||||
+39
-22
@@ -13,10 +13,6 @@ local function buf_uri(bufnr)
|
|||||||
return vim.uri_from_bufnr(bufnr or 0)
|
return vim.uri_from_bufnr(bufnr or 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function position_params()
|
|
||||||
return vim.lsp.util.make_position_params()
|
|
||||||
end
|
|
||||||
|
|
||||||
local function find_client()
|
local function find_client()
|
||||||
local fn = vim.lsp.get_clients or vim.lsp.get_active_clients
|
local fn = vim.lsp.get_clients or vim.lsp.get_active_clients
|
||||||
local clients = fn({ name = 'nuwiki', bufnr = 0 })
|
local clients = fn({ name = 'nuwiki', bufnr = 0 })
|
||||||
@@ -27,29 +23,49 @@ local function find_client()
|
|||||||
return clients[1]
|
return clients[1]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function position_params(client)
|
||||||
|
-- Neovim 0.12+ requires `position_encoding` explicitly; older
|
||||||
|
-- versions accept the no-arg form.
|
||||||
|
local encoding = client and client.offset_encoding or 'utf-16'
|
||||||
|
local ok, params = pcall(vim.lsp.util.make_position_params, 0, encoding)
|
||||||
|
if ok then return params end
|
||||||
|
-- Fallback for Neovim < 0.10 where the second arg wasn't a thing.
|
||||||
|
return vim.lsp.util.make_position_params()
|
||||||
|
end
|
||||||
|
|
||||||
local function exec(command, arguments, on_result)
|
local function exec(command, arguments, on_result)
|
||||||
local client = find_client()
|
local client = find_client()
|
||||||
if not client then
|
if not client then
|
||||||
vim.notify('nuwiki: language server not attached', vim.log.levels.ERROR)
|
vim.notify('nuwiki: language server not attached', vim.log.levels.ERROR)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
client.request(
|
local handler = function(err, result)
|
||||||
'workspace/executeCommand',
|
if err then
|
||||||
{ command = command, arguments = arguments or {} },
|
vim.notify(
|
||||||
function(err, result)
|
'nuwiki: ' .. command .. ' — ' .. (err.message or vim.inspect(err)),
|
||||||
if err then
|
vim.log.levels.ERROR
|
||||||
vim.notify(
|
)
|
||||||
'nuwiki: ' .. command .. ' — ' .. (err.message or vim.inspect(err)),
|
return
|
||||||
vim.log.levels.ERROR
|
end
|
||||||
)
|
if on_result then on_result(result) end
|
||||||
return
|
end
|
||||||
end
|
local bufnr = vim.api.nvim_get_current_buf()
|
||||||
if on_result then
|
local payload = { command = command, arguments = arguments or {} }
|
||||||
on_result(result)
|
-- Neovim 0.12 deprecates `client.request(...)` in favour of the
|
||||||
end
|
-- method form `client:request(...)`. Prefer the method, fall back
|
||||||
end,
|
-- on older Neovim where it isn't defined yet.
|
||||||
vim.api.nvim_get_current_buf()
|
local req = client.request
|
||||||
)
|
if type(req) ~= 'function' then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if rawget(getmetatable(client) or {}, '__index') and client.request ~= nil then
|
||||||
|
-- Method-style works for both colon and dot calls on Neovim's
|
||||||
|
-- Client metatable, but pass `self` explicitly for the older
|
||||||
|
-- function-style signature compatibility.
|
||||||
|
client:request('workspace/executeCommand', payload, handler, bufnr)
|
||||||
|
else
|
||||||
|
client.request('workspace/executeCommand', payload, handler, bufnr)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function open_uri(uri, tab)
|
local function open_uri(uri, tab)
|
||||||
@@ -71,7 +87,8 @@ local function open_uri(uri, tab)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function pos_args()
|
local function pos_args()
|
||||||
return { vim.tbl_extend('force', { uri = buf_uri() }, position_params()) }
|
local client = find_client()
|
||||||
|
return { vim.tbl_extend('force', { uri = buf_uri() }, position_params(client)) }
|
||||||
end
|
end
|
||||||
|
|
||||||
local function uri_args()
|
local function uri_args()
|
||||||
|
|||||||
@@ -200,11 +200,18 @@ function M.attach(bufnr, mappings)
|
|||||||
|
|
||||||
-- ===== Lists =====
|
-- ===== Lists =====
|
||||||
if on('lists') then
|
if on('lists') then
|
||||||
|
-- Three aliases for the same intent. Terminals disagree about
|
||||||
|
-- what byte(s) Ctrl+Space produces:
|
||||||
|
-- * GUI Neovim / kitty-protocol terminals → `<C-Space>`
|
||||||
|
-- * xterm, most legacy terminals → NUL byte → `<C-@>`
|
||||||
|
-- * Some Neovim builds spell that same byte `<Nul>` in keymaps
|
||||||
|
-- Map all three so the user gets the binding regardless.
|
||||||
map('n', '<C-Space>', cmd.toggle_list_item, { desc = 'nuwiki: toggle checkbox' }, bufnr)
|
map('n', '<C-Space>', cmd.toggle_list_item, { desc = 'nuwiki: toggle checkbox' }, bufnr)
|
||||||
map('x', '<C-Space>', cmd.toggle_list_item, { desc = 'nuwiki: toggle checkbox' }, bufnr)
|
map('x', '<C-Space>', cmd.toggle_list_item, { desc = 'nuwiki: toggle checkbox' }, bufnr)
|
||||||
-- <C-@> is the terminal byte for C-Space — keep parity with vimwiki.
|
|
||||||
map('n', '<C-@>', cmd.toggle_list_item, { desc = 'nuwiki: toggle checkbox' }, bufnr)
|
map('n', '<C-@>', cmd.toggle_list_item, { desc = 'nuwiki: toggle checkbox' }, bufnr)
|
||||||
map('x', '<C-@>', cmd.toggle_list_item, { desc = 'nuwiki: toggle checkbox' }, bufnr)
|
map('x', '<C-@>', cmd.toggle_list_item, { desc = 'nuwiki: toggle checkbox' }, bufnr)
|
||||||
|
map('n', '<Nul>', cmd.toggle_list_item, { desc = 'nuwiki: toggle checkbox' }, bufnr)
|
||||||
|
map('x', '<Nul>', cmd.toggle_list_item, { desc = 'nuwiki: toggle checkbox' }, bufnr)
|
||||||
map('n', 'gnt', cmd.next_task, { desc = 'nuwiki: next unfinished task' }, bufnr)
|
map('n', 'gnt', cmd.next_task, { desc = 'nuwiki: next unfinished task' }, bufnr)
|
||||||
map('n', 'gln', cmd.cycle_list_item, { desc = 'nuwiki: increment checkbox' }, bufnr)
|
map('n', 'gln', cmd.cycle_list_item, { desc = 'nuwiki: increment checkbox' }, bufnr)
|
||||||
map('x', 'gln', cmd.cycle_list_item, { desc = 'nuwiki: increment checkbox' }, bufnr)
|
map('x', 'gln', cmd.cycle_list_item, { desc = 'nuwiki: increment checkbox' }, bufnr)
|
||||||
|
|||||||
Reference in New Issue
Block a user