mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 7.4.1262
Problem: The channel callback is not invoked. Solution: Make a list of pending callbacks.
This commit is contained in:
parent
4b6a6dcbe7
commit
a07fec9c85
@ -84,6 +84,15 @@ struct jsonqueue
|
|||||||
};
|
};
|
||||||
typedef struct jsonqueue jsonq_T;
|
typedef struct jsonqueue jsonq_T;
|
||||||
|
|
||||||
|
struct cbqueue
|
||||||
|
{
|
||||||
|
char_u *callback;
|
||||||
|
int seq_nr;
|
||||||
|
struct cbqueue *next;
|
||||||
|
struct cbqueue *prev;
|
||||||
|
};
|
||||||
|
typedef struct cbqueue cbq_T;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
sock_T ch_fd; /* the socket, -1 for a closed channel */
|
sock_T ch_fd; /* the socket, -1 for a closed channel */
|
||||||
int ch_idx; /* used by channel_poll_setup() */
|
int ch_idx; /* used by channel_poll_setup() */
|
||||||
@ -106,7 +115,7 @@ typedef struct {
|
|||||||
void (*ch_close_cb)(void); /* callback for when channel is closed */
|
void (*ch_close_cb)(void); /* callback for when channel is closed */
|
||||||
|
|
||||||
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 */
|
cbq_T ch_cb_head; /* dummy node for pre-request callbacks */
|
||||||
|
|
||||||
int ch_json_mode; /* TRUE for a json channel */
|
int ch_json_mode; /* TRUE for a json channel */
|
||||||
jsonq_T ch_json_head; /* dummy node, header for circular queue */
|
jsonq_T ch_json_head; /* dummy node, header for circular queue */
|
||||||
@ -168,6 +177,8 @@ add_channel(void)
|
|||||||
/* initialize circular queues */
|
/* initialize circular queues */
|
||||||
ch->ch_head.next = &ch->ch_head;
|
ch->ch_head.next = &ch->ch_head;
|
||||||
ch->ch_head.prev = &ch->ch_head;
|
ch->ch_head.prev = &ch->ch_head;
|
||||||
|
ch->ch_cb_head.next = &ch->ch_cb_head;
|
||||||
|
ch->ch_cb_head.prev = &ch->ch_cb_head;
|
||||||
ch->ch_json_head.next = &ch->ch_json_head;
|
ch->ch_json_head.next = &ch->ch_json_head;
|
||||||
ch->ch_json_head.prev = &ch->ch_json_head;
|
ch->ch_json_head.prev = &ch->ch_json_head;
|
||||||
|
|
||||||
@ -426,15 +437,23 @@ channel_set_callback(int idx, char_u *callback)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the callback for channel "idx" for the next response.
|
* Set the callback for channel "idx" for the response with "id".
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
channel_set_req_callback(int idx, char_u *callback)
|
channel_set_req_callback(int idx, char_u *callback, int id)
|
||||||
{
|
{
|
||||||
/* TODO: make a list of callbacks */
|
cbq_T *cbhead = &channels[idx].ch_cb_head;
|
||||||
vim_free(channels[idx].ch_req_callback);
|
cbq_T *item = (cbq_T *)alloc((int)sizeof(cbq_T));
|
||||||
channels[idx].ch_req_callback = callback == NULL
|
|
||||||
? NULL : vim_strsave(callback);
|
if (item != NULL)
|
||||||
|
{
|
||||||
|
item->callback = vim_strsave(callback);
|
||||||
|
item->seq_nr = id;
|
||||||
|
item->prev = cbhead->prev;
|
||||||
|
cbhead->prev = item;
|
||||||
|
item->next = cbhead;
|
||||||
|
item->prev->next = item;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -597,6 +616,19 @@ channel_parse_json(int ch_idx)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove "node" from the queue that it is in and free it.
|
||||||
|
* Also frees the contained callback name.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
remove_cb_node(cbq_T *node)
|
||||||
|
{
|
||||||
|
node->prev->next = node->next;
|
||||||
|
node->next->prev = node->prev;
|
||||||
|
vim_free(node->callback);
|
||||||
|
vim_free(node);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remove "node" from the queue that it is in and free it.
|
* Remove "node" from the queue that it is in and free it.
|
||||||
* Caller should have freed or used node->value.
|
* Caller should have freed or used node->value.
|
||||||
@ -628,8 +660,7 @@ channel_get_json(int ch_idx, int id, typval_T **rettv)
|
|||||||
typval_T *tv = &l->lv_first->li_tv;
|
typval_T *tv = &l->lv_first->li_tv;
|
||||||
|
|
||||||
if ((id > 0 && tv->v_type == VAR_NUMBER && tv->vval.v_number == id)
|
if ((id > 0 && tv->v_type == VAR_NUMBER && tv->vval.v_number == id)
|
||||||
|| (id <= 0
|
|| id <= 0)
|
||||||
&& (tv->v_type != VAR_NUMBER || tv->vval.v_number < 0)))
|
|
||||||
{
|
{
|
||||||
*rettv = item->value;
|
*rettv = item->value;
|
||||||
remove_json_node(item);
|
remove_json_node(item);
|
||||||
@ -742,9 +773,10 @@ may_invoke_callback(int idx)
|
|||||||
typval_T *typetv;
|
typval_T *typetv;
|
||||||
typval_T argv[3];
|
typval_T argv[3];
|
||||||
int seq_nr = -1;
|
int seq_nr = -1;
|
||||||
int json_mode = channels[idx].ch_json_mode;
|
channel_T *channel = &channels[idx];
|
||||||
|
int json_mode = channel->ch_json_mode;
|
||||||
|
|
||||||
if (channels[idx].ch_close_cb != NULL)
|
if (channel->ch_close_cb != NULL)
|
||||||
/* this channel is handled elsewhere (netbeans) */
|
/* this channel is handled elsewhere (netbeans) */
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
@ -804,17 +836,27 @@ may_invoke_callback(int idx)
|
|||||||
argv[1].vval.v_string = msg;
|
argv[1].vval.v_string = msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channels[idx].ch_req_callback != NULL && seq_nr != 0)
|
if (seq_nr > 0)
|
||||||
{
|
{
|
||||||
/* TODO: check the sequence number */
|
cbq_T *cbhead = &channel->ch_cb_head;
|
||||||
/* invoke the one-time callback */
|
cbq_T *cbitem = cbhead->next;
|
||||||
invoke_callback(idx, channels[idx].ch_req_callback, argv);
|
|
||||||
channels[idx].ch_req_callback = NULL;
|
/* invoke the one-time callback with the matching nr */
|
||||||
|
while (cbitem != cbhead)
|
||||||
|
{
|
||||||
|
if (cbitem->seq_nr == seq_nr)
|
||||||
|
{
|
||||||
|
invoke_callback(idx, cbitem->callback, argv);
|
||||||
|
remove_cb_node(cbitem);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cbitem = cbitem->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (channels[idx].ch_callback != NULL)
|
else if (channel->ch_callback != NULL)
|
||||||
{
|
{
|
||||||
/* invoke the channel callback */
|
/* invoke the channel callback */
|
||||||
invoke_callback(idx, channels[idx].ch_callback, argv);
|
invoke_callback(idx, channel->ch_callback, argv);
|
||||||
}
|
}
|
||||||
/* else: drop the message TODO: give error */
|
/* else: drop the message TODO: give error */
|
||||||
|
|
||||||
@ -844,6 +886,7 @@ channel_close(int idx)
|
|||||||
{
|
{
|
||||||
channel_T *channel = &channels[idx];
|
channel_T *channel = &channels[idx];
|
||||||
jsonq_T *jhead;
|
jsonq_T *jhead;
|
||||||
|
cbq_T *cbhead;
|
||||||
|
|
||||||
if (channel->ch_fd >= 0)
|
if (channel->ch_fd >= 0)
|
||||||
{
|
{
|
||||||
@ -859,6 +902,10 @@ channel_close(int idx)
|
|||||||
while (channel_peek(idx) != NULL)
|
while (channel_peek(idx) != NULL)
|
||||||
vim_free(channel_get(idx));
|
vim_free(channel_get(idx));
|
||||||
|
|
||||||
|
cbhead = &channel->ch_cb_head;
|
||||||
|
while (cbhead->next != cbhead)
|
||||||
|
remove_cb_node(cbhead->next);
|
||||||
|
|
||||||
jhead = &channel->ch_json_head;
|
jhead = &channel->ch_json_head;
|
||||||
while (jhead->next != jhead)
|
while (jhead->next != jhead)
|
||||||
{
|
{
|
||||||
|
14
src/eval.c
14
src/eval.c
@ -9800,7 +9800,7 @@ f_ch_open(typval_T *argvars, typval_T *rettv)
|
|||||||
* Otherwise returns -1.
|
* Otherwise returns -1.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
send_common(typval_T *argvars, char_u *text, char *fun)
|
send_common(typval_T *argvars, char_u *text, int id, char *fun)
|
||||||
{
|
{
|
||||||
int ch_idx;
|
int ch_idx;
|
||||||
char_u *callback = NULL;
|
char_u *callback = NULL;
|
||||||
@ -9815,10 +9815,10 @@ send_common(typval_T *argvars, char_u *text, char *fun)
|
|||||||
if (callback == NULL)
|
if (callback == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* Set the callback or clear it. An empty callback means no callback and
|
/* Set the callback. An empty callback means no callback and not reading
|
||||||
* not reading the response. */
|
* the response. */
|
||||||
channel_set_req_callback(ch_idx,
|
if (callback != NULL && *callback != NUL)
|
||||||
callback != NULL && *callback == NUL ? NULL : callback);
|
channel_set_req_callback(ch_idx, callback, id);
|
||||||
|
|
||||||
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;
|
||||||
@ -9845,7 +9845,7 @@ f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
|
|||||||
if (text == NULL)
|
if (text == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ch_idx = send_common(argvars, text, "sendexpr");
|
ch_idx = send_common(argvars, text, id, "sendexpr");
|
||||||
vim_free(text);
|
vim_free(text);
|
||||||
if (ch_idx >= 0)
|
if (ch_idx >= 0)
|
||||||
{
|
{
|
||||||
@ -9883,7 +9883,7 @@ f_ch_sendraw(typval_T *argvars, typval_T *rettv)
|
|||||||
rettv->vval.v_string = NULL;
|
rettv->vval.v_string = NULL;
|
||||||
|
|
||||||
text = get_tv_string_buf(&argvars[1], buf);
|
text = get_tv_string_buf(&argvars[1], buf);
|
||||||
ch_idx = send_common(argvars, text, "sendraw");
|
ch_idx = send_common(argvars, text, 0, "sendraw");
|
||||||
if (ch_idx >= 0)
|
if (ch_idx >= 0)
|
||||||
rettv->vval.v_string = channel_read_block(ch_idx);
|
rettv->vval.v_string = channel_read_block(ch_idx);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ void channel_gui_register_all(void);
|
|||||||
int channel_open(char *hostname, int port_in, void (*close_cb)(void));
|
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, int id);
|
||||||
char_u *channel_get(int idx);
|
char_u *channel_get(int idx);
|
||||||
int channel_collapse(int idx);
|
int channel_collapse(int idx);
|
||||||
int channel_is_open(int idx);
|
int channel_is_open(int idx);
|
||||||
|
@ -69,6 +69,13 @@ func s:kill_server()
|
|||||||
endif
|
endif
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
let s:responseHandle = -1
|
||||||
|
let s:responseMsg = ''
|
||||||
|
func s:RequestHandler(handle, msg)
|
||||||
|
let s:responseHandle = a:handle
|
||||||
|
let s:responseMsg = a:msg
|
||||||
|
endfunc
|
||||||
|
|
||||||
func Test_communicate()
|
func Test_communicate()
|
||||||
let handle = s:start_server()
|
let handle = s:start_server()
|
||||||
if handle < 0
|
if handle < 0
|
||||||
@ -86,6 +93,12 @@ func Test_communicate()
|
|||||||
call assert_equal('added1', getline(line('$') - 1))
|
call assert_equal('added1', getline(line('$') - 1))
|
||||||
call assert_equal('added2', getline('$'))
|
call assert_equal('added2', getline('$'))
|
||||||
|
|
||||||
|
" Send a request with a specific handler.
|
||||||
|
call ch_sendexpr(handle, 'hello!', 's:RequestHandler')
|
||||||
|
sleep 10m
|
||||||
|
call assert_equal(handle, s:responseHandle)
|
||||||
|
call assert_equal('got it', s:responseMsg)
|
||||||
|
|
||||||
" Send an eval request that works.
|
" Send an eval request that works.
|
||||||
call assert_equal('ok', ch_sendexpr(handle, 'eval-works'))
|
call assert_equal('ok', ch_sendexpr(handle, 'eval-works'))
|
||||||
sleep 10m
|
sleep 10m
|
||||||
|
@ -742,6 +742,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 */
|
||||||
|
/**/
|
||||||
|
1262,
|
||||||
/**/
|
/**/
|
||||||
1261,
|
1261,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user