Skip to content

Commit

Permalink
Overhauls previous line diffing - closes #719
Browse files Browse the repository at this point in the history
Changes & Details hovers now know about staged vs unstaged changes
Significantly increased accuracy with the following:
  - Open Line Changes with Previous Revision
  - Open Changes with Previous Revision
  - Changes & Details hovers
  • Loading branch information
eamodio committed May 5, 2019
1 parent 26cbee6 commit 643e226
Show file tree
Hide file tree
Showing 11 changed files with 356 additions and 200 deletions.
168 changes: 114 additions & 54 deletions src/annotations/annotations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {
GitBlameCommit,
GitCommit,
GitDiffHunkLine,
GitLogCommit,
GitService,
GitUri
} from '../git/gitService';
import { Objects, Strings } from '../system';
Expand Down Expand Up @@ -62,74 +64,121 @@ export class Annotations {
commit: GitBlameCommit,
uri: GitUri,
editorLine: number
): Promise<MarkdownString | undefined>;
static async changesHoverMessage(
commit: GitLogCommit,
uri: GitUri,
editorLine: number,
hunkLine: GitDiffHunkLine
): Promise<MarkdownString | undefined>;
static async changesHoverMessage(
commit: GitBlameCommit | GitLogCommit,
uri: GitUri,
editorLine: number,
hunkLine?: GitDiffHunkLine
): Promise<MarkdownString | undefined> {
let ref;
if (commit.isUncommitted) {
if (uri.isUncommittedStaged) {
ref = uri.sha;
const documentRef = uri.sha;
if (commit instanceof GitBlameCommit) {
// TODO: Figure out how to optimize this
let ref;
if (commit.isUncommitted) {
if (GitService.isUncommittedStaged(documentRef)) {
ref = documentRef;
}
}
else {
ref = commit.sha;
}
}
else {
ref = commit.sha;
}

const line = editorLine + 1;
const commitLine = commit.lines.find(l => l.line === line) || commit.lines[0];
const line = editorLine + 1;
const commitLine = commit.lines.find(l => l.line === line) || commit.lines[0];

let originalFileName = commit.originalFileName;
if (originalFileName === undefined) {
if (uri.fsPath !== commit.uri.fsPath) {
originalFileName = commit.fileName;
let originalFileName = commit.originalFileName;
if (originalFileName === undefined) {
if (uri.fsPath !== commit.uri.fsPath) {
originalFileName = commit.fileName;
}
}
}

const commitEditorLine = commitLine.originalLine - 1;
const hunkLine = await Container.git.getDiffForLine(uri, commitEditorLine, ref, undefined, originalFileName);
return this.changesHoverDiffMessage(commit, uri, hunkLine, commitEditorLine);
}
editorLine = commitLine.originalLine - 1;
hunkLine = await Container.git.getDiffForLine(uri, editorLine, ref, undefined, originalFileName);

// If we didn't find a diff & ref is undefined (meaning uncommitted), check for a staged diff
if (hunkLine === undefined && ref === undefined) {
hunkLine = await Container.git.getDiffForLine(
uri,
editorLine,
undefined,
GitService.uncommittedStagedSha,
originalFileName
);
}
}

static changesHoverDiffMessage(
commit: GitCommit,
uri: GitUri,
hunkLine: GitDiffHunkLine | undefined,
editorLine?: number
): MarkdownString | undefined {
if (hunkLine === undefined || commit.previousSha === undefined) return undefined;

const diff = this.getDiffFromHunkLine(hunkLine);

let message: string;
let message;
let previous;
let current;
if (commit.isUncommitted) {
if (uri.isUncommittedStaged) {
message = `[\`Changes\`](${DiffWithCommand.getMarkdownCommandArgs(
commit,
editorLine
)} "Open Changes") &nbsp; ${GlyphChars.Dash} &nbsp; [\`${
commit.previousShortSha
}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(
commit.previousSha!
)} "Show Commit Details") ${GlyphChars.ArrowLeftRightLong} _${uri.shortSha}_\n${diff}`;
}
else {
message = `[\`Changes\`](${DiffWithCommand.getMarkdownCommandArgs(
commit,
editorLine
)} "Open Changes") &nbsp; ${GlyphChars.Dash} &nbsp; _uncommitted changes_\n${diff}`;
const diffUris = await commit.getPreviousLineDiffUris(uri, editorLine, documentRef);
if (diffUris === undefined || diffUris.previous === undefined) {
return undefined;
}

message = `[\`Changes\`](${DiffWithCommand.getMarkdownCommandArgs({
lhs: {
sha: diffUris.previous.sha || '',
uri: diffUris.previous.documentUri()
},
rhs: {
sha: diffUris.current.sha || '',
uri: diffUris.current.documentUri()
},
repoPath: commit.repoPath,
line: editorLine
})} "Open Changes")`;

previous =
diffUris.previous.sha === undefined || diffUris.previous.isUncommitted
? `_${GitService.shortenSha(diffUris.previous.sha, {
working: 'Working Tree'
})}_`
: `[\`${GitService.shortenSha(
diffUris.previous.sha || ''
)}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(
diffUris.previous.sha || ''
)} "Show Commit Details")`;

current =
diffUris.current.sha === undefined || diffUris.current.isUncommitted
? `_${GitService.shortenSha(diffUris.current.sha, {
working: 'Working Tree'
})}_`
: `[\`${GitService.shortenSha(
diffUris.current.sha || ''
)}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(
diffUris.current.sha || ''
)} "Show Commit Details")`;
}
else {
message = `[\`Changes\`](${DiffWithCommand.getMarkdownCommandArgs(
commit,
editorLine
)} "Open Changes") &nbsp; ${GlyphChars.Dash} &nbsp; [\`${
commit.previousShortSha
}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(commit.previousSha!)} "Show Commit Details") ${
GlyphChars.ArrowLeftRightLong
} [\`${commit.shortSha}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(
message = `[\`Changes\`](${DiffWithCommand.getMarkdownCommandArgs(commit, editorLine)} "Open Changes")`;

previous = `[\`${commit.previousShortSha}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(
commit.previousSha!
)} "Show Commit Details")`;

current = `[\`${commit.shortSha}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(
commit.sha
)} "Show Commit Details")\n${diff}`;
)} "Show Commit Details")`;
}

message += ` &nbsp; ${GlyphChars.Dash} &nbsp; ${previous} &nbsp;${
GlyphChars.ArrowLeftRightLong
}&nbsp; ${current}\n${diff}`;

const markdown = new MarkdownString(message);
markdown.isTrusted = true;
return markdown;
Expand All @@ -140,14 +189,15 @@ export class Annotations {
uri: GitUri,
editorLine: number,
dateFormat: string | null,
annotationType?: FileAnnotationType
annotationType: FileAnnotationType | undefined
): Promise<MarkdownString> {
if (dateFormat === null) {
dateFormat = 'MMMM Do, YYYY h:mma';
}

const [presence, remotes] = await Promise.all([
const [presence, previousLineDiffUris, remotes] = await Promise.all([
Container.vsls.getContactPresence(commit.email),
commit.isUncommitted ? commit.getPreviousLineDiffUris(uri, editorLine, uri.sha) : undefined,
Container.git.getRemotes(commit.repoPath)
]);

Expand All @@ -158,6 +208,7 @@ export class Annotations {
line: editorLine,
markdown: true,
presence: presence,
previousLineDiffUris: previousLineDiffUris,
remotes: remotes
})
);
Expand Down Expand Up @@ -274,13 +325,22 @@ export class Annotations {

static trailing(
commit: GitCommit,
// uri: GitUri,
// editorLine: number,
format: string,
dateFormat: string | null,
scrollable: boolean = true
): Partial<DecorationOptions> {
// TODO: Enable this once there is better caching
// let diffUris;
// if (commit.isUncommitted) {
// diffUris = await commit.getPreviousLineDiffUris(uri, editorLine, uri.sha);
// }

const message = CommitFormatter.fromTemplate(format, commit, {
truncateMessageAtNewLine: true,
dateFormat: dateFormat
dateFormat: dateFormat,
// previousLineDiffUris: diffUris,
truncateMessageAtNewLine: true
});

return {
Expand Down
3 changes: 3 additions & 0 deletions src/annotations/lineAnnotationController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,13 +185,16 @@ export class LineAnnotationController implements Disposable {

const decoration = Annotations.trailing(
state.commit,
// await GitUri.fromUri(editor.document.uri),
// l,
cfg.format,
cfg.dateFormat === null ? Container.config.defaultDateFormat : cfg.dateFormat,
cfg.scrollable
) as DecorationOptions;
decoration.range = editor.document.validateRange(
new Range(l, Number.MAX_SAFE_INTEGER, l, Number.MAX_SAFE_INTEGER)
);

decorations.push(decoration);
}

Expand Down
2 changes: 1 addition & 1 deletion src/annotations/recentChangesAnnotationProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export class RecentChangesAnnotationProvider extends AnnotationProviderBase {
}

if (cfg.hovers.annotations.changes) {
message = Annotations.changesHoverDiffMessage(commit, this._uri, hunkLine, count);
message = await Annotations.changesHoverMessage(commit, this._uri, count, hunkLine);
if (message === undefined) continue;
}
}
Expand Down
60 changes: 3 additions & 57 deletions src/commands/diffLineWithPrevious.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,66 +31,12 @@ export class DiffLineWithPreviousCommand extends ActiveEditorCommand {

const gitUri = args.commit !== undefined ? GitUri.fromCommit(args.commit) : await GitUri.fromUri(uri);

if (gitUri.sha === undefined || gitUri.isUncommitted) {
const blame =
editor && editor.document.isDirty
? await Container.git.getBlameForLineContents(gitUri, args.line, editor.document.getText())
: await Container.git.getBlameForLine(gitUri, args.line);
if (blame === undefined) {
return Messages.showFileNotUnderSourceControlWarningMessage('Unable to open compare');
}

// If the line is uncommitted, change the previous commit
if (blame.commit.isUncommitted) {
// Since there could be a change in the line number, update it
args.line = blame.line.originalLine - 1;

try {
const previous = await Container.git.getPreviousUri(
gitUri.repoPath!,
gitUri,
gitUri.sha,
0,
args.line
);

if (previous === undefined) {
return Messages.showCommitHasNoPreviousCommitWarningMessage();
}

const diffArgs: DiffWithCommandArgs = {
repoPath: gitUri.repoPath!,
lhs: {
sha: previous.sha || '',
uri: previous.documentUri()
},
rhs: {
sha: gitUri.sha || '',
uri: gitUri.documentUri()
},
line: args.line,
showOptions: args.showOptions
};
return commands.executeCommand(Commands.DiffWith, diffArgs);
}
catch (ex) {
Logger.error(
ex,
'DiffLineWithPreviousCommand',
`getPreviousUri(${gitUri.repoPath}, ${gitUri.fsPath}, ${gitUri.sha})`
);
return Messages.showGenericErrorMessage('Unable to open compare');
}
}
}

try {
const diffUris = await Container.git.getPreviousDiffUris(
const diffUris = await Container.git.getPreviousLineDiffUris(
gitUri.repoPath!,
gitUri,
gitUri.sha,
0,
args.line
args.line,
gitUri.sha
);

if (diffUris === undefined || diffUris.previous === undefined) {
Expand Down
2 changes: 1 addition & 1 deletion src/commands/externalDiff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export class ExternalDiffCommand extends Command {
args.files = [
{
uri: GitUri.fromFile(context.node.file, context.node.file.repoPath || context.node.repoPath),
staged: context.node.commit.isStagedUncommitted || context.node.file.indexStatus !== undefined,
staged: context.node.commit.isUncommittedStaged || context.node.file.indexStatus !== undefined,
ref1: ref1,
ref2: ref2
}
Expand Down

0 comments on commit 643e226

Please sign in to comment.