Skip to content

Commit e0cb891

Browse files
committed
Adds comparison range picker to search UI
Adds @me choice to author: filter Adds @me highlighting in search queries
1 parent c446283 commit e0cb891

File tree

5 files changed

+97
-10
lines changed

5 files changed

+97
-10
lines changed

src/git/search.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,14 @@ export function getSearchQueryComparisonKey(search: SearchQuery | StoredSearchQu
104104
}${search.matchRegex ? 'R' : ''}${search.matchWholeWord ? 'W' : ''}${search.naturalLanguage ? 'NL' : ''}`;
105105
}
106106

107+
/** Operators plus special tokens that can be highlighted */
108+
export type HighlightableOperator = SearchOperators | '@me';
109+
107110
export interface ParsedSearchQuery {
108111
operations: Map<SearchOperatorsLongForm, Set<string>>;
109112
errors?: string[];
110113
/** Positions of operators in the original query string */
111-
operatorRanges?: { start: number; end: number; operator: SearchOperators }[];
114+
operatorRanges?: { start: number; end: number; operator: HighlightableOperator }[];
112115
}
113116

114117
export function createSearchQueryForCommit(ref: string): string;
@@ -128,7 +131,7 @@ export function parseSearchQuery(search: SearchQuery, validate: boolean = false)
128131
const query = search.query.trim();
129132

130133
let errors: string[] | undefined;
131-
let operatorRanges: Array<{ start: number; end: number; operator: SearchOperators }> | undefined;
134+
let operatorRanges: Array<{ start: number; end: number; operator: HighlightableOperator }> | undefined;
132135
let pos = 0;
133136

134137
while (pos < query.length) {
@@ -192,6 +195,7 @@ export function parseSearchQuery(search: SearchQuery, validate: boolean = false)
192195

193196
if (!matchedOperator) {
194197
// No operator found, parse as text
198+
const textStart = pos;
195199
let text: string;
196200

197201
// Check if text is quoted
@@ -214,7 +218,18 @@ export function parseSearchQuery(search: SearchQuery, validate: boolean = false)
214218
}
215219

216220
// Handle special text tokens (@me, SHA)
217-
op = text === '@me' ? 'author:' : isSha(text) ? 'commit:' : 'message:';
221+
if (text === '@me') {
222+
op = 'author:';
223+
// Track @me position for highlighting
224+
operatorRanges ??= [];
225+
operatorRanges.push({
226+
start: textStart,
227+
end: textStart + text.length,
228+
operator: '@me',
229+
});
230+
} else {
231+
op = isSha(text) ? 'commit:' : 'message:';
232+
}
218233
value = text;
219234
}
220235

src/webviews/apps/shared/components/search/models.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export type SearchCompletionItem = CompletionItem<
1010
export type SearchCompletionCommand =
1111
| { command: 'toggle-natural-language-mode' }
1212
| { command: 'pick-author' | 'pick-file'; multi?: boolean }
13-
| { command: 'pick-folder' | 'pick-ref'; multi?: never };
13+
| { command: 'pick-folder' | 'pick-ref' | 'pick-comparison'; multi?: never };
1414

1515
export interface SearchCompletionValue {
1616
/** The operator this value belongs to */
@@ -74,11 +74,17 @@ export const searchCompletionOperators: SearchCompletionOperator[] = [
7474
example: html`Use a name or email, e.g. <code>author:eamodio</code>, <code>@:john</code>, or
7575
<code>@me</code> for your own commits`,
7676
values: [
77+
{
78+
value: '@me',
79+
label: '@me',
80+
description: 'Filter to only show your own commits',
81+
icon: 'person',
82+
},
7783
{
7884
value: { command: 'pick-author', multi: true },
7985
label: 'Choose authors\u2026',
8086
description: 'Select one or more contributors to filter by',
81-
icon: 'person',
87+
icon: 'organization',
8288
},
8389
],
8490
},
@@ -99,10 +105,16 @@ export const searchCompletionOperators: SearchCompletionOperator[] = [
99105
values: [
100106
{
101107
value: { command: 'pick-ref' },
102-
label: 'Choose a branch, tag, or range\u2026',
103-
description: 'Select a branch, tag, or range to filter by',
108+
label: 'Choose a branch or tag\u2026',
109+
description: 'Select a branch or tag to filter by',
104110
icon: 'git-branch',
105111
},
112+
{
113+
value: { command: 'pick-comparison' },
114+
label: 'Choose a comparison range\u2026',
115+
description: 'Select two refs to compare (e.g. main..feature)',
116+
icon: 'git-compare',
117+
},
106118
],
107119
},
108120
{

src/webviews/apps/shared/components/search/search-input.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { filterMap } from '../../../../../system/array';
1111
import { fuzzyFilter } from '../../../../../system/fuzzy';
1212
import {
1313
ChooseAuthorRequest,
14+
ChooseComparisonRequest,
1415
ChooseFileRequest,
1516
ChooseRefRequest,
1617
SearchHistoryDeleteRequest,
@@ -776,9 +777,9 @@ export class GlSearchInput extends GlElement {
776777

777778
case 'pick-ref': {
778779
const result = await this._ipc.sendRequest(ChooseRefRequest, {
779-
title: 'Search by Reference or Range',
780-
placeholder: 'Choose a reference to search',
781-
allowedAdditionalInput: { range: true, rev: false },
780+
title: 'Search by Branch or Tag',
781+
placeholder: 'Choose a branch or tag to filter by',
782+
allowedAdditionalInput: { range: false, rev: false },
782783
include: ['branches', 'tags', 'HEAD'],
783784
picked: currentValue || undefined,
784785
});
@@ -789,6 +790,18 @@ export class GlSearchInput extends GlElement {
789790
break;
790791
}
791792

793+
case 'pick-comparison': {
794+
const result = await this._ipc.sendRequest(ChooseComparisonRequest, {
795+
title: 'Search by Comparison Range',
796+
placeholder: 'Choose two refs to compare',
797+
});
798+
799+
if (result?.range) {
800+
this.insertPickerValues([result.range], operator, false);
801+
}
802+
break;
803+
}
804+
792805
case 'pick-file':
793806
case 'pick-folder': {
794807
const result = await this._ipc.sendRequest(ChooseFileRequest, {

src/webviews/plus/graph/graphWebview.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ import { isMcpBannerEnabled } from '../../../plus/gk/utils/-webview/mcp.utils';
116116
import type { ConnectionStateChangeEvent } from '../../../plus/integrations/integrationService';
117117
import { getPullRequestBranchDeepLink } from '../../../plus/launchpad/launchpadProvider';
118118
import type { AssociateIssueWithBranchCommandArgs } from '../../../plus/startWork/startWork';
119+
import { showComparisonPicker } from '../../../quickpicks/comparisonPicker';
119120
import { showContributorsPicker } from '../../../quickpicks/contributorsPicker';
120121
import { showReferencePicker2 } from '../../../quickpicks/referencePicker';
121122
import { getRepositoryPickerTitleAndPlaceholder, showRepositoryPicker } from '../../../quickpicks/repositoryPicker';
@@ -209,6 +210,7 @@ import type {
209210
} from './protocol';
210211
import {
211212
ChooseAuthorRequest,
213+
ChooseComparisonRequest,
212214
ChooseFileRequest,
213215
ChooseRefRequest,
214216
ChooseRepositoryCommand,
@@ -831,6 +833,9 @@ export class GraphWebviewProvider implements WebviewProvider<State, State, Graph
831833
case ChooseRefRequest.is(e):
832834
void this.onChooseRef(ChooseRefRequest, e);
833835
break;
836+
case ChooseComparisonRequest.is(e):
837+
void this.onChooseComparison(ChooseComparisonRequest, e);
838+
break;
834839
case ChooseFileRequest.is(e):
835840
void this.onChooseFile(ChooseFileRequest, e);
836841
break;
@@ -2074,6 +2079,36 @@ export class GraphWebviewProvider implements WebviewProvider<State, State, Graph
20742079
);
20752080
}
20762081

2082+
private async onChooseComparison<T extends typeof ChooseComparisonRequest>(
2083+
requestType: T,
2084+
msg: IpcCallMessageType<T>,
2085+
) {
2086+
if (this.repository == null) {
2087+
return this.host.respond(requestType, msg, { range: undefined });
2088+
}
2089+
2090+
const result = await showComparisonPicker(this.container, this.repository.path, {
2091+
getTitleAndPlaceholder: step => {
2092+
switch (step) {
2093+
case 1:
2094+
return {
2095+
title: msg.params.title,
2096+
placeholder: 'Choose a branch or tag to show commits from',
2097+
};
2098+
case 2:
2099+
return {
2100+
title: msg.params.title,
2101+
placeholder: 'Choose a base to compare against (e.g., main)',
2102+
};
2103+
}
2104+
},
2105+
});
2106+
2107+
return this.host.respond(requestType, msg, {
2108+
range: result != null ? `${result.base.ref}..${result.head.ref}` : undefined,
2109+
});
2110+
}
2111+
20772112
private async onChooseAuthor<T extends typeof ChooseAuthorRequest>(requestType: T, msg: IpcCallMessageType<T>) {
20782113
if (this.repository == null) {
20792114
return this.host.respond(requestType, msg, { authors: undefined });

src/webviews/plus/graph/protocol.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,18 @@ export interface ChooseRefParams {
338338
}
339339
export const ChooseRefRequest = new IpcRequest<ChooseRefParams, DidChooseRefParams>(scope, 'chooseRef');
340340

341+
export interface ChooseComparisonParams {
342+
title: string;
343+
placeholder: string;
344+
}
345+
export interface DidChooseComparisonParams {
346+
range: string | undefined;
347+
}
348+
export const ChooseComparisonRequest = new IpcRequest<ChooseComparisonParams, DidChooseComparisonParams>(
349+
scope,
350+
'chooseComparison',
351+
);
352+
341353
export interface ChooseAuthorParams {
342354
title: string;
343355
placeholder: string;

0 commit comments

Comments
 (0)