Files
fzf/test/vim/fzf.vader
T
Junegunn Choi a52ac843d7
CodeQL / Analyze (go) (push) Canceled after 0s
build / build (push) Canceled after 0s
Test fzf on macOS / build (push) Canceled after 0s
[vim] Open fzf in a tmux or Zellij floating pane by default (#4905)
The window fzf was started from stays visible, and can be used while fzf
runs, which a popup inside Vim cannot offer.

Only where the pane is not modal, so tmux 3.7 or above, or Zellij 0.44 or
above with fzf 0.71.0 or above. A tmux popup from 3.3 to 3.6 cannot be left,
and below 3.3 fzf goes through the fzf-tmux script, whose options are
spelled differently. Both keep the window inside Vim. An explicit popup
layout is unaffected and still works from 3.3.

fzf checks tmux before Zellij, so tmux wins when both are set.

g:fzf_layout still wins, so anyone who set it sees no change.
2026-09-06 00:36:08 +09:00

256 lines
8.3 KiB
Plaintext

Execute (Setup):
let g:dir = fnamemodify(g:vader_file, ':p:h')
unlet! g:fzf_layout g:fzf_action g:fzf_history_dir
Log 'Test directory: ' . g:dir
Save &acd
" fzf#run runs fzf in a terminal buffer and returns immediately, so the
" assertions have to wait for the run to finish. 'exit' is called from the
" same handler that runs the sink, just before it, so once it has fired the
" sink has run too. It also fires when nothing is selected, unlike the sink.
function! g:FzfExit(code)
let g:fzf_done = 1
endfunction
" Collects the output without displacing a 'sink' the spec already has.
" s:callback runs both
function! g:FzfCollect(lines)
call extend(g:fzf_lines, a:lines)
endfunction
function! g:FzfRun(spec) abort
let g:fzf_done = 0
let g:fzf_lines = []
call fzf#run(extend(copy(a:spec),
\ { 'exit': function('g:FzfExit'), 'sinklist': function('g:FzfCollect') }))
let started = reltime()
while !g:fzf_done && reltimefloat(reltime(started)) < 10
sleep 10m
endwhile
if !g:fzf_done
throw 'Timed out waiting for fzf#run'
endif
return g:fzf_lines
endfunction
Execute (fzf#run with dir option):
let cwd = getcwd()
let result = g:FzfRun({ 'source': 'git ls-files', 'options': '--filter=vdr', 'dir': g:dir })
AssertEqual ['fzf.vader'], result
AssertEqual 0, haslocaldir()
AssertEqual getcwd(), cwd
execute 'lcd' fnameescape(cwd)
let result = sort(g:FzfRun({ 'source': 'git ls-files', 'options': '--filter e', 'dir': g:dir }))
AssertEqual ['fzf.vader'], result
AssertEqual 1, haslocaldir()
AssertEqual getcwd(), cwd
Execute (fzf#run with Funcref command):
let g:ret = []
function! g:FzfTest(e)
call add(g:ret, a:e)
endfunction
let result = sort(g:FzfRun({ 'source': 'git ls-files', 'sink': function('g:FzfTest'), 'options': '--filter e', 'dir': g:dir }))
AssertEqual ['fzf.vader'], result
AssertEqual ['fzf.vader'], sort(g:ret)
Execute (fzf#run with string source):
let result = sort(g:FzfRun({ 'source': 'echo hi', 'options': '-f i' }))
AssertEqual ['hi'], result
Execute (fzf#run with list source):
let result = sort(g:FzfRun({ 'source': ['hello', 'world'], 'options': '-f e' }))
AssertEqual ['hello'], result
let result = sort(g:FzfRun({ 'source': ['hello', 'world'], 'options': '-f o' }))
AssertEqual ['hello', 'world'], result
Execute (fzf#run with string source):
let result = sort(g:FzfRun({ 'source': 'echo hi', 'options': '-f i' }))
AssertEqual ['hi'], result
Execute (fzf#run with dir option and noautochdir):
set noacd
let cwd = getcwd()
call g:FzfRun({'source': ['/foobar'], 'sink': 'e', 'dir': '/tmp', 'options': '-1'})
" No change in working directory
AssertEqual cwd, getcwd()
call g:FzfRun({'source': ['/foobar'], 'sink': 'tabe', 'dir': '/tmp', 'options': '-1'})
AssertEqual cwd, getcwd()
tabclose
AssertEqual cwd, getcwd()
Execute (Incomplete fzf#run with dir option and autochdir):
set acd
let cwd = getcwd()
call g:FzfRun({'source': [], 'sink': 'e', 'dir': '/tmp', 'options': '-0'})
" No change in working directory even if &acd is set
AssertEqual cwd, getcwd()
Execute (FIXME: fzf#run with dir option and autochdir):
set acd
call g:FzfRun({'source': ['/foobar'], 'sink': 'e', 'dir': '/tmp', 'options': '-1'})
" Working directory changed due to &acd
AssertEqual '/foobar', expand('%')
AssertEqual '/', getcwd()
Execute (fzf#run with dir option and autochdir when final cwd is same as dir):
set acd
cd /tmp
call g:FzfRun({'source': ['/foobar'], 'sink': 'e', 'dir': '/', 'options': '-1'})
" Working directory changed due to &acd
AssertEqual '/', getcwd()
Execute (Default layout):
unlet! g:fzf_layout g:fzf_height
let layout_keys = ['window', 'popup', 'tmux', 'up', 'down', 'left', 'right']
let opts = fzf#wrap('foobar')
Log opts
let found = filter(copy(layout_keys), 'has_key(opts, v:val)')
AssertEqual 1, len(found)
if found[0] ==# 'tmux'
" Only where fzf opens a floating pane, which can be left while fzf runs
Assert !empty($TMUX) || !empty($ZELLIJ)
AssertEqual '90%,60%', opts.tmux
elseif found[0] ==# 'window'
AssertEqual 0.9, opts.window.width
else
" No popup support in this build
AssertEqual '~40%', opts.down
endif
" Fullscreen strips it, whichever it was
let opts = fzf#wrap('foobar', {}, 1)
Log opts
AssertEqual [], filter(copy(layout_keys), 'has_key(opts, v:val)')
Execute (fzf#wrap):
AssertThrows fzf#wrap({'foo': 'bar'})
" Pin the layout so the assertions do not depend on the environment
let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
let opts = fzf#wrap('foobar')
Log opts
AssertEqual 0.9, opts.window.width
Assert opts.options =~ '--expect='
Assert !has_key(opts, 'sink')
Assert has_key(opts, 'sink*')
let opts = fzf#wrap('foobar', {}, 0)
Log opts
AssertEqual 0.9, opts.window.width
let opts = fzf#wrap('foobar', {}, 1)
Log opts
Assert !has_key(opts, 'window')
let opts = fzf#wrap('foobar', {'down': '50%'})
Log opts
AssertEqual '50%', opts.down
let opts = fzf#wrap('foobar', {'down': '50%'}, 1)
Log opts
Assert !has_key(opts, 'down')
let opts = fzf#wrap('foobar', {'sink': 'e'})
Log opts
AssertEqual 'e', opts.sink
Assert !has_key(opts, 'sink*')
let opts = fzf#wrap('foobar', {'options': '--reverse'})
Log opts
Assert opts.options =~ '--expect='
Assert opts.options =~ '--reverse'
let g:fzf_layout = {'window': 'enew'}
let opts = fzf#wrap('foobar')
Log opts
AssertEqual 'enew', opts.window
let opts = fzf#wrap('foobar', {}, 1)
Log opts
Assert !has_key(opts, 'window')
let opts = fzf#wrap('foobar', {'right': '50%'})
Log opts
Assert !has_key(opts, 'window')
AssertEqual '50%', opts.right
let opts = fzf#wrap('foobar', {'right': '50%'}, 1)
Log opts
Assert !has_key(opts, 'window')
Assert !has_key(opts, 'right')
let g:fzf_action = {'a': 'tabe'}
let opts = fzf#wrap('foobar')
Log opts
Assert opts.options =~ '--expect=a'
Assert !has_key(opts, 'sink')
Assert has_key(opts, 'sink*')
let opts = fzf#wrap('foobar', {'sink': 'e'})
Log opts
AssertEqual 'e', opts.sink
Assert !has_key(opts, 'sink*')
let g:fzf_history_dir = '/tmp'
let opts = fzf#wrap('foobar', {'options': '--color light'})
Log opts
Assert opts.options =~ "--history '/tmp/foobar'"
Assert opts.options =~ '--color light'
let g:fzf_colors = { 'fg': ['fg', 'Error'] }
let opts = fzf#wrap({})
Assert opts.options =~ '--color=fg:'
Execute (popup is a synonym of tmux):
unlet! g:fzf_layout
" Treated as a layout option, so g:fzf_layout is not applied on top
let opts = fzf#wrap('foobar', {'popup': '90%,70%'})
AssertEqual '90%,70%', opts.popup
Assert !has_key(opts, 'window')
" And stripped in fullscreen, like the others
let opts = fzf#wrap('foobar', {'popup': '90%,70%'}, 1)
Assert !has_key(opts, 'popup')
" Accepted in g:fzf_layout
let g:fzf_layout = {'popup': '90%,70%'}
let opts = fzf#wrap('foobar')
AssertEqual '90%,70%', opts.popup
unlet g:fzf_layout
" Listed as a valid key
let g:fzf_layout = {'bogus': 1}
AssertThrows call fzf#wrap('foobar')
Assert g:vader_exception =~ 'popup'
unlet g:fzf_layout
Execute (fzf#shellescape with sh):
AssertEqual '''''', fzf#shellescape('', 'sh')
AssertEqual '''\''', fzf#shellescape('\', 'sh')
AssertEqual '''""''', fzf#shellescape('""', 'sh')
AssertEqual '''foobar>''', fzf#shellescape('foobar>', 'sh')
AssertEqual '''\\\"\\\''', fzf#shellescape('\\\"\\\', 'sh')
AssertEqual '''echo ''\''''a''\'''' && echo ''\''''b''\''''''', fzf#shellescape('echo ''a'' && echo ''b''', 'sh')
Execute (fzf#shellescape with cmd.exe):
AssertEqual '^"^"', fzf#shellescape('', 'cmd.exe')
AssertEqual '^"\\^"', fzf#shellescape('\', 'cmd.exe')
AssertEqual '^"\^"\^"^"', fzf#shellescape('""', 'cmd.exe')
AssertEqual '^"foobar^>^"', fzf#shellescape('foobar>', 'cmd.exe')
AssertEqual '^"\\\\\\\^"\\\\\\^"', fzf#shellescape('\\\"\\\', 'cmd.exe')
AssertEqual '^"echo ''a'' ^&^& echo ''b''^"', fzf#shellescape('echo ''a'' && echo ''b''', 'cmd.exe')
AssertEqual '^"C:\Program Files ^(x86^)\\^"', fzf#shellescape('C:\Program Files (x86)\', 'cmd.exe')
AssertEqual '^"C:/Program Files ^(x86^)/^"', fzf#shellescape('C:/Program Files (x86)/', 'cmd.exe')
AssertEqual '^"%%USERPROFILE%%^"', fzf#shellescape('%USERPROFILE%', 'cmd.exe')
Execute (Cleanup):
unlet g:dir
Restore