diff --git a/package.json b/package.json index 24136e0d..bbb05f3c 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "dependencies": { "@codemirror/commands": "^6.6.0", "@codemirror/lang-javascript": "^6.2.2", + "@codemirror/search": "^6.5.6", "@codemirror/state": "^6.4.1", "@codemirror/view": "^6.33.0", "@radix-ui/react-dropdown-menu": "^2.1.1", diff --git a/src/app/codePreview.tsx b/src/app/codePreview.tsx index 9fb1629f..40a5e173 100644 --- a/src/app/codePreview.tsx +++ b/src/app/codePreview.tsx @@ -2,29 +2,39 @@ import { Button } from "@/components/ui/button"; import { ScrollArea } from "@/components/ui/scroll-area"; -import { EditorView, keymap, ViewPlugin, ViewUpdate } from "@codemirror/view"; -import { Cross1Icon, FileIcon } from "@radix-ui/react-icons"; -import { useTheme } from "next-themes"; -import { useEffect, useMemo, useState } from "react"; -import CodeMirror from '@uiw/react-codemirror'; -import { vim } from "@replit/codemirror-vim"; +import { useExtensionWithDependency } from "@/hooks/useExtensionWithDependency"; +import { gutterWidthExtension } from "@/lib/extensions/gutterWidthExtension"; +import { markMatches, searchResultHighlightExtension } from "@/lib/extensions/searchResultHighlightExtension"; +import { ZoektMatch } from "@/lib/types"; import { defaultKeymap } from "@codemirror/commands"; import { javascript } from "@codemirror/lang-javascript"; +import { search } from "@codemirror/search"; +import { EditorView, keymap } from "@codemirror/view"; +import { Cross1Icon, FileIcon } from "@radix-ui/react-icons"; import { Scrollbar } from "@radix-ui/react-scroll-area"; +import { vim } from "@replit/codemirror-vim"; +import CodeMirror, { ReactCodeMirrorRef } from '@uiw/react-codemirror'; +import { useTheme } from "next-themes"; +import { useEffect, useMemo, useRef, useState } from "react"; + +export interface CodePreviewFile { + content: string; + filepath: string; + matches: ZoektMatch[]; +} interface CodePreviewProps { - code: string; - filepath: string; + file?: CodePreviewFile; keymapType: "default" | "vim"; onClose: () => void; } export const CodePreview = ({ - code, - filepath, + file, keymapType, onClose, }: CodePreviewProps) => { + const editorRef = useRef(null); const { theme: _theme, systemTheme } = useTheme(); const theme = useMemo(() => { if (_theme === "system") { @@ -35,21 +45,27 @@ export const CodePreview = ({ }, [_theme, systemTheme]); const [gutterWidth, setGutterWidth] = useState(0); - const gutterWidthPlugin = useMemo(() => { - return ViewPlugin.fromClass(class { - width: number = 0; - constructor(view: EditorView) { - this.measureWidth(view) + + const keymapExtension = useExtensionWithDependency( + editorRef.current?.view ?? null, + () => { + switch (keymapType) { + case "default": + return keymap.of(defaultKeymap); + case "vim": + return vim(); } - update(update: ViewUpdate) { - if (update.geometryChanged) this.measureWidth(update.view) - } - measureWidth(view: EditorView) { - let gutter = view.scrollDOM.querySelector('.cm-gutters') as HTMLElement - if (gutter) this.width = gutter.offsetWidth - } - }); - }, []); + }, + [keymapType] + ); + + useEffect(() => { + if (!file || !editorRef.current?.view) { + return; + } + + markMatches(file.matches, editorRef.current.view); + }, [file?.matches]); return (
@@ -61,7 +77,7 @@ export const CodePreview = ({ >
- {filepath} + {file?.filepath}