folke / which-key.nvim

💥 Create key bindings that stick. WhichKey helps you remember your Neovim keymaps, by showing available keybindings in a popup as you type.
Apache License 2.0
5.49k stars 175 forks source link

bug: Conflict Between which-key Operator Preset and Custom Mappings #904

Closed PannenetsF closed 18 hours ago

PannenetsF commented 18 hours ago

Did you check docs and existing issues?

Neovim version (nvim -v)

NVIM v0.10.0

Operating system/version

macOS 13.4 22F66 x86_64

Describe the bug

When using which-key.nvim, the preset for operators (e.g., c for change) conflicts with custom mappings. If a custom mapping (e.g., cit) is defined, the WhichKey menu splits the behavior into two separate groups:

  1. The c key remains under the change operator group.
  2. The custom mapping (cit) is treated as an independent mapping, causing inconsistency.

Steps To Reproduce

(run with the repro.lua)

Trigger the following scenarios: Press c → i → t in normal mode to use the change operator. Run :WhichKey and check the group for c. Observe that c → i → t appears under the test_handler mapping instead of being grouped under the change operator.

Expected Behavior

When pressing c → i → t, nvim should exec the _test_handler in the config instead of the original one.

Actual behavior: c → i → t is still recognized as part of the change operator preset for the inner tag. Running :WhichKey shows c → i → t as an independent mapping, associated with the test_handler function.

SO the issue is about inconsistency.

Health

==============================================================================
which-key: require("which-key.health").check()

- OK Most of these checks are for informational purposes only.
  WARNINGS should be treated as a warning, and don't necessarily indicate a problem with your config.
  Please |DON'T| report these warnings as an issue.

Checking your config ~
- WARNING |mini.icons| is not installed
- OK |nvim-web-devicons| is installed

Checking for issues with your mappings ~
- OK No issues reported

checking for overlapping keymaps ~
- OK Overlapping keymaps are only reported for informational purposes.
  This doesn't necessarily mean there is a problem with your config.

Checking for duplicate mappings ~
- OK No duplicate mappings found

Log

Debug Started for v3.14.1
{
  branch = "main",
  commit = "9b365a6428a9633e3eeb34dbef1b791511c54f70"
}
new Mode(n:1)
Trigger(add) Mode(n:1) ` ' " g` g' z= g [ z <C-W> ] ci
on_key: <Esc>
on_key: <Esc>
on_key: <Esc>
on_key: <Esc>
on_key: a
ModeChanged(n:i)
  new Mode(i:1)
  Safe(true)
Trigger(add) Mode(i:1) <C-R>
on_key: <Esc>
ModeChanged(i:n)
  Safe(true)
on_key: a
ModeChanged(n:i)
  Safe(true)
on_key: h
on_key: e
on_key: l
on_key: l
on_key: o
on_key: <Esc>
ModeChanged(i:n)
  Safe(true)
on_key: <Esc>
on_key: <Esc>
on_key: c
ModeChanged(n:no)
  new Mode(o:1)
  Safe(true)
  State(start): Mode(o:0) Node() { defer = false }
    update Mode(o:1)
    continue:  Mode(o:1)
    getchar
    Trigger(add) Mode(o:1) g [ ]
    on_key: i
    got: i
    continue: i Mode(o:1)
    getchar
    on_key: t
    got: t
    suspend: Mode(o:1)
    Trigger(del) Mode(o:1) [ g ]
    feedkeys: Mode(o:1) it
on_key: i
on_key: t
ModeChanged(no:n)
  Safe(true)
Trigger(add) Mode(o:1) g [ ]
on_key: :
ModeChanged(n:c)
  new Mode(c:1)
  Safe(true)
Trigger(add) Mode(c:1) <C-R>
on_key: W
on_key: h
on_key: i
on_key: <Tab>
on_key: <Space>
on_key: <CR>
ModeChanged(c:n)
  Unsafe(command-mode)
  suspend: Mode(n:1)
  Trigger(del) Mode(n:1) <C-W> ] ci ` ' " g' [ g` z= g z
State(start): Mode(n:0) Node() { delay = 0, keys = "", mode = "n", waited = 1000 }
  update Mode(n:1)
  continue:  Mode(n:1)
  getchar
  Trigger(add) Mode(n:1) ` ' " g` g' z= g [ z <C-W> ] ci
  on_key: c
  got: c
  continue: c Mode(n:1)
  getchar
  on_key: i
  got: i
  continue: ci Mode(n:1)
  getchar
  on_key: t
  got: t
  suspend: Mode(n:1)
  Trigger(del) Mode(n:1) <C-W> ] ci ` ' " g' [ g` z= g z
  feedkeys: Mode(n:1) cit
on_key: cit
Trigger(add) Mode(n:1) ` ' " g` g' z= g [ z <C-W> ] ci
on_key: :
ModeChanged(n:c)
  Safe(true)
on_key: w
on_key: q
on_key: <BS>
on_key: <BS>
on_key: q
on_key: !
on_key: <CR>
ModeChanged(c:n)
  Unsafe(command-mode)
  suspend: Mode(n:1)
  Trigger(del) Mode(n:1) <C-W> ] ci ` ' " g' [ g` z= g z
Trigger(add) Mode(n:1) ` ' " g` g' z= g [ z <C-W> ] ci

Repro

vim.env.LAZY_STDPATH = ".repro"
load(vim.fn.system("curl -s https://raw.githubusercontent.com/folke/lazy.nvim/main/bootstrap.lua"))()

function _test_handler()
  print("test_handler")
end
vim.keymap.set('n', 'cit', '<cmd>lua _test_handler()<cr>', { noremap = true, silent = true })

require("lazy.minit").repro({
  spec = {
    { "folke/which-key.nvim", opts = {} },
  },
})
folke commented 18 hours ago

you misunderstand mappings. When you press c and wait, timeoutlen expires and you enter op-pending mode, so which-key will show you continuations for operator pending mode (this won't include your cit mapping).

The old which-key did this incorrectly.

not a bug

PannenetsF commented 18 hours ago

I get it now, thanks, folke.