50 Commits
Author SHA1 Message Date
Junegunn Choi 0097439b74 Show no preview for an entry with no address
Ex mode starts on the last line, so the preview reported the end of the file as
the tag, while every other path refuses such an entry.
2026-09-28 07:07:45 +09:00
Junegunn Choi b4a045f8b4 Put the starting window back before the action opens the tag
The loop opens each entry of a multi-selection in the starting window, so giving
the survivor's action that window left it on the tag's file, and 'ctrl-v' showed
the tag twice. Restore buffer and view first, as the quickfix branch does, then
open where the key asks and go to the line the entry reached.
2026-09-28 06:44:54 +09:00
Junegunn Choi 21aacd5304 Give the action the last tag standing in a multi-selection
Entries opened in the loop take the action only when one was selected, so
refusing the others left the survivor opened with ':edit' and the key ignored.
2026-09-28 06:04:49 +09:00
Junegunn Choi bbe5cacb28 Find the ';"' that ends an address by reading the address
Taking the first ';"' before a tab could land inside the pattern: a line holding
';"' followed by a tab, such as a comment, cut the address there and left the
real tab unescaped, so the entry was refused.
2026-09-28 06:04:49 +09:00
Junegunn Choi 14f808b543 End an address fragment at a tab
On the :Tags path the rest of the line carries the extension fields, and an
unterminated pattern took them into the search, so '/^foo' became
'/^foo<Tab>f<Tab>file:' and found nothing. A helptags address, the case the
fragment is for, holds no tab.
2026-09-28 05:33:53 +09:00
Junegunn Choi 319f5ac437 Rewrite the tabs of an address only where it ends in ';"'
Without the terminator nothing says which tab belongs to the pattern and which
separates a column, so a tag command that adds columns without one had its
address merged with them and refused.
2026-09-28 05:33:53 +09:00
Junegunn Choi b268241f4a Keep a tab inside a BTags pattern from cutting the address
ctags leaves a tab as it found it, so splitting the source line on tabs left
'/^' for a tab-indented definition, which matched whatever line came next, and
'/^static int g = 1;' for a tab later on, which only happened to match. Write
the tab as '\t', which matches the same text and keeps the address one field.

:BTags with 'ctags --excmd=pattern' now reaches every tag in a tab-indented
file, where the address was a fragment before.
2026-09-28 05:01:20 +09:00
Junegunn Choi 3e34f1dc6d Name a too-short Tags entry the way BTags does
s:strip(parts[0]) on an empty line raises E684, which the loop then reports in
place of the message.
2026-09-28 05:01:19 +09:00
Junegunn Choi 81afa1b9d9 Take the carriage return off a tag address
A tags file with CRLF endings and no ';"' terminator, as 'ctags --format=1'
writes on Windows, left a stray CR on the address, and s:strip() counts only
spaces and tabs. Every entry in such a file was refused.
2026-09-28 04:24:49 +09:00
Junegunn Choi 74cab39bbf Name the tag when a BTags entry is too short to hold an address
A source of fewer than three columns raised E684 from parts[2], which the loop
reported in place of the message the line below it gives.
2026-09-28 04:01:19 +09:00
Junegunn Choi 0ce4cca7bd Leave the cursor alone when no tag was opened
Refusing the address of a single selected tag leaves the quickfix list empty,
and 'normal! ^zvzz' then moved the cursor in whatever buffer the user was in.
2026-09-28 03:36:17 +09:00
Junegunn Choi 747cd594a2 Do not run backticks in a file name from a tags file
expand() globs and runs backticks, so an entry naming '`touch FILE`.c' ran the
command, and on CTRL-O it ran even for an address the new check then refused.
fnamemodify(':p') instead, as s:in_dir already does for the same reason. It
gives up '$VAR' in a name, which no tag generator writes.

The address is now checked before the name is touched, so nothing happens at all
for an entry that will not be used.
2026-09-28 03:10:41 +09:00
Junegunn Choi b1c03ea0ef Drop an unreachable newline guard
'read' without '-d' stops at the first newline, so EXCMD never holds one, and a
newline inside the ':execute' string stays in the sandbox anyway.
2026-09-28 02:40:06 +09:00
Junegunn Choi ba458b129e Say why CTRL-O did nothing on a refused address
The sinks name the tag; the Show callback returned without a word, so the key
looked broken.
2026-09-28 02:40:06 +09:00
Junegunn Choi 8da2aa53ab Take an address fragment only where the whole line is in hand
:BTags reads the address field on its own, so a tab inside a ctags pattern
leaves a fragment such as '/^', which matched whatever line came next and
recorded it in the quickfix list. ctags always terminates its patterns, so on
the field alone a fragment is the cut and is refused. The '/*:Ag*' of a helptags
file has no terminator and still goes through, :Tags having the whole line.
2026-09-28 02:40:05 +09:00
Junegunn Choi 8039b2747c Hand the preview address to Vim as an argument again
Through the environment it depended on WSLENV reaching a Windows vim.exe, and
the guard for that turned a missing address into a blank preview. An argument
always arrives. Doubling the quotes keeps it one ':execute' string, so the
sandbox still covers all of it.
2026-09-28 01:57:21 +09:00
Junegunn Choi adcdb91d70 Search a tag address with case sensitivity
Builtin tag jumps clear 'ignorecase' along with setting 'nomagic' and
'wrapscan'. Without it, ':Tags' on '/^foo$/' stopped at a line holding 'FOO'
with 'ignorecase' set, and wrote that line into the quickfix list.

'smartcase' only applies while 'ignorecase' is on, so it needs nothing.
2026-09-28 01:57:21 +09:00
Junegunn Choi 32baf162c0 Say what a lone address fragment does
The comment read as if every fragment were dropped. One with nothing before it
cannot be told apart from a helptags address, so it goes through as is.
2026-09-28 01:29:04 +09:00
Junegunn Choi 5ad2fa7bed Show no preview when the address does not reach Vim
Ex mode starts on the last line, so an empty $FZFVIM_EXCMD centered the preview
at the end of the file and said nothing. Quit with an error instead, which the
existing '|| exit' turns into a blank preview.
2026-09-28 01:29:03 +09:00
Junegunn Choi 777e783382 Name the preview variable in WSLENV
WSL shares only the variables listed there with a Windows vim.exe, as
s:preview_cmd already does for MSWINHOME. Untested, no WSL here.
2026-09-28 00:49:38 +09:00
Junegunn Choi 63fb5c974f Drop a tag address part cut short by a tab
:BTags reads the address field on its own, so ctags writing a tab inside a
pattern leaves it unterminated: '--excmd=combine' gives '5;/^int', whose
fragment matched line 7 instead of 5, silently and with a quickfix item to
match. Keep the parts that did parse, so the line number still stands.

An unterminated pattern is still taken on its own, being the whole address in a
helptags file.
2026-09-28 00:49:38 +09:00
Junegunn Choi 2b6e8b2132 Sandbox the address the same way on the Show paths
They passed ':sandbox' as a modifier, which the address check makes safe today
but which stops covering anything that ever slips past it.
2026-09-28 00:08:50 +09:00
Junegunn Choi 81ae642d5b Keep the whole tag address inside the preview sandbox
':sandbox' is a modifier and covers only the command up to the first '|', so an
address like '/pat/|!touch file' still ran the shell command as soon as an entry
was highlighted. ':execute' on a value taken from the environment keeps all of
it inside the sandbox, and takes the address out of the '-c' string as well.

:Helptags previews a plugin's doc/tags through the same script.
2026-09-28 00:08:49 +09:00
Junegunn Choi 35e8ef8e20 Search a BTags address as the other paths do
The sink left 'magic' and 'wrapscan' at the user's values, so a ctags pattern
holding '*' or '.' could land on an earlier line than the CTRL-O preview shows,
and a failing address threw out of the loop, dropping the rest of a
multi-selection.
2026-09-27 23:48:25 +09:00
Junegunn Choi a4979fdcd4 Refuse a tag entry before opening its file
A refused address left the buffer on that entry's file while contributing no
quickfix item, so a multi-selection lost its valid matches. Name the refused
tag as well, since nothing happens otherwise.
2026-09-27 23:47:01 +09:00
Junegunn Choi 9705771895 Run the tag address in a sandbox in the preview too
A preview runs as soon as an entry is highlighted, so a crafted tags file did
not even need to be selected to get a shell command out of
'vim -c "silent {excmd}"'.

The preview Vim starts with '-u NONE' and exits right after, so the sandbox
alone is enough there; nothing it still permits outlives the process.
2026-09-27 23:20:27 +09:00
Junegunn Choi c228c70ee3 Allow an unterminated pattern after earlier address parts
A field holding a tab arrives cut short, so :BTags with 'ctags
--excmd=combine' sees '2;/^int tabbed(void) {' and stopped jumping. The last
part runs to the end of the line, taking any '|' or ';' with it, so it still
cannot chain a command.
2026-09-27 21:37:04 +09:00
Junegunn Choi a5717367fc Do not add a quickfix item for a refused tag address
The cursor has not moved, so the item repeated the previous entry's line and
text. :BTags already skips such an entry.
2026-09-27 21:24:52 +09:00
Junegunn Choi 88b0ae41c8 Check the address on the BTags paths too
The sink and the CTRL-O Show callback passed the raw field into the Ex command.
A custom tag command can emit any address, so put it through the same check as
:Tags. The BTags source aligns its columns, hence the strip.
2026-09-27 20:59:01 +09:00
Junegunn Choi d538da05b6 Do not run arbitrary Ex commands from tag addresses
A tags file can come from an untrusted source, and its address field can hold
any Ex command, which :Tags, :BTags and their CTRL-O Show callback ran as is.

- Take only a line number or a search pattern, chained with ';' for
  '--excmd=combine' and cut at the ';"' terminator as Vim's find_extra() does.
  A pattern left unterminated runs to the end of the line, taking any '|' or
  ';' with it, so it cannot chain a command
- Run the address in a sandbox, as builtin tag jumps do since Vim 6.0

Close #1626
2026-09-27 20:52:29 +09:00
Junegunn Choi a630ef91e1 Fix UTF-8 corruption when pasting at multibyte character
col('.') is the first byte of the character under the cursor, so splitting
the line there left one byte in head and the rest in tail. Advance past the
whole character instead.

Close #1627
2026-09-26 17:04:35 +09:00
Junegunn Choi 8a0068127a Add g:fzf_vim.options for fzf options shared by all commands (#1624)
- Key hint footer had no off switch. $FZF_DEFAULT_OPTS could not give one,
  since fzf reads it before the options fzf.vim passes
- Merged ahead of the per-call and command-level options, so both still
  take precedence
- '--no-footer' there hides the hints. Documented as fzf-vim-key-hints,
  the footer had no name to look up
- Help TOC also gained Paste key and Show key, missing since those
  sections were added

Close #1623
2026-09-07 11:39:02 +09:00
Pavol Juhas dfeb973a54 Update tag stack after BTags and Tags commands
Let CTRL-T function just as after builtin tag jumps.

Close #240
2026-09-06 23:51:12 +09:00
Junegunn Choi 88104829b1 Add ctrl-o to show the entry without closing fzf (#1621)
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-09-06 10:26:02 +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
Junegunn Choi 98dcd77a18 Fix dictionary alignments 2025-06-08 10:51:25 +09:00
Scott LaiandJunegunn Choi a2ed9fb885 Add :BMarks command (#1593)
And allow passing arguments of :marks to :Marks command. Close #1158.

Co-authored-by: Junegunn Choi <junegunn.c@gmail.com>
2025-06-08 10:48:17 +09:00
6 changed files with 1133 additions and 174 deletions
+67
View File
@@ -79,6 +79,7 @@ Commands
| `:BTags [QUERY]` | Tags in the current buffer |
| `:Changes` | Changelist across all open buffers |
| `:Marks` | Marks |
| `:BMarks` | Marks in the current buffer |
| `:Jumps` | Jumps |
| `:Windows` | Windows |
| `:Locate PATTERN` | `locate` command output |
@@ -95,6 +96,21 @@ Commands
- 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
- 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
- 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.
@@ -155,6 +171,57 @@ let g:fzf_vim.preview_window = []
" 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'
```
#### Key hints
Most commands show a footer listing the keys they bind, so you can see what
`Show`, `Open`, `HSplit` and the rest are without leaving fzf. It is fzf's
footer, so `--no-footer` hides it:
```vim
let g:fzf_vim.options = '--no-footer'
```
#### Global fzf options
You can set fzf options for all commands with `g:fzf_vim.options`.
`g:fzf_vim.{command}_options` takes precedence over it.
For example, add `--no-footer` to hide the key hints.
```vim
let g:fzf_vim.options = '--no-footer'
```
#### Command-level options
```vim
+891 -131
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
endfunction
" Channels in flight, keyed by fifo path, so concurrent fzf runs do not clash
let s:channels = {}
function! fzf#vim#ipc#start(Callback)
if !exists('*job_start') && !exists('*jobstart')
call s:warn('job_start/jobstart function not supported')
@@ -39,57 +42,95 @@ function! fzf#vim#ipc#start(Callback)
return ''
endif
call fzf#vim#ipc#stop()
let g:fzf_ipc = { 'fifo': tempname(), 'callback': a:Callback }
if !filereadable(g:fzf_ipc.fifo)
call system('mkfifo '..shellescape(g:fzf_ipc.fifo))
if v:shell_error
let fifo = tempname()
call system('mkfifo '.shellescape(fifo))
if v:shell_error
if !exists('s:mkfifo_failed')
let s:mkfifo_failed = 1
call s:warn('Failed to create fifo')
endif
return ''
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
function! fzf#vim#ipc#restart()
if !exists('g:fzf_ipc')
" Nvim hands over everything one read produced, which can be several messages
" 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'
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')
let g:fzf_ipc.job = job_start(
\ ['cat', g:fzf_ipc.fifo],
\ {'out_cb': { _, msg -> call(Callback, [msg]) },
\ 'exit_cb': { _, status -> status == 0 ? fzf#vim#ipc#restart() : '' }}
let chan.job = job_start(
\ ['cat', fifo],
\ {'out_cb': { _, msg -> has_key(s:channels, fifo) ? call(Callback, [msg]) : '' },
\ 'exit_cb': { _, status -> status == 0 && has_key(s:channels, fifo) ? fzf#vim#ipc#restart(fifo) : s:drop(fifo) }}
\ )
else
let eof = ['']
let g:fzf_ipc.job = jobstart(
\ ['cat', g:fzf_ipc.fifo],
let chan.job = jobstart(
\ ['cat', fifo],
\ {'stdout_buffered': 1,
\ 'on_stdout': { j, msg, e -> msg != eof ? call(Callback, msg) : '' },
\ 'on_exit': { j, status, e -> status == 0 ? fzf#vim#ipc#restart() : '' }}
\ 'on_stdout': { j, msg, e -> has_key(s:channels, fifo) ? s:deliver(Callback, msg) : '' },
\ 'on_exit': { j, status, e -> status == 0 && has_key(s:channels, fifo) ? fzf#vim#ipc#restart(fifo) : s:drop(fifo) }}
\ )
endif
endfunction
function! fzf#vim#ipc#stop()
if !exists('g:fzf_ipc')
" Whether the job handle refers to a live job. Nvim returns -1 or 0 instead of
" 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
endif
let job = g:fzf_ipc.job
if exists('*job_stop')
call job_stop(job)
else
call jobstop(job)
call jobwait([job])
endif
" Drop it first, so the exit handler does not restart the job
let chan = remove(s:channels, a:fifo)
" Never throw from here, this runs as part of fzf's exit handling
try
if exists('*job_stop')
call job_stop(chan.job)
else
call jobstop(chan.job)
call jobwait([chan.job])
endif
catch
endtry
call delete(g:fzf_ipc.fifo)
unlet g:fzf_ipc
call delete(chan.fifo)
endfunction
+13 -1
View File
@@ -30,9 +30,21 @@ else
exit 1
fi
# Ex mode starts on the last line, so an entry with no address would report the
# end of the file as the tag. Every other path refuses such an entry
if [ -z "${EXCMD}" ]; then
exit 1
fi
# The address comes from a tags file, which can be untrusted, and a preview runs
# as soon as an entry is highlighted. Sandboxed as a builtin tag jump is, so that
# it cannot run a shell command or touch a file. ':sandbox' on its own only covers
# the command up to the first '|', so hand the whole address to ':execute' as a
# string literal, doubling the quotes in it
EXCMD_LITERAL=${EXCMD//\'/\'\'}
CENTER="$("${VIMNAME}" -R -i NONE -u NONE -e -m -s "${FILE}" \
-c "set nomagic" \
-c "silent ${EXCMD}" \
-c "silent sandbox execute '${EXCMD_LITERAL}'" \
-c 'let l=line(".") | new | put =l | print | qa!')" || exit
START_LINE="$(( CENTER - FZF_PREVIEW_LINES / 2 ))"
+75 -3
View File
@@ -1,4 +1,4 @@
fzf-vim.txt fzf-vim Last change: March 3 2025
fzf-vim.txt fzf-vim Last change: May 31 2026
FZF-VIM - TABLE OF CONTENTS *fzf-vim* *fzf-vim-toc*
==============================================================================
@@ -13,6 +13,10 @@ FZF-VIM - TABLE OF CONTENTS *fzf-vim* *fzf-vim-to
Configuration options of the base plugin |fzf-vim-configuration-options-of-the-base-plugin|
Configuration options for fzf.vim |fzf-vim-configuration-options-for-fzf-vim|
Preview window |fzf-vim-preview-window|
Paste key |fzf-vim-paste-key|
Show key |fzf-vim-show-key|
Key hints |fzf-vim-key-hints|
Global fzf options |fzf-vim-global-fzf-options|
Command-level options |fzf-vim-command-level-options|
Command-level fzf options |fzf-vim-command-level-fzf-options|
List type to handle multiple selections |fzf-vim-list-type-to-handle-multiple-selections|
@@ -110,8 +114,8 @@ COMMANDS *fzf-vim-commands*
==============================================================================
*:Files* *:GFiles* *:Buffers* *:Colors* *:Ag* *:Rg* *:RG* *:Lines* *:BLines* *:Tags* *:BTags*
*:Changes* *:Marks* *:Jumps* *:Windows* *:Locate* *:History* *:Snippets* *:Commits* *:BCommits*
*:Commands* *:Maps* *:Helptags* *:Filetypes*
*:Changes* *:Marks* *:BMarks* *:Jumps* *:Windows* *:Locate* *:History* *:Snippets* *:Commits*
*:BCommits* *:Commands* *:Maps* *:Helptags* *:Filetypes*
-----------------------+--------------------------------------------------------------------------------------
Command | List ~
@@ -130,6 +134,7 @@ COMMANDS *fzf-vim-commands*
`:BTags [QUERY]` | Tags in the current buffer
`:Changes` | Changelist across all open buffers
`:Marks` | Marks
`:BMarks` | Marks in the current buffer
`:Jumps` | Jumps
`:Windows` | Windows
`:Locate PATTERN` | `locate` command output
@@ -149,6 +154,19 @@ COMMANDS *fzf-vim-commands*
- 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
- 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
- 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.
@@ -223,6 +241,60 @@ behavior with `g:fzf_vim.preview_window`. Here are some examples:
" 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'
<
Key hints~
*fzf-vim-key-hints*
Most commands show a footer listing the keys they bind, so you can see what
Show, Open, HSplit and the rest are without leaving fzf. It is fzf's footer,
so `--no-footer` hides it:
>
let g:fzf_vim.options = '--no-footer'
<
Global fzf options~
*fzf-vim-global-fzf-options*
*g:fzf_vim.options*
You can set fzf options for all commands with `g:fzf_vim.options`.
`g:fzf_vim.{command}_options` takes precedence over it.
For example, add `--no-footer` to hide the key hints.
>
let g:fzf_vim.options = '--no-footer'
<
Command-level options~
*fzf-vim-command-level-options*
+15 -8
View File
@@ -67,7 +67,8 @@ call s:defs([
\'command! -bar -bang Snippets call fzf#vim#snippets(<bang>0)',
\'command! -bar -bang Commands call fzf#vim#commands(<bang>0)',
\'command! -bar -bang Jumps call fzf#vim#jumps(fzf#vim#with_preview({ "placeholder": "{2..4}"}), <bang>0)',
\'command! -bar -bang Marks call fzf#vim#marks(<bang>0)',
\'command! -bar -bang -nargs=* Marks call fzf#vim#marks(<q-args>, <bang>0)',
\'command! -bar -bang -nargs=* BMarks call fzf#vim#marks("abcdefghijklmnopqrstuvwxyz", <bang>0)',
\'command! -bar -bang Changes call fzf#vim#changes(<bang>0)',
\'command! -bar -bang Helptags call fzf#vim#helptags(fzf#vim#with_preview({ "placeholder": "--tag {2}:{3}:{4}" }), <bang>0)',
\'command! -bar -bang Windows call fzf#vim#windows(fzf#vim#with_preview({ "placeholder": "{2}" }), <bang>0)',
@@ -97,14 +98,20 @@ if (has('nvim') || has('terminal') && has('patch-8.0.995')) && (s:conf('statusli
if exists('#User#FzfStatusLine')
doautocmd User FzfStatusLine
else
if $TERM !~ "256color"
highlight default fzf1 ctermfg=1 ctermbg=8 guifg=#E12672 guibg=#565656
highlight default fzf2 ctermfg=2 ctermbg=8 guifg=#BCDDBD guibg=#565656
highlight default fzf3 ctermfg=7 ctermbg=8 guifg=#D9D9D9 guibg=#565656
" Do not display statusline when fzf is running in a floating window
" (e.g. nvim-fzf)
if has('nvim') && len(nvim_win_get_config(0).relative)
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
highlight default fzf1 ctermfg=161 ctermbg=238 guifg=#E12672 guibg=#565656
highlight default fzf2 ctermfg=151 ctermbg=238 guifg=#BCDDBD guibg=#565656
highlight default fzf3 ctermfg=252 ctermbg=238 guifg=#D9D9D9 guibg=#565656
highlight default fzf1 ctermfg=1 ctermbg=8 guifg=#E12672 guibg=#565656 gui=nocombine
highlight default fzf2 ctermfg=2 ctermbg=8 guifg=#BCDDBD guibg=#565656 gui=nocombine
highlight default fzf3 ctermfg=7 ctermbg=8 guifg=#D9D9D9 guibg=#565656 gui=nocombine
endif
setlocal statusline=%#fzf1#\ >\ %#fzf2#fz%#fzf3#f
endif