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.
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.
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.
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.
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.
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.
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.
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.
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.
: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.
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.
: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.
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.
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.
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.
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.
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
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
- 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
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.
- 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
- 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
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')
There's a known issue regarding `normal` usage in neovim. See
https://github.com/neovim/neovim/issues/4895 for more details.
As a temporary workaround, use setpos to set the
bookmark instead.