Job_control

Nvim :help ページは、生成された 出典 から tree-sitter-vimdoc パーサーを使用して生み出されました。


Nvim ジョブコントロール job-control
ジョブコントロールは Nvim でマルチタスクを実行する方法であり、スクリプトは複数プロセスを生成して制御することができ、現在の Nvim インスタンスをブロックしません。

概念

ジョブ ID job-id
各ジョブは整数 ID で識別され、現在の Nvim セッション期間中は一意になります。各ジョブ ID は有効な channel-id です。これらは同じ「キー空間」を共有します。 jobstart() などの関数はジョブ ID を返します。 jobstop()chansend()rpcnotify()rpcrequest() などの関数はジョブ ID を取得します。
ジョブの stdio ストリームは、生バイトか msgpack-rpc メッセージを送受信できる channel を形成します。

使用方法 job-control-usage

ジョブを制御するには、「job…」関数のファミリーを使用します。 jobstart()jobstop() などです。
function! s:OnEvent(job_id, data, event) dict
  if a:event == 'stdout'
    let str = self.shell.' stdout: '.join(a:data)
  elseif a:event == 'stderr'
    let str = self.shell.' stderr: '.join(a:data)
  else
    let str = self.shell.' exited'
  endif
  call append(line('$'), str)
endfunction
let s:callbacks = {
\ 'on_stdout': function('s:OnEvent'),
\ 'on_stderr': function('s:OnEvent'),
\ 'on_exit': function('s:OnEvent')
\ }
let job1 = jobstart(['bash'], extend({'shell': 'shell 1'}, s:callbacks))
let job2 = jobstart(['bash', '-c', 'for i in {1..10}; do echo hello $i!; sleep 1; done'], extend({'shell': 'shell 2'}, s:callbacks))
上記のスクリプトをテストするには、~/foo.vim ファイルにコピーして実行します。
nvim -u ~/foo.vim
何が起こったかの説明
2 つの bash シェルが jobstart() によって生成され、それらの stdin/stdout/stderr ストリームは nvim に接続されています。
最初のシェルはアイドル状態であり、stdin からコマンドを読み取るのを待っています。
2 番目のシェルは -c で開始されます。これはコマンド(0 から 9 を印刷する for ループ)を実行してから終了します。
OnEvent() コールバックは jobstart() に渡され、さまざまなジョブイベントを処理します。シェルから受信した stdout/stderr データを表示します。
on_stdout および on_stderr については channel-callback を参照してください。 on_exit
on_exit コールバックに渡される引数: 0: job-id 1: プロセスの終了コード、またはシグナルによる場合は 128 + SIGNUM(たとえば、SIGTERM の場合は 143)。 2: イベントタイプ: 「終了」
注: 送信者によってフラッシュされていないバッファリングされた stdout/stderr データは on_stdout/on_stderr コールバックをトリガーしません(ただし、プロセスが終了すると on_exit コールバックが呼び出されます)。たとえば、「ruby -e」は出力をバッファリングするため、「自動フラッシング」($stdout.sync=true)が有効になっていない限り、小さな文字列はバッファリングされます。
function! Receive(job_id, data, event)
  echom printf('%s: %s',a:event,string(a:data))
endfunction
call jobstart(['ruby', '-e',
  \ '$stdout.sync = true; 5.times do sleep 1 and puts "Hello Ruby!" end'],
  \ {'on_stdout': 'Receive'})
注 2: ジョブイベントハンドラーは部分的な(不完全な)行を受け取ることがあります。on_stdout/on_stderr のある呼び出しの場合、a:data は改行で終わるとは限りません。
abcdefg は、['abc']['defg'] のように受信される場合があります。
abc\nefg は、['abc', '']['efg'] または ['abc']['','efg']、あるいは ['ab']['c','efg'] のように受信される場合があります。これを処理するための簡単な方法があります。リストを [''] として初期化し、次のようにアペンドします。
let s:chunks = ['']
func! s:on_stdout(job_id, data, event) dict
  let s:chunks[-1] .= a:data[0]
  call extend(s:chunks, a:data[1:])
endf
jobstart-options 辞書が self としてコールバックに渡されます。上記の例は、この「オブジェクト指向」スタイルで記述できます。
let Shell = {}
function Shell.on_stdout(_job_id, data, event)
  call append(line('$'),
        \ printf('[%s] %s: %s', a:event, self.name, join(a:data[:-2])))
endfunction
let Shell.on_stderr = function(Shell.on_stdout)
function Shell.on_exit(job_id, _data, event)
  let msg = printf('job %d ("%s") finished', a:job_id, self.name)
  call append(line('$'), printf('[%s] BOOM!', a:event))
  call append(line('$'), printf('[%s] %s!', a:event, msg))
endfunction
function Shell.new(name, cmd)
  let object = extend(copy(g:Shell), {'name': a:name})
  let object.cmd = ['sh', '-c', a:cmd]
  let object.id = jobstart(object.cmd, object)
  $
  return object
endfunction
let instance = Shell.new('bomb',
      \ 'for i in $(seq 9 -1 1); do echo $i 1>&$((i % 2 + 1)); sleep 1; done')
ジョブの標準入力にデータを送信するには、chansend() を使用します
:call chansend(job1, "ls\n")
:call chansend(job1, "invalid-command\n")
:call chansend(job1, "exit\n")
ジョブは、いつでも jobstop() 関数を使用して強制終了できます
:call jobstop(job1)
個々のストリームは、ジョブを強制終了せずに閉じることができます。詳細は chanclose() を参照してください。
メイン
コマンドのインデックス
クイックリファレンス