diff --git a/extensions/git/package.json b/extensions/git/package.json index 2c5def54ff3..2cfb5e83b27 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -98,6 +98,11 @@ "dark": "resources/icons/dark/unstage.svg" } }, + { + "command": "git.unstageSelectedRanges", + "title": "%command.unstageSelectedRanges%", + "category": "Git" + }, { "command": "git.clean", "title": "%command.clean%", diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index 00b08e7c617..c830eb7ff20 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -8,6 +8,7 @@ "command.stageSelectedRanges": "Stage Selected Ranges", "command.unstage": "Unstage", "command.unstageAll": "Unstage All", + "command.unstageSelectedRanges": "Unstage Selected Ranges", "command.clean": "Clean", "command.cleanAll": "Clean All", "command.commit": "Commit", diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 8137d344f0e..8209858a0fd 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -245,14 +245,12 @@ export class CommandCenter { const modifiedDocument = textEditor.document; const modifiedUri = modifiedDocument.uri; - const modifiedUriString = modifiedUri.toString(); - const resource = this.model.workingTreeGroup.resources.filter(r => r.uri.toString() === modifiedUriString)[0]; - const originalUri = this.getLeftResource(resource); - if (!originalUri) { + if (modifiedUri.scheme !== 'file') { return; } + const originalUri = modifiedUri.with({ scheme: 'git', query: '~' }); const originalDocument = await workspace.openTextDocument(originalUri); const diffs = await computeDiff(originalDocument, modifiedDocument); const selections = textEditor.selections; @@ -289,6 +287,48 @@ export class CommandCenter { return await this.model.revertFiles(); } + @command('git.unstageSelectedRanges') + async unstageSelectedRanges(): Promise { + const textEditor = window.activeTextEditor; + + if (!textEditor) { + return; + } + + const modifiedDocument = textEditor.document; + const modifiedUri = modifiedDocument.uri; + + if (modifiedUri.scheme !== 'git' || modifiedUri.query !== '') { + return; + } + + const originalUri = modifiedUri.with({ scheme: 'git', query: 'HEAD' }); + const originalDocument = await workspace.openTextDocument(originalUri); + const diffs = await computeDiff(originalDocument, modifiedDocument); + const selections = textEditor.selections; + const selectedDiffs = diffs.filter(diff => { + const modifiedRange = diff.modifiedEndLineNumber === 0 + ? new Range(diff.modifiedStartLineNumber - 1, 0, diff.modifiedStartLineNumber - 1, 0) + : new Range(modifiedDocument.lineAt(diff.modifiedStartLineNumber - 1).range.start, modifiedDocument.lineAt(diff.modifiedEndLineNumber - 1).range.end); + + return selections.some(selection => !!selection.intersection(modifiedRange)); + }); + + if (!selectedDiffs.length) { + return; + } + + const invertedDiffs = selectedDiffs.map(c => ({ + modifiedStartLineNumber: c.originalStartLineNumber, + modifiedEndLineNumber: c.originalEndLineNumber, + originalStartLineNumber: c.modifiedStartLineNumber, + originalEndLineNumber: c.modifiedEndLineNumber + })); + + const result = staging.applyChanges(modifiedDocument, originalDocument, invertedDiffs); + await this.model.stage(modifiedUri, result); + } + @command('git.clean') async clean(uri: Uri): Promise { const resource = resolveGitResource(uri);