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 */