Skip to content

Commit 0c22898

Browse files
committed
Fixes selection restore for search results
Refactors search results to extend commits node
1 parent fc0207e commit 0c22898

File tree

2 files changed

+132
-130
lines changed

2 files changed

+132
-130
lines changed

src/views/nodes/resultsCommitsNode.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { TreeItem, TreeItemCollapsibleState } from 'vscode';
2+
import type { TreeViewNodeTypes } from '../../constants.views';
23
import { GitUri } from '../../git/gitUri';
34
import { isStash } from '../../git/models/commit';
45
import type { GitRevisionRange } from '../../git/models/revision';
@@ -27,15 +28,16 @@ interface Options {
2728
description?: string;
2829
}
2930

30-
export class ResultsCommitsNode<View extends ViewsWithCommits = ViewsWithCommits>
31-
extends ViewNode<'results-commits', View>
31+
export class ResultsCommitsNodeBase<Type extends TreeViewNodeTypes, View extends ViewsWithCommits = ViewsWithCommits>
32+
extends ViewNode<Type, View>
3233
implements PageableViewNode
3334
{
3435
limit: number | undefined;
3536

3637
private readonly _options: Options;
3738

3839
constructor(
40+
type: Type,
3941
view: View,
4042
protected override readonly parent: ViewNode,
4143
public readonly repoPath: string,
@@ -49,7 +51,7 @@ export class ResultsCommitsNode<View extends ViewsWithCommits = ViewsWithCommits
4951
},
5052
options?: Partial<Options>,
5153
) {
52-
super('results-commits', GitUri.fromRepoPath(repoPath), view, parent);
54+
super(type, GitUri.fromRepoPath(repoPath), view, parent);
5355

5456
if (_results.direction != null) {
5557
this.updateContext({ branchStatusUpstreamType: _results.direction });
@@ -262,3 +264,25 @@ export class ResultsCommitsNode<View extends ViewsWithCommits = ViewsWithCommits
262264
return getChangesForChangelog(this.view.container, range, log);
263265
}
264266
}
267+
268+
export class ResultsCommitsNode<View extends ViewsWithCommits = ViewsWithCommits> extends ResultsCommitsNodeBase<
269+
'results-commits',
270+
View
271+
> {
272+
constructor(
273+
view: View,
274+
parent: ViewNode,
275+
repoPath: string,
276+
label: string,
277+
results: {
278+
query: (limit: number | undefined) => Promise<CommitsQueryResults>;
279+
comparison?: { ref1: string; ref2: string; range: GitRevisionRange };
280+
deferred?: boolean;
281+
direction?: 'ahead' | 'behind';
282+
files?: { ref1: string; ref2: string; query: () => Promise<FilesQueryResults> };
283+
},
284+
options?: Partial<Options>,
285+
) {
286+
super('results-commits', view, parent, repoPath, label, results, options);
287+
}
288+
}

src/views/nodes/searchResultsNode.ts

Lines changed: 105 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,14 @@ import { ThemeIcon } from 'vscode';
33
import { md5 } from '@env/crypto';
44
import type { SearchQuery } from '../../constants.search';
55
import { executeGitCommand } from '../../git/actions';
6-
import { GitUri } from '../../git/gitUri';
76
import type { GitLog } from '../../git/models/log';
87
import type { CommitsQueryResults } from '../../git/queryResults';
98
import { getSearchQueryComparisonKey, getStoredSearchQuery } from '../../git/search';
10-
import { debug } from '../../system/decorators/log';
119
import { pluralize } from '../../system/string';
1210
import type { SearchAndCompareView } from '../searchAndCompareView';
13-
import type { PageableViewNode } from './abstract/viewNode';
14-
import { ContextValues, getViewNodeId, ViewNode } from './abstract/viewNode';
15-
import { ResultsCommitsNode } from './resultsCommitsNode';
11+
import type { ViewNode } from './abstract/viewNode';
12+
import { ContextValues, getViewNodeId } from './abstract/viewNode';
13+
import { ResultsCommitsNodeBase } from './resultsCommitsNode';
1614

1715
interface SearchQueryResults {
1816
readonly label: string;
@@ -21,28 +19,51 @@ interface SearchQueryResults {
2119
more?(limit: number | undefined): Promise<void>;
2220
}
2321

24-
export class SearchResultsNode extends ViewNode<'search-results', SearchAndCompareView> implements PageableViewNode {
22+
export class SearchResultsNode extends ResultsCommitsNodeBase<'search-results', SearchAndCompareView> {
23+
private _search: SearchQuery;
24+
private _labels: {
25+
label: string;
26+
queryLabel: string | { label: string; resultsType?: { singular: string; plural: string } };
27+
resultsType?: { singular: string; plural: string };
28+
};
29+
private _storedAt: number;
30+
2531
constructor(
2632
view: SearchAndCompareView,
27-
protected override readonly parent: ViewNode,
28-
public readonly repoPath: string,
29-
private _search: SearchQuery,
30-
private _labels: {
33+
parent: ViewNode,
34+
repoPath: string,
35+
search: SearchQuery,
36+
labels: {
3137
label: string;
3238
queryLabel: string | { label: string; resultsType?: { singular: string; plural: string } };
3339
resultsType?: { singular: string; plural: string };
3440
},
35-
private _searchQueryOrLog?:
41+
searchQueryOrLog?:
3642
| ((limit: number | undefined) => Promise<CommitsQueryResults>)
3743
| Promise<GitLog | undefined>
3844
| GitLog
3945
| undefined,
40-
private _storedAt: number = 0,
46+
storedAt: number = 0,
4147
) {
42-
super('search-results', GitUri.fromRepoPath(repoPath), view, parent);
48+
const query = createSearchQuery(view, repoPath, search, labels, searchQueryOrLog);
49+
const deferred = searchQueryOrLog == null;
50+
51+
super(
52+
'search-results',
53+
view,
54+
parent,
55+
repoPath,
56+
labels.label,
57+
{ query: query, deferred: deferred },
58+
{ expand: false },
59+
);
60+
61+
this._search = search;
62+
this._labels = labels;
63+
this._storedAt = storedAt;
4364

4465
this.updateContext({ searchId: getSearchQueryComparisonKey(this._search) });
45-
this._uniqueId = getViewNodeId(this.type, this.context);
66+
this._uniqueId = getViewNodeId('search-results', this.context);
4667

4768
// If this is a new search, save it
4869
if (this._storedAt === 0) {
@@ -71,39 +92,8 @@ export class SearchResultsNode extends ViewNode<'search-results', SearchAndCompa
7192
void this.remove(true);
7293
}
7394

74-
private _resultsNode: ResultsCommitsNode | undefined;
75-
private ensureResults() {
76-
if (this._resultsNode == null) {
77-
let deferred;
78-
if (this._searchQueryOrLog == null) {
79-
deferred = true;
80-
this._searchQueryOrLog = this.getSearchQuery({ label: this._labels.queryLabel });
81-
} else if (typeof this._searchQueryOrLog !== 'function') {
82-
this._searchQueryOrLog = this.getSearchQuery(
83-
{ label: this._labels.queryLabel },
84-
this._searchQueryOrLog,
85-
);
86-
}
87-
88-
this._resultsNode = new ResultsCommitsNode(
89-
this.view,
90-
this,
91-
this.repoPath,
92-
this._labels.label,
93-
{ query: this._searchQueryOrLog, deferred: deferred },
94-
{ expand: false },
95-
);
96-
}
97-
98-
return this._resultsNode;
99-
}
100-
101-
async getChildren(): Promise<ViewNode[]> {
102-
return this.ensureResults().getChildren();
103-
}
104-
105-
async getTreeItem(): Promise<TreeItem> {
106-
const item = await this.ensureResults().getTreeItem();
95+
override async getTreeItem(): Promise<TreeItem> {
96+
const item = await super.getTreeItem();
10797
item.id = this.id;
10898
item.contextValue = ContextValues.SearchResults;
10999
if (this.view.container.git.repositoryCount > 1) {
@@ -115,14 +105,6 @@ export class SearchResultsNode extends ViewNode<'search-results', SearchAndCompa
115105
return item;
116106
}
117107

118-
get hasMore(): boolean {
119-
return this.ensureResults().hasMore;
120-
}
121-
122-
async loadMore(limit?: number): Promise<void> {
123-
return this.ensureResults().loadMore(limit);
124-
}
125-
126108
async edit(search?: {
127109
pattern: SearchQuery;
128110
labels: {
@@ -156,8 +138,6 @@ export class SearchResultsNode extends ViewNode<'search-results', SearchAndCompa
156138

157139
this._search = search.pattern;
158140
this._labels = search.labels;
159-
this._searchQueryOrLog = search.log;
160-
this._resultsNode = undefined;
161141

162142
// Remove the existing stored item and save a new one
163143
await this.replace(currentId, true);
@@ -166,76 +146,6 @@ export class SearchResultsNode extends ViewNode<'search-results', SearchAndCompa
166146
queueMicrotask(() => this.view.reveal(this, { expand: true, focus: true, select: true }));
167147
}
168148

169-
@debug()
170-
override refresh(reset: boolean = false): void {
171-
this._resultsNode?.refresh(reset);
172-
}
173-
174-
private getSearchLabel(
175-
label:
176-
| string
177-
| {
178-
label: string;
179-
resultsType?: { singular: string; plural: string };
180-
},
181-
log: GitLog | undefined,
182-
): string {
183-
if (typeof label === 'string') return label;
184-
185-
const count = log?.count ?? 0;
186-
187-
const resultsType =
188-
label.resultsType === undefined
189-
? { singular: 'search result', plural: 'search results' }
190-
: label.resultsType;
191-
192-
return `${pluralize(resultsType.singular, count, {
193-
format: c => (log?.hasMore ? `${c}+` : String(c)),
194-
plural: resultsType.plural,
195-
zero: 'No',
196-
})} ${label.label}`;
197-
}
198-
199-
private getSearchQuery(
200-
options: {
201-
label:
202-
| string
203-
| {
204-
label: string;
205-
resultsType?: { singular: string; plural: string };
206-
};
207-
},
208-
log?: Promise<GitLog | undefined> | GitLog,
209-
): (limit: number | undefined) => Promise<SearchQueryResults> {
210-
let useCacheOnce = true;
211-
212-
return async (limit: number | undefined) => {
213-
log = await (log ??
214-
this.view.container.git.getRepositoryService(this.repoPath).commits.searchCommits(this.search));
215-
216-
if (!useCacheOnce && log?.query != null) {
217-
log = await log.query(limit);
218-
}
219-
useCacheOnce = false;
220-
221-
const results: Mutable<SearchQueryResults> = {
222-
label: this.getSearchLabel(options.label, log),
223-
log: log,
224-
hasMore: log?.hasMore ?? false,
225-
};
226-
if (results.hasMore) {
227-
results.more = async (limit: number | undefined) => {
228-
results.log = (await results.log?.more?.(limit)) ?? results.log;
229-
230-
results.label = this.getSearchLabel(options.label, results.log);
231-
results.hasMore = results.log?.hasMore ?? true;
232-
};
233-
}
234-
235-
return results;
236-
};
237-
}
238-
239149
private getStorageId() {
240150
return md5(`${this.repoPath}|${getSearchQueryComparisonKey(this.search)}`, 'base64');
241151
}
@@ -263,3 +173,71 @@ export class SearchResultsNode extends ViewNode<'search-results', SearchAndCompa
263173
);
264174
}
265175
}
176+
177+
function createSearchQuery(
178+
view: SearchAndCompareView,
179+
repoPath: string,
180+
search: SearchQuery,
181+
labels: {
182+
label: string;
183+
queryLabel: string | { label: string; resultsType?: { singular: string; plural: string } };
184+
resultsType?: { singular: string; plural: string };
185+
},
186+
searchQueryOrLog?:
187+
| ((limit: number | undefined) => Promise<CommitsQueryResults>)
188+
| Promise<GitLog | undefined>
189+
| GitLog
190+
| undefined,
191+
): (limit: number | undefined) => Promise<CommitsQueryResults> {
192+
if (typeof searchQueryOrLog === 'function') {
193+
return searchQueryOrLog;
194+
}
195+
196+
// Create a search query function
197+
return async (limit: number | undefined) => {
198+
let log = searchQueryOrLog;
199+
if (log == null) {
200+
log = await view.container.git.getRepositoryService(repoPath).commits.searchCommits(search);
201+
} else if (log instanceof Promise) {
202+
log = await log;
203+
}
204+
205+
if (log?.query != null) {
206+
log = await log.query(limit);
207+
}
208+
209+
const count = log?.count ?? 0;
210+
const queryLabel = labels.queryLabel;
211+
const resultsType =
212+
typeof queryLabel === 'string'
213+
? { singular: 'search result', plural: 'search results' }
214+
: queryLabel.resultsType ?? { singular: 'search result', plural: 'search results' };
215+
216+
const label = `${pluralize(resultsType.singular, count, {
217+
format: c => (log?.hasMore ? `${c}+` : String(c)),
218+
plural: resultsType.plural,
219+
zero: 'No',
220+
})} ${typeof queryLabel === 'string' ? queryLabel : queryLabel.label}`;
221+
222+
const results: Mutable<SearchQueryResults> = {
223+
label: label,
224+
log: log,
225+
hasMore: log?.hasMore ?? false,
226+
};
227+
228+
if (results.hasMore) {
229+
results.more = async (limit: number | undefined) => {
230+
results.log = (await results.log?.more?.(limit)) ?? results.log;
231+
const newCount = results.log?.count ?? 0;
232+
results.label = `${pluralize(resultsType.singular, newCount, {
233+
format: c => (results.log?.hasMore ? `${c}+` : String(c)),
234+
plural: resultsType.plural,
235+
zero: 'No',
236+
})} ${typeof queryLabel === 'string' ? queryLabel : queryLabel.label}`;
237+
results.hasMore = results.log?.hasMore ?? true;
238+
};
239+
}
240+
241+
return results;
242+
};
243+
}

0 commit comments

Comments
 (0)