@@ -573,6 +573,59 @@ function Picker:_compute_headers(headers, actions)
573573 return vim .list_extend (headers , action_headers )
574574end
575575
576+ function Picker :_matching_worker (mode , list , match_query , total , __type )
577+ if __type == 1 then
578+ if self ._matching_worker_debounced == nil then
579+ self ._matching_worker_debounced = utils .debounce_callback (
580+ self ._options .match_debounce , self ._matching_worker
581+ )
582+ end
583+ self ._matching_worker_debounced (
584+ self , mode , list ,
585+ match_query , total
586+ )
587+ else
588+ -- since this call is sometimes debounced we want to minimize the chance of doing extra work, in case the query has
589+ -- changed in between the call of this callback and it actually execting, we can skip it, the finalization above
590+ -- will ensure that the check should_match will trigger the final matching if needed.
591+ local current = assert (self .select :query ())
592+ if # current == 0 or current ~= match_query then
593+ return
594+ end
595+ -- start a new matcher with a non-empty query, against the target list that list will either be the entire stream
596+ -- accumulated so far, or just the latest chunk from the stream,
597+ self .match :match (list , match_query , function (matching )
598+ if matching == nil then
599+ if not self .match :isvalid () or self .match :isempty () then
600+ local matching_state = self ._state .matching or {}
601+ local accum = matching_state and matching_state .accum
602+ if not accum or # accum [1 ] == 0 then
603+ self .select :list (
604+ utils .EMPTY_TABLE ,
605+ utils .EMPTY_TABLE
606+ )
607+ self .select :status (" 0/0" )
608+ self .select :list (nil , nil )
609+ end
610+ end
611+ else
612+ -- the running match will ensure to reset the state internally in case the query was any different than
613+ -- it is currently stored with the matching state, the matching argument here will either be all results
614+ -- or the current streaming buffer based on the call site of this callback
615+ if assert (mode ) == " all" then self :_running_match () end
616+ matching = self :_running_match (matching , match_query )
617+ self .select :list (matching [1 ], matching [2 ])
618+ self .select :status (string.format (
619+ " %d/%d" , # matching [1 ], total
620+ ))
621+ end
622+ end , self ._state .display )
623+ end
624+ end
625+
626+ -- match_state.workerd = utils.debounce_callback(
627+ -- self._options.match_debounce, match_state.worker)
628+
576629function Picker :_running_match (matching , query )
577630 -- Maintain a running accumulator of match results while a stream is active; it is a
578631 -- {matches, positions, scores} triplet that grows per chunk, resets on query change,
@@ -630,10 +683,6 @@ function Picker:_running_match(matching, query)
630683 debounced = nil ,
631684 }
632685 end
633- if state .matching .query ~= query then
634- self :_running_match ()
635- state .matching = {}
636- end
637686 local match_state = state .matching
638687 match_state .query = assert (query )
639688
@@ -801,52 +850,20 @@ function Picker:_flush_direct()
801850 local query = self .select :query ()
802851
803852 if # all > 0 and type (query ) == " string" and # query > 0 then
804- if not self ._state .matching then
805- self ._state .matching = {}
806- end
807- local match_state = self ._state .matching
808- if match_state .debounced == nil then
809- match_state .debounced = utils .debounce_callback (
810- self ._options .match_debounce ,
811- function (mode , list , match_query , total )
812- local current = self .select :query ()
813- if current ~= match_query or current == " " then
814- return
815- end
816- self .match :match (list , match_query , function (matching )
817- if matching == nil then
818- if not self .match :isvalid () or self .match :isempty () then
819- local current_state = self ._state .matching
820- local accum = current_state and current_state .accum
821- if not accum or # accum [1 ] == 0 then
822- self .select :list (
823- utils .EMPTY_TABLE ,
824- utils .EMPTY_TABLE
825- )
826- self .select :status (" 0/0" )
827- self .select :list (nil , nil )
828- end
829- end
830- else
831- if mode == " all" then self :_running_match () end
832- matching = self :_running_match (matching , match_query )
833- self .select :list (matching [1 ], matching [2 ])
834- self .select :status (string.format (
835- " %d/%d" , # matching [1 ], total
836- ))
837- end
838- end , self ._state .display )
839- end
840- )
841- end
842-
843853 -- If the query changed we have to do a match on all stream entries thus far, to reflect the matching state of these entries
844- -- while the stream is still emitting
845- local query_changed = not match_state or match_state .query ~= query
846- if query_changed and # all > 0 then
847- match_state .debounced (" all" , all , query , # all )
854+ -- while the stream is still emitting. We have two options here the query changed and we have to match on the entire set of
855+ -- results, or keep matching the incoming chunks of the stream and merge with current running match results, since the query
856+ -- never changed
857+ local match_all = not self ._state .matching
858+ or self ._state .matching .query ~= query
859+ if match_all and # all > 0 then
860+ -- debounce call, match onto all stream results, it is safe to debounce this call because we always have access to the latest
861+ -- accumulated results
862+ self :_matching_worker (" all" , all , query , # all , 1 )
848863 elseif buf and # buf > 0 then
849- match_state .debounced (" buf" , buf , query , # all )
864+ -- directly call non-debounced accumulate match worker for the current buffer, it is not safe to debounce this call as
865+ -- the buffer we receive here will no longer be available and and we can not afford to skip it
866+ self :_matching_worker (" buf" , buf , query , # all , 0 )
850867 end
851868 else
852869 -- No query, render all of the results as-is and reset any running accumulator, as it will have become
0 commit comments