[vim] Don't start extra process at opening popup#2000
[vim] Don't start extra process at opening popup#2000junegunn merged 1 commit intojunegunn:masterfrom
Conversation
|
/cc @lacygoill |
|
If a terminal popup is already open when an fzf command is invoked, when leaving the fzf popup and getting back to the original popup, |
|
@lacygoill Hm,, we can fail pty cleanup. I devised the another plan, how is this? --- a/plugin/fzf.vim
+++ b/plugin/fzf.vim
@@ -648,6 +648,7 @@ function! s:split(dict)
\ 'left': ['vertical topleft', 'vertical resize', &columns],
\ 'right': ['vertical botright', 'vertical resize', &columns] }
let ppos = s:getpos()
+ let is_popup = v:false
try
if s:present(a:dict, 'window')
if type(a:dict.window) == type({})
@@ -655,6 +656,7 @@ function! s:split(dict)
throw 'Vim 8.2.191 or later is required for pop-up window'
end
call s:popup(a:dict.window)
+ let is_popup = v:true
else
execute 'keepalt' a:dict.window
endif
@@ -676,7 +678,7 @@ function! s:split(dict)
endif
endfor
endif
- return [ppos, { '&l:wfw': &l:wfw, '&l:wfh': &l:wfh }]
+ return [ppos, { '&l:wfw': &l:wfw, '&l:wfh': &l:wfh }, is_popup]
finally
setlocal winfixwidth winfixheight
endtry
@@ -685,7 +687,7 @@ endfunction
function! s:execute_term(dict, command, temps) abort
let winrest = winrestcmd()
let pbuf = bufnr('')
- let [ppos, winopts] = s:split(a:dict)
+ let [ppos, winopts, is_popup] = s:split(a:dict)
call s:use_sh()
let b:fzf = a:dict
let fzf = { 'buf': bufnr(''), 'pbuf': pbuf, 'ppos': ppos, 'dict': a:dict, 'temps': a:temps,
@@ -752,7 +754,13 @@ function! s:execute_term(dict, command, temps) abort
if !len(&bufhidden)
setlocal bufhidden=hide
endif
- let fzf.buf = term_start([&shell, &shellcmdflag, command], {'curwin': 1, 'exit_cb': function(fzf.on_exit)})
+ let term_opts = {'exit_cb': function(fzf.on_exit)}
+ if is_popup
+ let term_opts.hidden = 1
+ else
+ let term_opts.curwin = 1
+ endif
+ let fzf.buf = term_start([&shell, &shellcmdflag, command], term_opts)
if !has('patch-8.0.1261') && !has('nvim') && !s:is_win
call term_wait(fzf.buf, 20)
endif
@@ -824,23 +832,22 @@ if has('nvim')
else
function! s:create_popup(hl, opts) abort
let is_frame = has_key(a:opts, 'border')
- let buf = is_frame ? '' : term_start(&shell, #{hidden: 1, term_finish: 'close'})
- let id = popup_create(buf, #{
+ let s:popup_create = {buf -> popup_create(buf, #{
\ line: a:opts.row,
\ col: a:opts.col,
\ minwidth: a:opts.width,
\ minheight: a:opts.height,
\ zindex: 50 - is_frame,
- \ })
-
+ \ })}
if is_frame
+ let id = s:popup_create('')
call setwinvar(id, '&wincolor', a:hl)
call setbufline(winbufnr(id), 1, a:opts.border)
execute 'autocmd BufWipeout * ++once call popup_close('..id..')'
+ return winbufnr(id)
else
- execute 'autocmd BufWipeout * ++once call term_sendkeys('..buf..', "exit\<CR>")'
+ autocmd TerminalOpen * ++once call s:popup_create(str2nr(expand('<abuf>')))
endif
- return winbufnr(id)
endfunction
endif
|
|
Nice, it indeed fixes the issue. Unfortunately, it creates other issues. The same issue affects other commands like Note that these errors are raised, even if you don't have a popup terminal open before running these commands. I agree with you, it seems weird for an unused shell process to be started. But I don't think there's an easy way to get rid of it now; unless a deeper refactoring is performed. Besides, I'm not sure the added complexity is worth it. Maybe the best fix would be your first patch, which is much simpler. But for it to work reliably, |
|
I cannot reproduce the error... please provide an example (vimrc). |
|
Here is a minimal vimrc: Write the code in Finally, run this Ex command (provided by the It raises this error: You may wonder what is the purpose of these autocmds: The first one installs a mapping on I once asked @leonerd on the
Until Vim's keyboard input system is improved, the best workaround I have found so far is to double the Now, for the second autocmd: Its purpose is to remove the previous mapping in fzf buffers (which are terminal buffers). It's not needed there, and if it's installed you can't close the fzf window by pressing Escape anymore. I think the reason why the error is raised after I apply your patch, is because for some reason it doesn't trigger I guess I could fix it by simply using the Several events are no longer fired, including: This could cause issues if a user relies on one of them to customize an fzf buffer (in particular |
(part of diff) @@ -752,8 +754,17 @@ function! s:execute_term(dict, command, temps) abort
if !len(&bufhidden)
setlocal bufhidden=hide
endif
- let fzf.buf = term_start([&shell, &shellcmdflag, command], {'curwin': 1, 'exit_cb': function(fzf.on_exit)})
- if !has('patch-8.0.1261') && !has('nvim') && !s:is_win
+ let term_opts = {'exit_cb': function(fzf.on_exit)}
+ if is_popup
+ let term_opts.hidden = 1
+ else
+ let term_opts.curwin = 1
+ endif
+ let fzf.buf = term_start([&shell, &shellcmdflag, command], term_opts)
+ if is_popup
+ doautocmd TerminalWinOpen
+ endif
+ if !has('patch-8.0.1261') && !s:is_win
call term_wait(fzf.buf, 20)
endif
endif |
|
It works, but it creates an issue in Nvim when This patch seems to fix it: diff --git a/plugin/fzf.vim b/plugin/fzf.vim
index 356ceeb..24dd0b2 100644
--- a/plugin/fzf.vim
+++ b/plugin/fzf.vim
@@ -687,7 +687,11 @@ endfunction
function! s:execute_term(dict, command, temps) abort
let winrest = winrestcmd()
let pbuf = bufnr('')
- let [ppos, winopts, is_popup] = s:split(a:dict)
+ if has('nvim')
+ let [ppos, winopts] = s:split(a:dict)
+ else
+ let [ppos, winopts, is_popup] = s:split(a:dict)
+ endif
call s:use_sh()
let b:fzf = a:dict
let fzf = { 'buf': bufnr(''), 'pbuf': pbuf, 'ppos': ppos, 'dict': a:dict, 'temps': a:temps,The final patch looks like this: diff --git a/plugin/fzf.vim b/plugin/fzf.vim
index a84dcab..24dd0b2 100644
--- a/plugin/fzf.vim
+++ b/plugin/fzf.vim
@@ -648,6 +648,7 @@ function! s:split(dict)
\ 'left': ['vertical topleft', 'vertical resize', &columns],
\ 'right': ['vertical botright', 'vertical resize', &columns] }
let ppos = s:getpos()
+ let is_popup = v:false
try
if s:present(a:dict, 'window')
if type(a:dict.window) == type({})
@@ -655,6 +656,7 @@ function! s:split(dict)
throw 'Vim 8.2.191 or later is required for pop-up window'
end
call s:popup(a:dict.window)
+ let is_popup = v:true
else
execute 'keepalt' a:dict.window
endif
@@ -676,7 +678,7 @@ function! s:split(dict)
endif
endfor
endif
- return [ppos, { '&l:wfw': &l:wfw, '&l:wfh': &l:wfh }]
+ return [ppos, { '&l:wfw': &l:wfw, '&l:wfh': &l:wfh }, is_popup]
finally
setlocal winfixwidth winfixheight
endtry
@@ -685,7 +687,11 @@ endfunction
function! s:execute_term(dict, command, temps) abort
let winrest = winrestcmd()
let pbuf = bufnr('')
- let [ppos, winopts] = s:split(a:dict)
+ if has('nvim')
+ let [ppos, winopts] = s:split(a:dict)
+ else
+ let [ppos, winopts, is_popup] = s:split(a:dict)
+ endif
call s:use_sh()
let b:fzf = a:dict
let fzf = { 'buf': bufnr(''), 'pbuf': pbuf, 'ppos': ppos, 'dict': a:dict, 'temps': a:temps,
@@ -752,8 +758,23 @@ function! s:execute_term(dict, command, temps) abort
if !len(&bufhidden)
setlocal bufhidden=hide
endif
- let fzf.buf = term_start([&shell, &shellcmdflag, command], {'curwin': 1, 'exit_cb': function(fzf.on_exit)})
- if !has('patch-8.0.1261') && !has('nvim') && !s:is_win
+ let term_opts = {'exit_cb': function(fzf.on_exit)}
+ if is_popup
+ let term_opts.hidden = 1
+ else
+ let term_opts.curwin = 1
+ endif
+ let term_opts = {'exit_cb': function(fzf.on_exit)}
+ if is_popup
+ let term_opts.hidden = 1
+ else
+ let term_opts.curwin = 1
+ endif
+ let fzf.buf = term_start([&shell, &shellcmdflag, command], term_opts)
+ if is_popup
+ doautocmd TerminalWinOpen
+ endif
+ if !has('patch-8.0.1261') && !s:is_win
call term_wait(fzf.buf, 20)
endif
endif
@@ -824,23 +845,22 @@ if has('nvim')
else
function! s:create_popup(hl, opts) abort
let is_frame = has_key(a:opts, 'border')
- let buf = is_frame ? '' : term_start(&shell, #{hidden: 1, term_finish: 'close'})
- let id = popup_create(buf, #{
+ let s:popup_create = {buf -> popup_create(buf, #{
\ line: a:opts.row,
\ col: a:opts.col,
\ minwidth: a:opts.width,
\ minheight: a:opts.height,
\ zindex: 50 - is_frame,
- \ })
-
+ \ })}
if is_frame
+ let id = s:popup_create('')
call setwinvar(id, '&wincolor', a:hl)
call setbufline(winbufnr(id), 1, a:opts.border)
execute 'autocmd BufWipeout * ++once call popup_close('..id..')'
+ return winbufnr(id)
else
- execute 'autocmd BufWipeout * ++once call term_sendkeys('..buf..', "exit\<CR>")'
+ autocmd TerminalOpen * ++once call s:popup_create(str2nr(expand('<abuf>')))
endif
- return winbufnr(id)
endfunction
endifIt looks good to me; I tested it in:
I didn't find an error in any case. And the implementation looks cleaner. @ichizok Thank you for your patch. Can you push an updated version which includes your latest changes as well as the last patch to avoid an error in Nvim when @junegunn When it's ready, I think you'll want to merge this PR because the current implementation is now broken on Vim when fzf is configured to use a popup terminal. The issue is caused by the patch 8.2.0743. You can no longer replace the current terminal buffer with another one. As a result, this worked before the patch: But not anymore. Now, the last The current implementation does something similar. The new implementation from @ichizok fixes this new issue. |
|
Looks like I talked too fast; the patch still causes issues in Nvim. I'm looking into it. |
|
Ok, so the previous patch which I posted was wrong; it fixed the case where diff --git a/plugin/fzf.vim b/plugin/fzf.vim
index 356ceeb..c35062c 100644
--- a/plugin/fzf.vim
+++ b/plugin/fzf.vim
@@ -674,7 +674,7 @@ function! s:split(dict)
endif
execute cmd sz.'new'
execute resz sz
- return [ppos, {}]
+ return [ppos, {}, v:false]
endif
endfor
endifNow, the final patch looks like this: diff --git a/plugin/fzf.vim b/plugin/fzf.vim
index a84dcab..c35062c 100644
--- a/plugin/fzf.vim
+++ b/plugin/fzf.vim
@@ -648,6 +648,7 @@ function! s:split(dict)
\ 'left': ['vertical topleft', 'vertical resize', &columns],
\ 'right': ['vertical botright', 'vertical resize', &columns] }
let ppos = s:getpos()
+ let is_popup = v:false
try
if s:present(a:dict, 'window')
if type(a:dict.window) == type({})
@@ -655,6 +656,7 @@ function! s:split(dict)
throw 'Vim 8.2.191 or later is required for pop-up window'
end
call s:popup(a:dict.window)
+ let is_popup = v:true
else
execute 'keepalt' a:dict.window
endif
@@ -672,11 +674,11 @@ function! s:split(dict)
endif
execute cmd sz.'new'
execute resz sz
- return [ppos, {}]
+ return [ppos, {}, v:false]
endif
endfor
endif
- return [ppos, { '&l:wfw': &l:wfw, '&l:wfh': &l:wfh }]
+ return [ppos, { '&l:wfw': &l:wfw, '&l:wfh': &l:wfh }, is_popup]
finally
setlocal winfixwidth winfixheight
endtry
@@ -685,7 +687,7 @@ endfunction
function! s:execute_term(dict, command, temps) abort
let winrest = winrestcmd()
let pbuf = bufnr('')
- let [ppos, winopts] = s:split(a:dict)
+ let [ppos, winopts, is_popup] = s:split(a:dict)
call s:use_sh()
let b:fzf = a:dict
let fzf = { 'buf': bufnr(''), 'pbuf': pbuf, 'ppos': ppos, 'dict': a:dict, 'temps': a:temps,
@@ -752,8 +754,23 @@ function! s:execute_term(dict, command, temps) abort
if !len(&bufhidden)
setlocal bufhidden=hide
endif
- let fzf.buf = term_start([&shell, &shellcmdflag, command], {'curwin': 1, 'exit_cb': function(fzf.on_exit)})
- if !has('patch-8.0.1261') && !has('nvim') && !s:is_win
+ let term_opts = {'exit_cb': function(fzf.on_exit)}
+ if is_popup
+ let term_opts.hidden = 1
+ else
+ let term_opts.curwin = 1
+ endif
+ let term_opts = {'exit_cb': function(fzf.on_exit)}
+ if is_popup
+ let term_opts.hidden = 1
+ else
+ let term_opts.curwin = 1
+ endif
+ let fzf.buf = term_start([&shell, &shellcmdflag, command], term_opts)
+ if is_popup
+ doautocmd TerminalWinOpen
+ endif
+ if !has('patch-8.0.1261') && !s:is_win
call term_wait(fzf.buf, 20)
endif
endif
@@ -824,23 +841,22 @@ if has('nvim')
else
function! s:create_popup(hl, opts) abort
let is_frame = has_key(a:opts, 'border')
- let buf = is_frame ? '' : term_start(&shell, #{hidden: 1, term_finish: 'close'})
- let id = popup_create(buf, #{
+ let s:popup_create = {buf -> popup_create(buf, #{
\ line: a:opts.row,
\ col: a:opts.col,
\ minwidth: a:opts.width,
\ minheight: a:opts.height,
\ zindex: 50 - is_frame,
- \ })
-
+ \ })}
if is_frame
+ let id = s:popup_create('')
call setwinvar(id, '&wincolor', a:hl)
call setbufline(winbufnr(id), 1, a:opts.border)
execute 'autocmd BufWipeout * ++once call popup_close('..id..')'
+ return winbufnr(id)
else
- execute 'autocmd BufWipeout * ++once call term_sendkeys('..buf..', "exit\<CR>")'
+ autocmd TerminalOpen * ++once call s:popup_create(str2nr(expand('<abuf>')))
endif
- return winbufnr(id)
endfunction
endif |
|
Actually, I don't know whether it matters for Nvim, but the third argument should probably be I'll keep using the patch for a few days and report any issue I find. |
|
@lacygoill Thank you for your confirmation. I updated the PR commit. |
|
Merged, thanks! |
|
I believe there is a small bug with this commit - where after I use fzf in a popout (using normal vim, not nvim) and then start opening other splits - the window from which I spawned the fzf popup ends up not resizing properly. |
|
Here's an example video. If I move to the commit before this, then this does not reproduce. |
|
@lacygoill this does appear to fix my issue! |
I propose to use pty-buffer instead of unnecessary shell process when opening popup window.