1
0
forked from aniani/vim

patch 7.4.1217

Problem:    Execution of command on channel doesn't work yet.
Solution:   Implement the "ex" and "normal" commands.
This commit is contained in:
Bram Moolenaar
2016-01-30 23:20:33 +01:00
parent ba4ef2757c
commit 20fb9f3464
8 changed files with 136 additions and 69 deletions

View File

@@ -99,7 +99,6 @@ typedef struct {
char_u *ch_callback; /* function to call when a msg is not handled */ char_u *ch_callback; /* function to call when a msg is not handled */
char_u *ch_req_callback; /* function to call for current request */ char_u *ch_req_callback; /* function to call for current request */
int ch_will_block; /* do not use callback right now */
int ch_json_mode; int ch_json_mode;
} channel_T; } channel_T;
@@ -419,21 +418,13 @@ channel_set_req_callback(int idx, char_u *callback)
} }
/* /*
* Set the flag that the callback for channel "idx" should not be used now. * Decode JSON "msg", which must have the form "[expr1, expr2]".
*/ * Put "expr1" in "tv1".
void * Put "expr2" in "tv2".
channel_will_block(int idx)
{
channels[idx].ch_will_block = TRUE;
}
/*
* Decode JSON "msg", which must have the form "[nr, expr]".
* Put "expr" in "tv".
* Return OK or FAIL. * Return OK or FAIL.
*/ */
int int
channel_decode_json(char_u *msg, typval_T *tv) channel_decode_json(char_u *msg, typval_T *tv1, typval_T *tv2)
{ {
js_read_T reader; js_read_T reader;
typval_T listtv; typval_T listtv;
@@ -442,14 +433,14 @@ channel_decode_json(char_u *msg, typval_T *tv)
reader.js_eof = TRUE; reader.js_eof = TRUE;
reader.js_used = 0; reader.js_used = 0;
json_decode(&reader, &listtv); json_decode(&reader, &listtv);
/* TODO: use the sequence number */
if (listtv.v_type == VAR_LIST if (listtv.v_type == VAR_LIST && listtv.vval.v_list->lv_len == 2)
&& listtv.vval.v_list->lv_len == 2
&& listtv.vval.v_list->lv_first->li_tv.v_type == VAR_NUMBER)
{ {
/* Move the item from the list and then change the type to avoid the /* Move the item from the list and then change the type to avoid the
* item being freed. */ * item being freed. */
*tv = listtv.vval.v_list->lv_last->li_tv; *tv1 = listtv.vval.v_list->lv_first->li_tv;
listtv.vval.v_list->lv_first->li_tv.v_type = VAR_NUMBER;
*tv2 = listtv.vval.v_list->lv_last->li_tv;
listtv.vval.v_list->lv_last->li_tv.v_type = VAR_NUMBER; listtv.vval.v_list->lv_last->li_tv.v_type = VAR_NUMBER;
list_unref(listtv.vval.v_list); list_unref(listtv.vval.v_list);
return OK; return OK;
@@ -464,17 +455,79 @@ channel_decode_json(char_u *msg, typval_T *tv)
* Invoke the "callback" on channel "idx". * Invoke the "callback" on channel "idx".
*/ */
static void static void
invoke_callback(int idx, char_u *callback) invoke_callback(int idx, char_u *callback, typval_T *argv)
{ {
typval_T argv[3];
typval_T rettv; typval_T rettv;
int dummy; int dummy;
char_u *msg;
int ret = OK;
argv[0].v_type = VAR_NUMBER; argv[0].v_type = VAR_NUMBER;
argv[0].vval.v_number = idx; argv[0].vval.v_number = idx;
call_func(callback, (int)STRLEN(callback),
&rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL);
/* If an echo command was used the cursor needs to be put back where
* it belongs. */
setcursor();
cursor_on();
out_flush();
}
static void
channel_exe_cmd(char_u *cmd, typval_T *arg)
{
if (STRCMP(cmd, "ex") == 0)
{
if (arg->v_type == VAR_STRING)
do_cmdline_cmd(arg->vval.v_string);
else if (p_verbose > 2)
EMSG("E999: received ex command with non-string argument");
}
else if (STRCMP(cmd, "normal") == 0)
{
if (arg->v_type == VAR_STRING)
{
exarg_T ea;
ea.arg = arg->vval.v_string;
ea.addr_count = 0;
ea.forceit = TRUE; /* no mapping */
ex_normal(&ea);
update_screen(0);
showruler(FALSE);
setcursor();
out_flush();
#ifdef FEAT_GUI
if (gui.in_use)
{
gui_update_cursor(FALSE, FALSE);
gui_mch_flush();
}
#endif
}
else if (p_verbose > 2)
EMSG("E999: received normal command with non-string argument");
}
else if (p_verbose > 2)
EMSG2("E999: received unknown command: %s", cmd);
}
/*
* Invoke a callback for channel "idx" if needed.
*/
static void
may_invoke_callback(int idx)
{
char_u *msg;
typval_T typetv;
typval_T argv[3];
char_u *cmd = NULL;
int seq_nr = -1;
int ret = OK;
if (channel_peek(idx) == NULL)
return;
/* Concatenate everything into one buffer. /* Concatenate everything into one buffer.
* TODO: only read what the callback will use. * TODO: only read what the callback will use.
* TODO: avoid multiple allocations. */ * TODO: avoid multiple allocations. */
@@ -483,7 +536,16 @@ invoke_callback(int idx, char_u *callback)
msg = channel_get(idx); msg = channel_get(idx);
if (channels[idx].ch_json_mode) if (channels[idx].ch_json_mode)
ret = channel_decode_json(msg, &argv[1]); {
ret = channel_decode_json(msg, &typetv, &argv[1]);
if (ret == OK)
{
if (typetv.v_type == VAR_STRING)
cmd = typetv.vval.v_string;
else if (typetv.v_type == VAR_NUMBER)
seq_nr = typetv.vval.v_number;
}
}
else else
{ {
argv[1].v_type = VAR_STRING; argv[1].v_type = VAR_STRING;
@@ -492,41 +554,34 @@ invoke_callback(int idx, char_u *callback)
if (ret == OK) if (ret == OK)
{ {
call_func(callback, (int)STRLEN(callback), if (cmd != NULL)
&rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL); {
/* If an echo command was used the cursor needs to be put back where channel_exe_cmd(cmd, &argv[1]);
* it belongs. */ }
setcursor(); else if (channels[idx].ch_req_callback != NULL && seq_nr != 0)
cursor_on(); {
out_flush(); /* TODO: check the sequence number */
/* invoke the one-time callback */
invoke_callback(idx, channels[idx].ch_req_callback, argv);
channels[idx].ch_req_callback = NULL;
}
else if (channels[idx].ch_callback != NULL)
{
/* invoke the channel callback */
invoke_callback(idx, channels[idx].ch_callback, argv);
}
/* else: drop the message */
if (channels[idx].ch_json_mode)
{
clear_tv(&typetv);
clear_tv(&argv[1]);
}
} }
vim_free(msg); vim_free(msg);
} }
/*
* Invoke a callback for channel "idx" if needed.
*/
static void
may_invoke_callback(int idx)
{
if (channels[idx].ch_will_block)
return;
if (channel_peek(idx) == NULL)
return;
if (channels[idx].ch_req_callback != NULL)
{
/* invoke the one-time callback */
invoke_callback(idx, channels[idx].ch_req_callback);
channels[idx].ch_req_callback = NULL;
return;
}
if (channels[idx].ch_callback != NULL)
/* invoke the channel callback */
invoke_callback(idx, channels[idx].ch_callback);
}
/* /*
* Return TRUE when channel "idx" is open. * Return TRUE when channel "idx" is open.
* Also returns FALSE or invalid "idx". * Also returns FALSE or invalid "idx".
@@ -823,8 +878,6 @@ channel_read(int idx)
} }
} }
may_invoke_callback(idx);
#if defined(CH_HAS_GUI) && defined(FEAT_GUI_GTK) #if defined(CH_HAS_GUI) && defined(FEAT_GUI_GTK)
if (CH_HAS_GUI && gtk_main_level() > 0) if (CH_HAS_GUI && gtk_main_level() > 0)
gtk_main_quit(); gtk_main_quit();
@@ -845,10 +898,7 @@ channel_read_block(int idx)
/* Wait for up to 2 seconds. /* Wait for up to 2 seconds.
* TODO: use timeout set on the channel. */ * TODO: use timeout set on the channel. */
if (channel_wait(channels[idx].ch_fd, 2000) == FAIL) if (channel_wait(channels[idx].ch_fd, 2000) == FAIL)
{
channels[idx].ch_will_block = FALSE;
return NULL; return NULL;
}
channel_read(idx); channel_read(idx);
} }
@@ -857,7 +907,6 @@ channel_read_block(int idx)
while (channel_collapse(idx) == OK) while (channel_collapse(idx) == OK)
; ;
channels[idx].ch_will_block = FALSE;
return channel_get(idx); return channel_get(idx);
} }
@@ -1009,4 +1058,16 @@ channel_select_check(int ret_in, void *rfds_in)
} }
# endif /* !FEAT_GUI_W32 && HAVE_SELECT */ # endif /* !FEAT_GUI_W32 && HAVE_SELECT */
/*
* Invoked from the main loop when it's save to execute received commands.
*/
void
channel_parse_messages(void)
{
int i;
for (i = 0; i < channel_count; ++i)
may_invoke_callback(i);
}
#endif /* FEAT_CHANNEL */ #endif /* FEAT_CHANNEL */

View File

@@ -16889,8 +16889,6 @@ send_common(typval_T *argvars, char_u *text, char *fun)
* not reading the response. */ * not reading the response. */
channel_set_req_callback(ch_idx, channel_set_req_callback(ch_idx,
callback != NULL && *callback == NUL ? NULL : callback); callback != NULL && *callback == NUL ? NULL : callback);
if (callback == NULL)
channel_will_block(ch_idx);
if (channel_send(ch_idx, text, fun) == OK && callback == NULL) if (channel_send(ch_idx, text, fun) == OK && callback == NULL)
return ch_idx; return ch_idx;
@@ -16907,6 +16905,7 @@ f_sendexpr(typval_T *argvars, typval_T *rettv)
char_u *resp; char_u *resp;
typval_T nrtv; typval_T nrtv;
typval_T listtv; typval_T listtv;
typval_T typetv;
int ch_idx; int ch_idx;
/* return an empty string by default */ /* return an empty string by default */
@@ -16932,10 +16931,11 @@ f_sendexpr(typval_T *argvars, typval_T *rettv)
{ {
/* TODO: read until the whole JSON message is received */ /* TODO: read until the whole JSON message is received */
/* TODO: only use the message with the right message ID */ /* TODO: only use the message with the right message ID */
/* TODO: check sequence number */
resp = channel_read_block(ch_idx); resp = channel_read_block(ch_idx);
if (resp != NULL) if (resp != NULL)
{ {
channel_decode_json(resp, rettv); channel_decode_json(resp, &typetv, rettv);
vim_free(resp); vim_free(resp);
} }
} }

View File

@@ -345,7 +345,6 @@ static char_u *uc_fun_cmd(void);
static char_u *find_ucmd(exarg_T *eap, char_u *p, int *full, expand_T *xp, int *compl); static char_u *find_ucmd(exarg_T *eap, char_u *p, int *full, expand_T *xp, int *compl);
#endif #endif
#ifdef FEAT_EX_EXTRA #ifdef FEAT_EX_EXTRA
static void ex_normal(exarg_T *eap);
static void ex_startinsert(exarg_T *eap); static void ex_startinsert(exarg_T *eap);
static void ex_stopinsert(exarg_T *eap); static void ex_stopinsert(exarg_T *eap);
#else #else
@@ -9861,11 +9860,11 @@ update_topline_cursor(void)
update_curswant(); update_curswant();
} }
#ifdef FEAT_EX_EXTRA #if defined(FEAT_EX_EXTRA) || defined(PROTO)
/* /*
* ":normal[!] {commands}": Execute normal mode commands. * ":normal[!] {commands}": Execute normal mode commands.
*/ */
static void void
ex_normal(exarg_T *eap) ex_normal(exarg_T *eap)
{ {
int save_msg_scroll = msg_scroll; int save_msg_scroll = msg_scroll;

View File

@@ -256,7 +256,7 @@
/* /*
* +ex_extra ":retab", ":right", ":left", ":center", ":normal". * +ex_extra ":retab", ":right", ":left", ":center", ":normal".
*/ */
#ifdef FEAT_NORMAL #if defined(FEAT_NORMAL) || defined(FEAT_CHANNEL)
# define FEAT_EX_EXTRA # define FEAT_EX_EXTRA
#endif #endif

View File

@@ -6240,6 +6240,10 @@ parse_queued_messages(void)
/* Process the queued netbeans messages. */ /* Process the queued netbeans messages. */
netbeans_parse_messages(); netbeans_parse_messages();
# endif # endif
# ifdef FEAT_CHANNEL
/* Process the messages queued on channels. */
channel_parse_messages();
# endif
# if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11) # if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
/* Process the queued clientserver messages. */ /* Process the queued clientserver messages. */
server_parse_messages(); server_parse_messages();

View File

@@ -4,8 +4,7 @@ int channel_open(char *hostname, int port_in, void (*close_cb)(void));
void channel_set_json_mode(int idx, int json_mode); void channel_set_json_mode(int idx, int json_mode);
void channel_set_callback(int idx, char_u *callback); void channel_set_callback(int idx, char_u *callback);
void channel_set_req_callback(int idx, char_u *callback); void channel_set_req_callback(int idx, char_u *callback);
void channel_will_block(int idx); int channel_decode_json(char_u *msg, typval_T *tv1, typval_T *tv2);
int channel_decode_json(char_u *msg, typval_T *tv);
int channel_is_open(int idx); int channel_is_open(int idx);
void channel_close(int idx); void channel_close(int idx);
int channel_save(int idx, char_u *buf, int len); int channel_save(int idx, char_u *buf, int len);
@@ -22,4 +21,5 @@ int channel_poll_setup(int nfd_in, void *fds_in);
int channel_poll_check(int ret_in, void *fds_in); int channel_poll_check(int ret_in, void *fds_in);
int channel_select_setup(int maxfd_in, void *rfds_in); int channel_select_setup(int maxfd_in, void *rfds_in);
int channel_select_check(int ret_in, void *rfds_in); int channel_select_check(int ret_in, void *rfds_in);
void channel_parse_messages(void);
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@@ -49,6 +49,7 @@ void ex_may_print(exarg_T *eap);
int vim_mkdir_emsg(char_u *name, int prot); int vim_mkdir_emsg(char_u *name, int prot);
FILE *open_exfile(char_u *fname, int forceit, char *mode); FILE *open_exfile(char_u *fname, int forceit, char *mode);
void update_topline_cursor(void); void update_topline_cursor(void);
void ex_normal(exarg_T *eap);
void exec_normal_cmd(char_u *cmd, int remap, int silent); void exec_normal_cmd(char_u *cmd, int remap, int silent);
void exec_normal(int was_typed); void exec_normal(int was_typed);
int find_cmdline_var(char_u *src, int *usedlen); int find_cmdline_var(char_u *src, int *usedlen);

View File

@@ -746,6 +746,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1217,
/**/ /**/
1216, 1216,
/**/ /**/