From cc97d374da411fe34d23c4eb0ac300360648b139 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 22 Mar 2017 10:50:23 +0100 Subject: [PATCH] :sparkles: multi-select (un)stage & discard git commands --- extensions/git/src/commands.ts | 39 ++++++++++++------- extensions/git/src/util.ts | 15 +++++++ .../parts/scm/electron-browser/scmViewlet.ts | 8 ++++ 3 files changed, 47 insertions(+), 15 deletions(-) diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index ad4a995d531..3cdf9461078 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -11,6 +11,7 @@ import { Model, Resource, Status, CommitOptions } from './model'; import * as staging from './staging'; import * as path from 'path'; import * as os from 'os'; +import { uniqueFilter } from './util'; import TelemetryReporter from 'vscode-extension-telemetry'; import * as nls from 'vscode-nls'; @@ -272,14 +273,14 @@ export class CommandCenter { } @command('git.stage') - async stage(uri?: Uri): Promise { - const resource = this.resolveSCMResource(uri); + async stage(...uris: Uri[]): Promise { + const resources = this.toSCMResources(uris); - if (!resource) { + if (!resources.length) { return; } - return await this.model.add(resource); + return await this.model.add(...resources); } @command('git.stageAll') @@ -369,14 +370,14 @@ export class CommandCenter { } @command('git.unstage') - async unstage(uri?: Uri): Promise { - const resource = this.resolveSCMResource(uri); + async unstage(...uris: Uri[]): Promise { + const resources = this.toSCMResources(uris); - if (!resource) { + if (!resources.length) { return; } - return await this.model.revertFiles(resource); + return await this.model.revertFiles(...resources); } @command('git.unstageAll') @@ -427,15 +428,17 @@ export class CommandCenter { } @command('git.clean') - async clean(uri?: Uri): Promise { - const resource = this.resolveSCMResource(uri); + async clean(...uris: Uri[]): Promise { + const resources = this.toSCMResources(uris); - if (!resource) { + if (!resources.length) { return; } - const basename = path.basename(resource.uri.fsPath); - const message = localize('confirm discard', "Are you sure you want to discard changes in {0}?", basename); + const message = resources.length === 1 + ? localize('confirm discard', "Are you sure you want to discard changes in {0}?", path.basename(resources[0].uri.fsPath)) + : localize('confirm discard multiple', "Are you sure you want to discard changes in {0} files?", resources.length); + const yes = localize('discard', "Discard Changes"); const pick = await window.showWarningMessage(message, { modal: true }, yes); @@ -443,7 +446,7 @@ export class CommandCenter { return; } - await this.model.clean(resource); + await this.model.clean(...resources); } @command('git.cleanAll') @@ -773,7 +776,7 @@ export class CommandCenter { uri = uri || window.activeTextEditor && window.activeTextEditor.document.uri; if (!uri) { - return; + return undefined; } if (uri.scheme === 'scm' && uri.authority === 'git') { @@ -793,6 +796,12 @@ export class CommandCenter { } } + private toSCMResources(uris: Uri[]): Resource[] { + return uris.filter(uniqueFilter(uri => uri.toString())) + .map(uri => this.resolveSCMResource(uri)) + .filter(r => !!r) as Resource[]; + } + dispose(): void { this.disposables.forEach(d => d.dispose()); } diff --git a/extensions/git/src/util.ts b/extensions/git/src/util.ts index 95d89cd16de..29888e54890 100644 --- a/extensions/git/src/util.ts +++ b/extensions/git/src/util.ts @@ -147,4 +147,19 @@ export async function mkdirp(path: string, mode?: number): Promise { } return true; +} + +export function uniqueFilter(keyFn: (t: T) => string): (t: T) => boolean { + const seen: { [key: string]: boolean; } = Object.create(null); + + return element => { + const key = keyFn(element); + + if (seen[key]) { + return false; + } + + seen[key] = true; + return true; + }; } \ No newline at end of file diff --git a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts index 9ae85ecb644..c840b5e75ff 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts @@ -105,6 +105,14 @@ class MultipleSelectionActionRunner extends ActionRunner { super(); } + /** + * Calls the action.run method with the current selection. Note + * that these actions already have the current scm resource context + * within, so we don't want to pass in the selection if there is only + * one selected element. The user should be able to select a single + * item and run an action on another element and only the latter should + * be influenced. + */ runAction(action: IAction, context?: any): TPromise { if (action instanceof MenuItemAction) { const selection = this.getSelectedResources(); -- GitLab