diff --git a/frontend/app/element/search.tsx b/frontend/app/element/search.tsx index 652fdefdd..3b520d102 100644 --- a/frontend/app/element/search.tsx +++ b/frontend/app/element/search.tsx @@ -16,6 +16,7 @@ type SearchProps = SearchAtoms & { onSearch?: (search: string) => void; onNext?: () => void; onPrev?: () => void; + additionalButtons?: IconButtonDecl[]; }; const SearchComponent = ({ @@ -29,6 +30,7 @@ const SearchComponent = ({ onSearch, onNext, onPrev, + additionalButtons, }: SearchProps) => { const [isOpen, setIsOpen] = useAtom(isOpenAtom); const [search, setSearch] = useAtom(searchAtom); @@ -74,7 +76,7 @@ const SearchComponent = ({ ); middleware.push(offset(offsetCallback)); - const { refs, floatingStyles, context } = useFloating({ + const { refs, floatingStyles } = useFloating({ placement: "top-end", open: isOpen, onOpenChange: handleOpenChange, @@ -148,6 +150,13 @@ const SearchComponent = ({ > {index + 1}/{numResults} + {additionalButtons?.length && ( +
+ {additionalButtons.map((decl, i) => ( + + ))} +
+ )}
diff --git a/frontend/app/view/term/term.tsx b/frontend/app/view/term/term.tsx index 4d0d01897..e1dc9e45c 100644 --- a/frontend/app/view/term/term.tsx +++ b/frontend/app/view/term/term.tsx @@ -792,10 +792,53 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => { const fullConfig = globalStore.get(atoms.fullConfigAtom); const connFontFamily = fullConfig.connections?.[blockData?.meta?.connection]?.["term:fontfamily"]; + // search const searchProps = useSearch(viewRef, model); + const { additionalButtons, stateAtoms } = React.useMemo(() => { + const regexAtom = jotai.atom(false); + const wholeWordAtom = jotai.atom(false); + const caseSensitiveAtom = jotai.atom(false); + const additionalButtons: IconButtonDecl[] = [ + { + elemtype: "iconbutton", + icon: "font-case", + title: "Case Sensitive", + click: () => { + globalStore.set(caseSensitiveAtom, !globalStore.get(caseSensitiveAtom)); + }, + }, + { + elemtype: "iconbutton", + icon: "w", + title: "Whole Word", + click: () => { + globalStore.set(wholeWordAtom, !globalStore.get(wholeWordAtom)); + }, + }, + { + elemtype: "iconbutton", + icon: "asterisk", + title: "Regex Search", + click: () => { + globalStore.set(regexAtom, !globalStore.get(regexAtom)); + }, + }, + ]; + return { + additionalButtons, + stateAtoms: { caseSensitiveAtom, wholeWordAtom, regexAtom }, + }; + }, []); + searchProps.additionalButtons = additionalButtons; + const caseSensitive = jotai.useAtomValue(stateAtoms.caseSensitiveAtom); + const wholeWord = jotai.useAtomValue(stateAtoms.wholeWordAtom); + const regex = jotai.useAtomValue(stateAtoms.regexAtom); const searchVal = jotai.useAtomValue(searchProps.searchAtom); const searchOpts: ISearchOptions = { incremental: true, + regex, + wholeWord, + caseSensitive, decorations: { matchOverviewRuler: "#e0e0e0", activeMatchColorOverviewRuler: "#e0e0e0", @@ -816,6 +859,7 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => { searchProps.onNext = React.useCallback(() => { model.termRef.current?.searchAddon.findNext(searchVal, searchOpts); }, [searchVal]); + // end search React.useEffect(() => { const fullConfig = globalStore.get(atoms.fullConfigAtom);