Mercurial > vim
comparison src/channel.c @ 7840:28f569c7dab9 v7.4.1217
commit https://github.com/vim/vim/commit/20fb9f346497daca4d19402fdfa5de7958642477
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Jan 30 23:20:33 2016 +0100
patch 7.4.1217
Problem: Execution of command on channel doesn't work yet.
Solution: Implement the "ex" and "normal" commands.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sat, 30 Jan 2016 23:30:05 +0100 |
parents | 83861277e6a3 |
children | 6b0891de44a9 |
comparison
equal
deleted
inserted
replaced
7839:daacc8ad538b | 7840:28f569c7dab9 |
---|---|
97 | 97 |
98 void (*ch_close_cb)(void); /* callback for when channel is closed */ | 98 void (*ch_close_cb)(void); /* callback for when channel is closed */ |
99 | 99 |
100 char_u *ch_callback; /* function to call when a msg is not handled */ | 100 char_u *ch_callback; /* function to call when a msg is not handled */ |
101 char_u *ch_req_callback; /* function to call for current request */ | 101 char_u *ch_req_callback; /* function to call for current request */ |
102 int ch_will_block; /* do not use callback right now */ | |
103 | 102 |
104 int ch_json_mode; | 103 int ch_json_mode; |
105 } channel_T; | 104 } channel_T; |
106 | 105 |
107 /* | 106 /* |
417 channels[idx].ch_req_callback = callback == NULL | 416 channels[idx].ch_req_callback = callback == NULL |
418 ? NULL : vim_strsave(callback); | 417 ? NULL : vim_strsave(callback); |
419 } | 418 } |
420 | 419 |
421 /* | 420 /* |
422 * Set the flag that the callback for channel "idx" should not be used now. | 421 * Decode JSON "msg", which must have the form "[expr1, expr2]". |
423 */ | 422 * Put "expr1" in "tv1". |
424 void | 423 * Put "expr2" in "tv2". |
425 channel_will_block(int idx) | |
426 { | |
427 channels[idx].ch_will_block = TRUE; | |
428 } | |
429 | |
430 /* | |
431 * Decode JSON "msg", which must have the form "[nr, expr]". | |
432 * Put "expr" in "tv". | |
433 * Return OK or FAIL. | 424 * Return OK or FAIL. |
434 */ | 425 */ |
435 int | 426 int |
436 channel_decode_json(char_u *msg, typval_T *tv) | 427 channel_decode_json(char_u *msg, typval_T *tv1, typval_T *tv2) |
437 { | 428 { |
438 js_read_T reader; | 429 js_read_T reader; |
439 typval_T listtv; | 430 typval_T listtv; |
440 | 431 |
441 reader.js_buf = msg; | 432 reader.js_buf = msg; |
442 reader.js_eof = TRUE; | 433 reader.js_eof = TRUE; |
443 reader.js_used = 0; | 434 reader.js_used = 0; |
444 json_decode(&reader, &listtv); | 435 json_decode(&reader, &listtv); |
445 /* TODO: use the sequence number */ | 436 |
446 if (listtv.v_type == VAR_LIST | 437 if (listtv.v_type == VAR_LIST && listtv.vval.v_list->lv_len == 2) |
447 && listtv.vval.v_list->lv_len == 2 | |
448 && listtv.vval.v_list->lv_first->li_tv.v_type == VAR_NUMBER) | |
449 { | 438 { |
450 /* Move the item from the list and then change the type to avoid the | 439 /* Move the item from the list and then change the type to avoid the |
451 * item being freed. */ | 440 * item being freed. */ |
452 *tv = listtv.vval.v_list->lv_last->li_tv; | 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; | |
453 listtv.vval.v_list->lv_last->li_tv.v_type = VAR_NUMBER; | 444 listtv.vval.v_list->lv_last->li_tv.v_type = VAR_NUMBER; |
454 list_unref(listtv.vval.v_list); | 445 list_unref(listtv.vval.v_list); |
455 return OK; | 446 return OK; |
456 } | 447 } |
457 | 448 |
462 | 453 |
463 /* | 454 /* |
464 * Invoke the "callback" on channel "idx". | 455 * Invoke the "callback" on channel "idx". |
465 */ | 456 */ |
466 static void | 457 static void |
467 invoke_callback(int idx, char_u *callback) | 458 invoke_callback(int idx, char_u *callback, typval_T *argv) |
468 { | 459 { |
469 typval_T argv[3]; | |
470 typval_T rettv; | 460 typval_T rettv; |
471 int dummy; | 461 int dummy; |
472 char_u *msg; | |
473 int ret = OK; | |
474 | 462 |
475 argv[0].v_type = VAR_NUMBER; | 463 argv[0].v_type = VAR_NUMBER; |
476 argv[0].vval.v_number = idx; | 464 argv[0].vval.v_number = idx; |
465 | |
466 call_func(callback, (int)STRLEN(callback), | |
467 &rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL); | |
468 /* If an echo command was used the cursor needs to be put back where | |
469 * it belongs. */ | |
470 setcursor(); | |
471 cursor_on(); | |
472 out_flush(); | |
473 } | |
474 | |
475 static void | |
476 channel_exe_cmd(char_u *cmd, typval_T *arg) | |
477 { | |
478 if (STRCMP(cmd, "ex") == 0) | |
479 { | |
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"); | |
484 } | |
485 else if (STRCMP(cmd, "normal") == 0) | |
486 { | |
487 if (arg->v_type == VAR_STRING) | |
488 { | |
489 exarg_T ea; | |
490 | |
491 ea.arg = arg->vval.v_string; | |
492 ea.addr_count = 0; | |
493 ea.forceit = TRUE; /* no mapping */ | |
494 ex_normal(&ea); | |
495 | |
496 update_screen(0); | |
497 showruler(FALSE); | |
498 setcursor(); | |
499 out_flush(); | |
500 #ifdef FEAT_GUI | |
501 if (gui.in_use) | |
502 { | |
503 gui_update_cursor(FALSE, FALSE); | |
504 gui_mch_flush(); | |
505 } | |
506 #endif | |
507 } | |
508 else if (p_verbose > 2) | |
509 EMSG("E999: received normal command with non-string argument"); | |
510 } | |
511 else if (p_verbose > 2) | |
512 EMSG2("E999: received unknown command: %s", cmd); | |
513 } | |
514 | |
515 /* | |
516 * Invoke a callback for channel "idx" if needed. | |
517 */ | |
518 static void | |
519 may_invoke_callback(int idx) | |
520 { | |
521 char_u *msg; | |
522 typval_T typetv; | |
523 typval_T argv[3]; | |
524 char_u *cmd = NULL; | |
525 int seq_nr = -1; | |
526 int ret = OK; | |
527 | |
528 if (channel_peek(idx) == NULL) | |
529 return; | |
477 | 530 |
478 /* Concatenate everything into one buffer. | 531 /* Concatenate everything into one buffer. |
479 * TODO: only read what the callback will use. | 532 * TODO: only read what the callback will use. |
480 * TODO: avoid multiple allocations. */ | 533 * TODO: avoid multiple allocations. */ |
481 while (channel_collapse(idx) == OK) | 534 while (channel_collapse(idx) == OK) |
482 ; | 535 ; |
483 msg = channel_get(idx); | 536 msg = channel_get(idx); |
484 | 537 |
485 if (channels[idx].ch_json_mode) | 538 if (channels[idx].ch_json_mode) |
486 ret = channel_decode_json(msg, &argv[1]); | 539 { |
540 ret = channel_decode_json(msg, &typetv, &argv[1]); | |
541 if (ret == OK) | |
542 { | |
543 if (typetv.v_type == VAR_STRING) | |
544 cmd = typetv.vval.v_string; | |
545 else if (typetv.v_type == VAR_NUMBER) | |
546 seq_nr = typetv.vval.v_number; | |
547 } | |
548 } | |
487 else | 549 else |
488 { | 550 { |
489 argv[1].v_type = VAR_STRING; | 551 argv[1].v_type = VAR_STRING; |
490 argv[1].vval.v_string = msg; | 552 argv[1].vval.v_string = msg; |
491 } | 553 } |
492 | 554 |
493 if (ret == OK) | 555 if (ret == OK) |
494 { | 556 { |
495 call_func(callback, (int)STRLEN(callback), | 557 if (cmd != NULL) |
496 &rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL); | 558 { |
497 /* If an echo command was used the cursor needs to be put back where | 559 channel_exe_cmd(cmd, &argv[1]); |
498 * it belongs. */ | 560 } |
499 setcursor(); | 561 else if (channels[idx].ch_req_callback != NULL && seq_nr != 0) |
500 cursor_on(); | 562 { |
501 out_flush(); | 563 /* TODO: check the sequence number */ |
502 } | 564 /* invoke the one-time callback */ |
565 invoke_callback(idx, channels[idx].ch_req_callback, argv); | |
566 channels[idx].ch_req_callback = NULL; | |
567 } | |
568 else if (channels[idx].ch_callback != NULL) | |
569 { | |
570 /* invoke the channel callback */ | |
571 invoke_callback(idx, channels[idx].ch_callback, argv); | |
572 } | |
573 /* else: drop the message */ | |
574 | |
575 if (channels[idx].ch_json_mode) | |
576 { | |
577 clear_tv(&typetv); | |
578 clear_tv(&argv[1]); | |
579 } | |
580 } | |
581 | |
503 vim_free(msg); | 582 vim_free(msg); |
504 } | |
505 | |
506 /* | |
507 * Invoke a callback for channel "idx" if needed. | |
508 */ | |
509 static void | |
510 may_invoke_callback(int idx) | |
511 { | |
512 if (channels[idx].ch_will_block) | |
513 return; | |
514 if (channel_peek(idx) == NULL) | |
515 return; | |
516 | |
517 if (channels[idx].ch_req_callback != NULL) | |
518 { | |
519 /* invoke the one-time callback */ | |
520 invoke_callback(idx, channels[idx].ch_req_callback); | |
521 channels[idx].ch_req_callback = NULL; | |
522 return; | |
523 } | |
524 | |
525 if (channels[idx].ch_callback != NULL) | |
526 /* invoke the channel callback */ | |
527 invoke_callback(idx, channels[idx].ch_callback); | |
528 } | 583 } |
529 | 584 |
530 /* | 585 /* |
531 * Return TRUE when channel "idx" is open. | 586 * Return TRUE when channel "idx" is open. |
532 * Also returns FALSE or invalid "idx". | 587 * Also returns FALSE or invalid "idx". |
821 CHERROR("%s(): cannot from channel\n", "channel_read"); | 876 CHERROR("%s(): cannot from channel\n", "channel_read"); |
822 PERROR(_("E999: read from channel")); | 877 PERROR(_("E999: read from channel")); |
823 } | 878 } |
824 } | 879 } |
825 | 880 |
826 may_invoke_callback(idx); | |
827 | |
828 #if defined(CH_HAS_GUI) && defined(FEAT_GUI_GTK) | 881 #if defined(CH_HAS_GUI) && defined(FEAT_GUI_GTK) |
829 if (CH_HAS_GUI && gtk_main_level() > 0) | 882 if (CH_HAS_GUI && gtk_main_level() > 0) |
830 gtk_main_quit(); | 883 gtk_main_quit(); |
831 #endif | 884 #endif |
832 } | 885 } |
843 if (channel_peek(idx) == NULL) | 896 if (channel_peek(idx) == NULL) |
844 { | 897 { |
845 /* Wait for up to 2 seconds. | 898 /* Wait for up to 2 seconds. |
846 * TODO: use timeout set on the channel. */ | 899 * TODO: use timeout set on the channel. */ |
847 if (channel_wait(channels[idx].ch_fd, 2000) == FAIL) | 900 if (channel_wait(channels[idx].ch_fd, 2000) == FAIL) |
848 { | |
849 channels[idx].ch_will_block = FALSE; | |
850 return NULL; | 901 return NULL; |
851 } | |
852 channel_read(idx); | 902 channel_read(idx); |
853 } | 903 } |
854 | 904 |
855 /* Concatenate everything into one buffer. | 905 /* Concatenate everything into one buffer. |
856 * TODO: avoid multiple allocations. */ | 906 * TODO: avoid multiple allocations. */ |
857 while (channel_collapse(idx) == OK) | 907 while (channel_collapse(idx) == OK) |
858 ; | 908 ; |
859 | 909 |
860 channels[idx].ch_will_block = FALSE; | |
861 return channel_get(idx); | 910 return channel_get(idx); |
862 } | 911 } |
863 | 912 |
864 # if defined(WIN32) || defined(PROTO) | 913 # if defined(WIN32) || defined(PROTO) |
865 /* | 914 /* |
1007 | 1056 |
1008 return ret; | 1057 return ret; |
1009 } | 1058 } |
1010 # endif /* !FEAT_GUI_W32 && HAVE_SELECT */ | 1059 # endif /* !FEAT_GUI_W32 && HAVE_SELECT */ |
1011 | 1060 |
1061 /* | |
1062 * Invoked from the main loop when it's save to execute received commands. | |
1063 */ | |
1064 void | |
1065 channel_parse_messages(void) | |
1066 { | |
1067 int i; | |
1068 | |
1069 for (i = 0; i < channel_count; ++i) | |
1070 may_invoke_callback(i); | |
1071 } | |
1072 | |
1012 #endif /* FEAT_CHANNEL */ | 1073 #endif /* FEAT_CHANNEL */ |