fix: speed up fff file search (#31366)

This commit is contained in:
Shoubhit Dash 2026-06-08 19:09:55 +05:30 committed by GitHub
commit b1a6c40ad0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 68 additions and 39 deletions

View file

@ -134,15 +134,12 @@ function item(hit: Fff.Hit): Item {
}
function collectPaths<T>(
out: { items: T[]; scores: Array<{ total: number }> },
items: T[],
toPath: (item: T) => string,
opts?: { includeZeroScore?: boolean },
): string[] {
return Array.from(
new Set(
out.items.flatMap((item, idx): string[] => {
const score = out.scores[idx]
if (!score || (!opts?.includeZeroScore && score.total <= 0)) return []
items.flatMap((item): string[] => {
const text = toPath(item)
if (!text) return []
return [text]
@ -162,7 +159,7 @@ function searchFff(
if (!out.ok) return out
return {
ok: true,
value: collectPaths(out.value, (entry) => normalize(entry.relativePath), { includeZeroScore: !query }),
value: collectPaths(out.value.items, (entry) => normalize(entry.relativePath)),
}
}
if (kind === "all") {
@ -170,14 +167,14 @@ function searchFff(
if (!out.ok) return out
return {
ok: true,
value: collectPaths(out.value, (entry) => normalize(entry.item.relativePath), { includeZeroScore: !query }),
value: collectPaths(out.value.items, (entry) => normalize(entry.item.relativePath)),
}
}
const out = pick.fileSearch(query, opts)
if (!out.ok) return out
return {
ok: true,
value: collectPaths(out.value, (entry) => normalize(entry.relativePath), { includeZeroScore: !query }),
value: collectPaths(out.value.items, (entry) => normalize(entry.relativePath)),
}
}
@ -241,6 +238,13 @@ export const layer: Layer.Layer<Service, never, FSUtil.Service | Ripgrep.Service
// remove before process exit, so use ripgrep instead of native FFF there.
if (process.env.OPENCODE_TEST_HOME) return undefined
const dir = FSUtil.resolve(cwd)
const existing = state.pick.get(dir)
if (existing) return existing
const pending = state.wait.get(dir)
if (pending) return yield* Deferred.await(pending)
const available = yield* fffSync("check availability", () => Fff.available()).pipe(
Effect.catch((error) => {
log.warn("fff availability check failed", { error })
@ -249,13 +253,6 @@ export const layer: Layer.Layer<Service, never, FSUtil.Service | Ripgrep.Service
)
if (!available) return undefined
const dir = FSUtil.resolve(cwd)
const existing = state.pick.get(dir)
if (existing) return existing
const pending = state.wait.get(dir)
if (pending) return yield* Deferred.await(pending)
const gate = yield* Deferred.make<Picker, Error>()
state.wait.set(dir, gate)
return yield* Effect.gen(function* () {
@ -353,13 +350,12 @@ export const layer: Layer.Layer<Service, never, FSUtil.Service | Ripgrep.Service
const query = input.query.trim()
const kind = input.kind ?? "file"
const pick = yield* picker(input.cwd)
if (!pick) return undefined
const entry = yield* acquire(input.cwd).pipe(Effect.catch(() => Effect.succeed<Picker | undefined>(undefined)))
if (!entry) return undefined
const dir = FSUtil.resolve(input.cwd)
const limit = input.limit ?? 100
const fffResult = yield* fffSync(`${kind} search`, () =>
searchFff(pick, kind, query, {
searchFff(entry.pick, kind, query, {
pageIndex: 0,
currentFile: input.current, // supports both relative and absolute (relative preferred)
pageSize: limit,