如何從陷阱中啟動 Vim 並在暫停後仍然能夠恢復它?
我的程式碼中有以下程式碼
~/.zshrc
:nv() ( if vim --serverlist | grep -q VIM; then if [[ $# -eq 0 ]]; then vim elif [[ $1 == -b ]]; then shift 1 IFS=' ' vim --remote "$@" vim --remote-send ":argdo setl binary ft=xxd<cr>" vim --remote-send ":argdo %!xxd<cr><cr>" elif [[ $1 == -d ]]; then shift 1 IFS=' ' vim --remote-send ":tabnew<cr>" vim --remote "$@" vim --remote-send ":argdo vsplit<cr>:q<cr>" vim --remote-send ":windo diffthis<cr>" elif [[ $1 == -o ]]; then shift 1 IFS=' ' vim --remote "$@" vim --remote-send ":argdo split<cr>:q<cr><cr>" elif [[ $1 == -O ]]; then shift 1 IFS=' ' vim --remote "$@" vim --remote-send ":argdo vsplit<cr>:q<cr><cr>" elif [[ $1 == -p ]]; then shift 1 IFS=' ' vim --remote "$@" vim --remote-send ":argdo tabedit<cr>:q<cr>" elif [[ $1 == -q ]]; then shift 1 IFS=' ' vim --remote-send ":cexpr system('$*')<cr>" else vim --remote "$@" fi else vim -w /tmp/.vimkeys --servername VIM "$@" fi )
它的目的是安裝一個
nv
函式來啟動一個 Vim 實例以及一個 Vim 伺服器。如果 Vim 伺服器已經在執行,該函式應該將它收到的文件參數發送到伺服器。到目前為止,它運作良好。
我的中有以下映射
~/.vimrc
:nno <silent><unique> <space>R :<c-u>sil call <sid>vim_quit_reload()<cr> fu! s:vim_quit_reload() abort sil! update call system('kill -USR1 $(ps -p $(ps -p $$ -o ppid=) -o ppid=)') qa! endfu
其目的是通過向
USR1
父 shell 發送信號來重新啟動 Vim。我也有以下陷阱,
~/.zshrc
當它捕捉到信號時它會重新啟動 VimUSR1
。catch_signal_usr1() { trap catch_signal_usr1 USR1 clear vim } trap catch_signal_usr1 USR1
到目前為止,它也運作良好。
但我注意到,如果我
C-z
在 shell 中按 , 掛起 Vim,即使 Vim 程序仍在執行,我也無法恢復它(使用$ fg
),因為 shell 沒有任何工作。
zshrc
這是我能夠重現該問題的最小值:catch_signal_usr1() { trap catch_signal_usr1 USR1 vim } trap catch_signal_usr1 USR1 func() { vim }
這是一個最小的
vimrc
:nnoremap <space>R :call Func()<cr> function! Func() call system('kill -USR1 $(ps -p $(ps -p $$ -o ppid=) -o ppid=)') qa! endfunction
如果我使用以下函式啟動 Vim:
$ func
然後,按 重新啟動 Vim
Space R
,然後按 掛起它C-z
,一旦我回到 shell,我可以看到 Vim 程序正在執行:$ ps -efH | grep vim user 24803 24684 10 03:56 pts/9 00:00:01 vim user 24990 24684 0 03:56 pts/9 00:00:00 grep vim
但我無法恢復它:
$ fg fg: no current job
如果我使用
$ vim
命令而不是$ func
函式來啟動 Vim,我可以重新啟動 Vim 程序,將其掛起並恢復它。問題似乎來自功能$ func
。這是我的環境:
vim --version
: VIM - Vi IMproved 8.1 由使用者編譯- 作業系統:Ubuntu 16.04.4 LTS
- 終端模擬器:rxvt-unicode v9.22
- 終端多路復用器:tmux 2.7
$TERM
: tmux-256color- 外殼:zsh 5.5.1
如何從函式啟動 Vim 並在掛起後仍然能夠恢復它?
編輯:
更多資訊:
(1) 當您鍵入 Ctrl+Z 時,您的終端上會顯示什麼?
當我鍵入時沒有顯示任何內容
C-z
。(A) 如果我用下面的命令啟動 Vim,
$ vim
按下 後會顯示C-z
:ubuntu% vim zsh: suspended vim
我可以用 恢復
$ fg
。(B) 如果我使用以下函式啟動 Vim
$ func
:ubuntu% func zsh: suspended func
我也可以用
$ fg
.(C) 如果我使用
$ vim
命令啟動 Vim,然後按 重新啟動 VimSpace R
:ubuntu% vim zsh: suspended catch_signal_usr1
同樣,我可以繼續使用
$ fg
.(D) 但是,如果我使用該
$ func
功能啟動 Vim 並按 重新啟動它Space R
:ubuntu% func ubuntu%
當我回到提示符時沒有顯示任何內容,並且我無法使用
$ fg
.(2) 如果你輸入jobs,你的shell 會說什麼?
$ jobs
沒有輸出。這是前四種情況下的輸出:(一種)
ubuntu% jobs [1] + suspended vim
(乙)
ubuntu% jobs [1] + suspended (signal) func
(C)
ubuntu% jobs [1] + suspended (signal) catch_signal_usr1
(四)
ubuntu% jobs ubuntu%
似乎這個問題
zsh
至少特定於 up to5.5.1
,因為我無法用 bash 重現4.4
。
問題是從陷阱開始後台作業。這份工作有時似乎會“迷失”。更改
vim
為vim &
有時會保留工作,因此可能存在競爭條件。您可以通過不從陷阱開始工作來避免這種情況。在陷阱中設置一個標誌,並在陷阱外的
precmd
鉤子中啟動 vim。這是您的最小範例的改編。restart_vim= catch_signal_usr1() { trap catch_signal_usr1 USR1 restart_vim=1 } precmd () { if [[ -n $restart_vim ]]; then restart_vim= vim fi } trap catch_signal_usr1 USR1 func() { vim }
您在編輯命令提示符時失去了將 Vim 彈出到前台的能力,但這無論如何都不起作用,因為 vim 和 zsh 將競爭終端。
在您的真實程式碼中,您可能會遇到麻煩,因為您是從子 shell 啟動 vim。不要
nv
在子 shell 中執行該函式:使用大括號 { … }around the body, not parentheses. Use
local IFSto make the
IFS` 變數 local。