diff options
-rw-r--r-- | runtime/doc/eval.txt | 54 | ||||
-rw-r--r-- | runtime/tools/demoserver.py | 10 | ||||
-rw-r--r-- | src/eval.c | 451 | ||||
-rw-r--r-- | src/version.c | 2 |
4 files changed, 258 insertions, 259 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 5727918a0..4a298dfce 100644 --- 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 01 +*eval.txt* For Vim version 7.4. Last change: 2016 Feb 02 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1810,6 +1810,13 @@ byteidxcomp( {expr}, {nr}) Number byte index of {nr}'th char in {expr} call( {func}, {arglist} [, {dict}]) any call {func} with arguments {arglist} ceil( {expr}) Float round {expr} up +ch_close( {handle}) none close a channel +ch_open( {address}, {mode} [, {callback}]) + Number open a channel +ch_sendexpr( {handle}, {expr} [, {callback}]) + any send {expr} over JSON channel {handle} +ch_sendraw( {handle}, {string} [, {callback}]) + any send {string} over raw channel {handle} 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} @@ -1820,8 +1827,6 @@ complete_add( {expr}) Number add completion match complete_check() Number check for key typed during completion confirm( {msg} [, {choices} [, {default} [, {type}]]]) Number number of choice picked by user -connect( {address}, {mode} [, {callback}]) - Number open a channel copy( {expr}) any make a shallow copy of {expr} cos( {expr}) Float cosine of {expr} cosh( {expr}) Float hyperbolic cosine of {expr} @@ -2029,10 +2034,6 @@ searchpairpos( {start}, {middle}, {end} [, {flags} [, {skip} [...]]]) List search for other end of start/end pair searchpos( {pattern} [, {flags} [, {stopline} [, {timeout}]]]) List search for {pattern} -sendexpr( {handle}, {expr} [, {callback}]) - any send {expr} over JSON channel {handle} -sendraw( {handle}, {string} [, {callback}]) - any send {string} over raw channel {handle} server2client( {clientid}, {string}) Number send reply string serverlist() String get a list of available servers @@ -2666,7 +2667,10 @@ confirm({msg} [, {choices} [, {default} [, {type}]]]) don't fit, a vertical layout is used anyway. For some systems the horizontal layout is always used. -connect({address}, {mode} [, {callback}]) *connect()* +ch_close({handle}) *ch_close()* + Close channel {handle}. See |channel|. + +ch_open({address}, {mode} [, {callback}]) *ch_open()* Open a channel to {address}. See |channel|. Returns the channel handle on success. Returns a negative number for failure. @@ -2680,6 +2684,23 @@ connect({address}, {mode} [, {callback}]) *connect()* {callback} is a function that handles received messages on the channel. See |channel-callback|. +ch_sendexpr({handle}, {expr} [, {callback}]) ch_*sendexpr()* + Send {expr} over JSON channel {handle}. See |channel-use|. + + When {callback} is given returns immediately. Without + {callback} waits for a JSON response and returns the decoded + expression. When there is an error or timeout returns an + empty string. + + When {callback} is zero no response is expected. + Otherwise {callback} must be a Funcref or the name of a + function. It is called when the response is received. See + |channel-callback|. + +ch_sendraw({handle}, {string} [, {callback}]) *ch_sendraw()* + Send {string} over raw channel {handle}. See |channel-raw|. + Works like |ch_sendexpr()|, but does not decode the response. + *copy()* copy({expr}) Make a copy of {expr}. For Numbers and Strings this isn't different from using {expr} directly. @@ -5615,23 +5636,6 @@ searchpos({pattern} [, {flags} [, {stopline} [, {timeout}]]]) *searchpos()* < In this example "submatch" is 2 when a lowercase letter is found |/\l|, 3 when an uppercase letter is found |/\u|. -sendexpr({handle}, {expr} [, {callback}]) *sendexpr()* - Send {expr} over JSON channel {handle}. See |channel-use|. - - When {callback} is given returns immediately. Without - {callback} waits for a JSON response and returns the decoded - expression. When there is an error or timeout returns an - empty string. - - When {callback} is zero no response is expected. - Otherwise {callback} must be a Funcref or the name of a - function. It is called when the response is received. See - |channel-callback|. - -sendraw({handle}, {string} [, {callback}]) *sendraw()* - Send {string} over raw channel {handle}. See |channel-raw|. - Works like |sendexpr()|, but does not decode the response. - server2client( {clientid}, {string}) *server2client()* Send a reply string to {clientid}. The most recent {clientid} that sent a string can be retrieved with expand("<client>"). diff --git a/runtime/tools/demoserver.py b/runtime/tools/demoserver.py index 0f6a3740c..9f22aa293 100644 --- a/runtime/tools/demoserver.py +++ b/runtime/tools/demoserver.py @@ -1,15 +1,21 @@ #!/usr/bin/python +# # Server that will accept connections from a Vim channel. # Run this server and then in Vim you can open the channel: -# :let handle = connect('localhost:8765', 'json') +# :let handle = ch_open('localhost:8765', 'json') # # Then Vim can send requests to the server: -# :let response = sendexpr(handle, 'hello!') +# :let response = ch_sendexpr(handle, 'hello!') # # And you can control Vim by typing a JSON message here, e.g.: # ["ex","echo 'hi there'"] # +# There is no prompt, just type a line and press Enter. +# To exit cleanly type "quit<Enter>". +# # See ":help channel-demo" in Vim. +# +# This requires Python 2.6 or later. from __future__ import print_function import json diff --git a/src/eval.c b/src/eval.c index 9a4e1bbe2..892e14ada 100644 --- a/src/eval.c +++ b/src/eval.c @@ -499,6 +499,12 @@ static void f_call(typval_T *argvars, typval_T *rettv); #ifdef FEAT_FLOAT static void f_ceil(typval_T *argvars, typval_T *rettv); #endif +#ifdef FEAT_CHANNEL +static void f_ch_open(typval_T *argvars, typval_T *rettv); +static void f_ch_close(typval_T *argvars, typval_T *rettv); +static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv); +static void f_ch_sendraw(typval_T *argvars, typval_T *rettv); +#endif static void f_changenr(typval_T *argvars, typval_T *rettv); static void f_char2nr(typval_T *argvars, typval_T *rettv); static void f_cindent(typval_T *argvars, typval_T *rettv); @@ -515,9 +521,6 @@ static void f_copy(typval_T *argvars, typval_T *rettv); static void f_cos(typval_T *argvars, typval_T *rettv); static void f_cosh(typval_T *argvars, typval_T *rettv); #endif -#ifdef FEAT_CHANNEL -static void f_connect(typval_T *argvars, typval_T *rettv); -#endif static void f_count(typval_T *argvars, typval_T *rettv); static void f_cscope_connection(typval_T *argvars, typval_T *rettv); static void f_cursor(typval_T *argsvars, typval_T *rettv); @@ -526,9 +529,6 @@ static void f_delete(typval_T *argvars, typval_T *rettv); static void f_did_filetype(typval_T *argvars, typval_T *rettv); static void f_diff_filler(typval_T *argvars, typval_T *rettv); static void f_diff_hlID(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_CHANNEL -static void f_disconnect(typval_T *argvars, typval_T *rettv); -#endif static void f_empty(typval_T *argvars, typval_T *rettv); static void f_escape(typval_T *argvars, typval_T *rettv); static void f_eval(typval_T *argvars, typval_T *rettv); @@ -703,10 +703,6 @@ static void f_searchdecl(typval_T *argvars, typval_T *rettv); static void f_searchpair(typval_T *argvars, typval_T *rettv); static void f_searchpairpos(typval_T *argvars, typval_T *rettv); static void f_searchpos(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_CHANNEL -static void f_sendexpr(typval_T *argvars, typval_T *rettv); -static void f_sendraw(typval_T *argvars, typval_T *rettv); -#endif static void f_server2client(typval_T *argvars, typval_T *rettv); static void f_serverlist(typval_T *argvars, typval_T *rettv); static void f_setbufvar(typval_T *argvars, typval_T *rettv); @@ -8003,6 +7999,12 @@ static struct fst #ifdef FEAT_FLOAT {"ceil", 1, 1, f_ceil}, #endif +#ifdef FEAT_CHANNEL + {"ch_close", 1, 1, f_ch_close}, + {"ch_open", 2, 3, f_ch_open}, + {"ch_sendexpr", 2, 3, f_ch_sendexpr}, + {"ch_sendraw", 2, 3, f_ch_sendraw}, +#endif {"changenr", 0, 0, f_changenr}, {"char2nr", 1, 2, f_char2nr}, {"cindent", 1, 1, f_cindent}, @@ -8014,9 +8016,6 @@ static struct fst {"complete_check", 0, 0, f_complete_check}, #endif {"confirm", 1, 4, f_confirm}, -#ifdef FEAT_CHANNEL - {"connect", 2, 3, f_connect}, -#endif {"copy", 1, 1, f_copy}, #ifdef FEAT_FLOAT {"cos", 1, 1, f_cos}, @@ -8030,9 +8029,6 @@ static struct fst {"did_filetype", 0, 0, f_did_filetype}, {"diff_filler", 1, 1, f_diff_filler}, {"diff_hlID", 2, 2, f_diff_hlID}, -#ifdef FEAT_CHANNEL - {"disconnect", 1, 1, f_disconnect}, -#endif {"empty", 1, 1, f_empty}, {"escape", 2, 2, f_escape}, {"eval", 1, 1, f_eval}, @@ -8211,10 +8207,6 @@ static struct fst {"searchpair", 3, 7, f_searchpair}, {"searchpairpos", 3, 7, f_searchpairpos}, {"searchpos", 1, 4, f_searchpos}, -#ifdef FEAT_CHANNEL - {"sendexpr", 2, 3, f_sendexpr}, - {"sendraw", 2, 3, f_sendraw}, -#endif {"server2client", 2, 2, f_server2client}, {"serverlist", 0, 0, f_serverlist}, {"setbufvar", 3, 3, f_setbufvar}, @@ -9685,6 +9677,213 @@ f_ceil(typval_T *argvars, typval_T *rettv) } #endif +#ifdef FEAT_CHANNEL +/* + * Get the channel index from the handle argument. + * Returns -1 if the handle is invalid or the channel is closed. + */ + static int +get_channel_arg(typval_T *tv) +{ + int ch_idx; + + if (tv->v_type != VAR_NUMBER) + { + EMSG2(_(e_invarg2), get_tv_string(tv)); + return -1; + } + ch_idx = tv->vval.v_number; + + if (!channel_is_open(ch_idx)) + { + EMSGN(_("E906: not an open channel"), ch_idx); + return -1; + } + return ch_idx; +} + +/* + * "ch_close()" function + */ + static void +f_ch_close(typval_T *argvars, typval_T *rettv UNUSED) +{ + int ch_idx = get_channel_arg(&argvars[0]); + + if (ch_idx >= 0) + channel_close(ch_idx); +} + +/* + * Get a callback from "arg". It can be a Funcref or a function name. + * When "arg" is zero return an empty string. + * Return NULL for an invalid argument. + */ + static char_u * +get_callback(typval_T *arg) +{ + if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING) + return arg->vval.v_string; + if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0) + return (char_u *)""; + EMSG(_("E999: Invalid callback argument")); + return NULL; +} + +/* + * "ch_open()" function + */ + static void +f_ch_open(typval_T *argvars, typval_T *rettv) +{ + char_u *address; + char_u *mode; + char_u *callback = NULL; + char_u buf1[NUMBUFLEN]; + char_u *p; + int port; + int json_mode = FALSE; + + /* default: fail */ + rettv->vval.v_number = -1; + + address = get_tv_string(&argvars[0]); + mode = get_tv_string_buf(&argvars[1], buf1); + if (argvars[2].v_type != VAR_UNKNOWN) + { + callback = get_callback(&argvars[2]); + if (callback == NULL) + return; + } + + /* parse address */ + p = vim_strchr(address, ':'); + if (p == NULL) + { + EMSG2(_(e_invarg2), address); + return; + } + *p++ = NUL; + port = atoi((char *)p); + if (*address == NUL || port <= 0) + { + p[-1] = ':'; + EMSG2(_(e_invarg2), address); + return; + } + + /* parse mode */ + if (STRCMP(mode, "json") == 0) + json_mode = TRUE; + else if (STRCMP(mode, "raw") != 0) + { + EMSG2(_(e_invarg2), mode); + return; + } + + rettv->vval.v_number = channel_open((char *)address, port, NULL); + if (rettv->vval.v_number >= 0) + { + channel_set_json_mode(rettv->vval.v_number, json_mode); + if (callback != NULL && *callback != NUL) + channel_set_callback(rettv->vval.v_number, callback); + } +} + +/* + * common for "sendexpr()" and "sendraw()" + * Returns the channel index if the caller should read the response. + * Otherwise returns -1. + */ + static int +send_common(typval_T *argvars, char_u *text, char *fun) +{ + int ch_idx; + char_u *callback = NULL; + + ch_idx = get_channel_arg(&argvars[0]); + if (ch_idx < 0) + return -1; + + if (argvars[2].v_type != VAR_UNKNOWN) + { + callback = get_callback(&argvars[2]); + if (callback == NULL) + return -1; + } + /* Set the callback or clear it. An empty callback means no callback and + * not reading the response. */ + channel_set_req_callback(ch_idx, + callback != NULL && *callback == NUL ? NULL : callback); + + if (channel_send(ch_idx, text, fun) == OK && callback == NULL) + return ch_idx; + return -1; +} + +/* + * "ch_sendexpr()" function + */ + static void +f_ch_sendexpr(typval_T *argvars, typval_T *rettv) +{ + char_u *text; + typval_T *listtv; + int ch_idx; + int id; + + /* return an empty string by default */ + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + + id = channel_get_id(); + text = json_encode_nr_expr(id, &argvars[1]); + if (text == NULL) + return; + + ch_idx = send_common(argvars, text, "sendexpr"); + if (ch_idx >= 0) + { + if (channel_read_json_block(ch_idx, id, &listtv) == OK) + { + if (listtv->v_type == VAR_LIST) + { + list_T *list = listtv->vval.v_list; + + if (list->lv_len == 2) + { + /* Move the item from the list and then change the type to + * avoid the value being freed. */ + *rettv = list->lv_last->li_tv; + list->lv_last->li_tv.v_type = VAR_NUMBER; + } + } + clear_tv(listtv); + } + } +} + +/* + * "ch_sendraw()" function + */ + static void +f_ch_sendraw(typval_T *argvars, typval_T *rettv) +{ + char_u buf[NUMBUFLEN]; + char_u *text; + int ch_idx; + + /* return an empty string by default */ + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + + text = get_tv_string_buf(&argvars[1], buf); + ch_idx = send_common(argvars, text, "sendraw"); + if (ch_idx >= 0) + rettv->vval.v_string = channel_read_block(ch_idx); +} +#endif + /* * "changenr()" function */ @@ -10033,84 +10232,6 @@ f_count(typval_T *argvars, typval_T *rettv) rettv->vval.v_number = n; } -#ifdef FEAT_CHANNEL -/* - * Get a callback from "arg". It can be a Funcref or a function name. - * When "arg" is zero return an empty string. - * Return NULL for an invalid argument. - */ - static char_u * -get_callback(typval_T *arg) -{ - if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING) - return arg->vval.v_string; - if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0) - return (char_u *)""; - EMSG(_("E999: Invalid callback argument")); - return NULL; -} - -/* - * "connect()" function - */ - static void -f_connect(typval_T *argvars, typval_T *rettv) -{ - char_u *address; - char_u *mode; - char_u *callback = NULL; - char_u buf1[NUMBUFLEN]; - char_u *p; - int port; - int json_mode = FALSE; - - /* default: fail */ - rettv->vval.v_number = -1; - - address = get_tv_string(&argvars[0]); - mode = get_tv_string_buf(&argvars[1], buf1); - if (argvars[2].v_type != VAR_UNKNOWN) - { - callback = get_callback(&argvars[2]); - if (callback == NULL) - return; - } - - /* parse address */ - p = vim_strchr(address, ':'); - if (p == NULL) - { - EMSG2(_(e_invarg2), address); - return; - } - *p++ = NUL; - port = atoi((char *)p); - if (*address == NUL || port <= 0) - { - p[-1] = ':'; - EMSG2(_(e_invarg2), address); - return; - } - - /* parse mode */ - if (STRCMP(mode, "json") == 0) - json_mode = TRUE; - else if (STRCMP(mode, "raw") != 0) - { - EMSG2(_(e_invarg2), mode); - return; - } - - rettv->vval.v_number = channel_open((char *)address, port, NULL); - if (rettv->vval.v_number >= 0) - { - channel_set_json_mode(rettv->vval.v_number, json_mode); - if (callback != NULL && *callback != NUL) - channel_set_callback(rettv->vval.v_number, callback); - } -} -#endif - /* * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function * @@ -10349,44 +10470,6 @@ f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED) #endif } -#ifdef FEAT_CHANNEL -/* - * Get the channel index from the handle argument. - * Returns -1 if the handle is invalid or the channel is closed. - */ - static int -get_channel_arg(typval_T *tv) -{ - int ch_idx; - - if (tv->v_type != VAR_NUMBER) - { - EMSG2(_(e_invarg2), get_tv_string(tv)); - return -1; - } - ch_idx = tv->vval.v_number; - - if (!channel_is_open(ch_idx)) - { - EMSGN(_("E906: not an open channel"), ch_idx); - return -1; - } - return ch_idx; -} - -/* - * "disconnect()" function - */ - static void -f_disconnect(typval_T *argvars, typval_T *rettv UNUSED) -{ - int ch_idx = get_channel_arg(&argvars[0]); - - if (ch_idx >= 0) - channel_close(ch_idx); -} -#endif - /* * "empty({expr})" function */ @@ -16860,102 +16943,6 @@ f_searchpos(typval_T *argvars, typval_T *rettv) list_append_number(rettv->vval.v_list, (varnumber_T)n); } -#ifdef FEAT_CHANNEL -/* - * common for "sendexpr()" and "sendraw()" - * Returns the channel index if the caller should read the response. - * Otherwise returns -1. - */ - static int -send_common(typval_T *argvars, char_u *text, char *fun) -{ - int ch_idx; - char_u *callback = NULL; - - ch_idx = get_channel_arg(&argvars[0]); - if (ch_idx < 0) - return -1; - - if (argvars[2].v_type != VAR_UNKNOWN) - { - callback = get_callback(&argvars[2]); - if (callback == NULL) - return -1; - } - /* Set the callback or clear it. An empty callback means no callback and - * not reading the response. */ - channel_set_req_callback(ch_idx, - callback != NULL && *callback == NUL ? NULL : callback); - - if (channel_send(ch_idx, text, fun) == OK && callback == NULL) - return ch_idx; - return -1; -} - -/* - * "sendexpr()" function - */ - static void -f_sendexpr(typval_T *argvars, typval_T *rettv) -{ - char_u *text; - typval_T *listtv; - int ch_idx; - int id; - - /* return an empty string by default */ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - - id = channel_get_id(); - text = json_encode_nr_expr(id, &argvars[1]); - if (text == NULL) - return; - - ch_idx = send_common(argvars, text, "sendexpr"); - if (ch_idx >= 0) - { - if (channel_read_json_block(ch_idx, id, &listtv) == OK) - { - if (listtv->v_type == VAR_LIST) - { - list_T *list = listtv->vval.v_list; - - if (list->lv_len == 2) - { - /* Move the item from the list and then change the type to - * avoid the value being freed. */ - *rettv = list->lv_last->li_tv; - list->lv_last->li_tv.v_type = VAR_NUMBER; - } - } - clear_tv(listtv); - } - } -} - -/* - * "sendraw()" function - */ - static void -f_sendraw(typval_T *argvars, typval_T *rettv) -{ - char_u buf[NUMBUFLEN]; - char_u *text; - int ch_idx; - - /* return an empty string by default */ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; - - text = get_tv_string_buf(&argvars[1], buf); - ch_idx = send_common(argvars, text, "sendraw"); - if (ch_idx >= 0) - rettv->vval.v_string = channel_read_block(ch_idx); -} -#endif - - static void f_server2client(typval_T *argvars UNUSED, typval_T *rettv) { diff --git a/src/version.c b/src/version.c index 34922b6ea..1676415e7 100644 --- a/src/version.c +++ b/src/version.c @@ -743,6 +743,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1244, +/**/ 1243, /**/ 1242, |