@@ -2153,11 +2153,67 @@ remove_json_node(jsonq_T *head, jsonq_T *node)
21532153 vim_free (node );
21542154}
21552155
2156+ /*
2157+ * Add "id" to the list of JSON message IDs we are waiting on.
2158+ */
2159+ static void
2160+ channel_add_block_id (chanpart_T * chanpart , int id )
2161+ {
2162+ garray_T * gap = & chanpart -> ch_block_ids ;
2163+
2164+ if (gap -> ga_growsize == 0 )
2165+ ga_init2 (gap , (int )sizeof (int ), 10 );
2166+ if (ga_grow (gap , 1 ) == OK )
2167+ {
2168+ ((int * )gap -> ga_data )[gap -> ga_len ] = id ;
2169+ ++ gap -> ga_len ;
2170+ }
2171+ }
2172+
2173+ /*
2174+ * Remove "id" from the list of JSON message IDs we are waiting on.
2175+ */
2176+ static void
2177+ channel_remove_block_id (chanpart_T * chanpart , int id )
2178+ {
2179+ garray_T * gap = & chanpart -> ch_block_ids ;
2180+ int i ;
2181+
2182+ for (i = 0 ; i < gap -> ga_len ; ++ i )
2183+ if (((int * )gap -> ga_data )[i ] == id )
2184+ {
2185+ -- gap -> ga_len ;
2186+ if (i < gap -> ga_len )
2187+ {
2188+ int * p = ((int * )gap -> ga_data ) + i ;
2189+
2190+ mch_memmove (p , p + 1 , (gap -> ga_len - i ) * sizeof (int ));
2191+ }
2192+ return ;
2193+ }
2194+ siemsg ("INTERNAL: channel_remove_block_id: cannot find id %d" , id );
2195+ }
2196+
2197+ /*
2198+ * Return TRUE if "id" is in the list of JSON message IDs we are waiting on.
2199+ */
2200+ static int
2201+ channel_has_block_id (chanpart_T * chanpart , int id )
2202+ {
2203+ garray_T * gap = & chanpart -> ch_block_ids ;
2204+ int i ;
2205+
2206+ for (i = 0 ; i < gap -> ga_len ; ++ i )
2207+ if (((int * )gap -> ga_data )[i ] == id )
2208+ return TRUE;
2209+ return FALSE;
2210+ }
2211+
21562212/*
21572213 * Get a message from the JSON queue for channel "channel".
21582214 * When "id" is positive it must match the first number in the list.
2159- * When "id" is zero or negative jut get the first message. But not the one
2160- * with id ch_block_id .
2215+ * When "id" is zero or negative jut get the first message. But not one
2216+ * in the ch_block_ids list .
21612217 * When "without_callback" is TRUE also get messages that were pushed back.
21622218 * Return OK when found and return the value in "rettv".
21632219 * Return FAIL otherwise.
@@ -2182,7 +2238,8 @@ channel_get_json(
21822238 && ((id > 0 && tv -> v_type == VAR_NUMBER && tv -> vval .v_number == id )
21832239 || (id <= 0 && (tv -> v_type != VAR_NUMBER
21842240 || tv -> vval .v_number == 0
2185- || tv -> vval .v_number != channel -> ch_part [part ].ch_block_id ))))
2241+ || !channel_has_block_id (
2242+ & channel -> ch_part [part ], tv -> vval .v_number )))))
21862243 {
21872244 * rettv = item -> jq_value ;
21882245 if (tv -> v_type == VAR_NUMBER )
@@ -3050,6 +3107,7 @@ channel_clear_one(channel_T *channel, ch_part_T part)
30503107 }
30513108
30523109 free_callback (& ch_part -> ch_callback );
3110+ ga_clear (& ch_part -> ch_block_ids );
30533111
30543112 while (ch_part -> ch_writeque .wq_next != NULL )
30553113 remove_from_writeque (& ch_part -> ch_writeque ,
@@ -3480,6 +3538,8 @@ channel_read_block(
34803538 * result in "rettv".
34813539 * When "id" is -1 accept any message;
34823540 * Blocks until the message is received or the timeout is reached.
3541+ * In corner cases this can be called recursively, that is why ch_block_ids is
3542+ * a list.
34833543 */
34843544 static int
34853545channel_read_json_block (
@@ -3494,17 +3554,19 @@ channel_read_json_block(
34943554 int timeout ;
34953555 chanpart_T * chanpart = & channel -> ch_part [part ];
34963556
3497- ch_log (channel , "Reading JSON" );
3498- if (id != -1 )
3499- chanpart -> ch_block_id = id ;
3557+ ch_log (channel , "Blocking read JSON for id %d" , id );
3558+ if (id >= 0 )
3559+ channel_add_block_id ( chanpart , id ) ;
35003560 for (;;)
35013561 {
35023562 more = channel_parse_json (channel , part );
35033563
3504- /* search for message "id" */
3564+ // search for message "id"
35053565 if (channel_get_json (channel , part , id , TRUE, rettv ) == OK )
35063566 {
3507- chanpart -> ch_block_id = 0 ;
3567+ if (id >= 0 )
3568+ channel_remove_block_id (chanpart , id );
3569+ ch_log (channel , "Received JSON for id %d" , id );
35083570 return OK ;
35093571 }
35103572
@@ -3551,15 +3613,16 @@ channel_read_json_block(
35513613 if (timeout == timeout_arg )
35523614 {
35533615 if (fd != INVALID_FD )
3554- ch_log (channel , "Timed out" );
3616+ ch_log (channel , "Timed out on id %d" , id );
35553617 break ;
35563618 }
35573619 }
35583620 else
35593621 channel_read (channel , part , "channel_read_json_block" );
35603622 }
35613623 }
3562- chanpart -> ch_block_id = 0 ;
3624+ if (id >= 0 )
3625+ channel_remove_block_id (chanpart , id );
35633626 return FAIL ;
35643627}
35653628
0 commit comments