Vim

如何從陷阱中啟動 Vim 並在暫停後仍然能夠恢復它?

  • May 21, 2018

我的程式碼中有以下程式碼~/.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當它捕捉到信號時它會重新啟動 Vim USR1

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,然後按 重新啟動 Vim Space 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 to 5.5.1,因為我無法用 bash 重現4.4

問題是從陷阱開始後台作業。這份工作有時似乎會“迷失”。更改vimvim &有時會保留工作,因此可能存在競爭條件。

您可以通過不從陷阱開始工作來避免這種情況。在陷阱中設置一個標誌,並在陷阱外的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. Uselocal IFS to make theIFS` 變數 local。

引用自:https://unix.stackexchange.com/questions/445051