Skip to content

Commit d6866e8

Browse files
refactor componenets into seperate files
1 parent 0a4db0a commit d6866e8

6 files changed

Lines changed: 259 additions & 243 deletions

File tree

src/app/search/codePreviewPanel.tsx renamed to src/app/search/components/codePreviewPanel/codePreview.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,19 @@ export interface CodePreviewFile {
2828
language: string;
2929
}
3030

31-
interface CodePreviewPanelProps {
31+
interface CodePreviewProps {
3232
file?: CodePreviewFile;
3333
selectedMatchIndex: number;
3434
onSelectedMatchIndexChange: (index: number) => void;
3535
onClose: () => void;
3636
}
3737

38-
export const CodePreviewPanel = ({
38+
export const CodePreview = ({
3939
file,
4040
selectedMatchIndex,
4141
onSelectedMatchIndexChange,
4242
onClose,
43-
}: CodePreviewPanelProps) => {
43+
}: CodePreviewProps) => {
4444
const editorRef = useRef<ReactCodeMirrorRef>(null);
4545

4646
const [ keymapType ] = useKeymapType();
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
'use client';
2+
3+
import { fetchFileSource } from "@/app/api/(client)/client";
4+
import { SearchResultFile } from "@/lib/schemas";
5+
import { getCodeHostFilePreviewLink } from "@/lib/utils";
6+
import { useQuery } from "@tanstack/react-query";
7+
import { CodePreview, CodePreviewFile } from "./codePreview";
8+
9+
interface CodePreviewPanelProps {
10+
fileMatch?: SearchResultFile;
11+
onClose: () => void;
12+
selectedMatchIndex: number;
13+
onSelectedMatchIndexChange: (index: number) => void;
14+
}
15+
16+
export const CodePreviewPanel = ({
17+
fileMatch,
18+
onClose,
19+
selectedMatchIndex,
20+
onSelectedMatchIndexChange,
21+
}: CodePreviewPanelProps) => {
22+
23+
const { data: file } = useQuery({
24+
queryKey: ["source", fileMatch?.FileName, fileMatch?.Repository],
25+
queryFn: async (): Promise<CodePreviewFile | undefined> => {
26+
if (!fileMatch) {
27+
return undefined;
28+
}
29+
30+
return fetchFileSource(fileMatch.FileName, fileMatch.Repository)
31+
.then(({ source }) => {
32+
// @todo : refector this to use the templates provided by zoekt.
33+
const link = getCodeHostFilePreviewLink(fileMatch.Repository, fileMatch.FileName)
34+
35+
const decodedSource = atob(source);
36+
37+
// Filter out filename matches
38+
const filteredMatches = fileMatch.ChunkMatches.filter((match) => {
39+
return !match.FileName;
40+
});
41+
42+
return {
43+
content: decodedSource,
44+
filepath: fileMatch.FileName,
45+
matches: filteredMatches,
46+
link: link,
47+
language: fileMatch.Language,
48+
};
49+
});
50+
},
51+
enabled: fileMatch !== undefined,
52+
});
53+
54+
return (
55+
<CodePreview
56+
file={file}
57+
onClose={onClose}
58+
selectedMatchIndex={selectedMatchIndex}
59+
onSelectedMatchIndexChange={onSelectedMatchIndexChange}
60+
/>
61+
)
62+
63+
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
'use client';
2+
3+
import { useExtensionWithDependency } from "@/hooks/useExtensionWithDependency";
4+
import { useSyntaxHighlightingExtension } from "@/hooks/useSyntaxHighlightingExtension";
5+
import { useThemeNormalized } from "@/hooks/useThemeNormalized";
6+
import { lineOffsetExtension } from "@/lib/extensions/lineOffsetExtension";
7+
import { SearchResultRange } from "@/lib/schemas";
8+
import CodeMirror, { Decoration, DecorationSet, EditorState, EditorView, ReactCodeMirrorRef, StateField, Transaction } from "@uiw/react-codemirror";
9+
import { useMemo, useRef } from "react";
10+
11+
const markDecoration = Decoration.mark({
12+
class: "cm-searchMatch"
13+
});
14+
15+
const cmTheme = EditorView.baseTheme({
16+
"&light .cm-searchMatch": {
17+
border: "1px #6b7280ff",
18+
},
19+
"&dark .cm-searchMatch": {
20+
border: "1px #d1d5dbff",
21+
},
22+
});
23+
24+
interface CodePreviewProps {
25+
content: string,
26+
language: string,
27+
ranges: SearchResultRange[],
28+
lineOffset: number,
29+
}
30+
31+
export const CodePreview = ({
32+
content,
33+
language,
34+
ranges,
35+
lineOffset,
36+
}: CodePreviewProps) => {
37+
const editorRef = useRef<ReactCodeMirrorRef>(null);
38+
const { theme } = useThemeNormalized();
39+
40+
const syntaxHighlighting = useSyntaxHighlightingExtension(language, editorRef.current?.view);
41+
42+
const rangeHighlighting = useExtensionWithDependency(editorRef.current?.view ?? null, () => {
43+
return [
44+
StateField.define<DecorationSet>({
45+
create(editorState: EditorState) {
46+
const document = editorState.doc;
47+
48+
const decorations = ranges
49+
.sort((a, b) => {
50+
return a.Start.ByteOffset - b.Start.ByteOffset;
51+
})
52+
.filter(({ Start, End }) => {
53+
const startLine = Start.LineNumber - lineOffset;
54+
const endLine = End.LineNumber - lineOffset;
55+
56+
if (
57+
startLine < 1 ||
58+
endLine < 1 ||
59+
startLine > document.lines ||
60+
endLine > document.lines
61+
) {
62+
return false;
63+
}
64+
return true;
65+
})
66+
.map(({ Start, End }) => {
67+
const startLine = Start.LineNumber - lineOffset;
68+
const endLine = End.LineNumber - lineOffset;
69+
70+
const from = document.line(startLine).from + Start.Column - 1;
71+
const to = document.line(endLine).from + End.Column - 1;
72+
return markDecoration.range(from, to);
73+
});
74+
75+
return Decoration.set(decorations);
76+
},
77+
update(highlights: DecorationSet, _transaction: Transaction) {
78+
return highlights;
79+
},
80+
provide: (field) => EditorView.decorations.from(field),
81+
}),
82+
cmTheme
83+
];
84+
}, [ranges, lineOffset]);
85+
86+
const extensions = useMemo(() => {
87+
return [
88+
syntaxHighlighting,
89+
lineOffsetExtension(lineOffset),
90+
rangeHighlighting,
91+
];
92+
}, [syntaxHighlighting, lineOffset, rangeHighlighting]);
93+
94+
return (
95+
<CodeMirror
96+
ref={editorRef}
97+
readOnly={true}
98+
editable={false}
99+
value={content}
100+
theme={theme === "dark" ? "dark" : "light"}
101+
basicSetup={{
102+
lineNumbers: true,
103+
syntaxHighlighting: true,
104+
105+
// Disable all this other stuff...
106+
... {
107+
foldGutter: false,
108+
highlightActiveLineGutter: false,
109+
highlightSpecialChars: false,
110+
history: false,
111+
drawSelection: false,
112+
dropCursor: false,
113+
allowMultipleSelections: false,
114+
indentOnInput: false,
115+
bracketMatching: false,
116+
closeBrackets: false,
117+
autocompletion: false,
118+
rectangularSelection: false,
119+
crosshairCursor: false,
120+
highlightActiveLine: false,
121+
highlightSelectionMatches: false,
122+
closeBracketsKeymap: false,
123+
defaultKeymap: false,
124+
searchKeymap: false,
125+
historyKeymap: false,
126+
foldKeymap: false,
127+
completionKeymap: false,
128+
lintKeymap: false,
129+
}
130+
}}
131+
extensions={extensions}
132+
/>
133+
)
134+
}

0 commit comments

Comments
 (0)