11import type { SgSearch } from '../postMessage'
22import { childPort } from '../postMessage'
3- import { useCallback , useMemo , useState } from 'react'
3+ import { useCallback , useMemo , useState , useRef } from 'react'
44import { useDebounce } from 'react-use'
55
6+ type StreamHandler = ( r : SgSearch [ ] ) => void
7+
68// id should not overflow, the MOD is large enough
79// for most cases (unless there is buggy search)
810const MOD = 1e9 + 7
911
1012// maintain the latest search task id and callback
1113let id = 0
12- let currentResolve : ( r : SgSearch [ ] ) => void
14+ let currentResolve : ( id : number ) => void
1315let currentReject = ( ) => { }
16+ let currentHandler : StreamHandler
1417
15- function postSearch ( inputValue : string ) {
18+ function postSearch ( inputValue : string , onStream : StreamHandler ) {
1619 id = ( id + 1 ) % MOD
1720 childPort . postMessage ( 'search' , { id, inputValue } )
1821 currentReject ( )
19- return new Promise < SgSearch [ ] > ( ( resolve , reject ) => {
22+ currentHandler = onStream
23+ return new Promise < number > ( ( resolve , reject ) => {
2024 currentResolve = resolve
2125 currentReject = reject
2226 } )
@@ -26,17 +30,16 @@ childPort.onMessage('searchResultStreaming', event => {
2630 if ( event . id !== id ) {
2731 return
2832 }
29- currentResolve ( event . searchResult )
30- currentResolve = ( ) => { }
31- currentReject = ( ) => { }
33+ currentHandler ( event . searchResult )
3234} )
3335childPort . onMessage ( 'searchEnd' , event => {
3436 if ( event . id !== id ) {
3537 return
3638 }
37- currentResolve ( [ ] )
39+ currentResolve ( id )
3840 currentResolve = ( ) => { }
3941 currentReject = ( ) => { }
42+ currentHandler = ( ) => { }
4043} )
4144
4245function groupBy ( matches : SgSearch [ ] ) {
@@ -51,33 +54,35 @@ function groupBy(matches: SgSearch[]) {
5154}
5255
5356export const useSearchResult = ( inputValue : string ) => {
54- const [ searchResult , setResult ] = useState < SgSearch [ ] > ( [ ] )
57+ const resultRef = useRef < SgSearch [ ] > ( [ ] )
5558 const [ searching , setSearching ] = useState ( false )
5659 const [ queryInFlight , setQuery ] = useState ( inputValue )
5760
5861 const refreshSearchResult = useCallback ( ( ) => {
5962 setSearching ( true )
60- postSearch ( inputValue )
61- . then ( res => {
62- setResult ( res )
63+ resultRef . current = [ ]
64+ postSearch ( inputValue , ret => {
65+ resultRef . current . push ( ...ret )
66+ setQuery ( inputValue + resultRef . current . length )
67+ } )
68+ . then ( ( ) => {
6369 setSearching ( false )
64- setQuery ( inputValue )
6570 } )
6671 . catch ( ( ) => {
6772 // TODO: cancelled request, should send cancel to extension
6873 } )
6974 } , [ inputValue ] )
7075
7176 const groupedByFileSearchResult = useMemo ( ( ) => {
72- return [ ...groupBy ( searchResult ) . entries ( ) ]
73- } , [ searchResult ] )
77+ return [ ...groupBy ( resultRef . current ) . entries ( ) ]
78+ } , [ resultRef . current . length ] )
7479
7580 useDebounce ( refreshSearchResult , 100 , [ inputValue ] )
7681
7782 return {
7883 queryInFlight,
7984 searching,
80- searchResult,
85+ searchResult : resultRef . current ,
8186 groupedByFileSearchResult,
8287 refreshSearchResult
8388 }
0 commit comments