Mercurial > vim
comparison src/channel.c @ 7933:1f0743f4f88f v7.4.1262
commit https://github.com/vim/vim/commit/a07fec9c85d062acd9dd433a2e681770f459ba47
Author: Bram Moolenaar <Bram@vim.org>
Date: Fri Feb 5 21:04:08 2016 +0100
patch 7.4.1262
Problem: The channel callback is not invoked.
Solution: Make a list of pending callbacks.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Fri, 05 Feb 2016 21:15:04 +0100 |
parents | 2679e636e862 |
children | 3f2e0b62003d |
comparison
equal
deleted
inserted
replaced
7932:77f8fc004593 | 7933:1f0743f4f88f |
---|---|
82 struct jsonqueue *next; | 82 struct jsonqueue *next; |
83 struct jsonqueue *prev; | 83 struct jsonqueue *prev; |
84 }; | 84 }; |
85 typedef struct jsonqueue jsonq_T; | 85 typedef struct jsonqueue jsonq_T; |
86 | 86 |
87 struct cbqueue | |
88 { | |
89 char_u *callback; | |
90 int seq_nr; | |
91 struct cbqueue *next; | |
92 struct cbqueue *prev; | |
93 }; | |
94 typedef struct cbqueue cbq_T; | |
95 | |
87 typedef struct { | 96 typedef struct { |
88 sock_T ch_fd; /* the socket, -1 for a closed channel */ | 97 sock_T ch_fd; /* the socket, -1 for a closed channel */ |
89 int ch_idx; /* used by channel_poll_setup() */ | 98 int ch_idx; /* used by channel_poll_setup() */ |
90 readq_T ch_head; /* dummy node, header for circular queue */ | 99 readq_T ch_head; /* dummy node, header for circular queue */ |
91 | 100 |
104 #endif | 113 #endif |
105 | 114 |
106 void (*ch_close_cb)(void); /* callback for when channel is closed */ | 115 void (*ch_close_cb)(void); /* callback for when channel is closed */ |
107 | 116 |
108 char_u *ch_callback; /* function to call when a msg is not handled */ | 117 char_u *ch_callback; /* function to call when a msg is not handled */ |
109 char_u *ch_req_callback; /* function to call for current request */ | 118 cbq_T ch_cb_head; /* dummy node for pre-request callbacks */ |
110 | 119 |
111 int ch_json_mode; /* TRUE for a json channel */ | 120 int ch_json_mode; /* TRUE for a json channel */ |
112 jsonq_T ch_json_head; /* dummy node, header for circular queue */ | 121 jsonq_T ch_json_head; /* dummy node, header for circular queue */ |
113 } channel_T; | 122 } channel_T; |
114 | 123 |
166 ch->ch_inputHandler = -1; | 175 ch->ch_inputHandler = -1; |
167 #endif | 176 #endif |
168 /* initialize circular queues */ | 177 /* initialize circular queues */ |
169 ch->ch_head.next = &ch->ch_head; | 178 ch->ch_head.next = &ch->ch_head; |
170 ch->ch_head.prev = &ch->ch_head; | 179 ch->ch_head.prev = &ch->ch_head; |
180 ch->ch_cb_head.next = &ch->ch_cb_head; | |
181 ch->ch_cb_head.prev = &ch->ch_cb_head; | |
171 ch->ch_json_head.next = &ch->ch_json_head; | 182 ch->ch_json_head.next = &ch->ch_json_head; |
172 ch->ch_json_head.prev = &ch->ch_json_head; | 183 ch->ch_json_head.prev = &ch->ch_json_head; |
173 | 184 |
174 return channel_count++; | 185 return channel_count++; |
175 } | 186 } |
424 vim_free(channels[idx].ch_callback); | 435 vim_free(channels[idx].ch_callback); |
425 channels[idx].ch_callback = vim_strsave(callback); | 436 channels[idx].ch_callback = vim_strsave(callback); |
426 } | 437 } |
427 | 438 |
428 /* | 439 /* |
429 * Set the callback for channel "idx" for the next response. | 440 * Set the callback for channel "idx" for the response with "id". |
430 */ | 441 */ |
431 void | 442 void |
432 channel_set_req_callback(int idx, char_u *callback) | 443 channel_set_req_callback(int idx, char_u *callback, int id) |
433 { | 444 { |
434 /* TODO: make a list of callbacks */ | 445 cbq_T *cbhead = &channels[idx].ch_cb_head; |
435 vim_free(channels[idx].ch_req_callback); | 446 cbq_T *item = (cbq_T *)alloc((int)sizeof(cbq_T)); |
436 channels[idx].ch_req_callback = callback == NULL | 447 |
437 ? NULL : vim_strsave(callback); | 448 if (item != NULL) |
449 { | |
450 item->callback = vim_strsave(callback); | |
451 item->seq_nr = id; | |
452 item->prev = cbhead->prev; | |
453 cbhead->prev = item; | |
454 item->next = cbhead; | |
455 item->prev->next = item; | |
456 } | |
438 } | 457 } |
439 | 458 |
440 /* | 459 /* |
441 * Invoke the "callback" on channel "idx". | 460 * Invoke the "callback" on channel "idx". |
442 */ | 461 */ |
597 return ret; | 616 return ret; |
598 } | 617 } |
599 | 618 |
600 /* | 619 /* |
601 * Remove "node" from the queue that it is in and free it. | 620 * Remove "node" from the queue that it is in and free it. |
621 * Also frees the contained callback name. | |
622 */ | |
623 static void | |
624 remove_cb_node(cbq_T *node) | |
625 { | |
626 node->prev->next = node->next; | |
627 node->next->prev = node->prev; | |
628 vim_free(node->callback); | |
629 vim_free(node); | |
630 } | |
631 | |
632 /* | |
633 * Remove "node" from the queue that it is in and free it. | |
602 * Caller should have freed or used node->value. | 634 * Caller should have freed or used node->value. |
603 */ | 635 */ |
604 static void | 636 static void |
605 remove_json_node(jsonq_T *node) | 637 remove_json_node(jsonq_T *node) |
606 { | 638 { |
626 { | 658 { |
627 list_T *l = item->value->vval.v_list; | 659 list_T *l = item->value->vval.v_list; |
628 typval_T *tv = &l->lv_first->li_tv; | 660 typval_T *tv = &l->lv_first->li_tv; |
629 | 661 |
630 if ((id > 0 && tv->v_type == VAR_NUMBER && tv->vval.v_number == id) | 662 if ((id > 0 && tv->v_type == VAR_NUMBER && tv->vval.v_number == id) |
631 || (id <= 0 | 663 || id <= 0) |
632 && (tv->v_type != VAR_NUMBER || tv->vval.v_number < 0))) | |
633 { | 664 { |
634 *rettv = item->value; | 665 *rettv = item->value; |
635 remove_json_node(item); | 666 remove_json_node(item); |
636 return OK; | 667 return OK; |
637 } | 668 } |
740 typval_T *listtv = NULL; | 771 typval_T *listtv = NULL; |
741 list_T *list; | 772 list_T *list; |
742 typval_T *typetv; | 773 typval_T *typetv; |
743 typval_T argv[3]; | 774 typval_T argv[3]; |
744 int seq_nr = -1; | 775 int seq_nr = -1; |
745 int json_mode = channels[idx].ch_json_mode; | 776 channel_T *channel = &channels[idx]; |
746 | 777 int json_mode = channel->ch_json_mode; |
747 if (channels[idx].ch_close_cb != NULL) | 778 |
779 if (channel->ch_close_cb != NULL) | |
748 /* this channel is handled elsewhere (netbeans) */ | 780 /* this channel is handled elsewhere (netbeans) */ |
749 return FALSE; | 781 return FALSE; |
750 | 782 |
751 if (json_mode) | 783 if (json_mode) |
752 { | 784 { |
802 msg = channel_get_all(idx); | 834 msg = channel_get_all(idx); |
803 argv[1].v_type = VAR_STRING; | 835 argv[1].v_type = VAR_STRING; |
804 argv[1].vval.v_string = msg; | 836 argv[1].vval.v_string = msg; |
805 } | 837 } |
806 | 838 |
807 if (channels[idx].ch_req_callback != NULL && seq_nr != 0) | 839 if (seq_nr > 0) |
808 { | 840 { |
809 /* TODO: check the sequence number */ | 841 cbq_T *cbhead = &channel->ch_cb_head; |
810 /* invoke the one-time callback */ | 842 cbq_T *cbitem = cbhead->next; |
811 invoke_callback(idx, channels[idx].ch_req_callback, argv); | 843 |
812 channels[idx].ch_req_callback = NULL; | 844 /* invoke the one-time callback with the matching nr */ |
813 } | 845 while (cbitem != cbhead) |
814 else if (channels[idx].ch_callback != NULL) | 846 { |
847 if (cbitem->seq_nr == seq_nr) | |
848 { | |
849 invoke_callback(idx, cbitem->callback, argv); | |
850 remove_cb_node(cbitem); | |
851 break; | |
852 } | |
853 cbitem = cbitem->next; | |
854 } | |
855 } | |
856 else if (channel->ch_callback != NULL) | |
815 { | 857 { |
816 /* invoke the channel callback */ | 858 /* invoke the channel callback */ |
817 invoke_callback(idx, channels[idx].ch_callback, argv); | 859 invoke_callback(idx, channel->ch_callback, argv); |
818 } | 860 } |
819 /* else: drop the message TODO: give error */ | 861 /* else: drop the message TODO: give error */ |
820 | 862 |
821 if (listtv != NULL) | 863 if (listtv != NULL) |
822 clear_tv(listtv); | 864 clear_tv(listtv); |
842 void | 884 void |
843 channel_close(int idx) | 885 channel_close(int idx) |
844 { | 886 { |
845 channel_T *channel = &channels[idx]; | 887 channel_T *channel = &channels[idx]; |
846 jsonq_T *jhead; | 888 jsonq_T *jhead; |
889 cbq_T *cbhead; | |
847 | 890 |
848 if (channel->ch_fd >= 0) | 891 if (channel->ch_fd >= 0) |
849 { | 892 { |
850 sock_close(channel->ch_fd); | 893 sock_close(channel->ch_fd); |
851 channel->ch_fd = -1; | 894 channel->ch_fd = -1; |
856 vim_free(channel->ch_callback); | 899 vim_free(channel->ch_callback); |
857 channel->ch_callback = NULL; | 900 channel->ch_callback = NULL; |
858 | 901 |
859 while (channel_peek(idx) != NULL) | 902 while (channel_peek(idx) != NULL) |
860 vim_free(channel_get(idx)); | 903 vim_free(channel_get(idx)); |
904 | |
905 cbhead = &channel->ch_cb_head; | |
906 while (cbhead->next != cbhead) | |
907 remove_cb_node(cbhead->next); | |
861 | 908 |
862 jhead = &channel->ch_json_head; | 909 jhead = &channel->ch_json_head; |
863 while (jhead->next != jhead) | 910 while (jhead->next != jhead) |
864 { | 911 { |
865 clear_tv(jhead->next->value); | 912 clear_tv(jhead->next->value); |