diff --git a/extensions/git/src/blame.ts b/extensions/git/src/blame.ts index 916d906a0a21a..5c65fbcf1fccd 100644 --- a/extensions/git/src/blame.ts +++ b/extensions/git/src/blame.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { DecorationOptions, l10n, Position, Range, TextEditor, TextEditorChange, TextEditorDecorationType, TextEditorChangeKind, ThemeColor, Uri, window, workspace, EventEmitter, ConfigurationChangeEvent, StatusBarItem, StatusBarAlignment, Command, MarkdownString, TextEditorDiffInformation } from 'vscode'; +import { DecorationOptions, l10n, Position, Range, TextEditor, TextEditorChange, TextEditorDecorationType, TextEditorChangeKind, ThemeColor, Uri, window, workspace, EventEmitter, ConfigurationChangeEvent, StatusBarItem, StatusBarAlignment, Command, MarkdownString } from 'vscode'; import { Model } from './model'; import { dispose, fromNow, IDisposable } from './util'; import { Repository } from './repository'; @@ -11,6 +11,7 @@ import { throttle } from './decorators'; import { BlameInformation } from './git'; import { fromGitUri, isGitUri } from './uri'; import { emojify, ensureEmojis } from './emoji'; +import { getWorkingTreeAndIndexDiffInformation, getWorkingTreeDiffInformation } from './staging'; function lineRangesContainLine(changes: readonly TextEditorChange[], lineNumber: number): boolean { return changes.some(c => c.modified.startLineNumber <= lineNumber && lineNumber < c.modified.endLineNumberExclusive); @@ -277,10 +278,6 @@ export class GitBlameController { return blameInformation; } - private _findDiffInformation(textEditor: TextEditor, ref: string): TextEditorDiffInformation | undefined { - return textEditor.diffInformation?.find(diff => diff.original && isGitUri(diff.original) && fromGitUri(diff.original).ref === ref); - } - @throttle private async _updateTextEditorBlameInformation(textEditor: TextEditor | undefined, showBlameInformationForPositionZero = false): Promise { if (!textEditor?.diffInformation || textEditor !== window.activeTextEditor) { @@ -319,7 +316,7 @@ export class GitBlameController { workingTreeAndIndexChanges = undefined; } else if (ref === '') { // Resource on the right-hand side of the diff editor when viewing a resource from the index. - const diffInformationWorkingTreeAndIndex = this._findDiffInformation(textEditor, 'HEAD'); + const diffInformationWorkingTreeAndIndex = getWorkingTreeAndIndexDiffInformation(textEditor); // Working tree + index diff information is present and it is stale if (diffInformationWorkingTreeAndIndex && diffInformationWorkingTreeAndIndex.isStale) { @@ -333,7 +330,7 @@ export class GitBlameController { } } else { // Working tree diff information. Diff Editor (Working Tree) -> Text Editor - const diffInformationWorkingTree = this._findDiffInformation(textEditor, '~') ?? this._findDiffInformation(textEditor, ''); + const diffInformationWorkingTree = getWorkingTreeDiffInformation(textEditor); // Working tree diff information is not present or it is stale if (!diffInformationWorkingTree || diffInformationWorkingTree.isStale) { @@ -341,7 +338,7 @@ export class GitBlameController { } // Working tree + index diff information - const diffInformationWorkingTreeAndIndex = this._findDiffInformation(textEditor, 'HEAD'); + const diffInformationWorkingTreeAndIndex = getWorkingTreeAndIndexDiffInformation(textEditor); // Working tree + index diff information is present and it is stale if (diffInformationWorkingTreeAndIndex && diffInformationWorkingTreeAndIndex.isStale) { diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 8a31393120157..dde1c99049a87 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -12,7 +12,7 @@ import { ForcePushMode, GitErrorCodes, Ref, RefType, Status, CommitOptions, Remo import { Git, Stash } from './git'; import { Model } from './model'; import { GitResourceGroup, Repository, Resource, ResourceGroupType } from './repository'; -import { DiffEditorSelectionHunkToolbarContext, applyLineChanges, getModifiedRange, intersectDiffWithRange, invertLineChange, toLineRanges } from './staging'; +import { DiffEditorSelectionHunkToolbarContext, applyLineChanges, getModifiedRange, getWorkingTreeAndIndexDiffInformation, getWorkingTreeDiffInformation, intersectDiffWithRange, invertLineChange, toLineChanges, toLineRanges } from './staging'; import { fromGitUri, toGitUri, isGitUri, toMergeUris, toMultiFileDiffEditorUris } from './uri'; import { dispose, grep, isDefined, isDescendant, pathEquals, relativePath, truncate } from './util'; import { GitTimelineItem } from './timelineProvider'; @@ -1565,6 +1565,12 @@ export class CommandCenter { this.logger.trace(`[CommandCenter][stageSelectedChanges] changes: ${JSON.stringify(changes)}`); + const workingTreeDiffInformation = getWorkingTreeDiffInformation(textEditor); + if (workingTreeDiffInformation) { + this.logger.trace(`[CommandCenter][stageSelectedChanges] diffInformation: ${JSON.stringify(workingTreeDiffInformation)}`); + this.logger.trace(`[CommandCenter][stageSelectedChanges] diffInformation changes: ${JSON.stringify(toLineChanges(workingTreeDiffInformation))}`); + } + const modifiedDocument = textEditor.document; const selectedLines = toLineRanges(textEditor.selections, modifiedDocument); const selectedChanges = changes @@ -1751,6 +1757,12 @@ export class CommandCenter { this.logger.trace(`[CommandCenter][revertSelectedRanges] changes: ${JSON.stringify(changes)}`); + const workingTreeDiffInformation = getWorkingTreeDiffInformation(textEditor); + if (workingTreeDiffInformation) { + this.logger.trace(`[CommandCenter][revertSelectedRanges] diffInformation: ${JSON.stringify(workingTreeDiffInformation)}`); + this.logger.trace(`[CommandCenter][revertSelectedRanges] diffInformation changes: ${JSON.stringify(toLineChanges(workingTreeDiffInformation))}`); + } + const modifiedDocument = textEditor.document; const selections = textEditor.selections; const selectedChanges = changes.filter(change => { @@ -1845,6 +1857,18 @@ export class CommandCenter { this.logger.trace(`[CommandCenter][unstageSelectedRanges] changes: ${JSON.stringify(changes)}`); + const workingTreeDiffInformation = getWorkingTreeDiffInformation(textEditor); + if (workingTreeDiffInformation) { + this.logger.trace(`[CommandCenter][unstageSelectedRanges] diffInformation (working tree): ${JSON.stringify(workingTreeDiffInformation)}`); + this.logger.trace(`[CommandCenter][unstageSelectedRanges] diffInformation changes (working tree): ${JSON.stringify(toLineChanges(workingTreeDiffInformation))}`); + } + + const workingTreeAndIndexDiffInformation = getWorkingTreeAndIndexDiffInformation(textEditor); + if (workingTreeAndIndexDiffInformation) { + this.logger.trace(`[CommandCenter][unstageSelectedRanges] diffInformation (working tree + index): ${JSON.stringify(workingTreeAndIndexDiffInformation)}`); + this.logger.trace(`[CommandCenter][unstageSelectedRanges] diffInformation changes (working tree + index): ${JSON.stringify(toLineChanges(workingTreeAndIndexDiffInformation))}`); + } + const originalUri = toGitUri(modifiedUri, 'HEAD'); const originalDocument = await workspace.openTextDocument(originalUri); const selectedLines = toLineRanges(textEditor.selections, modifiedDocument); diff --git a/extensions/git/src/staging.ts b/extensions/git/src/staging.ts index 2dcc6d54487a7..38a462aedf62f 100644 --- a/extensions/git/src/staging.ts +++ b/extensions/git/src/staging.ts @@ -3,7 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { TextDocument, Range, LineChange, Selection, Uri } from 'vscode'; +import { TextDocument, Range, LineChange, Selection, Uri, TextEditor, TextEditorDiffInformation } from 'vscode'; +import { fromGitUri, isGitUri } from './uri'; export function applyLineChanges(original: TextDocument, modified: TextDocument, diffs: LineChange[]): string { const result: string[] = []; @@ -143,6 +144,53 @@ export function invertLineChange(diff: LineChange): LineChange { }; } +export function toLineChanges(diffInformation: TextEditorDiffInformation): LineChange[] { + return diffInformation.changes.map(x => { + let originalStartLineNumber: number; + let originalEndLineNumber: number; + let modifiedStartLineNumber: number; + let modifiedEndLineNumber: number; + + if (x.original.startLineNumber === x.original.endLineNumberExclusive) { + // Insertion + originalStartLineNumber = x.original.startLineNumber - 1; + originalEndLineNumber = 0; + } else { + originalStartLineNumber = x.original.startLineNumber; + originalEndLineNumber = x.original.endLineNumberExclusive - 1; + } + + if (x.modified.startLineNumber === x.modified.endLineNumberExclusive) { + // Deletion + modifiedStartLineNumber = x.modified.startLineNumber - 1; + modifiedEndLineNumber = 0; + } else { + modifiedStartLineNumber = x.modified.startLineNumber; + modifiedEndLineNumber = x.modified.endLineNumberExclusive - 1; + } + + return { + originalStartLineNumber, + originalEndLineNumber, + modifiedStartLineNumber, + modifiedEndLineNumber + }; + }); +} + +export function getWorkingTreeDiffInformation(textEditor: TextEditor): TextEditorDiffInformation | undefined { + // Working tree diff information. Diff Editor (Working Tree) -> Text Editor + return getDiffInformation(textEditor, '~') ?? getDiffInformation(textEditor, ''); +} + +export function getWorkingTreeAndIndexDiffInformation(textEditor: TextEditor): TextEditorDiffInformation | undefined { + return getDiffInformation(textEditor, 'HEAD'); +} + +function getDiffInformation(textEditor: TextEditor, ref: string): TextEditorDiffInformation | undefined { + return textEditor.diffInformation?.find(diff => diff.original && isGitUri(diff.original) && fromGitUri(diff.original).ref === ref); +} + export interface DiffEditorSelectionHunkToolbarContext { mapping: unknown; /**