mirror of
https://github.com/neovim/neovim.git
synced 2026-08-29 10:31:48 +00:00
doc: job-control
closes #4266 closes #4746 ref https://github.com/neovim/neovim/issues/7058#issuecomment-317196803
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user