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.12k stars 163 forks source link

bug: require"which-key".show causes freeze #761

Closed ir-ae closed 1 month ago

ir-ae commented 1 month ago

Did you check docs and existing issues?

Neovim version (nvim -v)

NVIM v0.10.0 Build type: Release LuaJIT 2.1.1713484068

Operating system/version

Windows 10

Describe the bug

Which-key freezes if you press a button that is not displayed after calling .show(). Pressing <C-c> lets you then type again

Steps To Reproduce

Using the keybinds in the repro

  1. Press <leader>w
  2. Press any button that isnt 1 or 2 (e.g j/k...)
  3. All keys do nothing until pressing <C-c>

Expected Behavior

which-key should just close the popup without freezing

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
- WARNING |nvim-web-devicons| is not installed
- WARNING Keymap icon support will be limited.

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

checking for overlapping keymaps ~
- WARNING In mode `n`, <gc> overlaps with <gcc>:
  - <gc>: Toggle comment
  - <gcc>: Toggle comment line
- WARNING In mode `n`, <<Space>w> overlaps with <<Space>w1>, <<Space>w2>:

- 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.10.0
new Mode(n:1)
Trigger(add) Mode(n:1) " ` ' g' g` z= [ ] <C-W> g z <Space>
on_key: <Space>
State(start): Mode(n:0) Node(<Space>) { keys = "<Space>" }
  update Mode(n:1)
  continue: <Space> Mode(n:1)
  getchar
  on_key: w
  got: w
  suspend: Mode(n:1)
  Trigger(del) Mode(n:1) <C-W> g " <Space> ` ' g' g` z= z [ ]
  feedkeys: Mode(n:1) <Space>w
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: j
  got: j
  suspend: Mode(n:1)
  feedkeys: Mode(n:1) <Space>wj
on_key: <Space>w
State(start): Mode(n:0) Node(<leader>w) { delay = 0, keys = "<leader>w", waited = 1000 }
  update Mode(n:1)
  continue: <Space>w Mode(n:1)
  getchar
  on_key: <C-C>
  nok: Keyboard interrupt
Trigger(add) Mode(n:1) " ` ' g' g` z= [ ] <C-W> g z <Space>
on_key: :
ModeChanged(n:c)
  new Mode(c:1)
  Safe(true)
Trigger(add) Mode(c:1) <C-R>
on_key: q
on_key: a
on_key: <CR>
ModeChanged(c:n)
  Unsafe(command-mode)
  suspend: Mode(n:1)
  Trigger(del) Mode(n:1) g' g` z= z [ ] <C-W> g " <Space> ` '
Trigger(add) Mode(n:1) " ` ' g' g` z= [ ] <C-W> g z <Space>

Repro

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

require"lazy.minit".repro({
  spec = {
    { "folke/which-key.nvim",
      init = function ()
        vim.g.mapleader = " "
        vim.keymap.set("n", "<leader>w", function() require"which-key".show("<leader>w") end)
        vim.keymap.set("n", "<leader>w1", "<cmd>echo 1<cr>")
        vim.keymap.set("n", "<leader>w2", "<cmd>echo 2<cr>")
      end,
      opts = {}
    },
    -- add any other plugins here
  },
})
folke commented 1 month ago

What do you expect to happen with that config? You have a keymap at <leader>w that shows and executes keymaps at <leader>w.

If you want to make this work, just define it as a trigger. Don't manually call it since it will load that same keymap again and again.

folke commented 1 month ago

I just added some checks that will show an error in this case.

ir-ae commented 1 month ago

What do you expect to happen with that config? You have a keymap at <leader>w that shows and executes keymaps at <leader>w.

The idea was to have <leader>w do something and then show the <leader>w1/<leader>w2 commands in which-key afterwards.

vim.keymap.set("n", "<leader>w", function()
   -- Do other stuff here --
   require"which-key".show("<leader>w") 
end)

Just defining it as a trigger doesn't allow that unless I'm missing something. I guess I was wanting a way for show() to just show which-key without actually executing the mapping I pass to it

towry commented 1 month ago

If you want to make this work, just define it as a trigger. Don't manually call it since it will load that same keymap again and again.

Seems not work

towry commented 1 month ago

Here is how I managed to make my old dynamic mapping works with which-key.

  1. Add dynamic local maps to a table, like which-key.extras did.
  2. call whichKey.add({ '<leader>z+', group = 'xxx', expand = function() return deep_cloned_table_of_previous_maps end }). Note: deep clone the table then return is important.
  3. We have to trigger this <leader>z+ keys in a strange way. 3.1 First, call it in vim.schedule(function() // call 3.2 end) 3.2 Second, must call it in vim.defer_fn(function() // trigger the keys using vim.api.nvim_feedkeys end, 1).

Without 3, which-keys will keep report can not found keys in mode 'n'.