neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

job_control.txt (5211B)


      1 *job_control.txt*    Nvim
      2 
      3 
      4 	 NVIM REFERENCE MANUAL	  by Thiago de Arruda
      5 
      6 
      7 Nvim job control					*job* *job-control*
      8 
      9 Job control is a way to perform multitasking in Nvim, so scripts can spawn and
     10 control multiple processes without blocking the current Nvim instance.
     11 
     12 			      Type |gO| to see the table of contents.
     13 
     14 ==============================================================================
     15 Concepts
     16 
     17 Job Id							*job-id*
     18 
     19 Each job is identified by an integer id, unique for the life of the current
     20 Nvim session. Each job-id is a valid |channel-id|: they share the same "key
     21 space". Functions like |jobstart()| return job ids; functions like
     22 |jobstop()|, |chansend()|, |rpcnotify()|, and |rpcrequest()| take job ids.
     23 
     24 Job stdio streams form a |channel| which can send and receive raw bytes or
     25 |msgpack-rpc| messages.
     26 
     27 ==============================================================================
     28 Usage							*job-control-usage*
     29 
     30 To control jobs, use the "job…" family of functions: |jobstart()|,
     31 |jobstop()|, etc.
     32 
     33 Example: >vim
     34 
     35    function! s:OnEvent(job_id, data, event) dict
     36      if a:event == 'stdout'
     37        let str = self.shell.' stdout: '.join(a:data)
     38      elseif a:event == 'stderr'
     39        let str = self.shell.' stderr: '.join(a:data)
     40      else
     41        let str = self.shell.' exited'
     42      endif
     43 
     44      call append(line('$'), str)
     45    endfunction
     46    let s:callbacks = {
     47    \ 'on_stdout': function('s:OnEvent'),
     48    \ 'on_stderr': function('s:OnEvent'),
     49    \ 'on_exit': function('s:OnEvent')
     50    \ }
     51    let job1 = jobstart(['bash'], extend({'shell': 'shell 1'}, s:callbacks))
     52    let job2 = jobstart(['bash', '-c', 'for i in {1..10}; do echo hello $i!; sleep 1; done'], extend({'shell': 'shell 2'}, s:callbacks))
     53 
     54 To test the above script, copy it to a file ~/foo.vim and run it: >bash
     55    nvim -u ~/foo.vim
     56 <
     57 Description of what happens:
     58  - Two bash shells are spawned by |jobstart()| with their stdin/stdout/stderr
     59    streams connected to nvim.
     60  - The first shell is idle, waiting to read commands from its stdin.
     61  - The second shell is started with -c which executes the command (a for-loop
     62    printing 0 through 9) and then exits.
     63  - `OnEvent()` callback is passed to |jobstart()| to handle various job
     64    events. It displays stdout/stderr data received from the shells.
     65 
     66 For |on_stdout| and |on_stderr| see |channel-callback|.
     67 						*on_exit*
     68 Arguments passed to on_exit callback:
     69  0: |job-id|
     70  1: Exit-code of the process, or 128+SIGNUM if by signal (e.g. 143 on SIGTERM).
     71  2: Event type: "exit"
     72 
     73 
     74  Note: Buffered stdout/stderr data which has not been flushed by the sender
     75 will not trigger the on_stdout/on_stderr callback (but if the process
     76 ends, the on_exit callback will be invoked).
     77        For example, "ruby -e" buffers output, so small strings will be
     78        buffered unless "auto-flushing" ($stdout.sync=true) is enabled. >vim
     79          function! Receive(job_id, data, event)
     80            echom printf('%s: %s',a:event,string(a:data))
     81          endfunction
     82          call jobstart(['ruby', '-e',
     83            \ '$stdout.sync = true; 5.times do sleep 1 and puts "Hello Ruby!" end'],
     84            \ {'on_stdout': 'Receive'})
     85 <       https://github.com/neovim/neovim/issues/1592
     86 
     87  Note 2:
     88 Job event handlers may receive partial (incomplete) lines. For a given
     89 invocation of on_stdout/on_stderr, `a:data` is not guaranteed to end
     90 with a newline.
     91   - `abcdefg` may arrive as `['abc']`, `['defg']`.
     92   - `abc\nefg` may arrive as `['abc', '']`, `['efg']` or `['abc']`,
     93     `['','efg']`, or even `['ab']`, `['c','efg']`.
     94 Easy way to deal with this: initialize a list as `['']`, then append
     95 to it as follows: >vim
     96   let s:chunks = ['']
     97   func! s:on_stdout(job_id, data, event) dict
     98     let s:chunks[-1] .= a:data[0]
     99     call extend(s:chunks, a:data[1:])
    100   endf
    101 <
    102 
    103 The |jobstart-options| dictionary is passed as |self| to the callback.
    104 The above example could be written in this "object-oriented" style: >vim
    105 
    106    let Shell = {}
    107 
    108    function Shell.on_stdout(_job_id, data, event)
    109      call append(line('$'),
    110            \ printf('[%s] %s: %s', a:event, self.name, join(a:data[:-2])))
    111    endfunction
    112 
    113    let Shell.on_stderr = function(Shell.on_stdout)
    114 
    115    function Shell.on_exit(job_id, _data, event)
    116      let msg = printf('job %d ("%s") finished', a:job_id, self.name)
    117      call append(line('$'), printf('[%s] BOOM!', a:event))
    118      call append(line('$'), printf('[%s] %s!', a:event, msg))
    119    endfunction
    120 
    121    function Shell.new(name, cmd)
    122      let object = extend(copy(g:Shell), {'name': a:name})
    123      let object.cmd = ['sh', '-c', a:cmd]
    124      let object.id = jobstart(object.cmd, object)
    125      $
    126      return object
    127    endfunction
    128 
    129    let instance = Shell.new('bomb',
    130          \ 'for i in $(seq 9 -1 1); do echo $i 1>&$((i % 2 + 1)); sleep 1; done')
    131 <
    132 To send data to the job's stdin, use |chansend()|: >vim
    133    :call chansend(job1, "ls\n")
    134    :call chansend(job1, "invalid-command\n")
    135    :call chansend(job1, "exit\n")
    136 <
    137 A job may be killed at any time with the |jobstop()| function:
    138 >vim
    139    :call jobstop(job1)
    140 <
    141 Individual streams can be closed without killing the job, see |chanclose()|.
    142 
    143 vim:tw=78:ts=8:noet:ft=help:norl: