@@ -84,6 +84,15 @@ struct jsonqueue
8484};
8585typedef struct jsonqueue jsonq_T ;
8686
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+
8796typedef struct {
8897 sock_T ch_fd ; /* the socket, -1 for a closed channel */
8998 int ch_idx ; /* used by channel_poll_setup() */
@@ -106,7 +115,7 @@ typedef struct {
106115 void (* ch_close_cb )(void ); /* callback for when channel is closed */
107116
108117 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 */
110119
111120 int ch_json_mode ; /* TRUE for a json channel */
112121 jsonq_T ch_json_head ; /* dummy node, header for circular queue */
@@ -168,6 +177,8 @@ add_channel(void)
168177 /* initialize circular queues */
169178 ch -> ch_head .next = & ch -> ch_head ;
170179 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 ;
171182 ch -> ch_json_head .next = & ch -> ch_json_head ;
172183 ch -> ch_json_head .prev = & ch -> ch_json_head ;
173184
@@ -426,15 +437,23 @@ channel_set_callback(int idx, char_u *callback)
426437}
427438
428439/*
429- * Set the callback for channel "idx" for the next response.
440+ * Set the callback for channel "idx" for the response with "id" .
430441 */
431442 void
432- channel_set_req_callback (int idx , char_u * callback )
443+ channel_set_req_callback (int idx , char_u * callback , int id )
433444{
434- /* TODO: make a list of callbacks */
435- vim_free (channels [idx ].ch_req_callback );
436- channels [idx ].ch_req_callback = callback == NULL
437- ? NULL : vim_strsave (callback );
445+ cbq_T * cbhead = & channels [idx ].ch_cb_head ;
446+ cbq_T * item = (cbq_T * )alloc ((int )sizeof (cbq_T ));
447+
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+ }
438457}
439458
440459/*
@@ -597,6 +616,19 @@ channel_parse_json(int ch_idx)
597616 return ret ;
598617}
599618
619+ /*
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+
600632/*
601633 * Remove "node" from the queue that it is in and free it.
602634 * Caller should have freed or used node->value.
@@ -628,8 +660,7 @@ channel_get_json(int ch_idx, int id, typval_T **rettv)
628660 typval_T * tv = & l -> lv_first -> li_tv ;
629661
630662 if ((id > 0 && tv -> v_type == VAR_NUMBER && tv -> vval .v_number == id )
631- || (id <= 0
632- && (tv -> v_type != VAR_NUMBER || tv -> vval .v_number < 0 )))
663+ || id <= 0 )
633664 {
634665 * rettv = item -> value ;
635666 remove_json_node (item );
@@ -742,9 +773,10 @@ may_invoke_callback(int idx)
742773 typval_T * typetv ;
743774 typval_T argv [3 ];
744775 int seq_nr = -1 ;
745- int json_mode = channels [idx ].ch_json_mode ;
776+ channel_T * channel = & channels [idx ];
777+ int json_mode = channel -> ch_json_mode ;
746778
747- if (channels [ idx ]. ch_close_cb != NULL )
779+ if (channel -> ch_close_cb != NULL )
748780 /* this channel is handled elsewhere (netbeans) */
749781 return FALSE;
750782
@@ -804,17 +836,27 @@ may_invoke_callback(int idx)
804836 argv [1 ].vval .v_string = msg ;
805837 }
806838
807- if (channels [ idx ]. ch_req_callback != NULL && seq_nr != 0 )
839+ if (seq_nr > 0 )
808840 {
809- /* TODO: check the sequence number */
810- /* invoke the one-time callback */
811- invoke_callback (idx , channels [idx ].ch_req_callback , argv );
812- channels [idx ].ch_req_callback = NULL ;
841+ cbq_T * cbhead = & channel -> ch_cb_head ;
842+ cbq_T * cbitem = cbhead -> next ;
843+
844+ /* invoke the one-time callback with the matching nr */
845+ while (cbitem != cbhead )
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+ }
813855 }
814- else if (channels [ idx ]. ch_callback != NULL )
856+ else if (channel -> ch_callback != NULL )
815857 {
816858 /* invoke the channel callback */
817- invoke_callback (idx , channels [ idx ]. ch_callback , argv );
859+ invoke_callback (idx , channel -> ch_callback , argv );
818860 }
819861 /* else: drop the message TODO: give error */
820862
@@ -844,6 +886,7 @@ channel_close(int idx)
844886{
845887 channel_T * channel = & channels [idx ];
846888 jsonq_T * jhead ;
889+ cbq_T * cbhead ;
847890
848891 if (channel -> ch_fd >= 0 )
849892 {
@@ -859,6 +902,10 @@ channel_close(int idx)
859902 while (channel_peek (idx ) != NULL )
860903 vim_free (channel_get (idx ));
861904
905+ cbhead = & channel -> ch_cb_head ;
906+ while (cbhead -> next != cbhead )
907+ remove_cb_node (cbhead -> next );
908+
862909 jhead = & channel -> ch_json_head ;
863910 while (jhead -> next != jhead )
864911 {
0 commit comments