Skip to content

Commit 4e1933d

Browse files
committed
Bound file matches in useSuggestionEngine and eliminate fuzzy match allocations
1 parent ffea1ee commit 4e1933d

2 files changed

Lines changed: 47 additions & 9 deletions

File tree

‎cli/src/hooks/__tests__/use-suggestion-engine-mention.test.ts‎

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import { describe, test, expect } from 'bun:test'
22

3-
import { isInsideStringDelimiters, parseAtInLine } from '../use-suggestion-engine'
3+
import {
4+
filterFileMatches,
5+
isInsideStringDelimiters,
6+
parseAtInLine,
7+
} from '../use-suggestion-engine'
48

59
describe('@ mention edge cases - quote detection', () => {
610
test('isInsideStringDelimiters detects position inside double quotes', () => {
@@ -359,3 +363,29 @@ describe('single quote handling - apostrophes should NOT suppress @ menu', () =>
359363
},
360364
)
361365
})
366+
367+
describe('filterFileMatches - bounding and ranking', () => {
368+
test('caps results to top 100 matches when exceeding threshold', () => {
369+
const manyFiles = Array.from({ length: 250 }, (_, i) => ({
370+
path: `src/components/item-${i}.tsx`,
371+
isDirectory: false,
372+
}))
373+
374+
const results = filterFileMatches(manyFiles, 'item')
375+
expect(results.length).toBe(100)
376+
// Check that results are properly sorted (lowest score first)
377+
for (let i = 1; i < results.length; i++) {
378+
expect((results[i].matchScore ?? 0) >= (results[i - 1].matchScore ?? 0)).toBe(true)
379+
}
380+
})
381+
382+
test('returns all matches when count is within 100 limit', () => {
383+
const files = Array.from({ length: 25 }, (_, i) => ({
384+
path: `src/components/item-${i}.tsx`,
385+
isDirectory: false,
386+
}))
387+
388+
const results = filterFileMatches(files, 'item')
389+
expect(results.length).toBe(25)
390+
})
391+
})

‎cli/src/hooks/use-suggestion-engine.ts‎

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -283,9 +283,13 @@ const getFileName = (filePath: string): string => {
283283
return lastSlash === -1 ? filePath : filePath.slice(lastSlash + 1)
284284
}
285285

286-
const createHighlightIndices = (start: number, end: number): number[] => [
287-
...range(start, end),
288-
]
286+
const createHighlightIndices = (start: number, end: number): number[] => {
287+
const result: number[] = []
288+
for (let i = start; i < end; i++) {
289+
result.push(i)
290+
}
291+
return result
292+
}
289293

290294
const createPushUnique = <T, K>(
291295
getKey: (item: T) => K,
@@ -351,9 +355,13 @@ const fuzzyMatch = (
351355
// - Fewer gaps = better
352356
// - Longer consecutive matches = better
353357
// - Matches at word boundaries (after /) = better
354-
const boundaryBonus = indices.filter(
355-
(idx) => idx === 0 || text[idx - 1] === '/'
356-
).length
358+
let boundaryBonus = 0
359+
for (let i = 0; i < indices.length; i++) {
360+
const idx = indices[i]
361+
if (idx === 0 || text[idx - 1] === '/') {
362+
boundaryBonus++
363+
}
364+
}
357365

358366
const score =
359367
gaps * 10 -
@@ -364,7 +372,7 @@ const fuzzyMatch = (
364372
return { indices, score }
365373
}
366374

367-
const filterFileMatches = (
375+
export const filterFileMatches = (
368376
pathInfos: PathInfo[],
369377
query: string,
370378
): MatchedFileInfo[] => {
@@ -489,7 +497,7 @@ const filterFileMatches = (
489497
// Sort by score (lower is better)
490498
matches.sort((a, b) => (a.matchScore ?? 0) - (b.matchScore ?? 0))
491499

492-
return matches
500+
return matches.length > 100 ? matches.slice(0, 100) : matches
493501
}
494502

495503
const filterAgentMatches = (

0 commit comments

Comments
 (0)