aboutsummaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
authorThiago de Arruda <tpadilha84@gmail.com>2015-03-25 23:11:05 -0300
committerThiago de Arruda <tpadilha84@gmail.com>2015-03-29 20:35:44 -0300
commit6e7757ad51dfe3b2de857ff8a8688718ff6115ac (patch)
treec8fa74f8960ccd84eb8c8f6272ef52c036abce50 /runtime
parent4b98ea1e80bf886e23500004e27799384c0af135 (diff)
downloadrneovim-6e7757ad51dfe3b2de857ff8a8688718ff6115ac.tar.gz
rneovim-6e7757ad51dfe3b2de857ff8a8688718ff6115ac.tar.bz2
rneovim-6e7757ad51dfe3b2de857ff8a8688718ff6115ac.zip
eval: Refactor vimscript job control API
- Remove JobActivity autocmd and v:job_data variable - Simplify `jobstart` to receive: - An argument vector - An optional dictionary which may contain any of the current `jobstart` options plus `on_stdout`, `on_stderr` and `on_exit` callbacks. - Refactor and add more job tests - Update documentation
Diffstat (limited to 'runtime')
-rw-r--r--runtime/doc/autocmd.txt5
-rw-r--r--runtime/doc/eval.txt31
-rw-r--r--runtime/doc/job_control.txt88
3 files changed, 82 insertions, 42 deletions
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index dc236fc78f..eea59754c8 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -307,7 +307,6 @@ Name triggered by ~
|InsertLeave| when leaving Insert mode
|InsertCharPre| when a character was typed in Insert mode, before
inserting it
-|JobActivity| when something interesting happens with a job
|TextChanged| after a change was made to the text in Normal mode
|TextChangedI| after a change was made to the text in Insert mode
@@ -733,10 +732,6 @@ InsertEnter Just before starting Insert mode. Also for
*InsertLeave*
InsertLeave When leaving Insert mode. Also when using
CTRL-O |i_CTRL-O|. But not for |i_CTRL-C|.
- {Nvim} *JobActivity*
-JobActivity When something interesting happens with a job
- spawned by |jobstart()|. See |job-control| for
- details.
*MenuPopup*
MenuPopup Just before showing the popup menu (under the
right mouse button). Useful for adjusting the
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 1d18a61dbd..909b4743a6 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -4012,6 +4012,11 @@ items({dict}) *items()*
entry and the value of this entry. The |List| is in arbitrary
order.
+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.
+
jobsend({job}, {data}) {Nvim} *jobsend()*
Send data to {job} by writing it to the stdin of the process.
Returns 1 if the write succeeded, 0 otherwise.
@@ -4024,14 +4029,28 @@ jobsend({job}, {data}) {Nvim} *jobsend()*
:call jobsend(j, ["abc", "123\n456", ""])
< will send "abc<NL>123<NUL>456<NL>".
-jobstart({name}, {prog}[, {argv}]) {Nvim} *jobstart()*
- Spawns {prog} as a job and associate it with the {name} string,
- which will be used to match the "filename pattern" in
- |JobActivity| events. It returns:
- - The job id on success, which is used by |jobsend()| and
+jobstart({argv}[, {opts}]) {Nvim} *jobstart()*
+ Spawns {argv}(list) as a job. If passed, {opts} must be a
+ dictionary with any of the following keys:
+ - on_stdout: stdout event handler
+ - on_stderr: stderr event handler
+ - on_exit: exit event handler
+ - pty: If set, the job will be connected to a new pseudo
+ terminal, and the job streams are connected to the master
+ file descriptor.
+ - width: Width of the terminal screen(only if pty is set)
+ - height: Height of the terminal screen(only if pty is set)
+ - TERM: $TERM environment variable(only if pty is set)
+ Either funcrefs or function names can be passed as event
+ handlers. The {opts} object is also used as the "self"
+ argument for the callback, so the caller may pass arbitrary
+ data by setting other key.(see |Dictionary-function| for more
+ information).
+ Returns:
+ - The job ID on success, which is used by |jobsend()| and
|jobstop()|
- 0 when the job table is full or on invalid arguments
- - -1 when {prog} is not executable
+ - -1 when {argv}[0] is not executable
See |job-control| for more information.
jobstop({job}) {Nvim} *jobstop()*
diff --git a/runtime/doc/job_control.txt b/runtime/doc/job_control.txt
index 1faf9bcd94..dc746bbe99 100644
--- a/runtime/doc/job_control.txt
+++ b/runtime/doc/job_control.txt
@@ -37,37 +37,28 @@ for details
==============================================================================
2. Usage *job-control-usage*
-Here's a quick one-liner that creates a job which invokes the "ls" shell
-command and prints the result:
->
- call jobstart('', 'ls', ['-a'])|au JobActivity * echo v:job_data|au!
- JobActivity
-
-In the one-liner above, creating the JobActivity event handler immediately
-after the call to jobstart() is not a race because the Nvim job system will
-not publish the job result (even though it may receive it) until evaluation of
-the chained user commands (`expr1|expr2|...|exprN`) has completed.
-
Job control is achieved by calling a combination of the |jobstart()|,
-|jobsend()| and |jobstop()| functions, and by listening to the |JobActivity|
-event. The best way to understand is with a complete example:
+|jobsend()| and |jobstop()| functions. Here's an example:
>
- let job1 = jobstart('shell1', 'bash')
- let job2 = jobstart('shell2', 'bash', ['-c', 'for ((i = 0; i < 10; i++)); do echo hello $i!; sleep 1; done'])
-
- function JobHandler()
- if v:job_data[1] == 'stdout'
- let str = 'shell '. v:job_data[0].' stdout: '.join(v:job_data[2])
- elseif v:job_data[1] == 'stderr'
- let str = 'shell '.v:job_data[0].' stderr: '.join(v:job_data[2])
+ function s:JobHandler(job_id, data, event)
+ if a:event == 'stdout'
+ let str = self.shell.' stdout: '.join(a:data)
+ elseif a:event == 'stderr'
+ let str = self.shell.' stderr: '.join(a:data)
else
- let str = 'shell '.v:job_data[0].' exited'
+ let str = self.shell.' exited'
endif
call append(line('$'), str)
endfunction
+ let s:callbacks = {
+ \ 'on_stdout': function('s:JobHandler'),
+ \ 'on_stderr': function('s:JobHandler'),
+ \ 'on_exit': function('s:JobHandler')
+ \ }
+ 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))
- au JobActivity shell* call JobHandler()
<
To test the above, copy it to the file ~/jobcontrol.vim and start with a clean
nvim instance:
@@ -82,16 +73,51 @@ Here's what is happening:
- 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 called by the `JobActivity` autocommand (notice
- how the shell* pattern matches the names `shell1` and `shell2` passed to
- |jobstart()|), and it takes care of displaying stdout/stderr received from
+- 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.
-- The v:job_data is an array set by the JobActivity event. It has the
- following elements:
+- The arguments passed to `JobHandler()` are:
+
0: The job id
- 1: The kind of activity: one of "stdout", "stderr" or "exit"
- 2: When "activity" is "stdout" or "stderr", this will contain a list of
- lines read from stdout or stderr
+ 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".
+
+The options dictionary is passed as the "self" variable to the callback
+function. Here's a more object-oriented version of the above:
+>
+ let Shell = {}
+
+ function Shell.on_stdout(job_id, data)
+ call append(line('$'), self.get_name().' stdout: '.join(a:data))
+ endfunction
+
+ function Shell.on_stderr(job_id, data)
+ call append(line('$'), self.get_name().' stderr: '.join(a:data))
+ endfunction
+
+ function Shell.on_exit(job_id, data)
+ call append(line('$'), self.get_name().' exited')
+ endfunction
+
+ function Shell.get_name()
+ return 'shell '.self.name
+ endfunction
+
+ function Shell.new(name, ...)
+ let instance = extend(copy(g:Shell), {'name': a:name})
+ let argv = ['bash']
+ if a:0 > 0
+ let argv += ['-c', a:1]
+ endif
+ let instance.id = jobstart(argv, instance)
+ return instance
+ endfunction
+
+ let s1 = Shell.new('1')
+ let s2 = Shell.new('2', 'for i in {1..10}; do echo hello $i!; sleep 1; done')
+
To send data to the job's stdin, one can use the |jobsend()| function, like
this: