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);