Skip to content

Commit c73c344

Browse files
File suggestions (#88)
1 parent 4b1a782 commit c73c344

File tree

4 files changed

+125
-42
lines changed

4 files changed

+125
-42
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Added file suggestions as a suggestion type. ([#88](https://github.com/sourcebot-dev/sourcebot/pull/88))
13+
1014
## [2.5.0] - 2024-11-22
1115

1216
### Added

packages/web/src/app/components/searchBar/searchBar.tsx

Lines changed: 17 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
'use client';
22

3+
import { useClickListener } from "@/hooks/useClickListener";
34
import { useTailwind } from "@/hooks/useTailwind";
4-
import { Repository, SearchQueryParams } from "@/lib/types";
5+
import { SearchQueryParams } from "@/lib/types";
56
import { cn, createPathWithQueryParams } from "@/lib/utils";
67
import {
78
cursorCharLeft,
@@ -31,12 +32,10 @@ import { createTheme } from '@uiw/codemirror-themes';
3132
import CodeMirror, { Annotation, EditorView, KeyBinding, keymap, ReactCodeMirrorRef } from "@uiw/react-codemirror";
3233
import { cva } from "class-variance-authority";
3334
import { useRouter } from "next/navigation";
34-
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
35+
import { useCallback, useMemo, useRef, useState } from "react";
3536
import { useHotkeys } from 'react-hotkeys-hook';
36-
import { SearchSuggestionsBox, Suggestion } from "./searchSuggestionsBox";
37-
import { useClickListener } from "@/hooks/useClickListener";
38-
import { getRepos } from "../../api/(client)/client";
39-
import languages from "./languages";
37+
import { SearchSuggestionsBox, SuggestionMode } from "./searchSuggestionsBox";
38+
import { useSuggestionsData } from "./useSuggestionsData";
4039
import { zoekt } from "./zoektLanguageExtension";
4140

4241
interface SearchBarProps {
@@ -97,6 +96,8 @@ export const SearchBar = ({
9796

9897
const focusEditor = useCallback(() => editorRef.current?.view?.focus(), []);
9998
const focusSuggestionsBox = useCallback(() => suggestionBoxRef.current?.focus(), []);
99+
const [suggestionMode, setSuggestionMode] = useState<SuggestionMode>("refine");
100+
const [suggestionQuery, setSuggestionQuery] = useState("");
100101

101102
const [_query, setQuery] = useState(defaultQuery ?? "");
102103
const query = useMemo(() => {
@@ -105,41 +106,10 @@ export const SearchBar = ({
105106
return _query.replaceAll(/\n/g, " ");
106107
}, [_query]);
107108

108-
const [repos, setRepos] = useState<Repository[]>([]);
109-
useEffect(() => {
110-
getRepos().then((response) => {
111-
setRepos(response.List.Repos.map(r => r.Repository));
112-
});
113-
}, []);
114-
115-
const suggestionData = useMemo(() => {
116-
const repoSuggestions: Suggestion[] = repos.map((repo) => {
117-
return {
118-
value: repo.Name,
119-
}
120-
});
121-
122-
const languageSuggestions: Suggestion[] = languages.map((lang) => {
123-
const spotlight = [
124-
"Python",
125-
"Java",
126-
"TypeScript",
127-
"Go",
128-
"C++",
129-
"C#"
130-
].includes(lang);
131-
132-
return {
133-
value: lang,
134-
spotlight,
135-
};
136-
})
137-
138-
return {
139-
repos: repoSuggestions,
140-
languages: languageSuggestions,
141-
}
142-
}, [repos]);
109+
const suggestionData = useSuggestionsData({
110+
suggestionMode,
111+
suggestionQuery,
112+
});
143113

144114
const theme = useMemo(() => {
145115
return createTheme({
@@ -286,6 +256,12 @@ export const SearchBar = ({
286256
}}
287257
cursorPosition={cursorPosition}
288258
data={suggestionData}
259+
onSuggestionModeChanged={(suggestionMode) => {
260+
setSuggestionMode(suggestionMode);
261+
}}
262+
onSuggestionQueryChanged={(suggestionQuery) => {
263+
setSuggestionQuery(suggestionQuery);
264+
}}
289265
/>
290266
</div>
291267
)

packages/web/src/app/components/searchBar/searchSuggestionsBox.tsx

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,13 @@ interface SearchSuggestionsBoxProps {
4747
onFocus: () => void;
4848
onBlur: () => void;
4949
onReturnFocus: () => void;
50+
onSuggestionModeChanged: (suggestionMode: SuggestionMode) => void;
51+
onSuggestionQueryChanged: (suggestionQuery: string) => void;
5052

5153
data: {
5254
repos: Suggestion[];
5355
languages: Suggestion[];
56+
files: Suggestion[];
5457
}
5558
}
5659

@@ -64,6 +67,8 @@ const SearchSuggestionsBox = forwardRef(({
6467
onFocus,
6568
onBlur,
6669
onReturnFocus,
70+
onSuggestionModeChanged,
71+
onSuggestionQueryChanged,
6772
}: SearchSuggestionsBoxProps, ref: Ref<HTMLDivElement>) => {
6873

6974
const [highlightedSuggestionIndex, setHighlightedSuggestionIndex] = useState(0);
@@ -137,6 +142,7 @@ const SearchSuggestionsBox = forwardRef(({
137142
list,
138143
isHighlightEnabled = false,
139144
isSpotlightEnabled = false,
145+
isClientSideSearchEnabled = true,
140146
onSuggestionClicked,
141147
Icon,
142148
} = ((): {
@@ -145,6 +151,7 @@ const SearchSuggestionsBox = forwardRef(({
145151
list: Suggestion[],
146152
isHighlightEnabled?: boolean,
147153
isSpotlightEnabled?: boolean,
154+
isClientSideSearchEnabled?: boolean,
148155
onSuggestionClicked: (value: string) => void,
149156
Icon?: Icon
150157
} => {
@@ -192,6 +199,11 @@ const SearchSuggestionsBox = forwardRef(({
192199
onSuggestionClicked: createOnSuggestionClickedHandler({ trailingSpace: false }),
193200
}
194201
case "file":
202+
return {
203+
list: data.files,
204+
onSuggestionClicked: createOnSuggestionClickedHandler(),
205+
isClientSideSearchEnabled: false,
206+
}
195207
case "revision":
196208
case "content":
197209
case "symbol":
@@ -228,6 +240,10 @@ const SearchSuggestionsBox = forwardRef(({
228240
return [];
229241
}
230242

243+
if (!isClientSideSearchEnabled) {
244+
return list;
245+
}
246+
231247
return fuse.search(suggestionQuery, {
232248
limit,
233249
}).map(result => result.item);
@@ -240,13 +256,25 @@ const SearchSuggestionsBox = forwardRef(({
240256
onSuggestionClicked,
241257
}
242258

243-
}, [suggestionQuery, suggestionMode, onCompletion, cursorPosition, data.repos, data.languages, query]);
259+
}, [suggestionQuery, suggestionMode, query, cursorPosition, onCompletion, data.repos, data.files, data.languages]);
244260

245261
// When the list of suggestions change, reset the highlight index
246262
useEffect(() => {
247263
setHighlightedSuggestionIndex(0);
248264
}, [suggestions]);
249265

266+
useEffect(() => {
267+
if (isDefined(suggestionMode)) {
268+
onSuggestionModeChanged(suggestionMode);
269+
}
270+
}, [onSuggestionModeChanged, suggestionMode]);
271+
272+
useEffect(() => {
273+
if (isDefined(suggestionQuery)) {
274+
onSuggestionQueryChanged(suggestionQuery);
275+
}
276+
}, [onSuggestionQueryChanged, suggestionQuery]);
277+
250278
const suggestionModeText = useMemo(() => {
251279
if (!suggestionMode) {
252280
return "";
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
'use client';
2+
3+
import { useQuery } from "@tanstack/react-query";
4+
import { Suggestion, SuggestionMode } from "./searchSuggestionsBox";
5+
import { getRepos, search } from "@/app/api/(client)/client";
6+
import { useMemo } from "react";
7+
import languages from "./languages";
8+
9+
interface Props {
10+
suggestionMode: SuggestionMode;
11+
suggestionQuery: string;
12+
}
13+
14+
/**
15+
* Fetches suggestions for the search bar.
16+
*/
17+
export const useSuggestionsData = ({
18+
suggestionMode,
19+
suggestionQuery,
20+
}: Props) => {
21+
const { data: repoSuggestions } = useQuery({
22+
queryKey: ["repoSuggestions"],
23+
queryFn: getRepos,
24+
select: (data): Suggestion[] => {
25+
return data.List.Repos
26+
.map(r => r.Repository)
27+
.map(r => ({
28+
value: r.Name
29+
}));
30+
},
31+
enabled: suggestionMode === "repo",
32+
});
33+
34+
const { data: fileSuggestions } = useQuery({
35+
queryKey: ["fileSuggestions", suggestionQuery],
36+
queryFn: () => search({
37+
query: `file:${suggestionQuery}`,
38+
maxMatchDisplayCount: 15,
39+
}),
40+
select: (data): Suggestion[] => {
41+
return data.Result.Files?.map((file) => ({
42+
value: file.FileName
43+
})) ?? [];
44+
},
45+
enabled: suggestionMode === "file"
46+
});
47+
48+
const languageSuggestions = useMemo((): Suggestion[] => {
49+
return languages.map((lang) => {
50+
const spotlight = [
51+
"Python",
52+
"Java",
53+
"TypeScript",
54+
"Go",
55+
"C++",
56+
"C#"
57+
].includes(lang);
58+
59+
return {
60+
value: lang,
61+
spotlight,
62+
};
63+
});
64+
}, []);
65+
66+
const data = useMemo(() => {
67+
return {
68+
repos: repoSuggestions ?? [],
69+
languages: languageSuggestions,
70+
files: fileSuggestions ?? [],
71+
}
72+
}, [repoSuggestions, fileSuggestions, languageSuggestions]);
73+
74+
return data;
75+
}

0 commit comments

Comments
 (0)