~/.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ユーザーがコンパイル$TERM
:tmux-256color関数から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
に固有のようです。
問題は、トラップからバックグラウンドジョブを開始することです。仕事は時々「失われる」ようです。 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がターミナルをめぐって競合するため、実際には機能しません。
実際のコードでは、サブシェルからvimを起動しているため、問題が発生する可能性があります。サブシェルでnv
関数を実行しないでください。中括弧{…} around the body, not parentheses. Use
local IFSto make the
IFS`変数をローカルで使用してください。