From 091f9c92f93e88b5b22e4f4aceaeae4cdc28220a Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Wed, 26 Aug 2026 20:52:47 +0900 Subject: [PATCH] Withhold the show key from a key the command binds Setting show_key to a key a command binds for its own hint, ctrl-alt-x on Buffers or alt-a on Rg, advertised both in the footer while the command's binding won by coming later in the options. '_hint' entries now carry the fzf key names behind the label, which is what the check compares, since a label like 'A-a/d' cannot be. --- autoload/fzf/vim.vim | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/autoload/fzf/vim.vim b/autoload/fzf/vim.vim index 8897f75..098a448 100755 --- a/autoload/fzf/vim.vim +++ b/autoload/fzf/vim.vim @@ -371,8 +371,8 @@ function! s:build_hint(entries, defaults, ...) endif endfor endif - for [key, action] in entries - call add(keys, s:magenta(key, 'Special').' '.action) + for entry in entries + call add(keys, s:magenta(entry[0], 'Special').' '.entry[1]) endfor return join(keys, ' ') endfunction @@ -801,7 +801,7 @@ endfunction " Whether the show key can be offered for this run. Decided from the merged " spec, since the layout can arrive with the per-call spec, and a bang puts " fzf on its own tabpage where the window we would open in is not visible. -function! s:can_show(spec, bang, key) abort +function! s:can_show(spec, bang, key, claimed) abort " Older fzf blocks Vim in popup and fullscreen modes, so the callback would " only run after fzf exits, overriding whatever was selected. fzf#run is " only asynchronous when it has a terminal to put fzf in, and win32unix @@ -816,12 +816,13 @@ function! s:can_show(spec, bang, key) abort return 0 endif " fzf matches --expect before the key bindings, so an action or the paste - " key would win over ours. Any key of the list losing disables all of them, - " so that the footer cannot advertise a key that does nothing + " key would win over ours, and a key the command binds itself would win by + " coming later in the options. Any key of the list losing disables all of + " them, so that the footer cannot advertise a key that does nothing let actions = get(g:, 'fzf_action', s:default_action) let paste = s:split_keys(s:paste_key()) for key in s:split_keys(a:key) - if has_key(actions, key) || index(paste, key) >= 0 + if has_key(actions, key) || index(paste, key) >= 0 || index(a:claimed, key) >= 0 return 0 endif endfor @@ -844,7 +845,9 @@ function! s:can_show(spec, bang, key) abort endfunction " Installs the show key binding and the key hint footer. '_show' names the entry -" kind, '_hint' opts in to the footer and carries the command's own keys. +" kind, '_hint' opts in to the footer and carries the command's own keys as +" [label, description] or [label, description, keys]. The fzf key names in +" 'keys' are what the show key is checked against, since the label cannot be. " Returns the fifo of the ipc channel it started, so the caller can stop it if " the run never reaches 'exit' function! s:add_hints(spec, bang) abort @@ -852,8 +855,16 @@ function! s:add_hints(spec, bang) abort let taken = [] let kind = s:pluck(a:spec, '_show', '') let entries = s:pluck(a:spec, '_hint', 0) + let claimed = [] + if type(entries) == s:TYPE.list + for entry in entries + for name in get(entry, 2, []) + call extend(claimed, s:split_keys(name)) + endfor + endfor + endif let key = s:show_key() - if !empty(kind) && !empty(key) && s:can_show(a:spec, a:bang, key) + if !empty(kind) && !empty(key) && s:can_show(a:spec, a:bang, key, claimed) let dir = get(a:spec, 'dir', '') let fifo = fzf#vim#ipc#start(function('s:show_entry', \ [win_getid(), empty(dir) ? getcwd() : dir, kind])) @@ -1347,7 +1358,7 @@ function! fzf#vim#buffers(...) \ '_paste': 1 \} let spec._show = 'buffer' - let spec._hint = [['C-A-X', 'Unload']] + let spec._hint = [['C-A-X', 'Unload', ['ctrl-alt-x']]] let options = ['+m', '-x', '--tiebreak=index', '--ansi', '-d', '\t', '--with-nth', '3..', '-n', '2,1..2', '--prompt', 'Buf> ', '--query', query, '--preview-window', '+{2}/2', '--tabstop', tabstop, '--bind', 'ctrl-alt-x:execute-silent(echo {} >> '.fzf#shellescape(delete_file).')+exclude'] if bufnr('') == first call extend(options, ['--sync', '--bind', 'start:pos:2']) @@ -1473,7 +1484,7 @@ function! fzf#vim#grep(grep_command, ...) let opts._paste = 1 let opts._show = 'grep' - let opts._hint = [['A-a/d', 'Select/deselect all']] + let opts._hint = [['A-a/d', 'Select/deselect all', ['alt-a', 'alt-d']]] function! opts.sink(lines) closure return s:ag_handler(get(opts, 'name', name), a:lines) endfunction @@ -1521,7 +1532,7 @@ function! fzf#vim#grep2(command_prefix, query, ...) endif let opts._paste = 1 let opts._show = 'grep' - let opts._hint = [['A-a/d', 'Select/deselect all']] + let opts._hint = [['A-a/d', 'Select/deselect all', ['alt-a', 'alt-d']]] function! opts.sink(lines) closure return s:ag_handler(name, a:lines) endfunction