diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c0f77e..ee72913 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ### Added - Adds favoriting of repositories and branches in the _Repositories_ view to allow for better (user-customized) sorting +- Adds _Set as Default_ and _Unset as Default_ commands to remotes in the _Repositories_ view to specify the default remote selection when using the _Open \* in Remote_ commands — closes [#504](https://github.com/eamodio/vscode-gitlens/issues/504) - Adds the ability to turn on file annotations (blame, heatmap, and recent changes) via user-defined modes — closes [#542](https://github.com/eamodio/vscode-gitlens/issues/542) ## [9.2.4] - 2018-12-26 diff --git a/package.json b/package.json index 8ad9a5c..e8ab6ba 100644 --- a/package.json +++ b/package.json @@ -2248,6 +2248,16 @@ } }, { + "command": "gitlens.views.setAsDefault", + "title": "Set as Default", + "category": "GitLens" + }, + { + "command": "gitlens.views.unsetAsDefault", + "title": "Unset as Default", + "category": "GitLens" + }, + { "command": "gitlens.views.stageFile", "title": "Stage Changes", "category": "GitLens", @@ -3034,6 +3044,14 @@ "when": "false" }, { + "command": "gitlens.views.setAsDefault", + "when": "false" + }, + { + "command": "gitlens.views.unsetAsDefault", + "when": "false" + }, + { "command": "gitlens.views.stageFile", "when": "false" }, @@ -4163,32 +4181,42 @@ }, { "command": "gitlens.views.fetch", - "when": "!gitlens:readonly && viewItem == gitlens:remote", + "when": "!gitlens:readonly && viewItem =~ /gitlens:remote\\b/", "group": "inline@97" }, { "command": "gitlens.openRepoInRemote", - "when": "viewItem == gitlens:remote", + "when": "viewItem =~ /gitlens:remote\\b/", "group": "inline@98" }, { "command": "gitlens.openRepoInRemote", - "when": "viewItem == gitlens:remote", + "when": "viewItem =~ /gitlens:remote\\b/", "group": "1_gitlens@1" }, { "command": "gitlens.openBranchesInRemote", - "when": "viewItem == gitlens:remote", + "when": "viewItem =~ /gitlens:remote\\b/", "group": "1_gitlens@2" }, { "command": "gitlens.views.fetch", - "when": "!gitlens:readonly && viewItem == gitlens:remote", + "when": "!gitlens:readonly && viewItem =~ /gitlens:remote\\b/", "group": "2_gitlens@1" }, { + "command": "gitlens.views.setAsDefault", + "when": "viewItem =~ /gitlens:remote\\b(?!.*?\\+default\\b.*?)/", + "group": "3_gitlens@1" + }, + { + "command": "gitlens.views.unsetAsDefault", + "when": "viewItem =~ /gitlens:remote\\b.*?\\+default\\b.*?/", + "group": "3_gitlens@1" + }, + { "command": "gitlens.views.terminalRemoveRemote", - "when": "!gitlens:readonly && viewItem == gitlens:remote", + "when": "!gitlens:readonly && viewItem =~ /gitlens:remote\\b/", "group": "8_gitlens@1" }, { diff --git a/src/commands/openInRemote.ts b/src/commands/openInRemote.ts index a3d2bde..a692f6d 100644 --- a/src/commands/openInRemote.ts +++ b/src/commands/openInRemote.ts @@ -36,9 +36,17 @@ export class OpenInRemoteCommand extends ActiveEditorCommand { } try { - if (args.remotes.length === 1) { + let remote: GitRemote | undefined; + if (args.remotes.length > 1) { + remote = args.remotes.find(r => r.default); + } + else if (args.remotes.length === 1) { + remote = args.remotes[0]; + } + + if (remote != null) { this.ensureRemoteBranchName(args); - const command = new OpenRemoteCommandQuickPickItem(args.remotes[0], args.resource, args.clipboard); + const command = new OpenRemoteCommandQuickPickItem(remote, args.resource, args.clipboard); return await command.execute(); } diff --git a/src/constants.ts b/src/constants.ts index a9abf61..6dd4f05 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -137,6 +137,7 @@ export interface StarredRepositories { } export enum WorkspaceState { + DefaultRemote = 'gitlens:remote:default', StarredBranches = 'gitlens:starred:branches', StarredRepositories = 'gitlens:starred:repositories', ViewsCompareKeepResults = 'gitlens:views:compare:keepResults', diff --git a/src/git/models/remote.ts b/src/git/models/remote.ts index 92363c5..add94b0 100644 --- a/src/git/models/remote.ts +++ b/src/git/models/remote.ts @@ -1,4 +1,6 @@ 'use strict'; +import { WorkspaceState } from '../../constants'; +import { Container } from '../../container'; import { RemoteProvider } from '../remotes/factory'; export enum GitRemoteType { @@ -9,6 +11,7 @@ export enum GitRemoteType { export class GitRemote { constructor( public readonly repoPath: string, + public readonly id: string, public readonly name: string, public readonly scheme: string, public readonly domain: string, @@ -16,4 +19,13 @@ export class GitRemote { public readonly provider: RemoteProvider | undefined, public readonly types: { type: GitRemoteType; url: string }[] ) {} + + get default() { + const defaultRemote = Container.context.workspaceState.get(WorkspaceState.DefaultRemote); + return this.id === defaultRemote; + } + + setAsDefault(state: boolean = true) { + return Container.context.workspaceState.update(WorkspaceState.DefaultRemote, state ? this.id : undefined); + } } diff --git a/src/git/parsers/remoteParser.ts b/src/git/parsers/remoteParser.ts index 784a5dd..65a2ccf 100644 --- a/src/git/parsers/remoteParser.ts +++ b/src/git/parsers/remoteParser.ts @@ -70,6 +70,7 @@ export class GitRemoteParser { if (remote === undefined) { remote = new GitRemote( repoPath, + uniqueness, // Stops excessive memory usage -- https://bugs.chromium.org/p/v8/issues/detail?id=2869 (' ' + match[1]).substr(1), scheme, diff --git a/src/quickpicks/remotesQuickPick.ts b/src/quickpicks/remotesQuickPick.ts index ffecef9..4073819 100644 --- a/src/quickpicks/remotesQuickPick.ts +++ b/src/quickpicks/remotesQuickPick.ts @@ -100,8 +100,15 @@ export class OpenRemotesCommandQuickPickItem extends CommandQuickPickItem { break; } - const remote = remotes[0]; - if (remotes.length === 1) { + let remote: GitRemote | undefined; + if (remotes.length > 1) { + remote = remotes.find(r => r.default); + } + else if (remotes.length === 1) { + remote = remotes[0]; + } + + if (remote != null) { super( { label: `$(link-external) Open ${name} on ${remote.provider!.name}`, @@ -125,7 +132,9 @@ export class OpenRemotesCommandQuickPickItem extends CommandQuickPickItem { return; } - const provider = remotes.every(r => r.provider !== undefined && r.provider.name === remote.provider!.name) + remote = remotes[0]; + // Use the real provider name if there is only 1 provider + const provider = remotes.every(r => r.provider !== undefined && r.provider.name === remote!.provider!.name) ? remote.provider!.name : 'Remote'; diff --git a/src/views/nodes/remoteNode.ts b/src/views/nodes/remoteNode.ts index c866310..134ec28 100644 --- a/src/views/nodes/remoteNode.ts +++ b/src/views/nodes/remoteNode.ts @@ -84,14 +84,17 @@ export class RemoteNode extends ViewNode { separator = GlyphChars.Dash; } - const item = new TreeItem(this.remote.name, TreeItemCollapsibleState.Collapsed); + const item = new TreeItem( + `${this.remote.default ? `${GlyphChars.Check} ${GlyphChars.Space}` : ''}${this.remote.name}`, + TreeItemCollapsibleState.Collapsed + ); item.description = `${separator}${GlyphChars.Space} ${ this.remote.provider !== undefined ? this.remote.provider.name : this.remote.domain } ${GlyphChars.Space}${GlyphChars.Dot}${GlyphChars.Space} ${this.remote.path}`; item.contextValue = ResourceType.Remote; - item.id = this.id; - item.tooltip = `${this.remote.name} -${this.remote.path} (${this.remote.provider !== undefined ? this.remote.provider.name : this.remote.domain})`; + if (this.remote.default) { + item.contextValue += '+default'; + } if (this.remote.provider !== undefined) { item.iconPath = { @@ -106,6 +109,11 @@ ${this.remote.path} (${this.remote.provider !== undefined ? this.remote.provider }; } + item.id = this.id; + item.tooltip = `${this.remote.name}\n${this.remote.path} (${ + this.remote.provider !== undefined ? this.remote.provider.name : this.remote.domain + })`; + return item; } @@ -113,4 +121,10 @@ ${this.remote.path} (${this.remote.provider !== undefined ? this.remote.provider fetch(options: { progress?: boolean } = {}) { return this.repo.fetch({ ...options, remote: this.remote.name }); } + + @log() + async setAsDefault(state: boolean = true) { + void (await this.remote.setAsDefault(state)); + void this.parent!.triggerChange(); + } } diff --git a/src/views/viewCommands.ts b/src/views/viewCommands.ts index 435931f..55fe300 100644 --- a/src/views/viewCommands.ts +++ b/src/views/viewCommands.ts @@ -73,6 +73,9 @@ export class ViewCommands implements Disposable { commands.registerCommand('gitlens.views.pushWithForce', n => this.push(n, true), this); commands.registerCommand('gitlens.views.closeRepository', this.closeRepository, this); + commands.registerCommand('gitlens.views.setAsDefault', this.setAsDefault, this); + commands.registerCommand('gitlens.views.unsetAsDefault', this.unsetAsDefault, this); + commands.registerCommand('gitlens.views.star', this.star, this); commands.registerCommand('gitlens.views.unstar', this.unstar, this); @@ -451,6 +454,16 @@ export class ViewCommands implements Disposable { } as OpenFileInRemoteCommandArgs); } + private setAsDefault(node: RemoteNode) { + if (node instanceof RemoteNode) return node.setAsDefault(); + return; + } + + private unsetAsDefault(node: RemoteNode) { + if (node instanceof RemoteNode) return node.setAsDefault(false); + return; + } + private async stageFile(node: CommitFileNode | StatusFileNode) { if (!(node instanceof CommitFileNode) && !(node instanceof StatusFileNode)) return;