15 Commits
Author SHA1 Message Date
Junegunn Choi cc50e8bece Add ctrl-o to show the entry without closing fzf
Files, GFiles, GFiles?, Rg/Ag, Buffers, History, Locate, Lines, BLines,
Tags, BTags, Marks, Changes, Commits and BCommits. Writes the entry to an
fzf#vim#ipc fifo, so it needs the asynchronous fzf#run from
junegunn/fzf@5cb7bab7 (junegunn/fzf#4897, 0.74.4), which the g:loaded_fzf
check detects.

Commands declare '_show' for the entry kind and '_hint' for footer keys, so
the footer and the binding cannot disagree. s:can_show withholds both when
the run would block, when the window to open in is not visible, or when
g:fzf_action, the paste key or the command itself already claims the key.

g:fzf_vim.show_key configures the key, empty to turn it off, comma-separated
to bind several ('ctrl-o,double-click'). Named for its 'Show' footer label,
since Enter already occupies 'Open' there. Only the first key is labelled,
and a clash on any of them drops all of them, so the footer cannot list a
key that does nothing. Binding Enter drops its 'Open' hint too, since fzf
accepts on Enter rather than through g:fzf_action.

s:show_entry parses each entry the way that command's sink does and runs
win_execute() in the window fzf started from. That keeps the focus in fzf
and works from a popup, which win_gotoid() cannot leave. It opens with
'keepalt keepjumps hide', so stepping through entries leaves the alternate
file and the jumplist unchanged. BLines, BTags and a lowercase mark carry a
position but no buffer, so the callback carries the buffer the run started
on as well as the window.

fzf#run is asynchronous, so runs can overlap, and a second run would stop
the first's ipc channel and overwrite the script locals its sink reads back
afterwards. Channels are now keyed by fifo path and per-run state is bound
into the callback instead, which is why Buffers, Colors, Jumps, Maps,
Helptags and complete change here.
2026-08-31 19:48:06 +09:00
Junegunn Choi d2a59a992a Use --footer for key binding hints
- Buffers: CTRL-ALT-X replaces SHIFT-DELETE to unload buffers
- History:, History/, Commits: use --scheme=history
- Bump min fzf version to 0.63.0 for --footer
2026-06-12 09:06:10 +09:00
sachit 356608e2ae Show lua colorschemes in :Colors command (#1619) 2026-06-02 11:09:22 +09:00
Junegunn Choi 7fd26e3609 Experiment: Replace '--info inline' with '--info inline-right' (#1617) 2026-05-31 23:41:34 +09:00
Junegunn Choi c2b97c62b9 Add ALT-ENTER to paste selected items into the buffer
- New fzf#vim#paste inserts selections instead of opening them
  - First item after cursor (space-padded), rest on following lines
  - Leading whitespace stripped only when pasting after text
- Commands opt in via `_paste`; key configurable with g:fzf_vim.paste_key
- Skip the key when buffer is not &modifiable
- Per command, paste:
  - path: Files, GFiles, GFiles?, Buffers, History, Locate
  - line text: Lines, BLines, Marks, Changes
  - matched text: Rg, Ag, Grep
  - tag name: Tags, BTags
  - commit hash: Commits, BCommits
2026-05-31 23:26:55 +09:00
Junegunn Choi e5b53de3d3 [Buffers] Allow selecting the current buffer
But place the initial cursor on the second item so quick switching is
still possible as before.
2026-05-24 10:51:04 +09:00
Junegunn Choi 11d44b1805 Make the appearance of History: and History/ consistent 2026-05-24 10:27:28 +09:00
Junegunn Choi b9b98ac574 Commands: Fix quotation mistake 2026-05-21 20:35:33 +09:00
Junegunn Choi 31e338e314 Buffers: SHIFT-DELETE to unload buffers
Close #75
Close #733
2026-05-21 19:04:45 +09:00
Junegunn Choi 28ed21ef3e Some facelift 2026-05-21 19:00:40 +09:00
Junegunn Choi b9624aa012 Do not display statusline when fzf is running in a floating window
Related: #1615
2026-04-10 21:30:27 +09:00
Junegunn Choi 34a564c81f Update README 2026-02-02 09:42:52 +09:00
Enno ddc14a6a54 Avoid cooked terminal mode (#1604)
as `:help system()` states

		When prepended by |:silent| the terminal will not be set to
		cooked mode.  This is meant to be used for commands that do
		not need the user to type.  It avoids stray characters showing
		up on the screen which require |CTRL-L| to remove. >
			:silent let f = system('ls *.vim')
2025-12-09 08:49:13 +09:00
Junegunn Choi 879db51d09 Update README.md 2025-09-03 09:59:37 +09:00
phanium 3725f364cc Fix cmd hisotry correctly (#1594) 2025-06-20 17:04:48 +09:00
5 changed files with 883 additions and 149 deletions
+45
View File
@@ -96,6 +96,21 @@ Commands
- Most commands support `CTRL-T` / `CTRL-X` / `CTRL-V` key - Most commands support `CTRL-T` / `CTRL-X` / `CTRL-V` key
bindings to open in a new tab, a new split, or in a new vertical split bindings to open in a new tab, a new split, or in a new vertical split
- Most commands support `ALT-ENTER` to insert the selected items into the
current buffer instead of opening them. The inserted text depends on the
command: file path (`:Files`, `:GFiles`, `:Buffers`, `:History`, `:Locate`),
line content (`:Lines`, `:BLines`, `:Marks`, `:Changes`), matched text
(`:Rg`, `:Ag`, `:Grep`), tag name (`:Tags`, `:BTags`), or commit hash
(`:Commits`, `:BCommits`)
- Most commands support `CTRL-O` to open the current entry in the window fzf
was started from, leaving fzf open, so you can look through several entries
in a single run (`:Files`, `:GFiles`, `:GFiles?`, `:Buffers`, `:History`,
`:Locate`, `:Rg`, `:Ag`, `:Grep`, `:Lines`, `:BLines`, `:Tags`, `:BTags`,
`:Marks`, `:Changes`, `:Commits`, `:BCommits`). Requires fzf 0.74.4 or
later, and is not offered in fullscreen mode, with a layout that leaves no
other window (`enew`, `tabnew`), on Windows, or when the key is already
used by `g:fzf_vim.paste_key`, `g:fzf_action`, or the command itself, as
`CTRL-ALT-X` is in `:Buffers`
- Bang-versions of the commands (e.g. `Ag!`) will open fzf in fullscreen - Bang-versions of the commands (e.g. `Ag!`) will open fzf in fullscreen
- You can set `g:fzf_vim.command_prefix` to give the same prefix to the commands - You can set `g:fzf_vim.command_prefix` to give the same prefix to the commands
- e.g. `let g:fzf_vim.command_prefix = 'Fzf'` and you have `FzfFiles`, etc. - e.g. `let g:fzf_vim.command_prefix = 'Fzf'` and you have `FzfFiles`, etc.
@@ -156,6 +171,36 @@ let g:fzf_vim.preview_window = []
" let g:fzf_vim.preview_bash = 'C:\Git\bin\bash.exe' " let g:fzf_vim.preview_bash = 'C:\Git\bin\bash.exe'
``` ```
#### Paste key
Most commands support a key to insert the selected items into the current
buffer instead of opening them (see the command list above for what each
command inserts). Customize it with `g:fzf_vim.paste_key`.
```vim
" Key to insert the selected items into the current buffer (default: 'alt-enter')
let g:fzf_vim.paste_key = 'alt-enter'
```
#### Show key
Most commands support a key that opens the current entry in the window fzf
was started from and leaves fzf open, so you can look through several entries
in one run (see the command list above). It is labelled `Show` in the footer
to set it apart from `Enter Open`, which opens the entry and closes fzf.
Customize it with `g:fzf_vim.show_key`, or set it to an empty string to turn
the key off. A comma-separated list binds every key in it. It takes the key
over from `$FZF_DEFAULT_OPTS`, so pick another key or turn it off to keep a
binding of your own.
```vim
" Key to open the current entry, leaving fzf open (default: 'ctrl-o')
let g:fzf_vim.show_key = 'ctrl-o'
" Use CTRL-O and double-click
let g:fzf_vim.show_key = 'ctrl-o,double-click'
```
#### Command-level options #### Command-level options
```vim ```vim
+707 -110
View File
File diff suppressed because it is too large Load Diff
+72 -31
View File
@@ -28,6 +28,9 @@ function! s:warn(message)
return 0 return 0
endfunction endfunction
" Channels in flight, keyed by fifo path, so concurrent fzf runs do not clash
let s:channels = {}
function! fzf#vim#ipc#start(Callback) function! fzf#vim#ipc#start(Callback)
if !exists('*job_start') && !exists('*jobstart') if !exists('*job_start') && !exists('*jobstart')
call s:warn('job_start/jobstart function not supported') call s:warn('job_start/jobstart function not supported')
@@ -39,57 +42,95 @@ function! fzf#vim#ipc#start(Callback)
return '' return ''
endif endif
call fzf#vim#ipc#stop() let fifo = tempname()
call system('mkfifo '..shellescape(fifo))
let g:fzf_ipc = { 'fifo': tempname(), 'callback': a:Callback } if v:shell_error
if !filereadable(g:fzf_ipc.fifo) if !exists('s:mkfifo_failed')
call system('mkfifo '..shellescape(g:fzf_ipc.fifo)) let s:mkfifo_failed = 1
if v:shell_error
call s:warn('Failed to create fifo') call s:warn('Failed to create fifo')
endif endif
return ''
endif endif
call fzf#vim#ipc#restart() let s:channels[fifo] = { 'fifo': fifo, 'callback': a:Callback }
call fzf#vim#ipc#restart(fifo)
if !s:running(s:channels[fifo].job)
call fzf#vim#ipc#stop(fifo)
return ''
endif
return g:fzf_ipc.fifo return fifo
endfunction endfunction
function! fzf#vim#ipc#restart() " Nvim hands over everything one read produced, which can be several messages
if !exists('g:fzf_ipc') " as well as the trailing empty element. Vim's out_cb passes one line at a
" time, so deliver line by line and both behave the same.
function! s:deliver(Callback, lines)
for line in a:lines
if !empty(line)
call call(a:Callback, [line])
endif
endfor
endfunction
" The reader is gone, so leaving the channel registered would block the next
" write on a fifo nothing reads
function! s:drop(fifo)
if has_key(s:channels, a:fifo)
call delete(remove(s:channels, a:fifo).fifo)
endif
endfunction
function! fzf#vim#ipc#restart(fifo)
if !has_key(s:channels, a:fifo)
throw 'fzf#vim#ipc not started' throw 'fzf#vim#ipc not started'
endif endif
let Callback = g:fzf_ipc.callback let chan = s:channels[a:fifo]
let Callback = chan.callback
let fifo = a:fifo
if exists('*job_start') if exists('*job_start')
let g:fzf_ipc.job = job_start( let chan.job = job_start(
\ ['cat', g:fzf_ipc.fifo], \ ['cat', fifo],
\ {'out_cb': { _, msg -> call(Callback, [msg]) }, \ {'out_cb': { _, msg -> has_key(s:channels, fifo) ? call(Callback, [msg]) : '' },
\ 'exit_cb': { _, status -> status == 0 ? fzf#vim#ipc#restart() : '' }} \ 'exit_cb': { _, status -> status == 0 && has_key(s:channels, fifo) ? fzf#vim#ipc#restart(fifo) : s:drop(fifo) }}
\ ) \ )
else else
let eof = [''] let chan.job = jobstart(
let g:fzf_ipc.job = jobstart( \ ['cat', fifo],
\ ['cat', g:fzf_ipc.fifo],
\ {'stdout_buffered': 1, \ {'stdout_buffered': 1,
\ 'on_stdout': { j, msg, e -> msg != eof ? call(Callback, msg) : '' }, \ 'on_stdout': { j, msg, e -> has_key(s:channels, fifo) ? s:deliver(Callback, msg) : '' },
\ 'on_exit': { j, status, e -> status == 0 ? fzf#vim#ipc#restart() : '' }} \ 'on_exit': { j, status, e -> status == 0 && has_key(s:channels, fifo) ? fzf#vim#ipc#restart(fifo) : s:drop(fifo) }}
\ ) \ )
endif endif
endfunction endfunction
function! fzf#vim#ipc#stop() " Whether the job handle refers to a live job. Nvim returns -1 or 0 instead of
if !exists('g:fzf_ipc') " a handle when it cannot start one
function! s:running(job)
if exists('*job_status')
return job_status(a:job) ==# 'run'
endif
return a:job > 0
endfunction
function! fzf#vim#ipc#stop(fifo)
if !has_key(s:channels, a:fifo)
return return
endif endif
let job = g:fzf_ipc.job " Drop it first, so the exit handler does not restart the job
if exists('*job_stop') let chan = remove(s:channels, a:fifo)
call job_stop(job) " Never throw from here, this runs as part of fzf's exit handling
else try
call jobstop(job) if exists('*job_stop')
call jobwait([job]) call job_stop(chan.job)
endif else
call jobstop(chan.job)
call jobwait([chan.job])
endif
catch
endtry
call delete(g:fzf_ipc.fifo) call delete(chan.fifo)
unlet g:fzf_ipc
endfunction endfunction
+46 -1
View File
@@ -1,4 +1,4 @@
fzf-vim.txt fzf-vim Last change: June 8 2025 fzf-vim.txt fzf-vim Last change: May 31 2026
FZF-VIM - TABLE OF CONTENTS *fzf-vim* *fzf-vim-toc* FZF-VIM - TABLE OF CONTENTS *fzf-vim* *fzf-vim-toc*
============================================================================== ==============================================================================
@@ -150,6 +150,19 @@ COMMANDS *fzf-vim-commands*
- Most commands support CTRL-T / CTRL-X / CTRL-V key bindings to open in a new - Most commands support CTRL-T / CTRL-X / CTRL-V key bindings to open in a new
tab, a new split, or in a new vertical split tab, a new split, or in a new vertical split
- Most commands support ALT-ENTER to insert the selected items into the
current buffer instead of opening them. The inserted text depends on the
command: file path (Files, GFiles, Buffers, History, Locate), line content
(Lines, BLines, Marks, Changes), matched text (Rg, Ag, Grep), tag name
(Tags, BTags), or commit hash (Commits, BCommits)
- Most commands support CTRL-O to open the current entry in the window fzf
was started from, leaving fzf open, so you can look through several
entries in a single run (Files, GFiles, GFiles?, Buffers, History, Locate,
Rg, Ag, Grep, Lines, BLines, Tags, BTags, Marks, Changes, Commits,
BCommits). Requires fzf 0.74.4 or later, and is not offered in fullscreen
mode, with a layout that leaves no other window (enew, tabnew), on
Windows, or when the key is already used by g:fzf_vim.paste_key,
g:fzf_action, or the command itself, as CTRL-ALT-X is in :Buffers
- Bang-versions of the commands (e.g. `Ag!`) will open fzf in fullscreen - Bang-versions of the commands (e.g. `Ag!`) will open fzf in fullscreen
- You can set `g:fzf_vim.command_prefix` to give the same prefix to the commands - You can set `g:fzf_vim.command_prefix` to give the same prefix to the commands
- e.g. `let g:fzf_vim.command_prefix = 'Fzf'` and you have `FzfFiles`, etc. - e.g. `let g:fzf_vim.command_prefix = 'Fzf'` and you have `FzfFiles`, etc.
@@ -224,6 +237,38 @@ behavior with `g:fzf_vim.preview_window`. Here are some examples:
" let g:fzf_vim.preview_bash = 'C:\Git\bin\bash.exe' " let g:fzf_vim.preview_bash = 'C:\Git\bin\bash.exe'
< <
Paste key~
*fzf-vim-paste-key*
*g:fzf_vim.paste_key*
Most commands support a key to insert the selected items into the current
buffer instead of opening them. Customize it with `g:fzf_vim.paste_key`.
>
" Key to insert the selected items into the current buffer
" (default: 'alt-enter')
let g:fzf_vim.paste_key = 'alt-enter'
<
Show key~
*fzf-vim-show-key*
*g:fzf_vim.show_key*
Most commands support a key that opens the current entry in the window fzf was
started from and leaves fzf open, so you can look through several entries in
one run. It is labelled Show in the footer to set it apart from Enter Open,
which opens the entry and closes fzf. Customize it with `g:fzf_vim.show_key`,
or set it to an empty string to turn the key off. A comma-separated list binds
every key in it. It takes the key over from `$FZF_DEFAULT_OPTS`, so pick
another key or turn it off to keep a binding of your own.
>
" Key to open the current entry, leaving fzf open
" (default: 'ctrl-o')
let g:fzf_vim.show_key = 'ctrl-o'
" Use CTRL-O and double-click
let g:fzf_vim.show_key = 'ctrl-o,double-click'
<
Command-level options~ Command-level options~
*fzf-vim-command-level-options* *fzf-vim-command-level-options*
+13 -7
View File
@@ -98,14 +98,20 @@ if (has('nvim') || has('terminal') && has('patch-8.0.995')) && (s:conf('statusli
if exists('#User#FzfStatusLine') if exists('#User#FzfStatusLine')
doautocmd User FzfStatusLine doautocmd User FzfStatusLine
else else
if $TERM !~ "256color" " Do not display statusline when fzf is running in a floating window
highlight default fzf1 ctermfg=1 ctermbg=8 guifg=#E12672 guibg=#565656 " (e.g. nvim-fzf)
highlight default fzf2 ctermfg=2 ctermbg=8 guifg=#BCDDBD guibg=#565656 if has('nvim') && len(nvim_win_get_config(0).relative)
highlight default fzf3 ctermfg=7 ctermbg=8 guifg=#D9D9D9 guibg=#565656 return
endif
if has('termguicolors') && &termguicolors || $TERM =~ "256color"
highlight default fzf1 ctermfg=161 ctermbg=238 guifg=#E12672 guibg=#565656 gui=nocombine
highlight default fzf2 ctermfg=151 ctermbg=238 guifg=#BCDDBD guibg=#565656 gui=nocombine
highlight default fzf3 ctermfg=252 ctermbg=238 guifg=#D9D9D9 guibg=#565656 gui=nocombine
else else
highlight default fzf1 ctermfg=161 ctermbg=238 guifg=#E12672 guibg=#565656 highlight default fzf1 ctermfg=1 ctermbg=8 guifg=#E12672 guibg=#565656 gui=nocombine
highlight default fzf2 ctermfg=151 ctermbg=238 guifg=#BCDDBD guibg=#565656 highlight default fzf2 ctermfg=2 ctermbg=8 guifg=#BCDDBD guibg=#565656 gui=nocombine
highlight default fzf3 ctermfg=252 ctermbg=238 guifg=#D9D9D9 guibg=#565656 highlight default fzf3 ctermfg=7 ctermbg=8 guifg=#D9D9D9 guibg=#565656 gui=nocombine
endif endif
setlocal statusline=%#fzf1#\ >\ %#fzf2#fz%#fzf3#f setlocal statusline=%#fzf1#\ >\ %#fzf2#fz%#fzf3#f
endif endif