To: vim_dev@googlegroups.com Subject: Patch 7.4.1244 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.1244 Problem: The channel functions don't sort together. Solution: Use a common "ch_" prefix. Files: src/eval.c, runtime/doc/eval.txt, runtime/tools/demoserver.py *** ../vim-7.4.1243/src/eval.c 2016-02-02 18:19:52.794743928 +0100 --- src/eval.c 2016-02-02 20:08:47.570922261 +0100 *************** *** 499,504 **** --- 499,510 ---- #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,523 **** 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); --- 521,526 ---- *************** *** 526,534 **** 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); --- 529,534 ---- *************** *** 703,712 **** 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); --- 703,708 ---- *************** *** 8003,8008 **** --- 7999,8010 ---- #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,8022 **** {"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}, --- 8016,8021 ---- *************** *** 8030,8038 **** {"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}, --- 8029,8034 ---- *************** *** 8211,8220 **** {"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}, --- 8207,8212 ---- *************** *** 9685,9690 **** --- 9677,9889 ---- } #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,10116 **** 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 * --- 10232,10237 ---- *************** *** 10349,10392 **** #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 */ --- 10470,10475 ---- *************** *** 16860,16961 **** 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) { --- 16943,16948 ---- *** ../vim-7.4.1243/runtime/doc/eval.txt 2016-01-28 22:36:15.056065002 +0100 --- runtime/doc/eval.txt 2016-02-02 19:59:46.840542732 +0100 *************** *** 1785,1790 **** --- 1810,1822 ---- 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} *************** *** 1795,1802 **** 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} --- 1827,1832 ---- *************** *** 2004,2013 **** 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 --- 2034,2039 ---- *************** *** 2637,2644 **** don't fit, a vertical layout is used anyway. For some systems the horizontal layout is always used. ! connect({address}, {mode} [, {callback}]) *connect()* Open a channel to {address}. See |channel|. {address} has the form "hostname:port", e.g., "localhost:8765". --- 2667,2679 ---- 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_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. {address} has the form "hostname:port", e.g., "localhost:8765". *************** *** 2649,2654 **** --- 2684,2706 ---- {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. *************** *** 5552,5574 **** < 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(""). --- 5636,5641 ---- *** ../vim-7.4.1243/runtime/tools/demoserver.py 2016-02-01 22:01:06.044672631 +0100 --- runtime/tools/demoserver.py 2016-02-02 20:01:33.583433236 +0100 *************** *** 1,15 **** #!/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') # # Then Vim can send requests to the server: ! # :let response = sendexpr(handle, 'hello!') # # And you can control Vim by typing a JSON message here, e.g.: # ["ex","echo 'hi there'"] # # See ":help channel-demo" in Vim. from __future__ import print_function import json --- 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 = ch_open('localhost:8765', 'json') # # Then Vim can send requests to the server: ! # :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". + # # See ":help channel-demo" in Vim. + # + # This requires Python 2.6 or later. from __future__ import print_function import json *** ../vim-7.4.1243/src/version.c 2016-02-02 19:43:53.046456217 +0100 --- src/version.c 2016-02-02 19:45:39.481349993 +0100 *************** *** 744,745 **** --- 744,747 ---- { /* Add new patch number below this line */ + /**/ + 1244, /**/ -- hundred-and-one symptoms of being an internet addict: 114. You are counting items, you go "0,1,2,3,4,5,6,7,8,9,A,B,C,D...". /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///