Просмотр исходного кода

core: keep file @mentions responsive on first search

Shoubhit Dash 4 месяцев назад
Родитель
Сommit
0ca507fd00

+ 3 - 0
packages/app/src/components/prompt-input.tsx

@@ -573,14 +573,17 @@ export const PromptInput: Component<PromptInputProps> = (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"

+ 22 - 5
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("/.")
 

+ 3 - 1
packages/ui/src/hooks/use-filtered-list.tsx

@@ -14,6 +14,7 @@ export interface FilteredListProps<T> {
   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<T>(props: FilteredListProps<T>) {
@@ -51,8 +52,9 @@ export function useFilteredList<T>(props: FilteredListProps<T>) {
   )
 
   const flat = createMemo(() => {
+    const groups = props.stale === false && grouped.loading ? empty : grouped.latest || []
     return pipe(
-      grouped.latest || [],
+      groups,
       flatMap((x) => x.items),
     )
   })