Skip to content

Commit d76f923

Browse files
committed
feat: use fuze for file grep when using @
1 parent d4414cb commit d76f923

1 file changed

Lines changed: 50 additions & 7 deletions

File tree

apps/array/src/renderer/features/message-editor/suggestions/getSuggestions.ts

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ import Fuse, { type IFuseOptions } from "fuse.js";
66
import { useDraftStore } from "../stores/draftStore";
77
import type { CommandSuggestionItem, FileSuggestionItem } from "../types";
88

9-
const FILE_LIMIT = 5;
9+
const FILE_DISPLAY_LIMIT = 25;
10+
const FILE_FETCH_LIMIT = 100;
1011
const COMMAND_LIMIT = 5;
1112

12-
const FUSE_OPTIONS: IFuseOptions<AvailableCommand> = {
13+
const COMMAND_FUSE_OPTIONS: IFuseOptions<AvailableCommand> = {
1314
keys: [
1415
{ name: "name", weight: 0.7 },
1516
{ name: "description", weight: 0.3 },
@@ -18,6 +19,20 @@ const FUSE_OPTIONS: IFuseOptions<AvailableCommand> = {
1819
includeScore: true,
1920
};
2021

22+
interface FileItem {
23+
path: string;
24+
name: string;
25+
}
26+
27+
const FILE_FUSE_OPTIONS: IFuseOptions<FileItem> = {
28+
keys: [
29+
{ name: "name", weight: 0.7 },
30+
{ name: "path", weight: 0.3 },
31+
],
32+
threshold: 0.4,
33+
includeScore: true,
34+
};
35+
2136
function searchCommands(
2237
commands: AvailableCommand[],
2338
query: string,
@@ -26,7 +41,7 @@ function searchCommands(
2641
return commands.slice(0, COMMAND_LIMIT);
2742
}
2843

29-
const fuse = new Fuse(commands, FUSE_OPTIONS);
44+
const fuse = new Fuse(commands, COMMAND_FUSE_OPTIONS);
3045
const results = fuse.search(query, { limit: COMMAND_LIMIT * 2 });
3146

3247
const lowerQuery = query.toLowerCase();
@@ -42,6 +57,27 @@ function searchCommands(
4257
return results.slice(0, COMMAND_LIMIT).map((result) => result.item);
4358
}
4459

60+
function searchFiles(files: FileItem[], query: string): FileItem[] {
61+
if (!query.trim()) {
62+
return files.slice(0, FILE_DISPLAY_LIMIT);
63+
}
64+
65+
const fuse = new Fuse(files, FILE_FUSE_OPTIONS);
66+
const results = fuse.search(query, { limit: FILE_DISPLAY_LIMIT * 2 });
67+
68+
const lowerQuery = query.toLowerCase();
69+
results.sort((a, b) => {
70+
const aStartsWithQuery = a.item.name.toLowerCase().startsWith(lowerQuery);
71+
const bStartsWithQuery = b.item.name.toLowerCase().startsWith(lowerQuery);
72+
73+
if (aStartsWithQuery && !bStartsWithQuery) return -1;
74+
if (!aStartsWithQuery && bStartsWithQuery) return 1;
75+
return (a.score ?? 0) - (b.score ?? 0);
76+
});
77+
78+
return results.slice(0, FILE_DISPLAY_LIMIT).map((result) => result.item);
79+
}
80+
4581
export async function getFileSuggestions(
4682
sessionId: string,
4783
query: string,
@@ -55,19 +91,26 @@ export async function getFileSuggestions(
5591
const results = await trpcVanilla.fs.listRepoFiles.query({
5692
repoPath,
5793
query,
58-
limit: FILE_LIMIT,
94+
limit: FILE_FETCH_LIMIT,
5995
});
6096

61-
return results
97+
const files: FileItem[] = results
6298
.filter(
6399
(file: MentionItem): file is MentionItem & { path: string } =>
64100
!!file.path,
65101
)
66102
.map((file) => ({
67-
id: file.path,
68-
label: file.path,
69103
path: file.path,
104+
name: file.path.split("/").pop() ?? file.path,
70105
}));
106+
107+
const matched = searchFiles(files, query);
108+
109+
return matched.map((file) => ({
110+
id: file.path,
111+
label: file.path,
112+
path: file.path,
113+
}));
71114
}
72115

73116
export function getCommandSuggestions(

0 commit comments

Comments
 (0)