From 0ca507fd008eb754f8f891204afd45376b261769 Mon Sep 17 00:00:00 2001 From: Shoubhit Dash Date: Wed, 25 Mar 2026 21:37:50 +0530 Subject: [PATCH] core: keep file @mentions responsive on first search --- packages/app/src/components/prompt-input.tsx | 3 +++ packages/opencode/src/file/index.ts | 27 ++++++++++++++++---- packages/ui/src/hooks/use-filtered-list.tsx | 4 ++- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index 3117723d31..ac8975bb4d 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -573,14 +573,17 @@ export const PromptInput: Component = (props) => { const seen = new Set(open) const pinned: AtOption[] = open.map((path) => ({ type: "file", path, display: path, recent: true })) if (!query.trim()) return [...agents, ...pinned] + const pathy = /[./\\]/.test(query) const paths = await files.searchFiles(query) const fileOptions: AtOption[] = paths .filter((path) => !seen.has(path)) .map((path) => ({ type: "file", path, display: path })) + if (pathy) return fileOptions return [...agents, ...pinned, ...fileOptions] }, key: atKey, filterKeys: ["display"], + stale: false, groupBy: (item) => { if (item.type === "agent") return "agent" if (item.recent) return "recent" diff --git a/packages/opencode/src/file/index.ts b/packages/opencode/src/file/index.ts index 9682caf129..540f1ac548 100644 --- a/packages/opencode/src/file/index.ts +++ b/packages/opencode/src/file/index.ts @@ -14,6 +14,7 @@ import { Instance } from "../project/instance" import { Filesystem } from "../util/filesystem" import { Glob } from "../util/glob" import { Log } from "../util/log" +import { Fff } from "./fff" import { Protected } from "./protected" export namespace File { @@ -660,15 +661,31 @@ export namespace File { dirs?: boolean type?: "file" | "directory" }) { + const query = input.query.trim() + const limit = input.limit ?? 100 + const kind = input.type ?? (input.dirs === false ? "file" : "all") + log.info("search", { query, kind }) + + if (query && kind === "file") { + const fast = yield* Effect.promise(() => + Fff.files({ + cwd: Instance.directory, + query, + size: limit, + }) + .then((out) => Array.from(new Set(out.items.map((item) => item.relativePath.replaceAll("\\", "/"))))) + .catch(() => []), + ) + if (fast.length) { + log.info("search", { query, kind, results: fast.length, mode: "fff" }) + return fast + } + } + yield* ensure() const { cache } = yield* InstanceState.get(state) return yield* Effect.promise(async () => { - const query = input.query.trim() - const limit = input.limit ?? 100 - const kind = input.type ?? (input.dirs === false ? "file" : "all") - log.info("search", { query, kind }) - const result = cache const preferHidden = query.startsWith(".") || query.includes("/.") diff --git a/packages/ui/src/hooks/use-filtered-list.tsx b/packages/ui/src/hooks/use-filtered-list.tsx index 2d4e2bdd1a..782f25d43b 100644 --- a/packages/ui/src/hooks/use-filtered-list.tsx +++ b/packages/ui/src/hooks/use-filtered-list.tsx @@ -14,6 +14,7 @@ export interface FilteredListProps { sortGroupsBy?: (a: { category: string; items: T[] }, b: { category: string; items: T[] }) => number onSelect?: (value: T | undefined, index: number) => void noInitialSelection?: boolean + stale?: boolean } export function useFilteredList(props: FilteredListProps) { @@ -51,8 +52,9 @@ export function useFilteredList(props: FilteredListProps) { ) const flat = createMemo(() => { + const groups = props.stale === false && grouped.loading ? empty : grouped.latest || [] return pipe( - grouped.latest || [], + groups, flatMap((x) => x.items), ) })