diff --git a/src/app/search/page.tsx b/src/app/search/page.tsx index 8c71c9a..236302b 100644 --- a/src/app/search/page.tsx +++ b/src/app/search/page.tsx @@ -102,9 +102,9 @@ export default function SearchPage() { { - setSelectedFile(match); - setSelectedMatchIndex(0); + onOpenFileMatch={(fileMatch, matchIndex) => { + setSelectedFile(fileMatch); + setSelectedMatchIndex(matchIndex); }} /> diff --git a/src/app/search/searchResults.tsx b/src/app/search/searchResults.tsx index f85b567..fd4d22e 100644 --- a/src/app/search/searchResults.tsx +++ b/src/app/search/searchResults.tsx @@ -4,10 +4,14 @@ import { ScrollArea } from "@/components/ui/scroll-area"; import { Separator } from "@/components/ui/separator"; import { ZoektFileMatch } from "@/lib/types"; import { Scrollbar } from "@radix-ui/react-scroll-area"; +import { useMemo, useState } from "react"; +import { DoubleArrowDownIcon, DoubleArrowUpIcon } from "@radix-ui/react-icons"; + +const MAX_MATCHES_TO_PREVIEW = 5; interface SearchResultsProps { fileMatches: ZoektFileMatch[]; - onOpenFileMatch: (match: ZoektFileMatch) => void; + onOpenFileMatch: (fileMatch: ZoektFileMatch, matchIndex: number) => void; } export const SearchResults = ({ @@ -17,12 +21,12 @@ export const SearchResults = ({ return (
- {fileMatches.map((match, index) => ( + {fileMatches.map((fileMatch, index) => ( { - onOpenFileMatch(match); + match={fileMatch} + onOpenFile={(matchIndex) => { + onOpenFileMatch(fileMatch, matchIndex); }} /> ))} @@ -34,7 +38,7 @@ export const SearchResults = ({ interface FileMatchProps { match: ZoektFileMatch; - onOpenFile: () => void; + onOpenFile: (matchIndex: number) => void; } const FileMatch = ({ @@ -42,12 +46,29 @@ const FileMatch = ({ onOpenFile, }: FileMatchProps) => { + const [showAll, setShowAll] = useState(false); + const matchCount = useMemo(() => { + return match.Matches.length; + }, [match]); + + const matches = useMemo(() => { + const sortedMatches = match.Matches.sort((a, b) => { + return a.LineNum - b.LineNum; + }); + + if (!showAll) { + return sortedMatches.slice(0, MAX_MATCHES_TO_PREVIEW); + } + + return sortedMatches; + }, [match, showAll]); + return (
{match.Repo} ยท {match.FileName}
- {match.Matches.map((match, index) => { + {matches.map((match, index) => { const fragment = match.Fragments[0]; return ( @@ -55,14 +76,25 @@ const FileMatch = ({ key={index} className="font-mono px-4 py-0.5 text-sm cursor-pointer" onClick={() => { - onOpenFile(); + onOpenFile(index); }} > -

{match.LineNum}: {fragment.Pre}{fragment.Match}{fragment.Post}

+

{match.LineNum > 0 ? match.LineNum : "file match"}: {fragment.Pre}{fragment.Match}{fragment.Post}

); })} + {matchCount > MAX_MATCHES_TO_PREVIEW && ( +
+

setShowAll(!showAll)} + className="text-blue-500 cursor-pointer text-sm flex flex-row items-center gap-2" + > + {showAll ? : } + {showAll ? `Show fewer matching lines` : `Show ${matchCount - MAX_MATCHES_TO_PREVIEW} more matching lines`} +

+
+ )}
); } diff --git a/src/lib/extensions/searchResultHighlightExtension.ts b/src/lib/extensions/searchResultHighlightExtension.ts index f3d0058..8f2eac1 100644 --- a/src/lib/extensions/searchResultHighlightExtension.ts +++ b/src/lib/extensions/searchResultHighlightExtension.ts @@ -34,11 +34,13 @@ const matchHighlighter = StateField.define({ if (effect.is(setMatchState)) { const { matches, selectedMatchIndex } = effect.value; - const decorations = matches.map((match, index) => { - const { from, to } = getMatchRange(match, transaction.newDoc); - const mark = index === selectedMatchIndex ? selectedMatchMark : matchMark; - return mark.range(from, to); - }); + const decorations = matches + .filter((match) => match.LineNum > 0) + .map((match, index) => { + const { from, to } = getMatchRange(match, transaction.newDoc); + const mark = index === selectedMatchIndex ? selectedMatchMark : matchMark; + return mark.range(from, to); + }); highlights = Decoration.set(decorations) } @@ -77,11 +79,15 @@ export const markMatches = (selectedMatchIndex: number, matches: ZoektMatch[], v if (selectedMatchIndex >= 0 && selectedMatchIndex < matches.length) { const match = matches[selectedMatchIndex]; - const { from, to } = getMatchRange(match, view.state.doc); - const selection = EditorSelection.range(from, to); - effects.push(EditorView.scrollIntoView(selection, { - y: "start", - })); + + // Don't scroll if the match is on the filename. + if (match.LineNum > 0) { + const { from, to } = getMatchRange(match, view.state.doc); + const selection = EditorSelection.range(from, to); + effects.push(EditorView.scrollIntoView(selection, { + y: "start", + })); + } }; view.dispatch({ effects });