fzf.vim
fzf.vim copied to clipboard
Ctrl+T/Ctrl+X/Ctrl+V actions don't work correctly in some cases when a swap file exists
- [x] I have fzf 0.30.0 or above
- [x] I have read through https://github.com/junegunn/fzf.vim/blob/master/README.md
- [x] I have read through https://github.com/junegunn/fzf/blob/master/README-VIM.md
- [x] I have read through the manual page of fzf (
man fzf
) - [x] I have searched through the existing issues
Problem exists since https://github.com/vim/vim/commit/c3f91c0648f4b04a6a9ceb4ccec45ea767a63796. Bisected and then checked again by reverting it on the current master branch of vim.
Steps to reproduce:
- Get yourself a vim v8.2.3833 or newer (I compiled it from source with the default Makefile, so steps assume you are in
vim/src
). - Open one instance with
./vim -p beval.c beval.h
(only needed for swap files to exist). - Use Ctrl+Z to put it in the background, or open another terminal.
- Open a new vim instance using minimal configuration.
vim -Nu <(curl https://gist.githubusercontent.com/junegunn/6936bf79fedd3a079aeb1dd2f3c81ef5/raw) beval.c
- In the newly opened instance, confirm opening
beval.c
as read only. - Using
:Files
command open second file selected in step (2) - in my casebeval.h
.
Observed result:
It doesn't matter if you choose O, E or R, the new tab or split won't be created.
Although the buffer itself will be opened (visible in :ls
).
Expected result: A new tab or split is being created.
I don't know enough about the inner workings of vim or fzf.vim to analyze it deeper. Also, it seems that for this bug to occur, one needs to have one file, which was opened when a swap file existed for it, and then tries to open another file, also with an existing swap file. As in, it doesn't matter if you try to open two files with swap files one after another, or if you open some other files in between.
Thanks for the report. I can reproduce the problem. I was able to fix the issue by commenting out some try-catches in the code. But unfortunately, I don't fully understand why this happens and why removing them helps. Doing this will likely cause problems in other areas, so we need to find a better solution.
diff --git a/plugin/fzf.vim b/plugin/fzf.vim
index dd10990..917af29 100644
--- a/plugin/fzf.vim
+++ b/plugin/fzf.vim
@@ -314,7 +314,7 @@ function! s:common_sink(action, lines) abort
\| call s:warn('fzf: E325: swap file exists: '.s:fzf_expand('<afile>'))
augroup END
endif
- try
+ " try
let empty = empty(s:fzf_expand('%')) && line('$') == 1 && empty(getline(1)) && !&modified
" Preserve the current working directory in case it's changed during
" the execution (e.g. `set autochdir` or `autocmd BufEnter * lcd ...`)
@@ -335,10 +335,10 @@ function! s:common_sink(action, lines) abort
doautocmd BufEnter
endif
endfor
- catch /^Vim:Interrupt$/
- finally
+ " catch /^Vim:Interrupt$/
+ " finally
silent! autocmd! fzf_swap
- endtry
+ " endtry
endfunction
function! s:get_color(attr, ...)
@@ -982,7 +982,7 @@ function! s:callback(dict, lines) abort
let w:fzf_pushd = a:dict.pushd
endif
- try
+ " try
if has_key(a:dict, 'sink')
for line in a:lines
if type(a:dict.sink) == 2
@@ -997,11 +997,11 @@ function! s:callback(dict, lines) abort
elseif has_key(a:dict, 'sinklist')
call a:dict['sinklist'](a:lines)
endif
- catch
- if stridx(v:exception, ':E325:') < 0
- echoerr v:exception
- endif
- endtry
+ " catch
+ " if stridx(v:exception, ':E325:') < 0
+ " echoerr v:exception
+ " endif
+ " endtry
" We may have opened a new window or tab
if popd
With the locations you provided, I tried debugging it further.
I ended up on this line https://github.com/junegunn/fzf/blob/91387a741b659ba709a67d55d68b74cb3daa812a/plugin/fzf.vim#L299.
Applying your diff, but surrounding this line with try-catch reproduced the issue. Then I thought, maybe it is not an fzf.vim issue after all?
I used the following as the new .vimrc:
func! TryTabSplit(what)
try
execute "tab split" a:what
catch
endtry
endfunc
And sure enough, it reproduced!
Then I looked at the file the regression happened in vim and noticed it's autocmd.c
.
So I removed all autocmd
and the problem disappeared.
Is the problem related to some autocmd then?
Turns out it is a pure vim problem :open_mouth: And a way to reproduce it is to:
- Save the following as a file. Let's use
reprorc
here.
autocmd BufEnter * echo "Hello there :)"
func! TryTabSplit(what)
try
execute "tab split" a:what
catch
endtry
endfunc
- Have two files, let's say
echo a > a.txt; echo b > b.txt
- Run
vim -u reprorc -p a.txt b.txt
- Ctrl+Z out of vim or open a new terminal. It is important that the swap files exist
- Open a new vim instance with
vim -u reprorc a.txt
- Confirm opening in read-only mode
- In this new vim run
:call TryTabSplit("b.txt")
- Confirm opening in read-only mode
- No new tab, but the buffer is opened.
For some reason, this also causes the Hello there :)
message to be displayed twice :shrug:
As tested earlier with reverting commit, commenting out this line https://github.com/vim/vim/blob/82f19734bfcbddbaee8d5d837f7b7a7119366020/src/autocmd.c#L2317 fixes the issue (and the message is being displayed only once).
I tried following debugging this with GDB, but to be honest I don't understand what vim is doing with its did_emsg
, did_throw
, need_rethrow
, force_abort
etc. :slightly_frowning_face:
Impressive research, thank you.
maybe it is not an fzf.vim issue after all?
Right. fzf.vim isn't doing something wrong. Vim as a scripting platform has many quirks, some by design, some by bugs. As a Vim plugin developer, you end up accepting the situation and get into the habit of finding ways to work around the problems you don't understand :)
I believe this is the same issue as https://github.com/junegunn/fzf/issues/2895