diff --git a/CHANGELOG.md b/CHANGELOG.md index cccf63c..5e63b89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [Unreleased] +- Adds a new `Active Repository` node to `Repository View` of the `GitLens` view -- closes [#224](https://github.com/eamodio/vscode-gitlens/issues/224) + - Automatically updates to track the repository of the active editor + - Only visible if there is more than 1 repository within the workspace + ## [6.4.0] - 2017-12-12 ### Added - Adds `gitlens.keymap` setting to specify the keymap to use for GitLens shortcut keys -- closes [#104](https://github.com/eamodio/vscode-gitlens/issues/104) diff --git a/src/views/activeRepositoryNode.ts b/src/views/activeRepositoryNode.ts new file mode 100644 index 0000000..bc793b5 --- /dev/null +++ b/src/views/activeRepositoryNode.ts @@ -0,0 +1,89 @@ +'use strict'; +import { Functions } from '../system'; +import { TextEditor, TreeItem, TreeItemCollapsibleState, window } from 'vscode'; +import { ExplorerNode } from './explorerNode'; +import { GitExplorer } from './gitExplorer'; +import { GitUri } from '../gitService'; +import { RepositoryNode } from './repositoryNode'; + +export class ActiveRepositoryNode extends ExplorerNode { + + private _repositoryNode: RepositoryNode | undefined; + + constructor( + private readonly explorer: GitExplorer + ) { + super(undefined!); + + explorer.context.subscriptions.push( + window.onDidChangeActiveTextEditor(Functions.debounce(this.onActiveEditorChanged, 500), this) + ); + + this.onActiveEditorChanged(window.activeTextEditor); + } + + dispose() { + super.dispose(); + + if (this._repositoryNode !== undefined) { + this._repositoryNode.dispose(); + this._repositoryNode = undefined; + } + } + + private async onActiveEditorChanged(editor: TextEditor | undefined) { + let changed = false; + + try { + const repoPath = await this.explorer.git.getActiveRepoPath(editor); + if (repoPath === undefined) { + if (this._repositoryNode !== undefined) { + changed = true; + + this._repositoryNode.dispose(); + this._repositoryNode = undefined; + } + + return; + } + + if (this._repositoryNode !== undefined && this._repositoryNode.repo.path === repoPath) return; + + const repo = await this.explorer.git.getRepository(repoPath); + if (repo === undefined) { + if (this._repositoryNode !== undefined) { + changed = true; + + this._repositoryNode.dispose(); + this._repositoryNode = undefined; + } + + return; + } + + changed = true; + if (this._repositoryNode !== undefined) { + this._repositoryNode.dispose(); + } + + this._repositoryNode = new RepositoryNode(GitUri.fromRepoPath(repo.path), repo, this.explorer, true); + } + finally { + if (changed) { + this.explorer.refreshNode(this); + } + } + } + + async getChildren(): Promise { + return this._repositoryNode !== undefined + ? this._repositoryNode.getChildren() + : []; + } + + getTreeItem(): TreeItem { + return this._repositoryNode !== undefined + ? this._repositoryNode.getTreeItem() + : new TreeItem('No active repository', TreeItemCollapsibleState.None); + } +} diff --git a/src/views/branchesNode.ts b/src/views/branchesNode.ts index f2ab9d2..783a7cc 100644 --- a/src/views/branchesNode.ts +++ b/src/views/branchesNode.ts @@ -11,7 +11,8 @@ export class BranchesNode extends ExplorerNode { constructor( uri: GitUri, private readonly repo: Repository, - private readonly explorer: GitExplorer + private readonly explorer: GitExplorer, + private readonly active: boolean = false ) { super(uri); } @@ -25,7 +26,8 @@ export class BranchesNode extends ExplorerNode { } async getTreeItem(): Promise { - const item = new TreeItem(`Branches`, TreeItemCollapsibleState.Expanded); + // HACK: Until https://github.com/Microsoft/vscode/issues/30918 is fixed + const item = new TreeItem(`Branches`, this.active ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.Collapsed); const remotes = await this.repo.getRemotes(); item.contextValue = (remotes !== undefined && remotes.length > 0) diff --git a/src/views/explorerNodes.ts b/src/views/explorerNodes.ts index 1b3ddd9..3448e20 100644 --- a/src/views/explorerNodes.ts +++ b/src/views/explorerNodes.ts @@ -1,6 +1,7 @@ 'use strict'; export * from './explorerNode'; +export * from './activeRepositoryNode'; export * from './branchesNode'; export * from './branchHistoryNode'; export * from './commitFileNode'; diff --git a/src/views/gitExplorer.ts b/src/views/gitExplorer.ts index 9f6dc0d..dcc739f 100644 --- a/src/views/gitExplorer.ts +++ b/src/views/gitExplorer.ts @@ -176,7 +176,7 @@ export class GitExplorer implements TreeDataProvider { if (repositories.length === 1) { const repo = repositories[0]; - return new RepositoryNode(GitUri.fromRepoPath(repo.path), repo, this); + return new RepositoryNode(GitUri.fromRepoPath(repo.path), repo, this, true); } return new RepositoriesNode(repositories, this); diff --git a/src/views/repositoriesNode.ts b/src/views/repositoriesNode.ts index 3566351..c27a9fa 100644 --- a/src/views/repositoriesNode.ts +++ b/src/views/repositoriesNode.ts @@ -1,5 +1,6 @@ 'use strict'; import { TreeItem, TreeItemCollapsibleState } from 'vscode'; +import { ActiveRepositoryNode } from './activeRepositoryNode'; import { ExplorerNode, ResourceType } from './explorerNode'; import { GitExplorer } from './gitExplorer'; import { GitUri, Repository } from '../gitService'; @@ -20,6 +21,11 @@ export class RepositoriesNode extends ExplorerNode { this.children = this.repositories .sort((a, b) => a.index - b.index) .map(repo => new RepositoryNode(GitUri.fromRepoPath(repo.path), repo, this.explorer)); + + if (this.children.length > 1) { + this.children.splice(0, 0, new ActiveRepositoryNode(this.explorer)); + } + return this.children; } diff --git a/src/views/repositoryNode.ts b/src/views/repositoryNode.ts index 5203132..a340763 100644 --- a/src/views/repositoryNode.ts +++ b/src/views/repositoryNode.ts @@ -15,8 +15,9 @@ export class RepositoryNode extends ExplorerNode { constructor( uri: GitUri, - private readonly repo: Repository, - private readonly explorer: GitExplorer + readonly repo: Repository, + private readonly explorer: GitExplorer, + private readonly active: boolean = false ) { super(uri); } @@ -26,8 +27,8 @@ export class RepositoryNode extends ExplorerNode { this.updateSubscription(); this.children = [ - new StatusNode(this.uri, this.repo, this, this.explorer), - new BranchesNode(this.uri, this.repo, this.explorer), + new StatusNode(this.uri, this.repo, this, this.explorer, this.active), + new BranchesNode(this.uri, this.repo, this.explorer, this.active), new RemotesNode(this.uri, this.repo, this.explorer), new StashesNode(this.uri, this.repo, this.explorer) ]; @@ -37,7 +38,11 @@ export class RepositoryNode extends ExplorerNode { getTreeItem(): TreeItem { this.updateSubscription(); - const item = new TreeItem(`Repository ${Strings.pad(GlyphChars.Dash, 1, 1)} ${this.repo.formattedName || this.uri.repoPath}`, TreeItemCollapsibleState.Expanded); + const label = this.active + ? `Active Repository ${Strings.pad(GlyphChars.Dash, 1, 1)} ${this.repo.formattedName || this.uri.repoPath}` + : `${this.repo.formattedName || this.uri.repoPath}`; + + const item = new TreeItem(label, this.active ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.Collapsed); item.contextValue = ResourceType.Repository; return item; } diff --git a/src/views/statusNode.ts b/src/views/statusNode.ts index 18e8393..9d7760b 100644 --- a/src/views/statusNode.ts +++ b/src/views/statusNode.ts @@ -12,7 +12,8 @@ export class StatusNode extends ExplorerNode { uri: GitUri, private readonly repo: Repository, private readonly parent: ExplorerNode, - private readonly explorer: GitExplorer + private readonly explorer: GitExplorer, + private readonly active: boolean = false ) { super(uri); } @@ -93,7 +94,16 @@ export class StatusNode extends ExplorerNode { label = `${status.branch} ${hasWorkingChanges ? 'has uncommitted changes' : this.includeWorkingTree ? 'has no changes' : 'has nothing to commit'}`; } - const item = new TreeItem(label, (hasChildren || hasWorkingChanges) ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.None); + let state: TreeItemCollapsibleState; + if (hasChildren || hasWorkingChanges) { + // HACK: Until https://github.com/Microsoft/vscode/issues/30918 is fixed + state = this.active ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.Collapsed; + } + else { + state = TreeItemCollapsibleState.None; + } + + const item = new TreeItem(label, state); item.contextValue = ResourceType.Status; item.iconPath = {