From e8e9bf066302262e57abe405bebaa94f9712415f Mon Sep 17 00:00:00 2001 From: Jonny Barnes Date: Sat, 8 Aug 2026 17:27:37 +0100 Subject: [PATCH] Fix which-key not seeing gitsigns maps, add diagnostic maps The gitsigns keymaps were defined in on_attach, so they were buffer-local and created asynchronously - gitsigns shells out to git before attaching. which-key had already built its keymap tree for the buffer by then, and it only invalidates that cache on BufReadPost, BufNew and LspAttach, so maps added afterwards stayed invisible. Buf:get() returns cached mode state unless explicitly passed `update`, which is why re-entering the buffer didn't help either. Mapping globally instead means the maps exist before which-key builds any tree. The gitsigns API no-ops in buffers it hasn't attached to (checked stage/reset/preview/blame/nav in a non-git directory), so the only change is that the maps now exist everywhere rather than just in git-tracked buffers. Also puts the diagnostic float and quickfix list on d. Nvim already binds d and ]d/[d for these, so this is a rebinding for discoverability rather than new capability. Co-Authored-By: Claude Opus 5 (1M context) --- neovim/config/diagnostics.lua | 5 ++ neovim/config/plugins/gitsigns.lua | 89 +++++++++++++++-------------- neovim/config/plugins/which-key.lua | 3 +- 3 files changed, 53 insertions(+), 44 deletions(-) diff --git a/neovim/config/diagnostics.lua b/neovim/config/diagnostics.lua index d09ad3f..366a246 100644 --- a/neovim/config/diagnostics.lua +++ b/neovim/config/diagnostics.lua @@ -16,3 +16,8 @@ vim.diagnostic.config({ }, }, }) + +-- Nvim already binds ]d / [d to jump and d to show the diagnostic under +-- the cursor; these put the same actions on so which-key lists them. +vim.keymap.set('n', 'dd', vim.diagnostic.open_float, { desc = 'Show diagnostic' }) +vim.keymap.set('n', 'dq', vim.diagnostic.setqflist, { desc = 'Diagnostics to quickfix' }) diff --git a/neovim/config/plugins/gitsigns.lua b/neovim/config/plugins/gitsigns.lua index 58df528..f1f352e 100644 --- a/neovim/config/plugins/gitsigns.lua +++ b/neovim/config/plugins/gitsigns.lua @@ -1,55 +1,58 @@ vim.pack.add({ 'https://github.com/lewis6991/gitsigns.nvim' }) -require('gitsigns').setup({ - on_attach = function(bufnr) - local gitsigns = require('gitsigns') +local gitsigns = require('gitsigns') - local function map(mode, lhs, rhs, desc) - vim.keymap.set(mode, lhs, rhs, { buffer = bufnr, desc = desc }) - end +gitsigns.setup() - -- Navigation, falling back to vim's own diff motions in diff mode - map('n', ']c', function() - if vim.wo.diff then - vim.cmd.normal({ ']c', bang = true }) - else - gitsigns.nav_hunk('next') - end - end, 'Next git hunk') +-- Mapped globally rather than from on_attach. Gitsigns attaches asynchronously, +-- after which-key has already built its keymap tree for the buffer, and +-- which-key only rebuilds that on BufReadPost/BufNew/LspAttach - so +-- buffer-local maps added later never show up in its popup. The gitsigns API +-- no-ops in buffers it hasn't attached to, so global maps are safe. +local function map(mode, lhs, rhs, desc) + vim.keymap.set(mode, lhs, rhs, { desc = desc }) +end - map('n', '[c', function() - if vim.wo.diff then - vim.cmd.normal({ '[c', bang = true }) - else - gitsigns.nav_hunk('prev') - end - end, 'Previous git hunk') +-- Navigation, falling back to vim's own diff motions in diff mode +map('n', ']c', function() + if vim.wo.diff then + vim.cmd.normal({ ']c', bang = true }) + else + gitsigns.nav_hunk('next') + end +end, 'Next git hunk') - -- Actions - map('n', 'hs', gitsigns.stage_hunk, 'Stage hunk') - map('n', 'hr', gitsigns.reset_hunk, 'Reset hunk') +map('n', '[c', function() + if vim.wo.diff then + vim.cmd.normal({ '[c', bang = true }) + else + gitsigns.nav_hunk('prev') + end +end, 'Previous git hunk') - map('v', 'hs', function() - gitsigns.stage_hunk({ vim.fn.line('.'), vim.fn.line('v') }) - end, 'Stage selected hunk') +-- Actions +map('n', 'hs', gitsigns.stage_hunk, 'Stage hunk') +map('n', 'hr', gitsigns.reset_hunk, 'Reset hunk') - map('v', 'hr', function() - gitsigns.reset_hunk({ vim.fn.line('.'), vim.fn.line('v') }) - end, 'Reset selected hunk') +map('v', 'hs', function() + gitsigns.stage_hunk({ vim.fn.line('.'), vim.fn.line('v') }) +end, 'Stage selected hunk') - map('n', 'hS', gitsigns.stage_buffer, 'Stage buffer') - map('n', 'hR', gitsigns.reset_buffer, 'Reset buffer') - map('n', 'hp', gitsigns.preview_hunk, 'Preview hunk') - map('n', 'hd', gitsigns.diffthis, 'Diff against index') +map('v', 'hr', function() + gitsigns.reset_hunk({ vim.fn.line('.'), vim.fn.line('v') }) +end, 'Reset selected hunk') - map('n', 'hb', function() - gitsigns.blame_line({ full = true }) - end, 'Blame line') +map('n', 'hS', gitsigns.stage_buffer, 'Stage buffer') +map('n', 'hR', gitsigns.reset_buffer, 'Reset buffer') +map('n', 'hp', gitsigns.preview_hunk, 'Preview hunk') +map('n', 'hd', gitsigns.diffthis, 'Diff against index') - map('n', 'hq', gitsigns.setqflist, 'Hunks to quickfix') +map('n', 'hb', function() + gitsigns.blame_line({ full = true }) +end, 'Blame line') - -- Toggles - map('n', 'tb', gitsigns.toggle_current_line_blame, 'Toggle line blame') - map('n', 'td', gitsigns.toggle_deleted, 'Toggle deleted lines') - end, -}) +map('n', 'hq', gitsigns.setqflist, 'Hunks to quickfix') + +-- Toggles +map('n', 'tb', gitsigns.toggle_current_line_blame, 'Toggle line blame') +map('n', 'td', gitsigns.toggle_deleted, 'Toggle deleted lines') diff --git a/neovim/config/plugins/which-key.lua b/neovim/config/plugins/which-key.lua index 0eb1d9c..2b6bf9e 100644 --- a/neovim/config/plugins/which-key.lua +++ b/neovim/config/plugins/which-key.lua @@ -4,8 +4,9 @@ local wk = require('which-key') wk.setup() --- Names for the gitsigns prefixes, so the popup groups them sensibly +-- Names for the prefixes, so the popup groups them sensibly wk.add({ + { 'd', group = 'diagnostics' }, { 'h', group = 'hunks' }, { 't', group = 'toggles' }, })