Mercurial > vim
comparison src/eval.c @ 7788:192ae655ac91 v7.4.1191
commit https://github.com/vim/vim/commit/3b5f929b18492fec291d1ec95a91f54e5912c03b
Author: Bram Moolenaar <Bram@vim.org>
Date: Thu Jan 28 22:37:01 2016 +0100
patch 7.4.1191
Problem: The channel feature isn't working yet.
Solution: Add the connect(), disconnect(), sendexpr() and sendraw()
functions. Add initial documentation. Add a demo server.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Thu, 28 Jan 2016 22:45:04 +0100 |
parents | 3d8e4e0d7127 |
children | 83861277e6a3 |
comparison
equal
deleted
inserted
replaced
7787:a0ae64e7006f | 7788:192ae655ac91 |
---|---|
456 static char_u *string_quote(char_u *str, int function); | 456 static char_u *string_quote(char_u *str, int function); |
457 static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate); | 457 static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate); |
458 static int find_internal_func(char_u *name); | 458 static int find_internal_func(char_u *name); |
459 static char_u *deref_func_name(char_u *name, int *lenp, int no_autoload); | 459 static char_u *deref_func_name(char_u *name, int *lenp, int no_autoload); |
460 static int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, dict_T *selfdict); | 460 static int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, dict_T *selfdict); |
461 static int call_func(char_u *funcname, int len, typval_T *rettv, int argcount, typval_T *argvars, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, dict_T *selfdict); | |
462 static void emsg_funcname(char *ermsg, char_u *name); | 461 static void emsg_funcname(char *ermsg, char_u *name); |
463 static int non_zero_arg(typval_T *argvars); | 462 static int non_zero_arg(typval_T *argvars); |
464 | 463 |
465 #ifdef FEAT_FLOAT | 464 #ifdef FEAT_FLOAT |
466 static void f_abs(typval_T *argvars, typval_T *rettv); | 465 static void f_abs(typval_T *argvars, typval_T *rettv); |
514 static void f_copy(typval_T *argvars, typval_T *rettv); | 513 static void f_copy(typval_T *argvars, typval_T *rettv); |
515 #ifdef FEAT_FLOAT | 514 #ifdef FEAT_FLOAT |
516 static void f_cos(typval_T *argvars, typval_T *rettv); | 515 static void f_cos(typval_T *argvars, typval_T *rettv); |
517 static void f_cosh(typval_T *argvars, typval_T *rettv); | 516 static void f_cosh(typval_T *argvars, typval_T *rettv); |
518 #endif | 517 #endif |
518 #ifdef FEAT_CHANNEL | |
519 static void f_connect(typval_T *argvars, typval_T *rettv); | |
520 #endif | |
519 static void f_count(typval_T *argvars, typval_T *rettv); | 521 static void f_count(typval_T *argvars, typval_T *rettv); |
520 static void f_cscope_connection(typval_T *argvars, typval_T *rettv); | 522 static void f_cscope_connection(typval_T *argvars, typval_T *rettv); |
521 static void f_cursor(typval_T *argsvars, typval_T *rettv); | 523 static void f_cursor(typval_T *argsvars, typval_T *rettv); |
522 static void f_deepcopy(typval_T *argvars, typval_T *rettv); | 524 static void f_deepcopy(typval_T *argvars, typval_T *rettv); |
523 static void f_delete(typval_T *argvars, typval_T *rettv); | 525 static void f_delete(typval_T *argvars, typval_T *rettv); |
524 static void f_did_filetype(typval_T *argvars, typval_T *rettv); | 526 static void f_did_filetype(typval_T *argvars, typval_T *rettv); |
525 static void f_diff_filler(typval_T *argvars, typval_T *rettv); | 527 static void f_diff_filler(typval_T *argvars, typval_T *rettv); |
526 static void f_diff_hlID(typval_T *argvars, typval_T *rettv); | 528 static void f_diff_hlID(typval_T *argvars, typval_T *rettv); |
529 #ifdef FEAT_CHANNEL | |
530 static void f_disconnect(typval_T *argvars, typval_T *rettv); | |
531 #endif | |
527 static void f_empty(typval_T *argvars, typval_T *rettv); | 532 static void f_empty(typval_T *argvars, typval_T *rettv); |
528 static void f_escape(typval_T *argvars, typval_T *rettv); | 533 static void f_escape(typval_T *argvars, typval_T *rettv); |
529 static void f_eval(typval_T *argvars, typval_T *rettv); | 534 static void f_eval(typval_T *argvars, typval_T *rettv); |
530 static void f_eventhandler(typval_T *argvars, typval_T *rettv); | 535 static void f_eventhandler(typval_T *argvars, typval_T *rettv); |
531 static void f_executable(typval_T *argvars, typval_T *rettv); | 536 static void f_executable(typval_T *argvars, typval_T *rettv); |
696 static void f_search(typval_T *argvars, typval_T *rettv); | 701 static void f_search(typval_T *argvars, typval_T *rettv); |
697 static void f_searchdecl(typval_T *argvars, typval_T *rettv); | 702 static void f_searchdecl(typval_T *argvars, typval_T *rettv); |
698 static void f_searchpair(typval_T *argvars, typval_T *rettv); | 703 static void f_searchpair(typval_T *argvars, typval_T *rettv); |
699 static void f_searchpairpos(typval_T *argvars, typval_T *rettv); | 704 static void f_searchpairpos(typval_T *argvars, typval_T *rettv); |
700 static void f_searchpos(typval_T *argvars, typval_T *rettv); | 705 static void f_searchpos(typval_T *argvars, typval_T *rettv); |
706 #ifdef FEAT_CHANNEL | |
707 static void f_sendexpr(typval_T *argvars, typval_T *rettv); | |
708 static void f_sendraw(typval_T *argvars, typval_T *rettv); | |
709 #endif | |
701 static void f_server2client(typval_T *argvars, typval_T *rettv); | 710 static void f_server2client(typval_T *argvars, typval_T *rettv); |
702 static void f_serverlist(typval_T *argvars, typval_T *rettv); | 711 static void f_serverlist(typval_T *argvars, typval_T *rettv); |
703 static void f_setbufvar(typval_T *argvars, typval_T *rettv); | 712 static void f_setbufvar(typval_T *argvars, typval_T *rettv); |
704 static void f_setcharsearch(typval_T *argvars, typval_T *rettv); | 713 static void f_setcharsearch(typval_T *argvars, typval_T *rettv); |
705 static void f_setcmdpos(typval_T *argvars, typval_T *rettv); | 714 static void f_setcmdpos(typval_T *argvars, typval_T *rettv); |
8168 {"complete", 2, 2, f_complete}, | 8177 {"complete", 2, 2, f_complete}, |
8169 {"complete_add", 1, 1, f_complete_add}, | 8178 {"complete_add", 1, 1, f_complete_add}, |
8170 {"complete_check", 0, 0, f_complete_check}, | 8179 {"complete_check", 0, 0, f_complete_check}, |
8171 #endif | 8180 #endif |
8172 {"confirm", 1, 4, f_confirm}, | 8181 {"confirm", 1, 4, f_confirm}, |
8182 #ifdef FEAT_CHANNEL | |
8183 {"connect", 2, 3, f_connect}, | |
8184 #endif | |
8173 {"copy", 1, 1, f_copy}, | 8185 {"copy", 1, 1, f_copy}, |
8174 #ifdef FEAT_FLOAT | 8186 #ifdef FEAT_FLOAT |
8175 {"cos", 1, 1, f_cos}, | 8187 {"cos", 1, 1, f_cos}, |
8176 {"cosh", 1, 1, f_cosh}, | 8188 {"cosh", 1, 1, f_cosh}, |
8177 #endif | 8189 #endif |
8181 {"deepcopy", 1, 2, f_deepcopy}, | 8193 {"deepcopy", 1, 2, f_deepcopy}, |
8182 {"delete", 1, 2, f_delete}, | 8194 {"delete", 1, 2, f_delete}, |
8183 {"did_filetype", 0, 0, f_did_filetype}, | 8195 {"did_filetype", 0, 0, f_did_filetype}, |
8184 {"diff_filler", 1, 1, f_diff_filler}, | 8196 {"diff_filler", 1, 1, f_diff_filler}, |
8185 {"diff_hlID", 2, 2, f_diff_hlID}, | 8197 {"diff_hlID", 2, 2, f_diff_hlID}, |
8198 #ifdef FEAT_CHANNEL | |
8199 {"disconnect", 1, 1, f_disconnect}, | |
8200 #endif | |
8186 {"empty", 1, 1, f_empty}, | 8201 {"empty", 1, 1, f_empty}, |
8187 {"escape", 2, 2, f_escape}, | 8202 {"escape", 2, 2, f_escape}, |
8188 {"eval", 1, 1, f_eval}, | 8203 {"eval", 1, 1, f_eval}, |
8189 {"eventhandler", 0, 0, f_eventhandler}, | 8204 {"eventhandler", 0, 0, f_eventhandler}, |
8190 {"executable", 1, 1, f_executable}, | 8205 {"executable", 1, 1, f_executable}, |
8359 {"search", 1, 4, f_search}, | 8374 {"search", 1, 4, f_search}, |
8360 {"searchdecl", 1, 3, f_searchdecl}, | 8375 {"searchdecl", 1, 3, f_searchdecl}, |
8361 {"searchpair", 3, 7, f_searchpair}, | 8376 {"searchpair", 3, 7, f_searchpair}, |
8362 {"searchpairpos", 3, 7, f_searchpairpos}, | 8377 {"searchpairpos", 3, 7, f_searchpairpos}, |
8363 {"searchpos", 1, 4, f_searchpos}, | 8378 {"searchpos", 1, 4, f_searchpos}, |
8379 #ifdef FEAT_CHANNEL | |
8380 {"sendexpr", 2, 3, f_sendexpr}, | |
8381 {"sendraw", 2, 3, f_sendraw}, | |
8382 #endif | |
8364 {"server2client", 2, 2, f_server2client}, | 8383 {"server2client", 2, 2, f_server2client}, |
8365 {"serverlist", 0, 0, f_serverlist}, | 8384 {"serverlist", 0, 0, f_serverlist}, |
8366 {"setbufvar", 3, 3, f_setbufvar}, | 8385 {"setbufvar", 3, 3, f_setbufvar}, |
8367 {"setcharsearch", 1, 1, f_setcharsearch}, | 8386 {"setcharsearch", 1, 1, f_setcharsearch}, |
8368 {"setcmdpos", 1, 1, f_setcmdpos}, | 8387 {"setcmdpos", 1, 1, f_setcmdpos}, |
8672 /* | 8691 /* |
8673 * Call a function with its resolved parameters | 8692 * Call a function with its resolved parameters |
8674 * Return FAIL when the function can't be called, OK otherwise. | 8693 * Return FAIL when the function can't be called, OK otherwise. |
8675 * Also returns OK when an error was encountered while executing the function. | 8694 * Also returns OK when an error was encountered while executing the function. |
8676 */ | 8695 */ |
8677 static int | 8696 int |
8678 call_func(funcname, len, rettv, argcount, argvars, firstline, lastline, | 8697 call_func(funcname, len, rettv, argcount, argvars, firstline, lastline, |
8679 doesrange, evaluate, selfdict) | 8698 doesrange, evaluate, selfdict) |
8680 char_u *funcname; /* name of the function */ | 8699 char_u *funcname; /* name of the function */ |
8681 int len; /* length of "name" */ | 8700 int len; /* length of "name" */ |
8682 typval_T *rettv; /* return value goes here */ | 8701 typval_T *rettv; /* return value goes here */ |
10291 else | 10310 else |
10292 EMSG2(_(e_listdictarg), "count()"); | 10311 EMSG2(_(e_listdictarg), "count()"); |
10293 rettv->vval.v_number = n; | 10312 rettv->vval.v_number = n; |
10294 } | 10313 } |
10295 | 10314 |
10315 #ifdef FEAT_CHANNEL | |
10316 /* | |
10317 * Get a callback from "arg". It can be a Funcref or a function name. | |
10318 * When "arg" is zero return an empty string. | |
10319 * Return NULL for an invalid argument. | |
10320 */ | |
10321 static char_u * | |
10322 get_callback(typval_T *arg) | |
10323 { | |
10324 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING) | |
10325 return arg->vval.v_string; | |
10326 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0) | |
10327 return (char_u *)""; | |
10328 EMSG(_("E999: Invalid callback argument")); | |
10329 return NULL; | |
10330 } | |
10331 | |
10332 /* | |
10333 * "connect()" function | |
10334 */ | |
10335 static void | |
10336 f_connect(argvars, rettv) | |
10337 typval_T *argvars; | |
10338 typval_T *rettv; | |
10339 { | |
10340 char_u *address; | |
10341 char_u *mode; | |
10342 char_u *callback = NULL; | |
10343 char_u buf1[NUMBUFLEN]; | |
10344 char_u *p; | |
10345 int port; | |
10346 int json_mode = FALSE; | |
10347 | |
10348 address = get_tv_string(&argvars[0]); | |
10349 mode = get_tv_string_buf(&argvars[1], buf1); | |
10350 if (argvars[2].v_type != VAR_UNKNOWN) | |
10351 { | |
10352 callback = get_callback(&argvars[2]); | |
10353 if (callback == NULL) | |
10354 return; | |
10355 } | |
10356 | |
10357 /* parse address */ | |
10358 p = vim_strchr(address, ':'); | |
10359 if (p == NULL) | |
10360 { | |
10361 EMSG2(_(e_invarg2), address); | |
10362 return; | |
10363 } | |
10364 *p++ = NUL; | |
10365 port = atoi((char *)p); | |
10366 if (*address == NUL || port <= 0) | |
10367 { | |
10368 p[-1] = ':'; | |
10369 EMSG2(_(e_invarg2), address); | |
10370 return; | |
10371 } | |
10372 | |
10373 /* parse mode */ | |
10374 if (STRCMP(mode, "json") == 0) | |
10375 json_mode = TRUE; | |
10376 else if (STRCMP(mode, "raw") != 0) | |
10377 { | |
10378 EMSG2(_(e_invarg2), mode); | |
10379 return; | |
10380 } | |
10381 | |
10382 rettv->vval.v_number = channel_open((char *)address, port, NULL); | |
10383 if (rettv->vval.v_number >= 0) | |
10384 { | |
10385 channel_set_json_mode(rettv->vval.v_number, json_mode); | |
10386 if (callback != NULL && *callback != NUL) | |
10387 channel_set_callback(rettv->vval.v_number, callback); | |
10388 } | |
10389 } | |
10390 #endif | |
10391 | |
10296 /* | 10392 /* |
10297 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function | 10393 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function |
10298 * | 10394 * |
10299 * Checks the existence of a cscope connection. | 10395 * Checks the existence of a cscope connection. |
10300 */ | 10396 */ |
10542 hlID = HLF_CHD; /* changed line */ | 10638 hlID = HLF_CHD; /* changed line */ |
10543 } | 10639 } |
10544 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID; | 10640 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID; |
10545 #endif | 10641 #endif |
10546 } | 10642 } |
10643 | |
10644 #ifdef FEAT_CHANNEL | |
10645 /* | |
10646 * Get the channel index from the handle argument. | |
10647 * Returns -1 if the handle is invalid or the channel is closed. | |
10648 */ | |
10649 static int | |
10650 get_channel_arg(typval_T *tv) | |
10651 { | |
10652 int ch_idx; | |
10653 | |
10654 if (tv->v_type != VAR_NUMBER) | |
10655 { | |
10656 EMSG2(_(e_invarg2), get_tv_string(tv)); | |
10657 return -1; | |
10658 } | |
10659 ch_idx = tv->vval.v_number; | |
10660 | |
10661 if (!channel_is_open(ch_idx)) | |
10662 { | |
10663 EMSGN(_("E999: not an open channel"), ch_idx); | |
10664 return -1; | |
10665 } | |
10666 return ch_idx; | |
10667 } | |
10668 | |
10669 /* | |
10670 * "disconnect()" function | |
10671 */ | |
10672 static void | |
10673 f_disconnect(argvars, rettv) | |
10674 typval_T *argvars; | |
10675 typval_T *rettv UNUSED; | |
10676 { | |
10677 int ch_idx = get_channel_arg(&argvars[0]); | |
10678 | |
10679 if (ch_idx >= 0) | |
10680 channel_close(ch_idx); | |
10681 } | |
10682 #endif | |
10547 | 10683 |
10548 /* | 10684 /* |
10549 * "empty({expr})" function | 10685 * "empty({expr})" function |
10550 */ | 10686 */ |
10551 static void | 10687 static void |
17375 list_append_number(rettv->vval.v_list, (varnumber_T)lnum); | 17511 list_append_number(rettv->vval.v_list, (varnumber_T)lnum); |
17376 list_append_number(rettv->vval.v_list, (varnumber_T)col); | 17512 list_append_number(rettv->vval.v_list, (varnumber_T)col); |
17377 if (flags & SP_SUBPAT) | 17513 if (flags & SP_SUBPAT) |
17378 list_append_number(rettv->vval.v_list, (varnumber_T)n); | 17514 list_append_number(rettv->vval.v_list, (varnumber_T)n); |
17379 } | 17515 } |
17516 | |
17517 #ifdef FEAT_CHANNEL | |
17518 /* | |
17519 * common for "sendexpr()" and "sendraw()" | |
17520 * Returns the channel index if the caller should read the response. | |
17521 * Otherwise returns -1. | |
17522 */ | |
17523 static int | |
17524 send_common(typval_T *argvars, char_u *text, char *fun) | |
17525 { | |
17526 int ch_idx; | |
17527 char_u *callback = NULL; | |
17528 | |
17529 ch_idx = get_channel_arg(&argvars[0]); | |
17530 if (ch_idx < 0) | |
17531 return -1; | |
17532 | |
17533 if (argvars[2].v_type != VAR_UNKNOWN) | |
17534 { | |
17535 callback = get_callback(&argvars[2]); | |
17536 if (callback == NULL) | |
17537 return -1; | |
17538 } | |
17539 /* Set the callback or clear it. An empty callback means no callback and | |
17540 * not reading the response. */ | |
17541 channel_set_req_callback(ch_idx, | |
17542 callback != NULL && *callback == NUL ? NULL : callback); | |
17543 if (callback == NULL) | |
17544 channel_will_block(ch_idx); | |
17545 | |
17546 if (channel_send(ch_idx, text, fun) == OK && callback == NULL) | |
17547 return ch_idx; | |
17548 return -1; | |
17549 } | |
17550 | |
17551 /* | |
17552 * "sendexpr()" function | |
17553 */ | |
17554 static void | |
17555 f_sendexpr(argvars, rettv) | |
17556 typval_T *argvars; | |
17557 typval_T *rettv; | |
17558 { | |
17559 char_u *text; | |
17560 char_u *resp; | |
17561 typval_T nrtv; | |
17562 typval_T listtv; | |
17563 int ch_idx; | |
17564 | |
17565 /* return an empty string by default */ | |
17566 rettv->v_type = VAR_STRING; | |
17567 rettv->vval.v_string = NULL; | |
17568 | |
17569 nrtv.v_type = VAR_NUMBER; | |
17570 nrtv.vval.v_number = channel_get_id(); | |
17571 if (rettv_list_alloc(&listtv) == FAIL) | |
17572 return; | |
17573 if (list_append_tv(listtv.vval.v_list, &nrtv) == FAIL | |
17574 || list_append_tv(listtv.vval.v_list, &argvars[1]) == FAIL) | |
17575 { | |
17576 list_unref(listtv.vval.v_list); | |
17577 return; | |
17578 } | |
17579 | |
17580 text = json_encode(&listtv); | |
17581 list_unref(listtv.vval.v_list); | |
17582 | |
17583 ch_idx = send_common(argvars, text, "sendexpr"); | |
17584 if (ch_idx >= 0) | |
17585 { | |
17586 /* TODO: read until the whole JSON message is received */ | |
17587 /* TODO: only use the message with the right message ID */ | |
17588 resp = channel_read_block(ch_idx); | |
17589 if (resp != NULL) | |
17590 { | |
17591 channel_decode_json(resp, rettv); | |
17592 vim_free(resp); | |
17593 } | |
17594 } | |
17595 } | |
17596 | |
17597 /* | |
17598 * "sendraw()" function | |
17599 */ | |
17600 static void | |
17601 f_sendraw(argvars, rettv) | |
17602 typval_T *argvars; | |
17603 typval_T *rettv; | |
17604 { | |
17605 char_u buf[NUMBUFLEN]; | |
17606 char_u *text; | |
17607 int ch_idx; | |
17608 | |
17609 /* return an empty string by default */ | |
17610 rettv->v_type = VAR_STRING; | |
17611 rettv->vval.v_string = NULL; | |
17612 | |
17613 text = get_tv_string_buf(&argvars[1], buf); | |
17614 ch_idx = send_common(argvars, text, "sendraw"); | |
17615 if (ch_idx >= 0) | |
17616 rettv->vval.v_string = channel_read_block(ch_idx); | |
17617 } | |
17618 #endif | |
17380 | 17619 |
17381 | 17620 |
17382 static void | 17621 static void |
17383 f_server2client(argvars, rettv) | 17622 f_server2client(argvars, rettv) |
17384 typval_T *argvars UNUSED; | 17623 typval_T *argvars UNUSED; |