트랩에서 Vim을 시작하고 일시 중지한 후에도 다시 시작할 수 있는 방법은 무엇입니까?

트랩에서 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이는 신호를 포착하면 Vim을 다시 시작합니다 USR1.

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

여태까지는 그런대로 잘됐다.


C-z하지만 셸에서 를 눌러 Vim을 일시 중지하면 Vim 프로세스가 계속 실행 중임에도 불구하고 $ fg셸이 아무 작업도 수행하지 않기 때문에 를 사용하여 Vim을 다시 시작할 수 없다는 것을 알았습니다 .

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-zVim 프로세스가 실행되는 것을 볼 수 있습니다.

$ 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함수 대신 명령을 사용하여 Vim을 시작하면 $ funcVim 프로세스를 다시 시작하고 일시 중지했다가 다시 시작할 수 있습니다. 문제는 기능에 있는 것 같습니다 $ func.


내 환경은 다음과 같습니다.

  • vim --version:VIM - 사용자가 컴파일한 Vi 향상된 8.1
  • 운영 체제: 우분투 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.


$ vim(C) Vim을 다음과 같이 시작 하면 Space R:

ubuntu% vim
zsh: suspended  catch_signal_usr1

이번에도 계속 사용할 수 있습니다 $ fg.


(D) 그러나 $ func이 기능을 사용하여 Vim을 시작하고 다음을 눌러 다시 시작 하면 Space R:

ubuntu% func
ubuntu%

프롬프트로 돌아가면 아무것도 표시되지 않으며 Restore Vim을 사용할 수 없습니다 $ fg.


(2) jobs를 입력하면 쉘에서 무엇을 말합니까?

$ jobs출력이 없습니다. 이전 네 가지 사례에 대한 출력은 다음과 같습니다.

(ㅏ)

ubuntu% jobs
[1]  + suspended  vim

(둘)

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

(씨)

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

(4)

ubuntu% jobs
ubuntu%

이 문제는 bash로 재현할 수 없기 때문에 zsh적어도 까지인 것 같습니다 .5.5.14.4

답변1

문제는 트랩에서 백그라운드 작업을 시작하는 것입니다. 작업은 때때로 "분실"되는 것 같습니다. 경쟁 조건이 발생할 수 있도록 가끔 작업을 유지 vim하도록 변경되었습니다 .vim &

트랩에서 작업을 시작하지 않음으로써 이를 방지할 수 있습니다. 트랩에 플래그를 설정하고 트랩 외부의 후크에서 vim을 시작하십시오 precmd. 이것은 최소한의 예를 적용한 것입니다.

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로컬 IFS to make theIFS` 변수 local.

관련 정보