import { slab } from "./slab" ; import { buildPatternForBasicMatch , buildPatternForExtendedMatch , } from "./pattern" ; import { computeExtendedMatch } from "./extended" ; import type { BaseFinder , SyncFinder , AsyncFinder } from "./finders" ; import { FzfResultItem , Token } from "./types" ; function getResultFromScoreMap < T > ( scoreMap , limit ) { const scoresInDesc = Object . keys ( scoreMap ) . map ( ( v ) => parseInt ( v , 10 ) ) . sort ( ( a , b ) => b - a ) ; let result = [ ] ; for ( const score of scoresInDesc ) { result = result . concat ( scoreMap [ score ] ) ; if ( result . length >= limit ) { break ; } } return result ; } function getBasicMatchIter < U > ( this , scoreMap , queryRunes , caseSensitive ) { return ( idx ) => { const itemRunes = this . runesList [ idx ] ; if ( queryRunes . length > itemRunes . length ) return ; let [ match , positions ] = this . algoFn ( caseSensitive , this . opts . normalize , this . opts . forward , itemRunes , queryRunes , true , slab ) ; if ( match . start === - 1 ) return ; if ( this . opts . fuzzy === false ) { positions = new Set ( ) ; for ( let position = match . start ; position < match . end ; ++ position ) { positions . add ( position ) ; } } const scoreKey = this . opts . sort ? match . score : 0 ; if ( scoreMap [ scoreKey ] === undefined ) { scoreMap [ scoreKey ] = [ ] ; } scoreMap [ scoreKey ] . push ( { item : this . items [ idx ] , ... match , positions : positions ?? new Set ( ) , } ) ; } ; } function getExtendedMatchIter < U > ( this , scoreMap , pattern ) { return ( idx ) => { const runes = this . runesList [ idx ] ; const match = computeExtendedMatch ( runes , pattern , this . algoFn , this . opts . forward ) ; if ( match . offsets . length !== pattern . termSets . length ) return ; let sidx = - 1 , eidx = - 1 ; if ( match . allPos . size > 0 ) { sidx = Math . min ( ... match . allPos ) ; eidx = Math . max ( ... match . allPos ) + 1 ; } const scoreKey = this . opts . sort ? match . totalScore : 0 ; if ( scoreMap [ scoreKey ] === undefined ) { scoreMap [ scoreKey ] = [ ] ; } scoreMap [ scoreKey ] . push ( { score : match . totalScore , item : this . items [ idx ] , positions : match . allPos , start : sidx , end : eidx , } ) ; } ; } export function basicMatch < U > ( this , query ) { const { queryRunes , caseSensitive } = buildPatternForBasicMatch ( query , this . opts . casing , this . opts . normalize ) ; const scoreMap = { } ; const iter = getBasicMatchIter . bind ( this as BaseFinder < readonly U [ ] > ) ( scoreMap , queryRunes , caseSensitive ) ; for ( let i = 0 , len = this . runesList . length ; i < len ; ++ i ) { iter ( i ) ; } return getResultFromScoreMap ( scoreMap , this . opts . limit ) ; } export function extendedMatch < U > ( this , query ) { const pattern = buildPatternForExtendedMatch ( Boolean ( this . opts . fuzzy ) , this . opts . casing , this . opts . normalize , query ) ; const scoreMap = { } ; const iter = getExtendedMatchIter . bind ( this as BaseFinder < readonly U [ ] > ) ( scoreMap , pattern ) ; for ( let i = 0 , len = this . runesList . length ; i < len ; ++ i ) { iter ( i ) ; } return getResultFromScoreMap ( scoreMap , this . opts . limit ) ; } const isNode = typeof require !== "undefined" && typeof window === "undefined" ; function asyncMatcher < F > ( token , len , iter , onFinish ) { return new Promise ( ( resolve , reject ) => { const INCREMENT = 1000 ; let i = 0 , end = Math . min ( INCREMENT , len ) ; const step = ( ) => { if ( token . cancelled ) return reject ( "search cancelled" ) ; for ( ; i < end ; ++ i ) { iter ( i ) ; } if ( end < len ) { end = Math . min ( end + INCREMENT , len ) ; isNode ? setImmediate ( step ) : setTimeout ( step ) ; } else { resolve ( onFinish ( ) ) ; } } ; step ( ) ; } ) ; } export function asyncBasicMatch < U > ( this , query , token ) { const { queryRunes , caseSensitive } = buildPatternForBasicMatch ( query , this . opts . casing , this . opts . normalize ) ; const scoreMap = { } ; return asyncMatcher ( token , this . runesList . length , getBasicMatchIter . bind ( this as BaseFinder < readonly U [ ] > ) ( scoreMap , queryRunes , caseSensitive ) , ( ) => getResultFromScoreMap ( scoreMap , this . opts . limit ) ) ; } export function asyncExtendedMatch < U > ( this , query , token ) { const pattern = buildPatternForExtendedMatch ( Boolean ( this . opts . fuzzy ) , this . opts . casing , this . opts . normalize , query ) ; const scoreMap = { } ; return asyncMatcher ( token , this . runesList . length , getExtendedMatchIter . bind ( this as BaseFinder < readonly U [ ] > ) ( scoreMap , pattern ) , ( ) => getResultFromScoreMap ( scoreMap , this . opts . limit ) ) ; }