diff --git a/src/views/explorer.ts b/src/views/explorer.ts index a3f7e99..034e237 100644 --- a/src/views/explorer.ts +++ b/src/views/explorer.ts @@ -90,8 +90,8 @@ export abstract class ExplorerBase implements TreeDa return this._root.getChildren(); } - getParent(): ExplorerNode | undefined { - return undefined; + getParent(node: ExplorerNode): ExplorerNode | undefined { + return node.getParent(); } getTreeItem(node: ExplorerNode): TreeItem | Promise { @@ -102,6 +102,12 @@ export abstract class ExplorerBase implements TreeDa this._onDidChangeVisibility.fire(e); } + get selection(): ExplorerNode[] { + if (this._tree === undefined || this._root === undefined) return []; + + return this._tree.selection; + } + get visible(): boolean { return this._tree !== undefined ? this._tree.visible : false; } diff --git a/src/views/nodes/branchNode.ts b/src/views/nodes/branchNode.ts index 1ee86fc..a7c34e4 100644 --- a/src/views/nodes/branchNode.ts +++ b/src/views/nodes/branchNode.ts @@ -19,16 +19,17 @@ export class BranchNode extends ExplorerRefNode implements PageableExplorerNode constructor( public readonly branch: GitBranch, uri: GitUri, - protected readonly explorer: GitExplorer, - private readonly markCurrent: boolean = true + parent: ExplorerNode, + public readonly explorer: GitExplorer, + private readonly _markCurrent: boolean = true ) { - super(uri); + super(uri, parent); } get id(): string { return `gitlens:repository(${this.branch.repoPath}):branch(${this.branch.name})${ this.branch.remote ? ':remote' : '' - }${this.markCurrent ? ':current' : ''}`; + }${this._markCurrent ? ':current' : ''}`; } get current(): boolean { @@ -52,7 +53,7 @@ export class BranchNode extends ExplorerRefNode implements PageableExplorerNode maxCount: this.maxCount || this.explorer.config.defaultItemLimit, ref: this.ref }); - if (log === undefined) return [new MessageNode('No commits yet')]; + if (log === undefined) return [new MessageNode(this, 'No commits yet')]; const branches = await Container.git.getBranches(this.uri.repoPath); // Get the sha length, since `git branch` can return variable length shas @@ -72,7 +73,7 @@ export class BranchNode extends ExplorerRefNode implements PageableExplorerNode const children: (CommitNode | ShowMoreNode)[] = [ ...Iterables.map( log.commits.values(), - c => new CommitNode(c, this.explorer, this.branch, getBranchTips) + c => new CommitNode(c, this, this.explorer, this.branch, getBranchTips) ) ]; @@ -113,7 +114,7 @@ export class BranchNode extends ExplorerRefNode implements PageableExplorerNode } const item = new TreeItem( - `${this.markCurrent && this.current ? `${GlyphChars.Check} ${GlyphChars.Space}` : ''}${name}`, + `${this._markCurrent && this.current ? `${GlyphChars.Check} ${GlyphChars.Space}` : ''}${name}`, TreeItemCollapsibleState.Collapsed ); item.id = this.id; diff --git a/src/views/nodes/branchOrTagFolderNode.ts b/src/views/nodes/branchOrTagFolderNode.ts index c4fcb96..980ebf0 100644 --- a/src/views/nodes/branchOrTagFolderNode.ts +++ b/src/views/nodes/branchOrTagFolderNode.ts @@ -14,10 +14,11 @@ export class BranchOrTagFolderNode extends ExplorerNode { public readonly folderName: string, public readonly relativePath: string | undefined, public readonly root: Arrays.IHierarchicalItem, - private readonly explorer: Explorer, - private readonly expanded: boolean = false + parent: ExplorerNode, + public readonly explorer: Explorer, + private readonly _expanded: boolean = false ) { - super(GitUri.fromRepoPath(repoPath)); + super(GitUri.fromRepoPath(repoPath), parent); } get id(): string { @@ -42,6 +43,7 @@ export class BranchOrTagFolderNode extends ExplorerNode { folder.name, folder.relativePath, folder, + this, this.explorer, expanded ) @@ -58,7 +60,7 @@ export class BranchOrTagFolderNode extends ExplorerNode { async getTreeItem(): Promise { const item = new TreeItem( this.label, - this.expanded ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.Collapsed + this._expanded ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.Collapsed ); item.id = this.id; item.contextValue = ResourceType.Folder; diff --git a/src/views/nodes/branchesNode.ts b/src/views/nodes/branchesNode.ts index 324afbc..1d1291d 100644 --- a/src/views/nodes/branchesNode.ts +++ b/src/views/nodes/branchesNode.ts @@ -14,10 +14,11 @@ export class BranchesNode extends ExplorerNode { constructor( uri: GitUri, - private readonly repo: Repository, - private readonly explorer: GitExplorer + public readonly repo: Repository, + parent: ExplorerNode, + public readonly explorer: GitExplorer ) { - super(uri); + super(uri, parent); } get id(): string { @@ -35,7 +36,7 @@ export class BranchesNode extends ExplorerNode { const branchNodes = [ ...Iterables.filterMap( branches, - b => (b.remote ? undefined : new BranchNode(b, this.uri, this.explorer)) + b => (b.remote ? undefined : new BranchNode(b, this.uri, this, this.explorer)) ) ]; if (this.explorer.config.branches.layout === ExplorerBranchesLayout.List) return branchNodes; @@ -47,7 +48,15 @@ export class BranchesNode extends ExplorerNode { this.explorer.config.files.compact ); - const root = new BranchOrTagFolderNode('branch', this.repo.path, '', undefined, hierarchy, this.explorer); + const root = new BranchOrTagFolderNode( + 'branch', + this.repo.path, + '', + undefined, + hierarchy, + this, + this.explorer + ); this._children = await root.getChildren(); } return this._children; diff --git a/src/views/nodes/commitFileNode.ts b/src/views/nodes/commitFileNode.ts index 79f758b..ddf3423 100644 --- a/src/views/nodes/commitFileNode.ts +++ b/src/views/nodes/commitFileNode.ts @@ -34,11 +34,12 @@ export class CommitFileNode extends ExplorerRefNode { constructor( public readonly status: IGitStatusFile, public commit: GitLogCommit, - protected readonly explorer: Explorer, + parent: ExplorerNode, + public readonly explorer: Explorer, private readonly _displayAs: CommitFileNodeDisplayAs, private readonly _selection?: Selection ) { - super(GitUri.fromFileStatus(status, commit.repoPath, commit.sha)); + super(GitUri.fromFileStatus(status, commit.repoPath, commit.sha), parent); } get ref(): string { diff --git a/src/views/nodes/commitNode.ts b/src/views/nodes/commitNode.ts index f0f13b3..7509f9c 100644 --- a/src/views/nodes/commitNode.ts +++ b/src/views/nodes/commitNode.ts @@ -15,11 +15,12 @@ import { FolderNode, IFileExplorerNode } from './folderNode'; export class CommitNode extends ExplorerRefNode { constructor( public readonly commit: GitLogCommit, - private readonly explorer: Explorer, + parent: ExplorerNode, + public readonly explorer: Explorer, public readonly branch?: GitBranch, private readonly getBranchTips?: (sha: string) => string | undefined ) { - super(commit.toGitUri()); + super(commit.toGitUri(), parent); } get ref(): string { @@ -31,7 +32,7 @@ export class CommitNode extends ExplorerRefNode { let children: IFileExplorerNode[] = [ ...Iterables.map( commit.fileStatuses, - s => new CommitFileNode(s, commit.toFileCommit(s), this.explorer, CommitFileNodeDisplayAs.File) + s => new CommitFileNode(s, commit.toFileCommit(s), this, this.explorer, CommitFileNodeDisplayAs.File) ) ]; @@ -43,7 +44,7 @@ export class CommitNode extends ExplorerRefNode { this.explorer.config.files.compact ); - const root = new FolderNode(this.repoPath, '', undefined, hierarchy, this.explorer); + const root = new FolderNode(this.repoPath, '', undefined, hierarchy, this, this.explorer); children = (await root.getChildren()) as IFileExplorerNode[]; } else { diff --git a/src/views/nodes/common.ts b/src/views/nodes/common.ts index 7a0e4f6..3a99ef2 100644 --- a/src/views/nodes/common.ts +++ b/src/views/nodes/common.ts @@ -7,6 +7,7 @@ import { ExplorerNode, ResourceType, unknownGitUri } from '../nodes/explorerNode export class MessageNode extends ExplorerNode { constructor( + parent: ExplorerNode, private readonly _message: string, private readonly _tooltip?: string, private readonly _iconPath?: @@ -18,7 +19,7 @@ export class MessageNode extends ExplorerNode { } | ThemeIcon ) { - super(unknownGitUri); + super(unknownGitUri, parent); } getChildren(): ExplorerNode[] | Promise { @@ -36,6 +37,7 @@ export class MessageNode extends ExplorerNode { export class UpdateableMessageNode extends ExplorerNode { constructor( + parent: ExplorerNode, public readonly id: string, private _message: string, private _tooltip?: string, @@ -48,7 +50,7 @@ export class UpdateableMessageNode extends ExplorerNode { } | ThemeIcon ) { - super(unknownGitUri); + super(unknownGitUri, parent); } getChildren(): ExplorerNode[] | Promise { @@ -101,10 +103,10 @@ export abstract class PagerNode extends ExplorerNode { constructor( protected readonly message: string, - protected readonly node: ExplorerNode, + protected readonly parent: ExplorerNode, protected readonly explorer: Explorer ) { - super(unknownGitUri); + super(unknownGitUri, parent); } getChildren(): ExplorerNode[] | Promise { @@ -126,7 +128,7 @@ export abstract class PagerNode extends ExplorerNode { return { title: 'Refresh', command: this.explorer.getQualifiedCommand('refreshNode'), - arguments: [this.node, this._args] + arguments: [this.parent, this._args] } as Command; } } @@ -134,7 +136,7 @@ export abstract class PagerNode extends ExplorerNode { export class ShowMoreNode extends PagerNode { constructor( type: string, - node: ExplorerNode, + parent: ExplorerNode, explorer: Explorer, maxCount: number = Container.config.advanced.maxListItems ) { @@ -142,7 +144,7 @@ export class ShowMoreNode extends PagerNode { maxCount === 0 ? `Show All ${type} ${GlyphChars.Space}${GlyphChars.Dash}${GlyphChars.Space} this may take a while` : `Show More ${type}`, - node, + parent, explorer ); this._args.maxCount = maxCount; diff --git a/src/views/nodes/explorerNode.ts b/src/views/nodes/explorerNode.ts index d098c07..5f68a9e 100644 --- a/src/views/nodes/explorerNode.ts +++ b/src/views/nodes/explorerNode.ts @@ -49,7 +49,10 @@ export interface NamedRef { export const unknownGitUri = new GitUri(); export abstract class ExplorerNode { - constructor(uri: GitUri) { + constructor( + uri: GitUri, + private readonly _parent: ExplorerNode | undefined + ) { this._uri = uri; } @@ -59,6 +62,9 @@ export abstract class ExplorerNode { } abstract getChildren(): ExplorerNode[] | Promise; + getParent(): ExplorerNode | undefined { + return this._parent; + } abstract getTreeItem(): TreeItem | Promise; getCommand(): Command | undefined { @@ -99,9 +105,10 @@ export abstract class SubscribeableExplorerNode exte constructor( uri: GitUri, + parent: ExplorerNode | undefined, public readonly explorer: TExplorer ) { - super(uri); + super(uri, parent); const disposables = [this.explorer.onDidChangeVisibility(this.onVisibilityChanged, this)]; diff --git a/src/views/nodes/fileHistoryNode.ts b/src/views/nodes/fileHistoryNode.ts index dff105d..f539d70 100644 --- a/src/views/nodes/fileHistoryNode.ts +++ b/src/views/nodes/fileHistoryNode.ts @@ -18,8 +18,8 @@ import { MessageNode } from './common'; import { ExplorerNode, ResourceType, SubscribeableExplorerNode } from './explorerNode'; export class FileHistoryNode extends SubscribeableExplorerNode { - constructor(uri: GitUri, explorer: FileHistoryExplorer) { - super(uri, explorer); + constructor(uri: GitUri, parent: ExplorerNode, explorer: FileHistoryExplorer) { + super(uri, parent, explorer); } async getChildren(): Promise { @@ -63,7 +63,7 @@ export class FileHistoryNode extends SubscribeableExplorerNode new CommitFileNode(c.fileStatuses[0], c, this.explorer, displayAs) + c => new CommitFileNode(c.fileStatuses[0], c, this, this.explorer, displayAs) ) ); } - if (children.length === 0) return [new MessageNode('No file history')]; + if (children.length === 0) return [new MessageNode(this, 'No file history')]; return children; } diff --git a/src/views/nodes/fileHistoryTrackerNode.ts b/src/views/nodes/fileHistoryTrackerNode.ts index db9fda3..c42c5b2 100644 --- a/src/views/nodes/fileHistoryTrackerNode.ts +++ b/src/views/nodes/fileHistoryTrackerNode.ts @@ -14,7 +14,7 @@ export class FileHistoryTrackerNode extends SubscribeableExplorerNode { if (this._child === undefined) { if (this.uri === unknownGitUri) { - return [new MessageNode('There are no editors open that can provide file history')]; + return [new MessageNode(this, 'There are no editors open that can provide file history')]; } - this._child = new FileHistoryNode(this.uri, this.explorer); + this._child = new FileHistoryNode(this.uri, this, this.explorer); } return [this._child]; diff --git a/src/views/nodes/folderNode.ts b/src/views/nodes/folderNode.ts index d90de13..1999bfe 100644 --- a/src/views/nodes/folderNode.ts +++ b/src/views/nodes/folderNode.ts @@ -22,9 +22,10 @@ export class FolderNode extends ExplorerNode { public readonly folderName: string, public readonly relativePath: string | undefined, public readonly root: Arrays.IHierarchicalItem, - private readonly explorer: Explorer + parent: ExplorerNode, + public readonly explorer: Explorer ) { - super(GitUri.fromRepoPath(repoPath)); + super(GitUri.fromRepoPath(repoPath), parent); } async getChildren(): Promise<(FolderNode | IFileExplorerNode)[]> { @@ -42,7 +43,7 @@ export class FolderNode extends ExplorerNode { for (const folder of Objects.values(this.root.children)) { if (folder.value === undefined) { children.push( - new FolderNode(this.repoPath, folder.name, folder.relativePath, folder, this.explorer) + new FolderNode(this.repoPath, folder.name, folder.relativePath, folder, this, this.explorer) ); continue; } diff --git a/src/views/nodes/lineHistoryNode.ts b/src/views/nodes/lineHistoryNode.ts index cb9b00b..a2a8386 100644 --- a/src/views/nodes/lineHistoryNode.ts +++ b/src/views/nodes/lineHistoryNode.ts @@ -20,9 +20,10 @@ export class LineHistoryNode extends SubscribeableExplorerNode { @@ -40,7 +41,7 @@ export class LineHistoryNode extends SubscribeableExplorerNode new CommitFileNode(c.fileStatuses[0], c, this.explorer, displayAs, this.selection) + c => new CommitFileNode(c.fileStatuses[0], c, this, this.explorer, displayAs, this.selection) ) ); } @@ -75,11 +76,15 @@ export class LineHistoryNode extends SubscribeableExplorerNode { if (this._child === undefined) { if (this.uri === unknownGitUri) { - return [new MessageNode('There are no editors open that can provide line history')]; + return [new MessageNode(this, 'There are no editors open that can provide line history')]; } - this._child = new LineHistoryNode(this.uri, this._selection!, this.explorer); + this._child = new LineHistoryNode(this.uri, this._selection!, this, this.explorer); } return [this._child]; diff --git a/src/views/nodes/remoteNode.ts b/src/views/nodes/remoteNode.ts index 984330b..d74f0c4 100644 --- a/src/views/nodes/remoteNode.ts +++ b/src/views/nodes/remoteNode.ts @@ -14,10 +14,11 @@ export class RemoteNode extends ExplorerNode { constructor( public readonly remote: GitRemote, uri: GitUri, - private readonly repo: Repository, - private readonly explorer: GitExplorer + public readonly repo: Repository, + parent: ExplorerNode, + public readonly explorer: GitExplorer ) { - super(uri); + super(uri, parent); } get id(): string { @@ -37,7 +38,7 @@ export class RemoteNode extends ExplorerNode { b => !b.remote || !b.name.startsWith(this.remote.name) ? undefined - : new BranchNode(b, this.uri, this.explorer) + : new BranchNode(b, this.uri, this, this.explorer) ) ]; if (this.explorer.config.branches.layout === ExplorerBranchesLayout.List) return branchNodes; @@ -55,6 +56,7 @@ export class RemoteNode extends ExplorerNode { '', undefined, hierarchy, + this, this.explorer ); const children = (await root.getChildren()) as (BranchOrTagFolderNode | BranchNode)[]; diff --git a/src/views/nodes/remotesNode.ts b/src/views/nodes/remotesNode.ts index 917afef..9b5103c 100644 --- a/src/views/nodes/remotesNode.ts +++ b/src/views/nodes/remotesNode.ts @@ -11,10 +11,11 @@ import { RemoteNode } from './remoteNode'; export class RemotesNode extends ExplorerNode { constructor( uri: GitUri, - private readonly repo: Repository, - private readonly explorer: GitExplorer + public readonly repo: Repository, + parent: ExplorerNode, + public readonly explorer: GitExplorer ) { - super(uri); + super(uri, parent); } get id(): string { @@ -23,10 +24,10 @@ export class RemotesNode extends ExplorerNode { async getChildren(): Promise { const remotes = await this.repo.getRemotes(); - if (remotes === undefined || remotes.length === 0) return [new MessageNode('No remotes configured')]; + if (remotes === undefined || remotes.length === 0) return [new MessageNode(this, 'No remotes configured')]; remotes.sort((a, b) => a.name.localeCompare(b.name)); - return [...Iterables.map(remotes, r => new RemoteNode(r, this.uri, this.repo, this.explorer))]; + return [...Iterables.map(remotes, r => new RemoteNode(r, this.uri, this.repo, this, this.explorer))]; } getTreeItem(): TreeItem { diff --git a/src/views/nodes/repositoriesNode.ts b/src/views/nodes/repositoriesNode.ts index 03efae9..0c2f294 100644 --- a/src/views/nodes/repositoriesNode.ts +++ b/src/views/nodes/repositoriesNode.ts @@ -13,7 +13,7 @@ export class RepositoriesNode extends SubscribeableExplorerNode { private _children: (RepositoryNode | MessageNode)[] | undefined; constructor(explorer: GitExplorer) { - super(unknownGitUri, explorer); + super(unknownGitUri, undefined, explorer); } dispose() { @@ -32,13 +32,13 @@ export class RepositoriesNode extends SubscribeableExplorerNode { async getChildren(): Promise { if (this._children === undefined) { const repositories = [...(await Container.git.getRepositories())]; - if (repositories.length === 0) return [new MessageNode('No repositories found')]; + if (repositories.length === 0) return [new MessageNode(this, 'No repositories found')]; const children = []; for (const repo of repositories.sort((a, b) => a.index - b.index)) { if (repo.closed) continue; - children.push(new RepositoryNode(GitUri.fromRepoPath(repo.path), repo, this.explorer)); + children.push(new RepositoryNode(GitUri.fromRepoPath(repo.path), repo, this, this.explorer)); } this._children = children; @@ -91,7 +91,7 @@ export class RepositoriesNode extends SubscribeableExplorerNode { if (repositories.length === 0 && (this._children === undefined || this._children.length === 0)) return; if (repositories.length === 0) { - this._children = [new MessageNode('No repositories found')]; + this._children = [new MessageNode(this, 'No repositories found')]; return; } @@ -104,7 +104,7 @@ export class RepositoriesNode extends SubscribeableExplorerNode { child.refresh(); } else { - children.push(new RepositoryNode(GitUri.fromRepoPath(repo.path), repo, this.explorer)); + children.push(new RepositoryNode(GitUri.fromRepoPath(repo.path), repo, this, this.explorer)); } } @@ -119,6 +119,8 @@ export class RepositoriesNode extends SubscribeableExplorerNode { } protected async subscribe() { + // TODO: Add a setting to control tracking the active editor + return Disposable.from( window.onDidChangeActiveTextEditor(Functions.debounce(this.onActiveEditorChanged, 500), this), Container.git.onDidChangeRepositories(this.onRepositoriesChanged, this) @@ -139,6 +141,14 @@ export class RepositoriesNode extends SubscribeableExplorerNode { | undefined; if (node === undefined) return; + // Check to see if this repo has a descendent that is already selected + let parent = this.explorer.selection.length === 0 ? undefined : this.explorer.selection[0]; + while (parent !== undefined) { + if (parent === node) return; + + parent = parent.getParent(); + } + // HACK: Since we have no expand/collapse api, reveal the first child to force an expand // See https://github.com/Microsoft/vscode/issues/55879 const children = await node.getChildren(); diff --git a/src/views/nodes/repositoryNode.ts b/src/views/nodes/repositoryNode.ts index f13a868..e36d27e 100644 --- a/src/views/nodes/repositoryNode.ts +++ b/src/views/nodes/repositoryNode.ts @@ -34,9 +34,10 @@ export class RepositoryNode extends SubscribeableExplorerNode { constructor( uri: GitUri, public readonly repo: Repository, + parent: ExplorerNode, explorer: GitExplorer ) { - super(uri, explorer); + super(uri, parent, explorer); this._status = this.repo.getStatus(); } @@ -61,29 +62,29 @@ export class RepositoryNode extends SubscribeableExplorerNode { status.state.behind, status.detached ); - children.push(new BranchNode(branch, this.uri, this.explorer, false)); + children.push(new BranchNode(branch, this.uri, this, this.explorer, false)); if (status.state.behind) { - children.push(new StatusUpstreamNode(status, 'behind', this.explorer)); + children.push(new StatusUpstreamNode(status, 'behind', this, this.explorer)); } if (status.state.ahead) { - children.push(new StatusUpstreamNode(status, 'ahead', this.explorer)); + children.push(new StatusUpstreamNode(status, 'ahead', this, this.explorer)); } if (status.state.ahead || (status.files.length !== 0 && this.includeWorkingTree)) { const range = status.upstream ? `${status.upstream}..${branch.ref}` : undefined; - children.push(new StatusFilesNode(status, range, this.explorer)); + children.push(new StatusFilesNode(status, range, this, this.explorer)); } - children.push(new MessageNode(GlyphChars.Dash.repeat(2), '')); + children.push(new MessageNode(this, GlyphChars.Dash.repeat(2), '')); } children.push( - new BranchesNode(this.uri, this.repo, this.explorer), - new RemotesNode(this.uri, this.repo, this.explorer), - new StashesNode(this.uri, this.repo, this.explorer), - new TagsNode(this.uri, this.repo, this.explorer) + new BranchesNode(this.uri, this.repo, this, this.explorer), + new RemotesNode(this.uri, this.repo, this, this.explorer), + new StashesNode(this.uri, this.repo, this, this.explorer), + new TagsNode(this.uri, this.repo, this, this.explorer) ); this._children = children; } diff --git a/src/views/nodes/resultsCommitNode.ts b/src/views/nodes/resultsCommitNode.ts index 19ebd53..1843848 100644 --- a/src/views/nodes/resultsCommitNode.ts +++ b/src/views/nodes/resultsCommitNode.ts @@ -8,13 +8,13 @@ import { ExplorerNode, ResourceType } from './explorerNode'; export class ResultsCommitNode extends ExplorerNode { constructor( public readonly commit: GitLogCommit, - private readonly explorer: ResultsExplorer + public readonly explorer: ResultsExplorer ) { - super(commit.toGitUri()); + super(commit.toGitUri(), undefined); } getChildren(): ExplorerNode[] { - return [new CommitNode(this.commit, this.explorer)]; + return [new CommitNode(this.commit, this, this.explorer)]; } getTreeItem(): TreeItem { diff --git a/src/views/nodes/resultsCommitsNode.ts b/src/views/nodes/resultsCommitsNode.ts index 5d58089..f9a7e44 100644 --- a/src/views/nodes/resultsCommitsNode.ts +++ b/src/views/nodes/resultsCommitsNode.ts @@ -18,11 +18,12 @@ export class ResultsCommitsNode extends ExplorerNode implements PageableExplorer constructor( public readonly repoPath: string, - private readonly commitsQuery: (maxCount: number | undefined) => Promise, - private readonly explorer: ResultsExplorer, - private readonly contextValue: ResourceType = ResourceType.ResultsCommits + private readonly _commitsQuery: (maxCount: number | undefined) => Promise, + parent: ExplorerNode | undefined, + public readonly explorer: ResultsExplorer, + private readonly _contextValue: ResourceType = ResourceType.ResultsCommits ) { - super(GitUri.fromRepoPath(repoPath)); + super(GitUri.fromRepoPath(repoPath), parent); } async getChildren(): Promise { @@ -30,7 +31,7 @@ export class ResultsCommitsNode extends ExplorerNode implements PageableExplorer if (log === undefined) return []; const children: (CommitNode | ShowAllNode)[] = [ - ...Iterables.map(log.commits.values(), c => new CommitNode(c, this.explorer)) + ...Iterables.map(log.commits.values(), c => new CommitNode(c, this, this.explorer)) ]; if (log.truncated) { @@ -47,20 +48,20 @@ export class ResultsCommitsNode extends ExplorerNode implements PageableExplorer label, log && log.count > 0 ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.None ); - item.contextValue = this.contextValue; + item.contextValue = this._contextValue; return item; } async refresh() { - this._commitsQueryResults = this.commitsQuery(this.maxCount); + this._commitsQueryResults = this._commitsQuery(this.maxCount); } private _commitsQueryResults: Promise | undefined; private getCommitsQueryResults() { if (this._commitsQueryResults === undefined) { - this._commitsQueryResults = this.commitsQuery(this.maxCount); + this._commitsQueryResults = this._commitsQuery(this.maxCount); } return this._commitsQueryResults; diff --git a/src/views/nodes/resultsComparisonNode.ts b/src/views/nodes/resultsComparisonNode.ts index e7e12f9..1ae9faf 100644 --- a/src/views/nodes/resultsComparisonNode.ts +++ b/src/views/nodes/resultsComparisonNode.ts @@ -14,9 +14,9 @@ export class ResultsComparisonNode extends ExplorerNode { public readonly repoPath: string, ref1: NamedRef, ref2: NamedRef, - private readonly explorer: ResultsExplorer + public readonly explorer: ResultsExplorer ) { - super(GitUri.fromRepoPath(repoPath)); + super(GitUri.fromRepoPath(repoPath), undefined); this._ref1 = ref1; this._ref2 = ref2; @@ -34,8 +34,8 @@ export class ResultsComparisonNode extends ExplorerNode { async getChildren(): Promise { return [ - new ResultsCommitsNode(this.uri.repoPath!, this.getCommitsQuery.bind(this), this.explorer), - new StatusFilesResultsNode(this.uri.repoPath!, this._ref1.ref, this._ref2.ref, this.explorer) + new ResultsCommitsNode(this.uri.repoPath!, this.getCommitsQuery.bind(this), this, this.explorer), + new StatusFilesResultsNode(this.uri.repoPath!, this._ref1.ref, this._ref2.ref, this, this.explorer) ]; } diff --git a/src/views/nodes/resultsNode.ts b/src/views/nodes/resultsNode.ts index dd397b8..ebab591 100644 --- a/src/views/nodes/resultsNode.ts +++ b/src/views/nodes/resultsNode.ts @@ -10,11 +10,11 @@ export class ResultsNode extends ExplorerNode { constructor( public readonly explorer: ResultsExplorer ) { - super(unknownGitUri); + super(unknownGitUri, undefined); } async getChildren(): Promise { - if (this._children.length === 0) return [new MessageNode('No results')]; + if (this._children.length === 0) return [new MessageNode(this, 'No results')]; return this._children; } diff --git a/src/views/nodes/stashFileNode.ts b/src/views/nodes/stashFileNode.ts index 249709d..0871ca6 100644 --- a/src/views/nodes/stashFileNode.ts +++ b/src/views/nodes/stashFileNode.ts @@ -2,11 +2,11 @@ import { GitLogCommit, IGitStatusFile } from '../../git/gitService'; import { Explorer } from '../explorer'; import { CommitFileNode, CommitFileNodeDisplayAs } from './commitFileNode'; -import { ResourceType } from './explorerNode'; +import { ExplorerNode, ResourceType } from './explorerNode'; export class StashFileNode extends CommitFileNode { - constructor(status: IGitStatusFile, commit: GitLogCommit, explorer: Explorer) { - super(status, commit, explorer, CommitFileNodeDisplayAs.File); + constructor(status: IGitStatusFile, commit: GitLogCommit, parent: ExplorerNode, explorer: Explorer) { + super(status, commit, parent, explorer, CommitFileNodeDisplayAs.File); } protected get resourceType(): ResourceType { diff --git a/src/views/nodes/stashNode.ts b/src/views/nodes/stashNode.ts index 56301b0..0af828b 100644 --- a/src/views/nodes/stashNode.ts +++ b/src/views/nodes/stashNode.ts @@ -10,9 +10,10 @@ import { StashFileNode } from './stashFileNode'; export class StashNode extends ExplorerRefNode { constructor( public readonly commit: GitStashCommit, - private readonly explorer: Explorer + parent: ExplorerNode, + public readonly explorer: Explorer ) { - super(commit.toGitUri()); + super(commit.toGitUri(), parent); } get id(): string { @@ -40,7 +41,7 @@ export class StashNode extends ExplorerRefNode { } } - const children = statuses.map(s => new StashFileNode(s, this.commit.toFileCommit(s), this.explorer)); + const children = statuses.map(s => new StashFileNode(s, this.commit.toFileCommit(s), this, this.explorer)); children.sort((a, b) => a.label!.localeCompare(b.label!)); return children; } diff --git a/src/views/nodes/stashesNode.ts b/src/views/nodes/stashesNode.ts index d321897..18fbf25 100644 --- a/src/views/nodes/stashesNode.ts +++ b/src/views/nodes/stashesNode.ts @@ -11,10 +11,11 @@ import { StashNode } from './stashNode'; export class StashesNode extends ExplorerNode { constructor( uri: GitUri, - private readonly repo: Repository, - private readonly explorer: Explorer + public readonly repo: Repository, + parent: ExplorerNode, + public readonly explorer: Explorer ) { - super(uri); + super(uri, parent); } get id(): string { @@ -23,9 +24,9 @@ export class StashesNode extends ExplorerNode { async getChildren(): Promise { const stash = await this.repo.getStashList(); - if (stash === undefined) return [new MessageNode('No stashed changes')]; + if (stash === undefined) return [new MessageNode(this, 'No stashed changes')]; - return [...Iterables.map(stash.commits.values(), c => new StashNode(c, this.explorer))]; + return [...Iterables.map(stash.commits.values(), c => new StashNode(c, this, this.explorer))]; } getTreeItem(): TreeItem { diff --git a/src/views/nodes/statusFileCommitsNode.ts b/src/views/nodes/statusFileCommitsNode.ts index ba8c3bc..804e885 100644 --- a/src/views/nodes/statusFileCommitsNode.ts +++ b/src/views/nodes/statusFileCommitsNode.ts @@ -22,9 +22,10 @@ export class StatusFileCommitsNode extends ExplorerNode { public readonly repoPath: string, public readonly status: IGitStatusFile, public readonly commits: GitLogCommit[], - private readonly explorer: Explorer + parent: ExplorerNode, + public readonly explorer: Explorer ) { - super(GitUri.fromFileStatus(status, repoPath, 'HEAD')); + super(GitUri.fromFileStatus(status, repoPath, 'HEAD'), parent); } async getChildren(): Promise { @@ -33,6 +34,7 @@ export class StatusFileCommitsNode extends ExplorerNode { new CommitFileNode( this.status, c, + this, this.explorer, CommitFileNodeDisplayAs.CommitLabel | (this.explorer.config.avatars diff --git a/src/views/nodes/statusFileNode.ts b/src/views/nodes/statusFileNode.ts index 26dfb64..d5a9eba 100644 --- a/src/views/nodes/statusFileNode.ts +++ b/src/views/nodes/statusFileNode.ts @@ -16,12 +16,13 @@ import { ExplorerNode, ResourceType } from './explorerNode'; export class StatusFileNode extends ExplorerNode { constructor( public readonly repoPath: string, - private readonly status: GitStatusFile, - private readonly ref1: string, - private readonly ref2: string, - private readonly explorer: Explorer + private readonly _status: GitStatusFile, + private readonly _ref1: string, + private readonly _ref2: string, + parent: ExplorerNode, + public readonly explorer: Explorer ) { - super(GitUri.fromFileStatus(status, repoPath, ref1 ? ref1 : ref2 ? ref2 : undefined)); + super(GitUri.fromFileStatus(_status, repoPath, _ref1 ? _ref1 : _ref2 ? _ref2 : undefined), parent); } getChildren(): ExplorerNode[] { @@ -31,9 +32,9 @@ export class StatusFileNode extends ExplorerNode { getTreeItem(): TreeItem { const item = new TreeItem(this.label, TreeItemCollapsibleState.None); item.contextValue = ResourceType.StatusFile; - item.tooltip = StatusFileFormatter.fromTemplate('${file}\n${directory}/\n\n${status}', this.status); + item.tooltip = StatusFileFormatter.fromTemplate('${file}\n${directory}/\n\n${status}', this._status); - const statusIcon = getGitStatusIcon(this.status.status); + const statusIcon = getGitStatusIcon(this._status.status); item.iconPath = { dark: Container.context.asAbsolutePath(path.join('images', 'dark', statusIcon)), light: Container.context.asAbsolutePath(path.join('images', 'light', statusIcon)) @@ -54,7 +55,7 @@ export class StatusFileNode extends ExplorerNode { private _label: string | undefined; get label() { if (this._label === undefined) { - this._label = StatusFileFormatter.fromTemplate(this.explorer.config.statusFileFormat, this.status, { + this._label = StatusFileFormatter.fromTemplate(this.explorer.config.statusFileFormat, this._status, { relativePath: this.relativePath } as IStatusFormatOptions); } @@ -82,14 +83,14 @@ export class StatusFileNode extends ExplorerNode { this.uri, { lhs: { - sha: this.ref1, + sha: this._ref1, uri: this.uri }, rhs: { - sha: this.ref2, + sha: this._ref2, uri: - this.status.status === 'R' - ? GitUri.fromFileStatus(this.status, this.uri.repoPath!, this.ref2, true) + this._status.status === 'R' + ? GitUri.fromFileStatus(this._status, this.uri.repoPath!, this._ref2, true) : this.uri }, repoPath: this.uri.repoPath!, diff --git a/src/views/nodes/statusFilesNode.ts b/src/views/nodes/statusFilesNode.ts index 26dc301..4d3b23f 100644 --- a/src/views/nodes/statusFilesNode.ts +++ b/src/views/nodes/statusFilesNode.ts @@ -25,9 +25,10 @@ export class StatusFilesNode extends ExplorerNode { constructor( public readonly status: GitStatus, public readonly range: string | undefined, - private readonly explorer: GitExplorer + parent: ExplorerNode, + public readonly explorer: GitExplorer ) { - super(GitUri.fromRepoPath(status.repoPath)); + super(GitUri.fromRepoPath(status.repoPath), parent); this.repoPath = status.repoPath; } @@ -89,6 +90,7 @@ export class StatusFilesNode extends ExplorerNode { repoPath, statuses[statuses.length - 1], statuses.map(s => s.commit), + this, this.explorer ) ) @@ -102,7 +104,7 @@ export class StatusFilesNode extends ExplorerNode { this.explorer.config.files.compact ); - const root = new FolderNode(repoPath, '', undefined, hierarchy, this.explorer); + const root = new FolderNode(repoPath, '', undefined, hierarchy, this, this.explorer); children = (await root.getChildren()) as IFileExplorerNode[]; } else { diff --git a/src/views/nodes/statusFilesResultsNode.ts b/src/views/nodes/statusFilesResultsNode.ts index d6bd246..83361f2 100644 --- a/src/views/nodes/statusFilesResultsNode.ts +++ b/src/views/nodes/statusFilesResultsNode.ts @@ -17,11 +17,12 @@ export class StatusFilesResultsNode extends ExplorerNode { constructor( public readonly repoPath: string, - private readonly ref1: string, - private readonly ref2: string, - private readonly explorer: Explorer + private readonly _ref1: string, + private readonly _ref2: string, + parent: ExplorerNode, + public readonly explorer: Explorer ) { - super(GitUri.fromRepoPath(repoPath)); + super(GitUri.fromRepoPath(repoPath), parent); } async getChildren(): Promise { @@ -29,7 +30,10 @@ export class StatusFilesResultsNode extends ExplorerNode { if (diff === undefined) return []; let children: IFileExplorerNode[] = [ - ...Iterables.map(diff, s => new StatusFileNode(this.repoPath, s, this.ref1, this.ref2, this.explorer)) + ...Iterables.map( + diff, + s => new StatusFileNode(this.repoPath, s, this._ref1, this._ref2, this, this.explorer) + ) ]; if (this.explorer.config.files.layout !== ExplorerFilesLayout.List) { @@ -40,7 +44,7 @@ export class StatusFilesResultsNode extends ExplorerNode { this.explorer.config.files.compact ); - const root = new FolderNode(this.repoPath, '', undefined, hierarchy, this.explorer); + const root = new FolderNode(this.repoPath, '', undefined, hierarchy, this, this.explorer); children = (await root.getChildren()) as IFileExplorerNode[]; } else { @@ -67,7 +71,7 @@ export class StatusFilesResultsNode extends ExplorerNode { private async ensureCache() { if (this._cache === undefined) { - const diff = await Container.git.getDiffStatus(this.uri.repoPath!, this.ref1, this.ref2); + const diff = await Container.git.getDiffStatus(this.uri.repoPath!, this._ref1, this._ref2); const count = diff !== undefined ? diff.length : 0; const label = `${Strings.pluralize('file', count, { zero: 'No' })} changed`; diff --git a/src/views/nodes/statusUpstreamNode.ts b/src/views/nodes/statusUpstreamNode.ts index e839349..abcdb29 100644 --- a/src/views/nodes/statusUpstreamNode.ts +++ b/src/views/nodes/statusUpstreamNode.ts @@ -15,9 +15,10 @@ export class StatusUpstreamNode extends ExplorerNode implements PageableExplorer constructor( public readonly status: GitStatus, public readonly direction: 'ahead' | 'behind', - private readonly explorer: GitExplorer + parent: ExplorerNode, + public readonly explorer: GitExplorer ) { - super(GitUri.fromRepoPath(status.repoPath)); + super(GitUri.fromRepoPath(status.repoPath), parent); } get id(): string { @@ -48,10 +49,10 @@ export class StatusUpstreamNode extends ExplorerNode implements PageableExplorer } } - children = commits.map(c => new CommitNode(c, this.explorer)); + children = commits.map(c => new CommitNode(c, this, this.explorer)); } else { - children = [...Iterables.map(log.commits.values(), c => new CommitNode(c, this.explorer))]; + children = [...Iterables.map(log.commits.values(), c => new CommitNode(c, this, this.explorer))]; } if (log.truncated) { diff --git a/src/views/nodes/tagNode.ts b/src/views/nodes/tagNode.ts index ce5bb65..f2f3bd7 100644 --- a/src/views/nodes/tagNode.ts +++ b/src/views/nodes/tagNode.ts @@ -16,9 +16,10 @@ export class TagNode extends ExplorerRefNode implements PageableExplorerNode { constructor( public readonly tag: GitTag, uri: GitUri, - private readonly explorer: GitExplorer + parent: ExplorerNode, + public readonly explorer: GitExplorer ) { - super(uri); + super(uri, parent); } get id(): string { @@ -40,10 +41,10 @@ export class TagNode extends ExplorerRefNode implements PageableExplorerNode { maxCount: this.maxCount || this.explorer.config.defaultItemLimit, ref: this.tag.name }); - if (log === undefined) return [new MessageNode('No commits yet')]; + if (log === undefined) return [new MessageNode(this, 'No commits yet')]; const children: (CommitNode | ShowMoreNode)[] = [ - ...Iterables.map(log.commits.values(), c => new CommitNode(c, this.explorer)) + ...Iterables.map(log.commits.values(), c => new CommitNode(c, this, this.explorer)) ]; if (log.truncated) { diff --git a/src/views/nodes/tagsNode.ts b/src/views/nodes/tagsNode.ts index 37da98c..2642709 100644 --- a/src/views/nodes/tagsNode.ts +++ b/src/views/nodes/tagsNode.ts @@ -13,10 +13,11 @@ import { TagNode } from './tagNode'; export class TagsNode extends ExplorerNode { constructor( uri: GitUri, - private readonly repo: Repository, - private readonly explorer: GitExplorer + public readonly repo: Repository, + parent: ExplorerNode, + public readonly explorer: GitExplorer ) { - super(uri); + super(uri, parent); } get id(): string { @@ -25,10 +26,10 @@ export class TagsNode extends ExplorerNode { async getChildren(): Promise { const tags = await this.repo.getTags(); - if (tags.length === 0) return [new MessageNode('No tags yet')]; + if (tags.length === 0) return [new MessageNode(this, 'No tags yet')]; tags.sort((a, b) => a.name.localeCompare(b.name)); - const tagNodes = [...tags.map(t => new TagNode(t, this.uri, this.explorer))]; + const tagNodes = [...tags.map(t => new TagNode(t, this.uri, this, this.explorer))]; if (this.explorer.config.branches.layout === ExplorerBranchesLayout.List) return tagNodes; const hierarchy = Arrays.makeHierarchical( @@ -38,7 +39,7 @@ export class TagsNode extends ExplorerNode { this.explorer.config.files.compact ); - const root = new BranchOrTagFolderNode('tag', this.repo.path, '', undefined, hierarchy, this.explorer); + const root = new BranchOrTagFolderNode('tag', this.repo.path, '', undefined, hierarchy, this, this.explorer); const children = (await root.getChildren()) as (BranchOrTagFolderNode | TagNode)[]; return children; } diff --git a/src/views/resultsExplorer.ts b/src/views/resultsExplorer.ts index 6271b56..711d9ad 100644 --- a/src/views/resultsExplorer.ts +++ b/src/views/resultsExplorer.ts @@ -180,7 +180,7 @@ export class ResultsExplorer extends ExplorerBase { }; return this.addResults( - new ResultsCommitsNode(results.repoPath, getCommitsQuery, this, ResourceType.SearchResults) + new ResultsCommitsNode(results.repoPath, getCommitsQuery, undefined, this, ResourceType.SearchResults) ); }