# HG changeset patch # User Christian Brabandt # Date 1456082104 -3600 # Node ID e77efd7a7dad1f3d307fb41d24b2ed7cade8a40e # Parent 0e3185eea369be9d56051e5d330c75775adb0e0f commit https://github.com/vim/vim/commit/02e83b438ea7071fdb176dabbaefea319ab2d686 Author: Bram Moolenaar Date: Sun Feb 21 20:10:26 2016 +0100 patch 7.4.1382 Problem: Can't get the job of a channel. Solution: Add ch_getjob(). diff --git a/runtime/doc/channel.txt b/runtime/doc/channel.txt --- a/runtime/doc/channel.txt +++ b/runtime/doc/channel.txt @@ -1,4 +1,4 @@ -*channel.txt* For Vim version 7.4. Last change: 2016 Feb 20 +*channel.txt* For Vim version 7.4. Last change: 2016 Feb 21 VIM REFERENCE MANUAL by Bram Moolenaar @@ -93,7 +93,7 @@ To handle asynchronous communication a c func MyHandler(channel, msg) echo "from the handler: " . a:msg endfunc - call ch_sendexpr(channel, 'hello!', "MyHandler") + call ch_sendexpr(channel, 'hello!', {'callback': "MyHandler"}) Vim will not wait for a response. Now the server can send the response later and MyHandler will be invoked. @@ -101,13 +101,15 @@ Instead of giving a callback with every when opening the channel: > call ch_close(channel) let channel = ch_open('localhost:8765', {'callback': "MyHandler"}) - call ch_sendexpr(channel, 'hello!', 0) + call ch_sendexpr(channel, 'hello!', {'callback': 0}) ============================================================================== 3. Opening a channel *channel-open* To open a channel: > let channel = ch_open({address} [, {options}]) + if ch_status(channel) == "open" + " use the channel Use |ch_status()| to see if the channel could be opened. @@ -131,25 +133,32 @@ Use |ch_status()| to see if the channel *channel-callback* "callback" A function that is called when a message is received that is not handled otherwise. It gets two arguments: the channel - handle and the received message. Example: > + and the received message. Example: > func Handle(channel, msg) echo 'Received: ' . a:msg endfunc let channel = ch_open("localhost:8765", {"callback": "Handle"}) < + When "mode" is "json" or "js" the "msg" argument is the body + of the received message, converted to Vim types. + When "mode" is "nl" the "msg" argument is one message, + excluding the NL. + When "mode" is "raw" the "msg" argument is the whole message + as a string. + *out-cb* "out-cb" A function like "callback" but used for stdout. Only for when the channel uses pipes. When "out-cb" wasn't set the channel callback is used. - + *err-cb* "err-cb" A function like "callback" but used for stderr. Only for when the channel uses pipes. When "err-cb" wasn't set the channel callback is used. - TODO: + TODO: *close-cb* "close-cb" A function that is called when the channel gets closed, other than by calling ch_close(). It should be defined like this: > func MyCloseHandler(channel) - +< *waittime* "waittime" The time to wait for the connection to be made in milliseconds. The default is zero, don't wait, which is useful if the server is supposed to be running already. A @@ -158,41 +167,34 @@ Use |ch_status()| to see if the channel "timeout" The time to wait for a request when blocking, E.g. when using ch_sendexpr(). In milliseconds. The default is 2000 (2 seconds). - + *out-timeout* *err-timeout* "out-timeout" Timeout for stdout. Only when using pipes. "err-timeout" Timeout for stderr. Only when using pipes. Note: when setting "timeout" the part specific mode is overwritten. Therefore set "timeout" first and the part specific mode later. -When "mode" is "json" or "js" the "msg" argument is the body of the received -message, converted to Vim types. -When "mode" is "raw" the "msg" argument is the whole message as a string. - When "mode" is "json" or "js" the "callback" is optional. When omitted it is only possible to receive a message after sending one. -To change the channel options after opening it use ch_setoptions(). The -arguments are similar to what is passed to ch_open(), but "waittime" cannot be -given, since that only applies to opening the channel. +To change the channel options after opening it use |ch_setoptions()|. The +arguments are similar to what is passed to |ch_open()|, but "waittime" cannot +be given, since that only applies to opening the channel. -The handler can be added or changed: > +For example, the handler can be added or changed: > call ch_setoptions(channel, {'callback': callback}) When "callback" is empty (zero or an empty string) the handler is removed. The timeout can be changed: > call ch_setoptions(channel, {'timeout': msec}) < - *E906* + *channel-close* *E906* Once done with the channel, disconnect it like this: > call ch_close(channel) When a socket is used this will close the socket for both directions. When pipes are used (stdin/stdout/stderr) they are all closed. This might not be what you want! Stopping the job with job_stop() might be better. -TODO: -Currently up to 10 channels can be in use at the same time. *E897* - When the channel can't be opened you will get an error message. There is a difference between MS-Windows and Unix: On Unix when the port doesn't exist ch_open() fails quickly. On MS-Windows "waittime" applies. @@ -211,12 +213,13 @@ This awaits a response from the other si When mode is JS this works the same, except that the messages use JavaScript encoding. See |js_encode()| for the difference. -To send a message, without handling a response: > - call ch_sendexpr(channel, {expr}, 0) +To send a message, without handling a response or letting the channel callback +handle the response: > + call ch_sendexpr(channel, {expr}, {'callback': 0}) To send a message and letting the response handled by a specific function, asynchronously: > - call ch_sendexpr(channel, {expr}, {callback}) + call ch_sendexpr(channel, {expr}, {'callback': Handler}) Vim will match the response with the request using the message ID. Once the response is received the callback will be invoked. Further responses with the @@ -424,13 +427,18 @@ The function will be called with the cha it like this: > func MyHandler(channel, msg) -Without the handler you need to read the output with ch_read(). +Without the handler you need to read the output with |ch_read()| or +|ch_readraw()|. -The handler defined for "out-cb" will also receive stderr. If you want to +The handler defined for "out-cb" will not receive stderr. If you want to handle that separately, add an "err-cb" handler: > let job = job_start(command, {"out-cb": "MyHandler", \ "err-cb": "ErrHandler"}) +If you want to handle both stderr and stdout with one handler use the +"callback" option: > + let job = job_start(command, {"callback": "MyHandler"}) + You can send a message to the command with ch_sendraw(). If the channel is in JSON or JS mode you can use ch_sendexpr(). @@ -481,7 +489,10 @@ This gives the job some time to make the 10. Job options *job-options* The {options} argument in job_start() is a dictionary. All entries are -optional. The same options can be used with job_setoptions(job, {options}). +optional. Some options can be used after the job has started, using +job_setoptions(job, {options}). Many options can be used with the channel +related to the job, using ch_setoptions(channel, {options}). +See |job_setoptions()| and |ch_setoptions()|. *job-callback* "callback": handler Callback for something to read on any part of the @@ -495,13 +506,18 @@ optional. The same options can be used TODO: *job-close-cb* "close-cb": handler Callback for when the channel is closed. Same as "close-cb" on ch_open(). -TODO: *job-exit-cb* + *job-exit-cb* "exit-cb": handler Callback for when the job ends. The arguments are the job and the exit status. -TODO: *job-killonexit* -"killonexit": 1 Stop the job when Vim exits. -"killonexit": 0 Do not stop the job when Vim exits. - The default is 1. + Vim checks about every 10 seconds for jobs that ended. + The callback can also be triggered by calling + |job_status()|. + *job-stoponexit* +"stoponexit": {signal} Send {signal} to the job when Vim exits. See + |job_stop()| for possible values. +"stoponexit": "" Do not stop the job when Vim exits. + The default is "term". + TODO: *job-term* "term": "open" Start a terminal and connect the job stdin/stdout/stderr to it. @@ -529,9 +545,6 @@ TODO: *job-err-io* "err-io": "buffer" stderr appends to a buffer "err-buffer": "name" buffer to append to -TODO: more options - - ============================================================================== 11. Controlling a job *job-control* diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1,4 +1,4 @@ -*eval.txt* For Vim version 7.4. Last change: 2016 Feb 19 +*eval.txt* For Vim version 7.4. Last change: 2016 Feb 21 VIM REFERENCE MANUAL by Bram Moolenaar @@ -59,11 +59,11 @@ Dictionary An associative, unordered arr Funcref A reference to a function |Funcref|. Example: function("strlen") -Special v:false, v:true, v:none and v:null - -Job Used for a job, see |job_start()|. - -Channel Used for a channel, see |ch_open()|. +Special |v:false|, |v:true|, |v:none| and |v:null|. *Special* + +Job Used for a job, see |job_start()|. *Job* + +Channel Used for a channel, see |ch_open()|. *Channel* The Number and String types are converted automatically, depending on how they are used. @@ -1817,17 +1817,19 @@ byteidxcomp( {expr}, {nr}) Number byte i call( {func}, {arglist} [, {dict}]) any call {func} with arguments {arglist} ceil( {expr}) Float round {expr} up -ch_close( {handle}) none close a channel +ch_close( {channel}) none close {channel} +ch_getjob( {channel}) Job get the Job of {channel} ch_log( {msg} [, {channel}]) none write {msg} in the channel log file ch_logfile( {fname} [, {mode}]) none start logging channel activity ch_open( {address} [, {options}]) Channel open a channel to {address} -ch_readraw( {handle}) String read from channel {handle} -ch_sendexpr( {handle}, {expr} [, {options}]) - any send {expr} over JSON channel {handle} -ch_sendraw( {handle}, {string} [, {options}]) - any send {string} over raw channel {handle} -ch_setoptions( {handle}, {options}) none set options for channel {handle} -ch_status( {handle}) String status of channel {handle} +ch_read( {channel} [, {options}]) String read from {channel} +ch_readraw( {channel} [, {options}]) String read raw from {channel} +ch_sendexpr( {channel}, {expr} [, {options}]) + any send {expr} over JSON {channel} +ch_sendraw( {channel}, {string} [, {options}]) + any send {string} over raw {channel} +ch_setoptions( {channel}, {options}) none set options for {channel} +ch_status( {channel}) String status of {channel} changenr() Number current change number char2nr( {expr}[, {utf8}]) Number ASCII/UTF8 value of first char in {expr} cindent( {lnum}) Number C indent for line {lnum} @@ -1960,10 +1962,11 @@ invert( {expr}) Number bitwise invert isdirectory( {directory}) Number TRUE if {directory} is a directory islocked( {expr}) Number TRUE if {expr} is locked items( {dict}) List key-value pairs in {dict} -job_getchannel( {job}) Number get the channel handle for {job} -job_start( {command} [, {options}]) Job start a job -job_status( {job}) String get the status of a job -job_stop( {job} [, {how}]) Number stop a job +job_getchannel( {job}) Channel get the channel handle for {job} +job_setoptions( {job}, {options}) none set options for {job} +job_start( {command} [, {options}]) Job start a job +job_status( {job}) String get the status of {job} +job_stop( {job} [, {how}]) Number stop {job} join( {list} [, {sep}]) String join {list} items into one String js_decode( {string}) any decode JS style JSON js_encode( {expr}) String encode JS style JSON @@ -2684,10 +2687,18 @@ confirm({msg} [, {choices} [, {default} don't fit, a vertical layout is used anyway. For some systems the horizontal layout is always used. -ch_close({handle}) *ch_close()* - Close channel {handle}. See |channel|. +ch_close({channel}) *ch_close()* + Close {channel}. See |channel-close|. {only available when compiled with the |+channel| feature} +ch_getjob({channel}) *ch_getjob()* + Get the Job associated with {channel}. + If there is no job calling |job_status()| on the returned Job + will result in "fail". + + {only available when compiled with the |+channel| and + |+job| features} + ch_log({msg} [, {channel}]) *ch_log()* Write {msg} in the channel log file, if it was opened with |ch_logfile()|. @@ -2706,8 +2717,8 @@ ch_logfile({fname} [, {mode}]) *ch_l ch_open({address} [, {options}]) *ch_open()* Open a channel to {address}. See |channel|. - Returns the channel handle on success. Returns a negative - number for failure. + Returns a Channel. Use |ch_status()| to check for + failure. {address} has the form "hostname:port", e.g., "localhost:8765". @@ -2722,19 +2733,38 @@ ch_open({address} [, {options}]) *ch_ waittime Specify connect timeout as milliseconds. Negative means forever. Default: 0 (don't wait) - timeout Specify response read timeout value as + timeout Specify response read timeout value in milliseconds. Default: 2000. {only available when compiled with the |+channel| feature} -ch_readraw({handle}) *ch_readraw()* - Read from channel {handle} and return the received message. +ch_read({channel} [, {options}]) *ch_read()* + Read from {channel} and return the received message. + This uses the channel timeout. When there is nothing to read - within that time an empty string is returned. - TODO: depends on channel mode. - -ch_sendexpr({handle}, {expr} [, {options}]) *ch_sendexpr()* - Send {expr} over channel {handle}. The {expr} is encoded + within that time an empty string is returned. To specify a + different timeout in msec use the "timeout" option: + {"timeout": 123} ~ + To read from the error output use the "part" option: + {"part": "err"} ~ + To read a message with a specific ID, on a JS or JSON channel: + {"id": 99} ~ + When no ID is specified or the ID is -1, the first message is + returned. This overrules any callback waiting for this + message. + + For a RAW channel this returns whatever is available, since + Vim does not know where a message ends. + For a NL channel this returns one message. + For a JS or JSON channel this returns one decoded message. + This includes any sequence number. + +ch_readraw({channel} [, {options}]) *ch_readraw()* + Like ch_read() but for a JS and JSON channel does not decode + the message. + +ch_sendexpr({channel}, {expr} [, {options}]) *ch_sendexpr()* + Send {expr} over {channel}. The {expr} is encoded according to the type of channel. The function cannot be used with a raw channel. See |channel-use|. *E912* @@ -2751,8 +2781,8 @@ ch_sendexpr({handle}, {expr} [, {options {only available when compiled with the |+channel| feature} -ch_sendraw({handle}, {string} [, {options}]) *ch_sendraw()* - Send {string} over channel {handle}. +ch_sendraw({channel}, {string} [, {options}]) *ch_sendraw()* + Send {string} over {channel}. Works like |ch_sendexpr()|, but does not encode the request or decode the response. The caller is responsible for the correct contents. Also does not add a newline for a channel @@ -2762,18 +2792,21 @@ ch_sendraw({handle}, {string} [, {option {only available when compiled with the |+channel| feature} -ch_setoptions({handle}, {options}) *ch_setoptions()* - Set options on channel {handle}: +ch_setoptions({channel}, {options}) *ch_setoptions()* + Set options on {channel}: "callback" the channel callback "timeout" default read timeout in msec + "mode" mode for the whole channel See |ch_open()| for more explanation. + Note that changing the mode may cause queued messages to be + lost. + These options cannot be changed: - "mode" cannot be changed once channel is open "waittime" only applies to "ch_open()| -ch_status({handle}) *ch_status()* - Return the status of channel {handle}: +ch_status({channel}) *ch_status()* + Return the status of {channel}: "fail" failed to open the channel "open" channel can be used "closed" channel can not be used @@ -4370,11 +4403,15 @@ items({dict}) *items()* entry and the value of this entry. The |List| is in arbitrary order. - job_getchannel({job}) *job_getchannel()* Get the channel handle that {job} is using. {only available when compiled with the |+job| feature} +job_setoptions({job}, {options}) *job_setoptions()* + Change options for {job}. Supported are: + "stoponexit" |job-stoponexit| + "exit-cb" |job-exit-cb| + job_start({command} [, {options}]) *job_start()* Start a job and return a Job object. Unlike |system()| and |:!cmd| this does not wait for the job to finish. @@ -4415,11 +4452,14 @@ job_start({command} [, {options}]) *jo {only available when compiled with the |+job| feature} -job_status({job}) *job_status()* +job_status({job}) *job_status()* *E916* Returns a String with the status of {job}: "run" job is running "fail" job failed to start "dead" job died or was stopped after running + + If an exit callback was set with the "exit-cb" option and the + job is now detected to be "dead" the callback will be invoked. {only available when compiled with the |+job| feature} @@ -7375,7 +7415,6 @@ vms VMS version of Vim. vreplace Compiled with |gR| and |gr| commands. wildignore Compiled with 'wildignore' option. wildmenu Compiled with 'wildmenu' option. -win16 Win16 version of Vim (MS-Windows 3.1). win32 Win32 version of Vim (MS-Windows 95 and later, 32 or 64 bits) win32unix Win32 version of Vim, using Unix files (Cygwin) diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -501,6 +501,9 @@ static void f_ceil(typval_T *argvars, ty #endif #ifdef FEAT_CHANNEL static void f_ch_close(typval_T *argvars, typval_T *rettv); +# ifdef FEAT_JOB +static void f_ch_getjob(typval_T *argvars, typval_T *rettv); +# endif static void f_ch_log(typval_T *argvars, typval_T *rettv); static void f_ch_logfile(typval_T *argvars, typval_T *rettv); static void f_ch_open(typval_T *argvars, typval_T *rettv); @@ -8186,6 +8189,9 @@ static struct fst #endif #ifdef FEAT_CHANNEL {"ch_close", 1, 1, f_ch_close}, +# ifdef FEAT_JOB + {"ch_getjob", 1, 1, f_ch_getjob}, +# endif {"ch_log", 1, 2, f_ch_log}, {"ch_logfile", 1, 2, f_ch_logfile}, {"ch_open", 1, 2, f_ch_open}, @@ -10186,6 +10192,25 @@ f_ch_close(typval_T *argvars, typval_T * channel_close(channel); } +# ifdef FEAT_JOB +/* + * "ch_getjob()" function + */ + static void +f_ch_getjob(typval_T *argvars, typval_T *rettv) +{ + channel_T *channel = get_channel_arg(&argvars[0]); + + if (channel != NULL) + { + rettv->v_type = VAR_JOB; + rettv->vval.v_job = channel->ch_job; + if (channel->ch_job != NULL) + ++channel->ch_job->jv_refcount; + } +} +# endif + /* * "ch_log()" function */ diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -748,6 +748,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1382, +/**/ 1381, /**/ 1380,