Skip to content

Commit fb1f626

Browse files
committed
patch 7.4.1229
Problem: "eval" and "expr" channel commands don't work yet. Solution: Implement them. Update the error numbers. Also add "redraw".
1 parent 1555000 commit fb1f626

9 files changed

Lines changed: 207 additions & 78 deletions

File tree

runtime/doc/channel.txt

Lines changed: 66 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*channel.txt* For Vim version 7.4. Last change: 2016 Jan 28
1+
*channel.txt* For Vim version 7.4. Last change: 2016 Jan 31
22

33

44
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -48,10 +48,10 @@ And the response is:
4848
The number will increase every time you send a message.
4949

5050
The server can send a command to Vim. Type this on T1 (literally, including
51-
the quotes): >
52-
NOT IMPLEMENTED YET
53-
["ex","echo 'hi there'"]
54-
And you should see the message in Vim.
51+
the quotes):
52+
["ex","echo 'hi there'"] ~
53+
And you should see the message in Vim. You can move the cursor a word forward:
54+
["normal","w"] ~
5555

5656
To handle asynchronous communication a callback needs to be used: >
5757
func MyHandler(handle, msg)
@@ -100,6 +100,14 @@ When {callback} is empty (zero or an empty string) the handler is removed.
100100
Once done with the channel, disconnect it like this: >
101101
call disconnect(handle)
102102
103+
Currently up to 10 channels can be in use at the same time. *E897*
104+
105+
When the channel can't be opened you will get an error message.
106+
*E898* *E899* *E900* *E901* *E902*
107+
108+
If there is an error reading or writing a channel it will be closed.
109+
*E896* *E630* *E631*
110+
103111
==============================================================================
104112
3. Using a JSON channel *channel-use*
105113

@@ -146,36 +154,77 @@ The channel will then be inactive.
146154
==============================================================================
147155
4. Vim commands *channel-commands*
148156

149-
NOT IMPLEMENTED YET
157+
PARTLY IMPLEMENTED: only "ex" and "normal" work
150158

151159
With a "json" channel the process can send commands to Vim that will be
152160
handled by Vim internally, it does not require a handler for the channel.
153161

154-
Possible commands are:
162+
Possible commands are: *E903* *E904* *E905*
163+
["redraw" {forced}]
155164
["ex", {Ex command}]
156165
["normal", {Normal mode command}]
157-
["eval", {number}, {expression}]
166+
["eval", {expression}, {number}]
158167
["expr", {expression}]
159168

160169
With all of these: Be careful what these commands do! You can easily
161170
interfere with what the user is doing. To avoid trouble use |mode()| to check
162171
that the editor is in the expected state. E.g., to send keys that must be
163-
inserted as text, not executed as a command: >
164-
["ex","if mode() == 'i' | call feedkeys('ClassName') | endif"]
172+
inserted as text, not executed as a command:
173+
["ex","if mode() == 'i' | call feedkeys('ClassName') | endif"] ~
174+
175+
Errors in these commands are normally not reported to avoid them messing up
176+
the display. If you do want to see them, set the 'verbose' option to 3 or
177+
higher.
178+
179+
180+
Command "redraw" ~
181+
182+
The other commands do not update the screen, so that you can send a sequence
183+
of commands without the cursor moving around. You must end with the "redraw"
184+
command to show any changed text and show the cursor where it belongs.
185+
186+
The argument is normally an empty string:
187+
["redraw", ""] ~
188+
To first clear the screen pass "force":
189+
["redraw", "force"] ~
190+
191+
192+
Command "ex" ~
165193

166194
The "ex" command is executed as any Ex command. There is no response for
167-
completion or error. You could use functions in an |autoload| script.
168-
You can also invoke |feedkeys()| to insert anything.
195+
completion or error. You could use functions in an |autoload| script:
196+
["ex","call myscript#MyFunc(arg)"]
197+
198+
You can also use "call |feedkeys()|" to insert any key sequence.
199+
200+
201+
Command "normal" ~
202+
203+
The "normal" command is executed like with |:normal!|, commands are not
204+
mapped. Example to open the folds under the cursor:
205+
["normal" "zO"]
169206

170-
The "normal" command is executed like with |:normal|.
171207

172-
The "eval" command will result in sending back the result of the expression:
208+
Command "eval" ~
209+
210+
The "eval" command an be used to get the result of an expression. For
211+
example, to get the number of lines in the current buffer:
212+
["eval","line('$')"] ~
213+
214+
it will send back the result of the expression:
173215
[{number}, {result}]
174-
Here {number} is the same as what was in the request.
216+
Here {number} is the same as what was in the request. Use a negative number
217+
to avoid confusion with message that Vim sends.
218+
219+
{result} is the result of the evaluation and is JSON encoded. If the
220+
evaluation fails it is the string "ERROR".
221+
222+
223+
Command "expr" ~
175224

176-
The "expr" command is similar, but does not send back any response.
225+
The "expr" command is similar to "eval", but does not send back any response.
177226
Example:
178-
["expr","setline('$', ['one', 'two', 'three'])"]
227+
["expr","setline('$', ['one', 'two', 'three'])"] ~
179228

180229
==============================================================================
181230
5. Using a raw channel *channel-raw*

src/channel.c

Lines changed: 105 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -293,14 +293,14 @@ channel_open(char *hostname, int port_in, void (*close_cb)(void))
293293
if (idx < 0)
294294
{
295295
CHERROR("All channels are in use\n", "");
296-
EMSG(_("E999: All channels are in use"));
296+
EMSG(_("E897: All channels are in use"));
297297
return -1;
298298
}
299299

300300
if ((sd = (sock_T)socket(AF_INET, SOCK_STREAM, 0)) == (sock_T)-1)
301301
{
302302
CHERROR("error in socket() in channel_open()\n", "");
303-
PERROR("E999: socket() in channel_open()");
303+
PERROR("E898: socket() in channel_open()");
304304
return -1;
305305
}
306306

@@ -312,7 +312,7 @@ channel_open(char *hostname, int port_in, void (*close_cb)(void))
312312
if ((host = gethostbyname(hostname)) == NULL)
313313
{
314314
CHERROR("error in gethostbyname() in channel_open()\n", "");
315-
PERROR("E999: gethostbyname() in channel_open()");
315+
PERROR("E901: gethostbyname() in channel_open()");
316316
sock_close(sd);
317317
return -1;
318318
}
@@ -330,7 +330,7 @@ channel_open(char *hostname, int port_in, void (*close_cb)(void))
330330
{
331331
SOCK_ERRNO;
332332
CHERROR("socket() retry in channel_open()\n", "");
333-
PERROR("E999: socket() retry in channel_open()");
333+
PERROR("E900: socket() retry in channel_open()");
334334
return -1;
335335
}
336336
if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
@@ -362,7 +362,7 @@ channel_open(char *hostname, int port_in, void (*close_cb)(void))
362362
{
363363
/* Get here when the server can't be found. */
364364
CHERROR("Cannot connect to port after retry\n", "");
365-
PERROR(_("E999: Cannot connect to port after retry2"));
365+
PERROR(_("E899: Cannot connect to port after retry2"));
366366
sock_close(sd);
367367
return -1;
368368
}
@@ -371,7 +371,7 @@ channel_open(char *hostname, int port_in, void (*close_cb)(void))
371371
else
372372
{
373373
CHERROR("Cannot connect to port\n", "");
374-
PERROR(_("E999: Cannot connect to port"));
374+
PERROR(_("E902: Cannot connect to port"));
375375
sock_close(sd);
376376
return -1;
377377
}
@@ -418,13 +418,15 @@ channel_set_req_callback(int idx, char_u *callback)
418418
}
419419

420420
/*
421-
* Decode JSON "msg", which must have the form "[expr1, expr2]".
421+
* Decode JSON "msg", which must have the form "[expr1, expr2, expr3]".
422422
* Put "expr1" in "tv1".
423423
* Put "expr2" in "tv2".
424+
* Put "expr3" in "tv3". If "tv3" is NULL there is no "expr3".
425+
*
424426
* Return OK or FAIL.
425427
*/
426428
int
427-
channel_decode_json(char_u *msg, typval_T *tv1, typval_T *tv2)
429+
channel_decode_json(char_u *msg, typval_T *tv1, typval_T *tv2, typval_T *tv3)
428430
{
429431
js_read_T reader;
430432
typval_T listtv;
@@ -434,16 +436,31 @@ channel_decode_json(char_u *msg, typval_T *tv1, typval_T *tv2)
434436
reader.js_used = 0;
435437
json_decode(&reader, &listtv);
436438

437-
if (listtv.v_type == VAR_LIST && listtv.vval.v_list->lv_len == 2)
439+
if (listtv.v_type == VAR_LIST)
438440
{
439-
/* Move the item from the list and then change the type to avoid the
440-
* item being freed. */
441-
*tv1 = listtv.vval.v_list->lv_first->li_tv;
442-
listtv.vval.v_list->lv_first->li_tv.v_type = VAR_NUMBER;
443-
*tv2 = listtv.vval.v_list->lv_last->li_tv;
444-
listtv.vval.v_list->lv_last->li_tv.v_type = VAR_NUMBER;
445-
list_unref(listtv.vval.v_list);
446-
return OK;
441+
list_T *list = listtv.vval.v_list;
442+
443+
if (list->lv_len == 2 || (tv3 != NULL && list->lv_len == 3))
444+
{
445+
/* Move the item from the list and then change the type to avoid the
446+
* item being freed. */
447+
*tv1 = list->lv_first->li_tv;
448+
list->lv_first->li_tv.v_type = VAR_NUMBER;
449+
*tv2 = list->lv_first->li_next->li_tv;
450+
list->lv_first->li_next->li_tv.v_type = VAR_NUMBER;
451+
if (tv3 != NULL)
452+
{
453+
if (list->lv_len == 3)
454+
{
455+
*tv3 = list->lv_last->li_tv;
456+
list->lv_last->li_tv.v_type = VAR_NUMBER;
457+
}
458+
else
459+
tv3->v_type = VAR_UNKNOWN;
460+
}
461+
list_unref(list);
462+
return OK;
463+
}
447464
}
448465

449466
/* give error message? */
@@ -472,44 +489,86 @@ invoke_callback(int idx, char_u *callback, typval_T *argv)
472489
out_flush();
473490
}
474491

492+
/*
493+
* Execute a command received over channel "idx".
494+
* "cmd" is the command string, "arg2" the second argument.
495+
* "arg3" is the third argument, NULL if missing.
496+
*/
475497
static void
476-
channel_exe_cmd(char_u *cmd, typval_T *arg)
498+
channel_exe_cmd(int idx, char_u *cmd, typval_T *arg2, typval_T *arg3)
477499
{
500+
char_u *arg;
501+
502+
if (arg2->v_type != VAR_STRING)
503+
{
504+
if (p_verbose > 2)
505+
EMSG("E903: received ex command with non-string argument");
506+
return;
507+
}
508+
arg = arg2->vval.v_string;
509+
478510
if (STRCMP(cmd, "ex") == 0)
479511
{
480-
if (arg->v_type == VAR_STRING)
481-
do_cmdline_cmd(arg->vval.v_string);
482-
else if (p_verbose > 2)
483-
EMSG("E999: received ex command with non-string argument");
512+
do_cmdline_cmd(arg);
484513
}
485514
else if (STRCMP(cmd, "normal") == 0)
486515
{
487-
if (arg->v_type == VAR_STRING)
488-
{
489-
exarg_T ea;
516+
exarg_T ea;
490517

491-
ea.arg = arg->vval.v_string;
492-
ea.addr_count = 0;
493-
ea.forceit = TRUE; /* no mapping */
494-
ex_normal(&ea);
518+
ea.arg = arg;
519+
ea.addr_count = 0;
520+
ea.forceit = TRUE; /* no mapping */
521+
ex_normal(&ea);
522+
}
523+
else if (STRCMP(cmd, "redraw") == 0)
524+
{
525+
exarg_T ea;
495526

496-
update_screen(0);
497-
showruler(FALSE);
498-
setcursor();
499-
out_flush();
527+
ea.forceit = *arg != NUL;
528+
ex_redraw(&ea);
529+
showruler(FALSE);
530+
setcursor();
531+
out_flush();
500532
#ifdef FEAT_GUI
501-
if (gui.in_use)
533+
if (gui.in_use)
534+
{
535+
gui_update_cursor(FALSE, FALSE);
536+
gui_mch_flush();
537+
}
538+
#endif
539+
}
540+
else if (STRCMP(cmd, "expr") == 0 || STRCMP(cmd, "eval") == 0)
541+
{
542+
int is_eval = cmd[1] == 'v';
543+
544+
if (is_eval && arg3->v_type != VAR_NUMBER)
545+
{
546+
if (p_verbose > 2)
547+
EMSG("E904: third argument for eval must be a number");
548+
}
549+
else
550+
{
551+
typval_T *tv = eval_expr(arg, NULL);
552+
typval_T err_tv;
553+
char_u *json;
554+
555+
if (is_eval)
502556
{
503-
gui_update_cursor(FALSE, FALSE);
504-
gui_mch_flush();
557+
if (tv == NULL)
558+
{
559+
err_tv.v_type = VAR_STRING;
560+
err_tv.vval.v_string = (char_u *)"ERROR";
561+
tv = &err_tv;
562+
}
563+
json = json_encode_nr_expr(arg3->vval.v_number, tv);
564+
channel_send(idx, json, "eval");
565+
vim_free(json);
505566
}
506-
#endif
567+
free_tv(tv);
507568
}
508-
else if (p_verbose > 2)
509-
EMSG("E999: received normal command with non-string argument");
510569
}
511570
else if (p_verbose > 2)
512-
EMSG2("E999: received unknown command: %s", cmd);
571+
EMSG2("E905: received unknown command: %s", cmd);
513572
}
514573

515574
/*
@@ -521,6 +580,7 @@ may_invoke_callback(int idx)
521580
char_u *msg;
522581
typval_T typetv;
523582
typval_T argv[3];
583+
typval_T arg3;
524584
char_u *cmd = NULL;
525585
int seq_nr = -1;
526586
int ret = OK;
@@ -537,9 +597,10 @@ may_invoke_callback(int idx)
537597

538598
if (channels[idx].ch_json_mode)
539599
{
540-
ret = channel_decode_json(msg, &typetv, &argv[1]);
600+
ret = channel_decode_json(msg, &typetv, &argv[1], &arg3);
541601
if (ret == OK)
542602
{
603+
/* TODO: error if arg3 is set when it shouldn't? */
543604
if (typetv.v_type == VAR_STRING)
544605
cmd = typetv.vval.v_string;
545606
else if (typetv.v_type == VAR_NUMBER)
@@ -556,7 +617,7 @@ may_invoke_callback(int idx)
556617
{
557618
if (cmd != NULL)
558619
{
559-
channel_exe_cmd(cmd, &argv[1]);
620+
channel_exe_cmd(idx, cmd, &argv[1], &arg3);
560621
}
561622
else if (channels[idx].ch_req_callback != NULL && seq_nr != 0)
562623
{
@@ -576,6 +637,7 @@ may_invoke_callback(int idx)
576637
{
577638
clear_tv(&typetv);
578639
clear_tv(&argv[1]);
640+
clear_tv(&arg3);
579641
}
580642
}
581643

@@ -874,7 +936,7 @@ channel_read(int idx)
874936
{
875937
/* Todo: which channel? */
876938
CHERROR("%s(): cannot from channel\n", "channel_read");
877-
PERROR(_("E999: read from channel"));
939+
PERROR(_("E896: read from channel"));
878940
}
879941
}
880942

0 commit comments

Comments
 (0)