From 157063b8556309ddd2200d2df900c344e2579259 Mon Sep 17 00:00:00 2001 From: bkellam Date: Tue, 12 Nov 2024 14:00:41 -0800 Subject: [PATCH 1/4] wip --- packages/web/src/app/globals.css | 4 + packages/web/src/app/searchBar.tsx | 144 ++++++++++++++++++----------- 2 files changed, 93 insertions(+), 55 deletions(-) diff --git a/packages/web/src/app/globals.css b/packages/web/src/app/globals.css index d1ff0cbb8..9cb88606d 100644 --- a/packages/web/src/app/globals.css +++ b/packages/web/src/app/globals.css @@ -87,6 +87,10 @@ border: solid; } +.cm-editor.cm-focused { + outline: none !important; +} + .truncate-start { direction: rtl; text-align: left; diff --git a/packages/web/src/app/searchBar.tsx b/packages/web/src/app/searchBar.tsx index ffb2a3d1d..cc2e8d395 100644 --- a/packages/web/src/app/searchBar.tsx +++ b/packages/web/src/app/searchBar.tsx @@ -1,22 +1,56 @@ 'use client'; -import { - Form, - FormControl, - FormField, - FormItem, - FormMessage, -} from "@/components/ui/form"; -import { Input } from "@/components/ui/input"; +import { useThemeNormalized } from "@/hooks/useThemeNormalized"; +import { SearchQueryParams } from "@/lib/types"; import { cn, createPathWithQueryParams } from "@/lib/utils"; -import { zodResolver } from "@hookform/resolvers/zod"; +import { + cursorCharLeft, + cursorCharRight, + cursorDocEnd, + cursorDocStart, + cursorLineBoundaryBackward, + cursorLineBoundaryForward, + deleteCharBackward, + deleteCharForward, + deleteGroupBackward, + deleteGroupForward, + deleteLineBoundaryBackward, + deleteLineBoundaryForward, + history, + historyKeymap, + selectAll, + selectCharLeft, + selectCharRight, + selectDocEnd, + selectDocStart, + selectLineBoundaryBackward, + selectLineBoundaryForward +} from "@codemirror/commands"; +import CodeMirror, { KeyBinding, keymap, ReactCodeMirrorRef } from "@uiw/react-codemirror"; import { cva } from "class-variance-authority"; import { useRouter } from "next/navigation"; -import { useForm } from "react-hook-form"; -import { z } from "zod"; -import { useHotkeys } from 'react-hotkeys-hook' -import { useRef } from "react"; -import { SearchQueryParams } from "@/lib/types"; +import { useRef, useState } from "react"; +import { useHotkeys } from 'react-hotkeys-hook'; + +const searchBarKeymap: readonly KeyBinding[] = ([ + { key: "ArrowLeft", run: cursorCharLeft, shift: selectCharLeft, preventDefault: true }, + { key: "ArrowRight", run: cursorCharRight, shift: selectCharRight, preventDefault: true }, + + { key: "Home", run: cursorLineBoundaryBackward, shift: selectLineBoundaryBackward, preventDefault: true }, + { key: "Mod-Home", run: cursorDocStart, shift: selectDocStart }, + + { key: "End", run: cursorLineBoundaryForward, shift: selectLineBoundaryForward, preventDefault: true }, + { key: "Mod-End", run: cursorDocEnd, shift: selectDocEnd }, + + { key: "Mod-a", run: selectAll }, + + { key: "Backspace", run: deleteCharBackward, shift: deleteCharBackward }, + { key: "Delete", run: deleteCharForward }, + { key: "Mod-Backspace", mac: "Alt-Backspace", run: deleteGroupBackward }, + { key: "Mod-Delete", mac: "Alt-Delete", run: deleteGroupForward }, + { mac: "Mod-Backspace", run: deleteLineBoundaryBackward }, + { mac: "Mod-Delete", run: deleteLineBoundaryForward } +] as KeyBinding[]).concat(historyKeymap); interface SearchBarProps { className?: string; @@ -25,12 +59,9 @@ interface SearchBarProps { autoFocus?: boolean; } -const formSchema = z.object({ - query: z.string(), -}); const searchBarVariants = cva( - "w-full", + "flex items-center w-full p-0.5 border rounded-md", { variants: { size: { @@ -51,54 +82,57 @@ export const SearchBar = ({ autoFocus, }: SearchBarProps) => { - const inputRef = useRef(null); + const [query, setQuery] = useState(defaultQuery ?? ""); + const { theme } = useThemeNormalized(); + const editorRef = useRef(null); + useHotkeys('/', (event) => { event.preventDefault(); - inputRef.current?.focus(); + editorRef.current?.view?.focus(); + if (editorRef.current?.view) { + cursorDocEnd({ + state: editorRef.current.view.state, + dispatch: editorRef.current.view.dispatch, + }); + } }); const router = useRouter(); - const form = useForm>({ - resolver: zodResolver(formSchema), - defaultValues: { - query: defaultQuery ?? "", - } - }); - const onSubmit = (values: z.infer) => { + const onSubmit = () => { const url = createPathWithQueryParams('/search', - [SearchQueryParams.query, values.query], + [SearchQueryParams.query, query], ) router.push(url); } return ( -
- - ( - - - - - - - )} - /> - - +
{ + if (e.key === 'Enter') { + e.preventDefault(); + onSubmit(); + } + }} + > + { + setQuery(value); + }} + theme={theme === 'dark' ? 'dark' : 'light'} + basicSetup={false} + extensions={[ + keymap.of(searchBarKeymap), + history(), + ]} + indentWithTab={false} + autoFocus={autoFocus ?? false} + /> +
) } \ No newline at end of file From f74b123473b8d02ac9c9a4bf17ea59d5f92340fc Mon Sep 17 00:00:00 2001 From: bkellam Date: Tue, 12 Nov 2024 14:53:41 -0800 Subject: [PATCH 2/4] fixed theming --- packages/web/package.json | 1 + packages/web/src/app/searchBar.tsx | 23 +++++++++++++++++------ packages/web/src/hooks/useTailwind.ts | 13 +++++++++++++ yarn.lock | 9 +++++++++ 4 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 packages/web/src/hooks/useTailwind.ts diff --git a/packages/web/package.json b/packages/web/package.json index 38443ca52..4fc540bf5 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -39,6 +39,7 @@ "@tanstack/react-query": "^5.53.3", "@tanstack/react-table": "^8.20.5", "@tanstack/react-virtual": "^3.10.8", + "@uiw/codemirror-themes": "^4.23.6", "@uiw/react-codemirror": "^4.23.0", "class-variance-authority": "^0.7.0", "client-only": "^0.0.1", diff --git a/packages/web/src/app/searchBar.tsx b/packages/web/src/app/searchBar.tsx index cc2e8d395..7c6f46d42 100644 --- a/packages/web/src/app/searchBar.tsx +++ b/packages/web/src/app/searchBar.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useThemeNormalized } from "@/hooks/useThemeNormalized"; +import { useTailwind } from "@/hooks/useTailwind"; import { SearchQueryParams } from "@/lib/types"; import { cn, createPathWithQueryParams } from "@/lib/utils"; import { @@ -26,12 +26,12 @@ import { selectLineBoundaryBackward, selectLineBoundaryForward } from "@codemirror/commands"; +import { createTheme } from '@uiw/codemirror-themes'; import CodeMirror, { KeyBinding, keymap, ReactCodeMirrorRef } from "@uiw/react-codemirror"; import { cva } from "class-variance-authority"; import { useRouter } from "next/navigation"; -import { useRef, useState } from "react"; +import { useMemo, useRef, useState } from "react"; import { useHotkeys } from 'react-hotkeys-hook'; - const searchBarKeymap: readonly KeyBinding[] = ([ { key: "ArrowLeft", run: cursorCharLeft, shift: selectCharLeft, preventDefault: true }, { key: "ArrowRight", run: cursorCharRight, shift: selectCharRight, preventDefault: true }, @@ -59,7 +59,6 @@ interface SearchBarProps { autoFocus?: boolean; } - const searchBarVariants = cva( "flex items-center w-full p-0.5 border rounded-md", { @@ -82,8 +81,20 @@ export const SearchBar = ({ autoFocus, }: SearchBarProps) => { + const tailwind = useTailwind(); + const theme = useMemo(() => { + return createTheme({ + theme: 'light', + settings: { + background: tailwind.theme.colors.background, + foreground: tailwind.theme.colors.foreground, + caret: '#AEAFAD', + }, + styles: [], + }); + }, []); + const [query, setQuery] = useState(defaultQuery ?? ""); - const { theme } = useThemeNormalized(); const editorRef = useRef(null); useHotkeys('/', (event) => { @@ -124,7 +135,7 @@ export const SearchBar = ({ onChange={(value) => { setQuery(value); }} - theme={theme === 'dark' ? 'dark' : 'light'} + theme={theme} basicSetup={false} extensions={[ keymap.of(searchBarKeymap), diff --git a/packages/web/src/hooks/useTailwind.ts b/packages/web/src/hooks/useTailwind.ts new file mode 100644 index 000000000..9c72ebecf --- /dev/null +++ b/packages/web/src/hooks/useTailwind.ts @@ -0,0 +1,13 @@ +'use client'; + +import { useMemo } from "react"; +import resolveConfig from 'tailwindcss/resolveConfig'; +import tailwindConfig from '../../tailwind.config'; + +export const useTailwind = () => { + const tailwind = useMemo(() => { + return resolveConfig(tailwindConfig); + }, [tailwindConfig]); + + return tailwind; +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index b8b785071..6a7c0a90d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1743,6 +1743,15 @@ "@codemirror/state" "^6.0.0" "@codemirror/view" "^6.0.0" +"@uiw/codemirror-themes@^4.23.6": + version "4.23.6" + resolved "https://registry.yarnpkg.com/@uiw/codemirror-themes/-/codemirror-themes-4.23.6.tgz#47a101733a9c4aa382696178bc4b7bc0ecf0e5fa" + integrity sha512-0dpuLQW+V6zrKvfvor/eo71V3tpr2L2Hsu8QZAdtSzksjWABxTOzH3ShaBRxCEsrz6sU9sa9o7ShwBMMDz59bQ== + dependencies: + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + "@uiw/react-codemirror@^4.23.0": version "4.23.5" resolved "https://registry.yarnpkg.com/@uiw/react-codemirror/-/react-codemirror-4.23.5.tgz#6a16c23062067732cba105ac33ad69cf8e5c2111" From a1515ecc7e6c75274c22403fc60472bd5280d1b7 Mon Sep 17 00:00:00 2001 From: bkellam Date: Tue, 12 Nov 2024 17:47:37 -0800 Subject: [PATCH 3/4] basic syntax highlighting --- packages/web/src/app/globals.css | 2 + packages/web/src/app/page.tsx | 2 +- packages/web/src/app/searchBar.tsx | 59 ++++++++++++++++++++++-------- packages/web/tailwind.config.ts | 1 + 4 files changed, 48 insertions(+), 16 deletions(-) diff --git a/packages/web/src/app/globals.css b/packages/web/src/app/globals.css index 9cb88606d..13502f6df 100644 --- a/packages/web/src/app/globals.css +++ b/packages/web/src/app/globals.css @@ -29,6 +29,7 @@ --chart-3: 197 37% 24%; --chart-4: 43 74% 66%; --chart-5: 27 87% 67%; + --highlight: 224, 76%, 48%; } .dark { @@ -56,6 +57,7 @@ --chart-3: 30 80% 55%; --chart-4: 280 65% 60%; --chart-5: 340 75% 55%; + --highlight: 217, 91%, 60%; } } diff --git a/packages/web/src/app/page.tsx b/packages/web/src/app/page.tsx index 0881f132e..542d80c77 100644 --- a/packages/web/src/app/page.tsx +++ b/packages/web/src/app/page.tsx @@ -148,7 +148,7 @@ const HowToSection = ({ title, children }: { title: string, children: React.Reac const Highlight = ({ children }: { children: React.ReactNode }) => { return ( - + {children} ) diff --git a/packages/web/src/app/searchBar.tsx b/packages/web/src/app/searchBar.tsx index 7c6f46d42..23ffb6acb 100644 --- a/packages/web/src/app/searchBar.tsx +++ b/packages/web/src/app/searchBar.tsx @@ -26,12 +26,22 @@ import { selectLineBoundaryBackward, selectLineBoundaryForward } from "@codemirror/commands"; +import { LanguageSupport, StreamLanguage } from "@codemirror/language"; +import { tags as t } from '@lezer/highlight'; import { createTheme } from '@uiw/codemirror-themes'; import CodeMirror, { KeyBinding, keymap, ReactCodeMirrorRef } from "@uiw/react-codemirror"; import { cva } from "class-variance-authority"; import { useRouter } from "next/navigation"; import { useMemo, useRef, useState } from "react"; import { useHotkeys } from 'react-hotkeys-hook'; + +interface SearchBarProps { + className?: string; + size?: "default" | "sm"; + defaultQuery?: string; + autoFocus?: boolean; +} + const searchBarKeymap: readonly KeyBinding[] = ([ { key: "ArrowLeft", run: cursorCharLeft, shift: selectCharLeft, preventDefault: true }, { key: "ArrowRight", run: cursorCharRight, shift: selectCharRight, preventDefault: true }, @@ -52,13 +62,31 @@ const searchBarKeymap: readonly KeyBinding[] = ([ { mac: "Mod-Delete", run: deleteLineBoundaryForward } ] as KeyBinding[]).concat(historyKeymap); -interface SearchBarProps { - className?: string; - size?: "default" | "sm"; - defaultQuery?: string; - autoFocus?: boolean; +const zoektLanguage = StreamLanguage.define({ + token: (stream) => { + if (stream.match(/-?(file|branch|revision|rev|case|repo|lang|content|sym):/)) { + return t.keyword.toString(); + } + + if (stream.match(/\bor\b/)) { + return t.keyword.toString(); + } + + stream.next(); + return null; + }, +}); + +const zoekt = () =>{ + return new LanguageSupport(zoektLanguage); } +const extensions = [ + keymap.of(searchBarKeymap), + history(), + zoekt() +]; + const searchBarVariants = cva( "flex items-center w-full p-0.5 border rounded-md", { @@ -72,7 +100,7 @@ const searchBarVariants = cva( size: "default", } } -) +); export const SearchBar = ({ className, @@ -80,8 +108,9 @@ export const SearchBar = ({ defaultQuery, autoFocus, }: SearchBarProps) => { - + const router = useRouter(); const tailwind = useTailwind(); + const theme = useMemo(() => { return createTheme({ theme: 'light', @@ -90,9 +119,14 @@ export const SearchBar = ({ foreground: tailwind.theme.colors.foreground, caret: '#AEAFAD', }, - styles: [], + styles: [ + { + tag: t.keyword, + color: tailwind.theme.colors.highlight, + }, + ], }); - }, []); + }, [tailwind]); const [query, setQuery] = useState(defaultQuery ?? ""); const editorRef = useRef(null); @@ -108,8 +142,6 @@ export const SearchBar = ({ } }); - const router = useRouter(); - const onSubmit = () => { const url = createPathWithQueryParams('/search', [SearchQueryParams.query, query], @@ -137,10 +169,7 @@ export const SearchBar = ({ }} theme={theme} basicSetup={false} - extensions={[ - keymap.of(searchBarKeymap), - history(), - ]} + extensions={extensions} indentWithTab={false} autoFocus={autoFocus ?? false} /> diff --git a/packages/web/tailwind.config.ts b/packages/web/tailwind.config.ts index 8b7dd5929..9ef8846a1 100644 --- a/packages/web/tailwind.config.ts +++ b/packages/web/tailwind.config.ts @@ -52,6 +52,7 @@ const config = { DEFAULT: "hsl(var(--card))", foreground: "hsl(var(--card-foreground))", }, + highlight: "hsl(var(--highlight))", }, borderRadius: { lg: "var(--radius)", From 0547cb4df36bca6a9f903e76e8dd2fe4cca1c07d Mon Sep 17 00:00:00 2001 From: bkellam Date: Tue, 12 Nov 2024 18:39:40 -0800 Subject: [PATCH 4/4] changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e68add2b..a20d7ccf4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- Added support for syntax highlighting in the search bar. ([#66](https://github.com/sourcebot-dev/sourcebot/pull/66)) + ## [2.4.1] - 2024-11-11 ### Added