You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

167 lines
7.3 KiB

'use strict';
import { commands, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
import { Container } from '../container';
import { GitCommit, GitService, GitUri } from '../git/gitService';
import { Logger } from '../logger';
import { Messages } from '../messages';
import { Iterables } from '../system';
import { ActiveEditorCommand, CommandContext, Commands, getCommandUri } from './common';
import { DiffWithCommandArgs } from './diffWith';
import { DiffWithWorkingCommandArgs } from './diffWithWorking';
export interface DiffWithPreviousCommandArgs {
commit?: GitCommit;
inDiffEditor?: boolean;
line?: number;
showOptions?: TextDocumentShowOptions;
}
export class DiffWithPreviousCommand extends ActiveEditorCommand {
constructor() {
super([Commands.DiffWithPrevious, Commands.DiffWithPreviousInDiff]);
}
protected async preExecute(context: CommandContext, args: DiffWithPreviousCommandArgs = {}): Promise<any> {
if (context.command === Commands.DiffWithPreviousInDiff) {
args.inDiffEditor = true;
}
return this.execute(context.editor, context.uri, args);
}
async execute(editor?: TextEditor, uri?: Uri, args: DiffWithPreviousCommandArgs = {}): Promise<any> {
uri = getCommandUri(uri, editor);
if (uri == null) return undefined;
args = { ...args };
if (args.line === undefined) {
args.line = editor == null ? 0 : editor.selection.active.line;
}
if (args.commit === undefined || !args.commit.isFile) {
const gitUri = await GitUri.fromUri(uri);
try {
let sha = args.commit === undefined ? gitUri.sha : args.commit.sha;
if (sha === GitService.deletedOrMissingSha) return Messages.showCommitHasNoPreviousCommitWarningMessage();
// If we are a fake "staged" sha, remove it
let isStagedUncommitted = false;
if (GitService.isStagedUncommitted(sha!)) {
gitUri.sha = sha = undefined;
isStagedUncommitted = true;
}
// If we are in a diff editor, assume we are on the right side, and need to move back 2 revisions
if (args.inDiffEditor && sha !== undefined) {
sha = sha + '^';
}
args.commit = undefined;
let log = await Container.git.getLogForFile(gitUri.repoPath, gitUri.fsPath, {
maxCount: 2,
ref: sha,
renames: true
});
if (log !== undefined) {
args.commit = (sha && log.commits.get(sha)) || Iterables.first(log.commits.values());
}
else {
// Only kick out if we aren't looking for the previous sha -- since renames won't return a log above
if (sha === undefined || !sha.endsWith('^')) {
return Messages.showFileNotUnderSourceControlWarningMessage('Unable to open compare');
}
// Check for renames
log = await Container.git.getLogForFile(gitUri.repoPath, gitUri.fsPath, {
maxCount: 3,
ref: sha.substring(0, sha.length - 1),
renames: true
});
if (log === undefined) {
return Messages.showFileNotUnderSourceControlWarningMessage('Unable to open compare');
}
args.commit =
Iterables.next(Iterables.skip(log.commits.values(), 1)) ||
Iterables.first(log.commits.values());
}
// If the sha is missing (i.e. working tree), check the file status
// If file is uncommitted, then treat it as a DiffWithWorking
if (gitUri.sha === undefined) {
const status = await Container.git.getStatusForFile(gitUri.repoPath!, gitUri.fsPath);
if (status !== undefined) {
if (isStagedUncommitted) {
const diffArgs: DiffWithCommandArgs = {
repoPath: args.commit.repoPath,
lhs: {
sha: args.inDiffEditor
? args.commit.previousSha || GitService.deletedOrMissingSha
: args.commit.sha,
uri: args.inDiffEditor ? args.commit.previousUri : args.commit.uri
},
rhs: {
sha: args.inDiffEditor ? args.commit.sha : GitService.stagedUncommittedSha,
uri: args.commit.uri
},
line: args.line,
showOptions: args.showOptions
};
return commands.executeCommand(Commands.DiffWith, diffArgs);
}
// Check if the file is staged
if (status.indexStatus !== undefined) {
const diffArgs: DiffWithCommandArgs = {
repoPath: args.commit.repoPath,
lhs: {
sha: args.inDiffEditor ? args.commit.sha : GitService.stagedUncommittedSha,
uri: args.commit.uri
},
rhs: {
sha: args.inDiffEditor ? GitService.stagedUncommittedSha : '',
uri: args.commit.uri
},
line: args.line,
showOptions: args.showOptions
};
return commands.executeCommand(Commands.DiffWith, diffArgs);
}
if (!args.inDiffEditor) {
return commands.executeCommand(Commands.DiffWithWorking, uri, {
commit: args.commit,
showOptions: args.showOptions
} as DiffWithWorkingCommandArgs);
}
}
}
}
catch (ex) {
Logger.error(ex, 'DiffWithPreviousCommand', `getLogForFile(${gitUri.repoPath}, ${gitUri.fsPath})`);
return Messages.showGenericErrorMessage('Unable to open compare');
}
}
const diffArgs: DiffWithCommandArgs = {
repoPath: args.commit.repoPath,
lhs: {
sha: args.commit.previousSha !== undefined ? args.commit.previousSha : GitService.deletedOrMissingSha,
uri: args.commit.previousUri
},
rhs: {
sha: args.commit.sha,
uri: args.commit.uri
},
line: args.line,
showOptions: args.showOptions
};
return commands.executeCommand(Commands.DiffWith, diffArgs);
}
}