我的代码中有以下代码~/.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
。
问题是从陷阱开始后台作业。这份工作有时似乎会“迷失”。更改
vim
为vim &
有时会保留工作,因此可能存在竞争条件。您可以通过不从陷阱开始工作来避免这种情况。在陷阱中设置一个标志,并在陷阱外的
precmd
钩子中启动 vim。这是您的最小示例的改编。您在编辑命令提示符时失去了将 Vim 弹出到前台的能力,但这无论如何都不起作用,因为 vim 和 zsh 将竞争终端。
在您的真实代码中,您可能会遇到麻烦,因为您是从子 shell 启动 vim。不要
nv
在子 shell 中运行该函数:使用大括号 { ... }around the body, not parentheses. Use
local IFSto make the
IFS` 变量 local。