Skip to content

Commit 4ee327b

Browse files
committed
Improves worktree view loading performance
1 parent a8d38b7 commit 4ee327b

File tree

2 files changed

+38
-28
lines changed

2 files changed

+38
-28
lines changed

src/views/nodes/worktreeNode.ts

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ import { getBestPath } from '../../system/-webview/path';
1717
import { gate } from '../../system/decorators/-webview/gate';
1818
import { debug } from '../../system/decorators/log';
1919
import { map } from '../../system/iterable';
20+
import { Logger } from '../../system/logger';
2021
import type { Deferred } from '../../system/promise';
21-
import { defer, getSettledValue } from '../../system/promise';
22+
import { defer, getSettledValue, pauseOnCancelOrTimeout } from '../../system/promise';
2223
import { pad } from '../../system/string';
2324
import type { ViewsWithWorktrees } from '../viewBase';
2425
import { createViewDecorationUri } from '../viewDecorationProvider';
@@ -48,7 +49,6 @@ export class WorktreeNode extends CacheableChildrenViewNode<'worktree', ViewsWit
4849
view: ViewsWithWorktrees,
4950
public override parent: ViewNode,
5051
public readonly worktree: GitWorktree,
51-
private readonly worktreeStatus: { status: GitStatus | undefined; missing: boolean } | undefined,
5252
) {
5353
super('worktree', uri, view, parent);
5454

@@ -194,8 +194,9 @@ export class WorktreeNode extends CacheableChildrenViewNode<'worktree', ViewsWit
194194
children.push(new LoadMoreNode(this.view, this, children[children.length - 1]));
195195
}
196196

197-
if (this.worktreeStatus?.status?.hasChanges) {
198-
children.unshift(new UncommittedFilesNode(this.view, this, this.worktreeStatus.status, undefined));
197+
const { status } = await this.getStatus();
198+
if (status?.hasChanges) {
199+
children.unshift(new UncommittedFilesNode(this.view, this, status, undefined));
199200
}
200201

201202
this.children = children;
@@ -224,7 +225,19 @@ export class WorktreeNode extends CacheableChildrenViewNode<'worktree', ViewsWit
224225
})`
225226
: '';
226227

227-
const status = this.worktreeStatus?.status;
228+
let status: GitStatus | undefined;
229+
let missing = false;
230+
231+
const result = await pauseOnCancelOrTimeout(this.getStatus(), undefined, 1);
232+
if (!result.paused) {
233+
({ status, missing } = result.value);
234+
} else {
235+
queueMicrotask(() => {
236+
void result.value.then(() => {
237+
this.view.triggerNodeChange(this);
238+
});
239+
});
240+
}
228241

229242
const folder = `\\\n$(folder) [\`${
230243
this.worktree.friendlyPath
@@ -368,7 +381,6 @@ export class WorktreeNode extends CacheableChildrenViewNode<'worktree', ViewsWit
368381
tooltip.appendMarkdown(`\n\n$(loading~spin) Loading associated pull request${GlyphChars.Ellipsis}`);
369382
}
370383

371-
const missing = this.worktreeStatus?.missing ?? false;
372384
if (missing) {
373385
tooltip.appendMarkdown(`\n\n${GlyphChars.Warning} Unable to locate worktree path`);
374386
}
@@ -456,6 +468,21 @@ export class WorktreeNode extends CacheableChildrenViewNode<'worktree', ViewsWit
456468
return this._log;
457469
}
458470

471+
private _status: { status: GitStatus | undefined; missing: boolean } | undefined;
472+
private async getStatus() {
473+
if (this._status == null) {
474+
try {
475+
const status = await this.worktree.getStatus();
476+
this._status = { status: status, missing: false };
477+
} catch (ex) {
478+
Logger.error(ex, `Worktree status failed: ${this.worktree.uri.toString(true)}`);
479+
this._status = { status: undefined, missing: true };
480+
}
481+
}
482+
483+
return this._status;
484+
}
485+
459486
get hasMore(): boolean {
460487
return this._log?.hasMore ?? true;
461488
}

src/views/nodes/worktreesNode.ts

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ import { GlyphChars } from '../../constants';
33
import type { GitUri } from '../../git/gitUri';
44
import type { Repository } from '../../git/models/repository';
55
import { sortWorktrees } from '../../git/utils/-webview/sorting';
6-
import { filterMap, makeHierarchical } from '../../system/array';
7-
import { map } from '../../system/iterable';
8-
import { Logger } from '../../system/logger';
6+
import { makeHierarchical } from '../../system/array';
97
import type { ViewsWithWorktreesNode } from '../viewBase';
108
import { CacheableChildrenViewNode } from './abstract/cacheableChildrenViewNode';
119
import type { ViewNode } from './abstract/viewNode';
@@ -43,30 +41,15 @@ export class WorktreesNode extends CacheableChildrenViewNode<'worktrees', ViewsW
4341
const worktrees = await this.repo.git.worktrees?.getWorktrees();
4442
if (!worktrees?.length) return [new MessageNode(this.view, this, 'No worktrees could be found.')];
4543

46-
const worktreeNodes = filterMap(
47-
await Promise.allSettled(
48-
map(sortWorktrees(worktrees), async w => {
49-
let status;
50-
let missing = false;
51-
try {
52-
status = await w.getStatus();
53-
} catch (ex) {
54-
Logger.error(ex, `Worktree status failed: ${w.uri.toString(true)}`);
55-
missing = true;
56-
}
57-
return new WorktreeNode(this.uri, this.view, this, w, { status: status, missing: missing });
58-
}),
59-
),
60-
r => (r.status === 'fulfilled' ? r.value : undefined),
61-
);
44+
const children = sortWorktrees(worktrees).map(w => new WorktreeNode(this.uri, this.view, this, w));
6245

6346
if (this.view.config.branches.layout === 'list' || this.view.config.worktrees.viewAs !== 'name') {
64-
this.children = worktreeNodes;
65-
return worktreeNodes;
47+
this.children = children;
48+
return children;
6649
}
6750

6851
const hierarchy = makeHierarchical(
69-
worktreeNodes,
52+
children,
7053
n => n.treeHierarchy,
7154
(...paths) => paths.join('/'),
7255
this.view.config.branches.compact,

0 commit comments

Comments
 (0)