Nvim documentation: channel

main help file
*channel.txt*    Nvim


		 NVIM REFERENCE MANUAL    by Thiago de Arruda



Nvim asynchronous IO					*channel*

				      Type |gO| to see the table of contents.

==============================================================================

1. Introduction						    *channel-intro*

Channels are nvim's way of communicating with external processes.

There are several ways to open a channel:

  1. Through stdin/stdout when `nvim` is started with `--headless`, and a startup
     script or --cmd  command opens the stdio channel using |stdioopen()|.

  2. Through stdin, stdout and stderr of a process spawned by |jobstart()|.

  3. Through the PTY master end of a PTY opened with
     `jobstart(..., {'pty': v:true})` or |termopen()|.

  4. By connecting to a TCP/IP socket or named pipe with |sockconnect()|.

  5. By another process connecting to a socket listened to by nvim. This only
     supports RPC channels, see |rpc-connecting|.

Channels support multiple modes or protocols. In the most basic
mode of operation, raw bytes are read and written to the channel.
The |rpc| protocol, based on the msgpack-rpc standard, enables nvim and the
process at the other end to send remote calls and events to each other.
The builtin |terminal-emulator| is also implemented on top of PTY channels.


Channel Id						*channel-id*

Each channel is identified by an integer id, unique for the life of the
current Nvim session. Functions like |stdioopen()| return channel ids;
functions like |chansend()| consume channel ids.

==============================================================================

2. Reading and writing raw bytes			      *channel-bytes*

Channels opened by Vimscript functions operate with raw bytes by default. For
a job channel using RPC, bytes can still be read over its stderr. Similarily,
only bytes can be written to Nvim's own stderr.


						*channel-callback*

on_stdout({chan-id}, {data}, {name})		*on_stdout* 

on_stderr({chan-id}, {data}, {name})		*on_stderr* 

on_stdin({chan-id}, {data}, {name})		*on_stdin* 

on_data({chan-id}, {data}, {name})		*on_data*
    Scripts can react to channel activity (received data) via callback
    functions assigned to the `on_stdout`, `on_stderr`, `on_stdin`, or
    `on_data` option keys. Callbacks should be fast: avoid potentially
    slow/expensive work.

    Parameters: 
      {chan-id}     Channel handle. |channel-id|
      {data}	    Raw data (|readfile()|-style list of strings) read from
		    the channel. EOF is a single-item list: `['']`. First and
		    last items may be partial lines! |channel-lines|
      {name}	    Stream name (string) like "stdout", so the same function
		    can handle multiple streams. Event names depend on how the
		    channel was opened and in what mode/protocol.


						*channel-buffered*
    The callback is invoked immediately as data is available, where
    a single-item list `['']` indicates EOF (stream closed).  Alternatively
    set the `stdout_buffered`, `stderr_buffered`, `stdin_buffered`, or
    `data_buffered` option keys to invoke the callback only after all output
    was gathered and the stream was closed.

						*E5210*
    If a buffering mode is used without a callback, the data is saved in the
    stream {name} key of the options dict. It is an error if the key exists.


							      *channel-lines*
    Stream event handlers receive data as it becomes available from the OS,
    thus the first and last items in the {data} list may be partial lines.
    Empty string completes the previous partial line. Examples (not including
    the final `['']` emitted at EOF):
      - `foobar` may arrive as `['fo'], ['obar']` 
      - `foo\nbar` may arrive as
	   `['foo','bar']`
	or `['foo',''], ['bar']`
	or `['foo'], ['','bar']`
	or `['fo'], ['o','bar']`
    There are two ways to deal with this:
    1. To wait for the entire output, use |channel-buffered| mode.
    2. To read line-by-line, use the following code:
	let s:lines = ['']
	func! s:on_event(job_id, data, event) dict
	  let eof = (a:data == [''])
	  " Complete the previous line.
	  let s:lines[-1] .= a:data[0]
	  " Append (last item may be a partial line, until EOF).
	  call extend(s:lines, a:data[1:])
	endf
 

If the callback functions are |Dictionary-function|s, |self| refers to the
options dictionary containing the callbacks. |Partial|s can also be used as
callbacks.

Data can be sent to the channel using the |chansend()| function. Here is a
simple example, echoing some data through a cat-process:

    function! s:OnEvent(id, data, event) dict
      let str = join(a:data, "\n")
      echomsg str
    endfunction
    let id = jobstart(['cat'], {'on_stdout': function('s:OnEvent') } )
    call chansend(id, "hello!")
 

Here is a example of setting a buffer to the result of grep, but only after
all data has been processed:

    function! s:OnEvent(id, data, event) dict
      call nvim_buf_set_lines(2, 0, -1, v:true, a:data)
    endfunction
    let id = jobstart(['grep', '^[0-9]'], { 'on_stdout': function('s:OnEvent'),
					  \ 'stdout_buffered':v:true } )

    call chansend(id, "stuff\n10 PRINT \"NVIM\"\nxx")
    " no output is received, buffer is empty

    call chansend(id, "xx\n20 GOTO 10\nzz\n")
    call chanclose(id, 'stdin')
    " now buffer has result
 
For additional examples with jobs, see |job-control|.


							      *channel-pty*
Special case: PTY channels opened with `jobstart(..., {'pty': v:true})` do not
preprocess ANSI escape sequences, these will be sent raw to the callback.
However, change of PTY size can be signaled to the slave using |jobresize()|.
See also |terminal-emulator|.

Terminal characteristics (termios) for |:terminal| and PTY channels are copied
from the host TTY, or if Nvim is |--headless| it uses default values:
    :echo system('nvim --headless +"te stty -a" +"sleep 1" +"1,/^$/print" +q')

==============================================================================

3. Communicating using msgpack-rpc			      *channel-rpc*

When channels are opened with the `rpc` option set to true, the channel can be
used for remote method calls in both directions, see |msgpack-rpc|. Note that
rpc channels are implicitly trusted and the process at the other end can
invoke any |api| function!

==============================================================================

4. Standard IO channel					    *channel-stdio*

Nvim uses stdin/stdout to interact with the user over the terminal interface
(TUI). If Nvim is |--headless| the TUI is not started and stdin/stdout can be
used as a channel. See also |--embed|.

Call |stdioopen()| during |startup| to open the stdio channel as |channel-id| 1.
Nvim's stderr is always available as |v:stderr|, a write-only bytes channel.

Example:
    func! OnEvent(id, data, event)
      if a:data == [""]
        quit
      end
      call chansend(a:id, map(a:data, {i,v -> toupper(v)}))
    endfunc
    call stdioopen({'on_stdin': 'OnEvent'})
 
Put this in `uppercase.vim` and run: 
    nvim --headless --cmd "source uppercase.vim"

==============================================================================
top - main help file