From 696d06beeb3e2e0fed0a435c6679e24f7aa92ba3 Mon Sep 17 00:00:00 2001
From: bkellam
Date: Wed, 19 Nov 2025 18:35:03 -0800
Subject: [PATCH] branch handling
---
.../app/[domain]/components/pathHeader.tsx | 2 +-
.../search/components/searchResultsPage.tsx | 12 +++++++++---
.../searchResultsPanel/fileMatchContainer.tsx | 2 +-
.../components/searchResultsPanel/index.tsx | 4 ++--
.../app/[domain]/search/useStreamedSearch.ts | 1 -
packages/web/src/features/search/query.ts | 13 ++++---------
packages/web/src/features/search/searchApi.ts | 19 ++++++++++++++++---
7 files changed, 33 insertions(+), 20 deletions(-)
diff --git a/packages/web/src/app/[domain]/components/pathHeader.tsx b/packages/web/src/app/[domain]/components/pathHeader.tsx
index d65d2c35..7d373b2e 100644
--- a/packages/web/src/app/[domain]/components/pathHeader.tsx
+++ b/packages/web/src/app/[domain]/components/pathHeader.tsx
@@ -233,7 +233,7 @@ export const PathHeader = ({
}}
>
@
- {`${branchDisplayName}`}
+ {`${branchDisplayName.replace(/^refs\/(heads|tags)\//, '')}`}
)}
ยท
diff --git a/packages/web/src/app/[domain]/search/components/searchResultsPage.tsx b/packages/web/src/app/[domain]/search/components/searchResultsPage.tsx
index 4e8982cc..285def39 100644
--- a/packages/web/src/app/[domain]/search/components/searchResultsPage.tsx
+++ b/packages/web/src/app/[domain]/search/components/searchResultsPage.tsx
@@ -12,6 +12,7 @@ import {
import { Separator } from "@/components/ui/separator";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { RepositoryInfo, SearchResultFile, SearchStats } from "@/features/search/types";
+import useCaptureEvent from "@/hooks/useCaptureEvent";
import { useDomain } from "@/hooks/useDomain";
import { useNonEmptyQueryParam } from "@/hooks/useNonEmptyQueryParam";
import { useSearchHistory } from "@/hooks/useSearchHistory";
@@ -32,7 +33,6 @@ import { CodePreviewPanel } from "./codePreviewPanel";
import { FilterPanel } from "./filterPanel";
import { useFilteredMatches } from "./filterPanel/useFilterMatches";
import { SearchResultsPanel, SearchResultsPanelHandle } from "./searchResultsPanel";
-import useCaptureEvent from "@/hooks/useCaptureEvent";
interface SearchResultsPageProps {
searchQuery: string;
@@ -156,6 +156,13 @@ export const SearchResultsPage = ({
router.push(url);
}, [maxMatchCount, router, searchQuery, domain]);
+ // Look for any files that are not on the default branch.
+ const isBranchFilteringEnabled = useMemo(() => {
+ return files.some((file) => {
+ return file.branches?.some((branch) => branch !== 'HEAD') ?? false;
+ });
+ }, [files]);
+
return (
{/* TopBar */}
@@ -189,8 +196,7 @@ export const SearchResultsPage = ({
isStreaming={isStreaming}
searchStats={stats}
isMoreResultsButtonVisible={!isExhaustive}
- // @todo: handle branch filtering
- isBranchFilteringEnabled={false}
+ isBranchFilteringEnabled={isBranchFilteringEnabled}
/>
)}
diff --git a/packages/web/src/app/[domain]/search/components/searchResultsPanel/fileMatchContainer.tsx b/packages/web/src/app/[domain]/search/components/searchResultsPanel/fileMatchContainer.tsx
index b10d656a..e7740ca9 100644
--- a/packages/web/src/app/[domain]/search/components/searchResultsPanel/fileMatchContainer.tsx
+++ b/packages/web/src/app/[domain]/search/components/searchResultsPanel/fileMatchContainer.tsx
@@ -75,7 +75,7 @@ export const FileMatchContainer = ({
}
return `${branches[0]}${branches.length > 1 ? ` +${branches.length - 1}` : ''}`;
- }, [isBranchFilteringEnabled, branches]);
+ }, [branches, isBranchFilteringEnabled]);
const repo = useMemo(() => {
return repoInfo[file.repositoryId];
diff --git a/packages/web/src/app/[domain]/search/components/searchResultsPanel/index.tsx b/packages/web/src/app/[domain]/search/components/searchResultsPanel/index.tsx
index aa5efdf8..5d199cc0 100644
--- a/packages/web/src/app/[domain]/search/components/searchResultsPanel/index.tsx
+++ b/packages/web/src/app/[domain]/search/components/searchResultsPanel/index.tsx
@@ -88,7 +88,7 @@ export const SearchResultsPanel = forwardRef {
virtualizer.scrollToIndex(0);
- }, [fileMatches.length, virtualizer]);
+ }, [virtualizer]);
// Expose the resetScroll function to parent components
useImperativeHandle(ref, () => ({
@@ -121,7 +121,7 @@ export const SearchResultsPanel = forwardRef {
};
export const useStreamedSearch = ({ query, matches, contextLines, whole, isRegexEnabled, isCaseSensitivityEnabled }: SearchRequest) => {
-
const [state, setState] = useState<{
isStreaming: boolean,
isExhaustive: boolean,
diff --git a/packages/web/src/features/search/query.ts b/packages/web/src/features/search/query.ts
index 2c0a831f..3505e451 100644
--- a/packages/web/src/features/search/query.ts
+++ b/packages/web/src/features/search/query.ts
@@ -61,7 +61,6 @@ export const transformLezerTreeToZoektGrpcQuery = async ({
isRegexEnabled: boolean;
onExpandSearchContext: (contextName: string) => Promise;
}): Promise => {
-
const transformNode = async (node: SyntaxNode): Promise => {
switch (node.type.id) {
case Program: {
@@ -200,7 +199,7 @@ export const transformLezerTreeToZoektGrpcQuery = async ({
query: "substring"
};
-
+
case LangExpr:
return {
language: {
@@ -277,11 +276,11 @@ export const transformLezerTreeToZoektGrpcQuery = async ({
}
case ForkExpr: {
const rawValue = value.toLowerCase();
-
+
if (!isForkValue(rawValue)) {
throw new Error(`Invalid fork value: ${rawValue}. Expected 'yes', 'no', or 'only'`);
}
-
+
const flags: ('FLAG_ONLY_FORKS' | 'FLAG_NO_FORKS')[] = [];
if (rawValue === 'yes') {
@@ -336,12 +335,8 @@ const getChildren = (node: SyntaxNode): SyntaxNode[] => {
const children: SyntaxNode[] = [];
let child = node.firstChild;
while (child) {
- // Skip certain node types that are just structural
- if (!["(", ")", "or"].includes(child.type.name)) {
- children.push(child);
- }
+ children.push(child);
child = child.nextSibling;
}
return children;
}
-
diff --git a/packages/web/src/features/search/searchApi.ts b/packages/web/src/features/search/searchApi.ts
index 974be894..b6630f7d 100644
--- a/packages/web/src/features/search/searchApi.ts
+++ b/packages/web/src/features/search/searchApi.ts
@@ -18,6 +18,7 @@ import path from 'path';
import { parseQueryIntoLezerTree, transformLezerTreeToZoektGrpcQuery } from './query';
import { RepositoryInfo, SearchRequest, SearchResponse, SearchResultFile, SearchStats, SourceRange, StreamedSearchResponse } from "./types";
import { FlushReason as ZoektFlushReason } from "@/proto/zoekt/webserver/v1/FlushReason";
+import { RevisionExpr } from "@sourcebot/query-language";
const logger = createLogger("searchApi");
@@ -454,18 +455,30 @@ const createZoektSearchRequest = async ({
},
});
+ // Find if there are any `rev:` filters in the query.
+ let containsRevExpression = false;
+ tree.iterate({
+ enter: (node) => {
+ if (node.type.id === RevisionExpr) {
+ containsRevExpression = true;
+ // false to stop the iteration.
+ return false;
+ }
+ }
+ });
+
const zoektSearchRequest: ZoektGrpcSearchRequest = {
query: {
and: {
children: [
zoektQuery,
- // @todo: handle branch filtering.
- {
+ // If the query does not contain a `rev:` filter, we default to searching `HEAD`.
+ ...(!containsRevExpression ? [{
branch: {
pattern: 'HEAD',
exact: true,
}
- }
+ }] : []),
]
}
},