diff options
author | Justin M. Keyes <justinkz@gmail.com> | 2017-11-06 01:23:32 +0100 |
---|---|---|
committer | Justin M. Keyes <justinkz@gmail.com> | 2017-11-06 01:56:04 +0100 |
commit | fb3c21e09070b87b1ac734be14109c0e84cd9b4f (patch) | |
tree | 11728350e20b9cd8f77ed9b414c949b54948c672 | |
parent | 5d2af7e45200c1e3337624449fe2be0906d1c7cf (diff) | |
download | rneovim-fb3c21e09070b87b1ac734be14109c0e84cd9b4f.tar.gz rneovim-fb3c21e09070b87b1ac734be14109c0e84cd9b4f.tar.bz2 rneovim-fb3c21e09070b87b1ac734be14109c0e84cd9b4f.zip |
doc: job-control
closes #4266
closes #4746
ref https://github.com/neovim/neovim/issues/7058#issuecomment-317196803
-rw-r--r-- | runtime/doc/eval.txt | 131 | ||||
-rw-r--r-- | runtime/doc/job_control.txt | 129 |
2 files changed, 130 insertions, 130 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 300bdd061e..b0796b8c5d 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -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. - -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. - -jobwait({ids}[, {timeout}]) {Nvim} *jobwait()* + {opts} is passed as |self| dictionary to the callback; the + caller may set other keys to pass application-specific data. + +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}]) *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. - - 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. + 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 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 diff --git a/runtime/doc/job_control.txt b/runtime/doc/job_control.txt index 2cf48f0f4f..7ba0acff48 100644 --- a/runtime/doc/job_control.txt +++ b/runtime/doc/job_control.txt @@ -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* - -Job control is a simple way to perform multitasking in vimscript. Wikipedia -contains a more generic/detailed description: +Concepts -"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." +Job Id *job-id* -In a few words: It allows a vimscript programmer to concurrently spawn and -control multiple processes without blocking the current Nvim instance. +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. -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. +============================================================================== +Usage *job-control-usage* -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. +To control jobs, use the "job…" family of functions: |jobstart()|, +|jobsend()|, |jobstop()|. -============================================================================== -2. Usage *job-control-usage* +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: - -- 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". +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. + + *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: |