doc: job-control

closes #4266
closes #4746
ref https://github.com/neovim/neovim/issues/7058#issuecomment-317196803
This commit is contained in:
Justin M. Keyes
2017-11-06 01:23:32 +01:00
parent 5d2af7e452
commit fb3c21e090
2 changed files with 127 additions and 127 deletions

View File

@@ -1785,7 +1785,7 @@ v:scrollstart String describing the script or function that caused the
*v:servername* *servername-variable*
*$NVIM_LISTEN_ADDRESS*
v:servername Default {Nvim} server address. Equivalent to
v:servername Default Nvim server address. Equivalent to
|$NVIM_LISTEN_ADDRESS| on startup. |serverstop()|
Read-only.
@@ -4915,42 +4915,48 @@ items({dict}) *items()*
entry and the value of this entry. The |List| is in arbitrary
order.
jobclose({job}[, {stream}]) {Nvim} *jobclose()*
Close {job}'s {stream}, which can be one of "stdin", "stdout",
"stderr" or "rpc" (closes the rpc channel for a job started
with the "rpc" option.) If {stream} is omitted, all streams
are closed. If the job is a pty job, this will then close the
pty master, sending SIGHUP to the job process.
jobclose({job}[, {stream}]) *jobclose()*
Close {stream} of |job-id| {job}, where {stream} is one of:
"stdin", "stdout", "stderr", "rpc" (RPC channel of a job
started with `"rpc":v:true`). If {stream} is omitted, all
streams are closed. If the job is a pty job, this will close
the pty master, sending SIGHUP to the job process.
jobpid({job}) {Nvim} *jobpid()*
Return the pid (process id) of {job}.
jobpid({job}) *jobpid()*
Return the PID (process id) of |job-id| {job}.
jobresize({job}, {width}, {height}) {Nvim} *jobresize()*
Resize {job}'s pseudo terminal window to {width} and {height}.
This function will fail if used on jobs started without the
"pty" option.
jobresize({job}, {width}, {height}) *jobresize()*
Resize the pseudo terminal window of |job-id| {job} to {width}
columns and {height} rows.
Fails if the job was not started with `"pty":v:true`.
jobsend({job}, {data}) {Nvim} *jobsend()*
Send data to {job} by writing it to the stdin of the process.
jobsend({job}, {data}) *jobsend()*
Writes to stdin of the process associated with |job-id| {job}.
Returns 1 if the write succeeded, 0 otherwise.
See |job-control| for more information.
See |job-control|.
{data} may be a string, string convertible, or a list. If
{data} is a list, the items will be separated by newlines and
any newlines in an item will be sent as a NUL. A final newline
can be sent by adding a final empty string. For example: >
{data} is a list, the items will be joined by newlines; any
newlines in an item will be sent as NUL. To send a final
newline, include a final empty string. Example: >
:call jobsend(j, ["abc", "123\n456", ""])
< will send "abc<NL>123<NUL>456<NL>".
If the job was started with the rpc option this function
cannot be used, instead use |rpcnotify()| and |rpcrequest()|
to communicate with the job.
jobsend() writes raw data, not RPC messages. If the job was
created with `"rpc":v:true` then the channel expects RPC
messages, use |rpcnotify()| and |rpcrequest()| instead.
jobstart({cmd}[, {opts}]) {Nvim} *jobstart()*
Spawns {cmd} as a job. If {cmd} is a |List| it is run
directly. If {cmd} is a |String| it is processed like this: >
jobstart({cmd}[, {opts}]) *jobstart()*
Spawns {cmd} as a job.
If {cmd} is a List it runs directly (no 'shell').
If {cmd} is a String it runs in the 'shell', like this: >
:call jobstart(split(&shell) + split(&shellcmdflag) + ['{cmd}'])
< (Only shows the idea; see |shell-unquoting| for full details.)
< (See |shell-unquoting| for details.)
Returns |job-id| on success, 0 on invalid arguments (or job
table is full), -1 if {cmd}[0] or 'shell' is not executable.
See |job-control| and |rpc|.
NOTE: on Windows if {cmd} is a List:
- cmd[0] must be an executable (not a "built-in"). If it is
@@ -4962,6 +4968,7 @@ jobstart({cmd}[, {opts}]) {Nvim} *jobstart()*
by CommandLineToArgvW https://msdn.microsoft.com/bb776391
unless cmd[0] is some form of "cmd.exe".
*jobstart-options*
{opts} is a dictionary with these keys:
|on_stdout|: stdout event handler (function name or |Funcref|)
|on_stderr|: stderr event handler (function name or |Funcref|)
@@ -4972,9 +4979,9 @@ jobstart({cmd}[, {opts}]) {Nvim} *jobstart()*
with the job over stdin and stdout. "on_stdout" is
then ignored, but "on_stderr" can still be used.
pty : If set, the job will be connected to a new pseudo
terminal, and the job streams are connected to
the master file descriptor. "on_stderr" is ignored
as all output will be received on stdout.
terminal and the job streams are connected to the
master file descriptor. "on_stderr" is ignored,
"on_stdout" receives all output.
width : (pty only) Width of the terminal screen
height : (pty only) Height of the terminal screen
@@ -4982,43 +4989,31 @@ jobstart({cmd}[, {opts}]) {Nvim} *jobstart()*
detach : (non-pty only) Detach the job process from the
nvim process. The process will not get killed
when nvim exits. If the process dies before
nvim exits, on_exit will still be invoked.
nvim exits, "on_exit" will still be invoked.
{opts} is passed as |self| to the callback; the caller may
pass arbitrary data by setting other keys.
Returns:
- The job ID on success, which is used by |jobsend()| (or
|rpcnotify()| and |rpcrequest()| if "rpc" option was used)
and |jobstop()|
- 0 on invalid arguments or if the job table is full
- -1 if {cmd}[0] is not executable.
See |job-control| and |msgpack-rpc| for more information.
{opts} is passed as |self| dictionary to the callback; the
caller may set other keys to pass application-specific data.
jobstop({job}) {Nvim} *jobstop()*
Stop a job created with |jobstart()| by sending a `SIGTERM`
to the corresponding process. If the process doesn't exit
cleanly soon, a `SIGKILL` will be sent. When the job is
finally closed, the exit handler provided to |jobstart()| or
|termopen()| will be run.
See |job-control| for more information.
jobstop({job}) *jobstop()*
Stop |job-id| {job} by sending SIGTERM to the job process. If
the process does not terminate after a timeout then SIGKILL
will be sent. When the job terminates its |on_exit| handler
(if any) will be invoked.
See |job-control|.
jobwait({ids}[, {timeout}]) {Nvim} *jobwait()*
jobwait({ids}[, {timeout}]) *jobwait()*
Wait for a set of jobs to finish. The {ids} argument is a list
of ids for jobs that will be waited for. If passed, {timeout}
is the maximum number of milliseconds to wait. While this
function is executing, callbacks for jobs not in the {ids}
list can be executed. Also, the screen wont be updated unless
|:redraw| is invoked by one of the callbacks.
of |job-id|s to wait for. {timeout} is the maximum number of
milliseconds to wait. During jobwait(), callbacks for jobs not
in the {ids} list may be invoked. The screen will not redraw
unless |:redraw| is invoked by a callback.
Returns a list of integers with the same length as {ids}, with
each integer representing the wait result for the
corresponding job id. The possible values for the resulting
integers are:
* the job return code if the job exited
* -1 if the wait timed out for the job
* -2 if the job was interrupted
* -3 if the job id is invalid.
Returns a list of len({ids}) integers, where each integer is
the wait-result of the corresponding job. Each wait-result is:
Job exit-code, if the job exited
-1 if the wait timed out for the job
-2 if the job was interrupted
-3 if the |job-id| is invalid.
join({list} [, {sep}]) *join()*
Join the items in {list} together into one String.
@@ -5652,7 +5647,7 @@ mode([expr]) Return a string that indicates the current mode.
i Insert
R Replace |R|
Rv Virtual Replace |gR|
t Terminal {Nvim}
t Terminal
c Command-line
cv Vim Ex mode |gQ|
ce Normal Ex mode |Q|
@@ -8201,9 +8196,9 @@ There are four types of features:
Example: >
:if has("win32")
< *has-patch*
3. {Nvim} version. The "nvim-1.2.3" feature means that the Nvim version is
1.2.3 or later. Example: >
:if has("nvim-1.2.3")
3. Nvim version. The "nvim-0.2.1" feature means that the Nvim version is
0.2.1 or later. Example: >
:if has("nvim-0.2.1")
<
4. Included patches. The "patch123" feature means that patch 123 has been
included. Note that this form does not check the version of Vim, you need

View File

@@ -4,41 +4,30 @@
NVIM REFERENCE MANUAL by Thiago de Arruda
Nvim's facilities for job control *job-control*
Nvim job control *job-control*
Job control is a way to perform multitasking in Nvim, so scripts can spawn and
control multiple processes without blocking the current Nvim instance.
Type |gO| to see the table of contents.
==============================================================================
1. Introduction *job-control-intro*
Concepts
Job control is a simple way to perform multitasking in vimscript. Wikipedia
contains a more generic/detailed description:
Job Id *job-id*
"Job control in computing refers to the control of multiple tasks or Jobs on a
computer system, ensuring that they each have access to adequate resources to
perform correctly, that competition for limited resources does not cause a
deadlock where two or more jobs are unable to complete, resolving such
situations where they do occur, and terminating jobs that, for any reason, are
not performing as expected."
In a few words: It allows a vimscript programmer to concurrently spawn and
control multiple processes without blocking the current Nvim instance.
Nvim's job control was designed to be simple and familiar to vimscript
programmers, instead of being very powerful but complex. Unlike Vim's
facilities for calling with external commands, job control does not depend on
available shells, instead relying on OS functionality for process management.
Internally, Nvim job control is powered by libuv, which has a nice
cross-platform API for managing processes. See https://github.com/libuv/libuv
for details.
When a job starts it is assigned a number, unique for the life of the current
Nvim session. Functions like |jobstart()| return job ids. Functions like
|jobsend()|, |jobstop()|, |rpcnotify()|, and |rpcrequest()| take job ids.
==============================================================================
2. Usage *job-control-usage*
Usage *job-control-usage*
To control jobs, use the "job…" family of functions: |jobstart()|,
|jobsend()|, |jobstop()|.
Example: >
Job control is achieved by calling a combination of the |jobstart()|,
|jobsend()| and |jobstop()| functions. Here's an example:
>
function! s:JobHandler(job_id, data, event) dict
if a:event == 'stdout'
let str = self.shell.' stdout: '.join(a:data)
@@ -58,35 +47,41 @@ Job control is achieved by calling a combination of the |jobstart()|,
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))
To test the above script, copy it to a file ~/foo.vim and run it: >
nvim -u ~/foo.vim
<
To test the above, copy it to the file ~/jobcontrol.vim and start with a clean
nvim instance:
>
nvim -u NONE -S ~/jobcontrol.vim
<
Here's what is happening:
Description of what happens:
- Two bash shells are spawned by |jobstart()| with their stdin/stdout/stderr
streams connected to nvim.
- The first shell is idle, waiting to read commands from its stdin.
- The second shell is started with -c which executes the command (a for-loop
printing 0 through 9) and then exits.
- `JobHandler()` callback is passed to |jobstart()| to handle various job
events. It displays stdout/stderr data received from the shells.
- Two bash instances are spawned by |jobstart()| with their stdin/stdout/stderr
connected to nvim.
- The first shell is idle, waiting to read commands from its stdin.
- The second shell is started with the -c argument, causing it to execute a
command then exit. In this case, the command is a for loop that will print 0
through 9 then exit.
- The `JobHandler()` function is a callback passed to |jobstart()| to handle
various job events. It takes care of displaying stdout/stderr received from
the shells.
*on_stdout* *on_stderr* *on_exit*
- The arguments passed to `JobHandler()` are:
0: The job id
1: If the event is "stdout" or "stderr", a list with lines read from the
corresponding stream. For "exit", it is the status returned by the
program.
2: The event type, which is "stdout", "stderr" or "exit".
*on_stdout*
Arguments passed to on_stdout callback:
0: |job-id|
1: List of lines read from the stream. If the last item is not "" (empty
string), then it is an incomplete line that might be continued at the
next on_stdout invocation. See Note 2 below.
2: Event type: "stdout"
*on_stderr*
Arguments passed to on_stderr callback:
0: |job-id|
1: List of lines read from the stream. If the last item is not "" (empty
string), then it is an incomplete line that might be continued at the
next on_stderr invocation. See Note 2 below.
2: Event type: "stderr"
*on_exit*
Arguments passed to on_exit callback:
0: |job-id|
1: Exit-code of the process.
2: Event type: "exit"
Note: Buffered stdout/stderr data which has not been flushed by the sender
will not trigger the "stdout" callback (but if the process ends, the
"exit" callback will be triggered).
will not trigger the on_stdout/on_stderr callback (but if the process
ends, the on_exit callback will be invoked).
For example, "ruby -e" buffers output, so small strings will be
buffered unless "auto-flushing" ($stdout.sync=true) is enabled. >
function! Receive(job_id, data, event)
@@ -97,9 +92,25 @@ Here's what is happening:
\ {'on_stdout': 'Receive'})
< https://github.com/neovim/neovim/issues/1592
The options dictionary is passed as the "self" variable to the callback
function. Here's a more object-oriented version of the above:
>
Note 2:
Job event handlers may receive partial (incomplete) lines. For a given
invocation of on_stdout/on_stderr, `a:data` is not guaranteed to end
with a newline.
- `abcdefg` may arrive as `['abc']`, `['defg']`.
- `abc\nefg` may arrive as `['abc', '']`, `['efg']` or `['abc']`,
`['','efg']`, or even `['ab']`, `['c','efg']`.
Easy way to deal with this: initialize a list as `['']`, then append
to it as follows: >
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
<
The |jobstart-options| dictionary is passed as |self| to the callback.
The above example could be written in this "object-oriented" style: >
let Shell = {}
function Shell.on_stdout(_job_id, data, event)
@@ -126,19 +137,13 @@ function. Here's a more object-oriented version of the above:
let instance = Shell.new('bomb',
\ 'for i in $(seq 9 -1 1); do echo $i 1>&$((i % 2 + 1)); sleep 1; done')
<
To send data to the job's stdin, one can use the |jobsend()| function, like
this:
>
To send data to the job's stdin, use |jobsend()|: >
:call jobsend(job1, "ls\n")
:call jobsend(job1, "invalid-command\n")
:call jobsend(job1, "exit\n")
<
A job may be killed at any time with the |jobstop()| function:
>
A job may be killed with |jobstop()|: >
:call jobstop(job1)
<
When |jobstop()| is called, `SIGTERM` will be sent to the job. If a job does
not exit after 2 seconds, `SIGKILL` will be sent.
==============================================================================
vim:tw=78:ts=8:noet:ft=help:norl: