fix: improve file mention suggestions without ripgrep

This commit is contained in:
Federico Jaramillo Martinez
2026-05-31 20:04:59 +02:00
parent 1ae28d8f59
commit fdd2cf2390
12 changed files with 247 additions and 41 deletions
@@ -0,0 +1,75 @@
import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { listFileSuggestions, type FileSuggestionDependencies } from "./fileSuggestions";
const temporaryRoots: string[] = [];
async function tempWorkspace(): Promise<string> {
const root = await mkdtemp(join(tmpdir(), "pi-web-files-"));
temporaryRoots.push(root);
return root;
}
afterEach(async () => {
await Promise.all(temporaryRoots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
});
describe("file suggestions", () => {
it("uses tracked git files for tracked-scope suggestions", async () => {
const calls: { file: string; args: string[] }[] = [];
const deps: FileSuggestionDependencies = {
execFile: (file, args) => {
calls.push({ file, args });
if (file === "git" && args.join(" ") === "ls-files") return Promise.resolve({ stdout: "src/app.ts\nREADME.md\n" });
return Promise.reject(new Error(`unexpected command: ${file} ${args.join(" ")}`));
},
};
await expect(listFileSuggestions("/repo", "", { scope: "tracked" }, deps)).resolves.toEqual([
{ path: "src/", kind: "tracked" },
{ path: "README.md", kind: "tracked" },
{ path: "src/app.ts", kind: "tracked" },
]);
expect(calls).toEqual([{ file: "git", args: ["ls-files"] }]);
});
it("asks ripgrep for hidden and ignored files in all-file scope", async () => {
const calls: { file: string; args: string[] }[] = [];
const deps: FileSuggestionDependencies = {
execFile: (file, args) => {
calls.push({ file, args });
return Promise.resolve({ stdout: "node_modules/pkg/index.js\nsrc/app.ts\n" });
},
};
await expect(listFileSuggestions("/repo", "pkg", { scope: "all" }, deps)).resolves.toEqual([
{ path: "node_modules/pkg/", kind: "other" },
{ path: "node_modules/pkg/index.js", kind: "other" },
]);
expect(calls).toEqual([{ file: "rg", args: ["--files", "--hidden", "--no-ignore"] }]);
});
it("falls back to a bounded filesystem scan without directory exclusions when git and rg are unavailable", async () => {
const root = await tempWorkspace();
await mkdir(join(root, "src"), { recursive: true });
await mkdir(join(root, "node_modules", "pkg"), { recursive: true });
await writeFile(join(root, "README.md"), "hello");
await writeFile(join(root, "src", "app.ts"), "export {};\n");
await writeFile(join(root, "node_modules", "pkg", "index.js"), "module.exports = {};\n");
const deps: FileSuggestionDependencies = {
execFile: (file) => Promise.reject(Object.assign(new Error(`spawn ${file} ENOENT`), { code: "ENOENT" })),
};
await expect(listFileSuggestions(root, "", { scope: "all" }, deps)).resolves.toEqual([
{ path: "node_modules/", kind: "other" },
{ path: "node_modules/pkg/", kind: "other" },
{ path: "src/", kind: "other" },
{ path: "node_modules/pkg/index.js", kind: "other" },
{ path: "README.md", kind: "other" },
{ path: "src/app.ts", kind: "other" },
]);
});
});