web-dev-qa-db-ja.com

トラップから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を親シェルに送信することにより、Vimを再起動することです。

また、~/.zshrcに次のトラップがあり、シグナルUSR1をキャッチするとVimを再起動します。

catch_signal_usr1() {
  trap catch_signal_usr1 USR1
  clear
  vim
}
trap catch_signal_usr1 USR1

これまでのところ、それもうまくいきました。


しかし、シェルからC-zを押してVimを一時停止すると、Vimプロセスがまだ実行されていても、シェルが再開しないため、再開できないことに気付きました($ fgを使用)。仕事があります。

これが、問題を再現できる最小限の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

次に、Space Rを押してVimを再起動し、C-zを押して一時停止します。シェルに戻ると、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 IMproved8.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)$ func関数でVimを起動した場合:

ubuntu% func
zsh: suspended  func

$ fgで再開することもできます。


(C)$ vimコマンドでVimを起動した場合は、Space Rを押してVimを再起動します。

ubuntu% vim
zsh: suspended  catch_signal_usr1

繰り返しますが、$ fgで再開できます。


(D)しかし、$ func関数でVimを起動し、Space Rを押して再起動した場合:

ubuntu% func
ubuntu%

プロンプトに戻っても何も表示されず、$ fgでVimを再開できません。


(2)あなたが仕事をタイプした場合、あなたのシェルは何と言いますか?

$ jobsには出力がありません。前の4つのケースでの出力は次のとおりです。

(A)

ubuntu% jobs
[1]  + suspended  vim

(B)

ubuntu% jobs
[1]  + suspended (signal)  func

(C)

ubuntu% jobs
[1]  + suspended (signal)  catch_signal_usr1

(D)

ubuntu% jobs
ubuntu%

Bash 5.5.1で再現できないため、この問題は少なくとも4.4まではzshに固有のようです。

2
user938271

問題は、トラップからバックグラウンドジョブを開始することです。仕事は時々「失われる」ようです。 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がターミナルをめぐって競合するため、実際には機能しません。

実際のコードでは、サブシェルからvimを起動しているため、問題が発生する可能性があります。サブシェルでnv関数を実行しないでください。中括弧{…} around the body, not parentheses. Uselocal IFSto make theIFS`変数をローカルで使用してください。