diff options
author | Thiago de Arruda <tpadilha84@gmail.com> | 2015-03-25 23:11:05 -0300 |
---|---|---|
committer | Thiago de Arruda <tpadilha84@gmail.com> | 2015-03-29 20:35:44 -0300 |
commit | 6e7757ad51dfe3b2de857ff8a8688718ff6115ac (patch) | |
tree | c8fa74f8960ccd84eb8c8f6272ef52c036abce50 /runtime | |
parent | 4b98ea1e80bf886e23500004e27799384c0af135 (diff) | |
download | rneovim-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.txt | 5 | ||||
-rw-r--r-- | runtime/doc/eval.txt | 31 | ||||
-rw-r--r-- | runtime/doc/job_control.txt | 88 |
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: |