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.
 

141 lines
4.3 KiB

import type { TextDocumentShowOptions, TextEditor, Uri } from 'vscode';
import { Commands } from '../constants';
import type { Container } from '../container';
import { GitUri } from '../git/gitUri';
import type { GitCommit } from '../git/models/commit';
import { GitRevision } from '../git/models/reference';
import { Logger } from '../logger';
import { showCommitHasNoPreviousCommitWarningMessage, showGenericErrorMessage } from '../messages';
import { command, executeCommand } from '../system/command';
import { findOrOpenEditor } from '../system/utils';
import type { CommandContext } from './base';
import { ActiveEditorCommand, getCommandUri } from './base';
import type { DiffWithCommandArgs } from './diffWith';
export interface DiffWithPreviousCommandArgs {
commit?: GitCommit;
inDiffRightEditor?: boolean;
uri?: Uri;
line?: number;
showOptions?: TextDocumentShowOptions;
}
@command()
export class DiffWithPreviousCommand extends ActiveEditorCommand {
constructor(private readonly container: Container) {
super([Commands.DiffWithPrevious, Commands.DiffWithPreviousInDiffLeft, Commands.DiffWithPreviousInDiffRight]);
}
protected override preExecute(context: CommandContext, args?: DiffWithPreviousCommandArgs) {
if (context.command === Commands.DiffWithPreviousInDiffRight) {
args = { ...args, inDiffRightEditor: true };
}
return this.execute(context.editor, context.uri, args);
}
async execute(editor?: TextEditor, uri?: Uri, args?: DiffWithPreviousCommandArgs) {
args = { ...args };
if (args.uri == null) {
uri = getCommandUri(uri, editor);
if (uri == null) return;
} else {
uri = args.uri;
}
if (args.line == null) {
args.line = editor?.selection.active.line ?? 0;
}
let gitUri;
if (args.commit?.file != null) {
if (!args.commit.isUncommitted) {
void (await executeCommand<DiffWithCommandArgs>(Commands.DiffWith, {
repoPath: args.commit.repoPath,
lhs: {
sha: `${args.commit.sha}^`,
uri: args.commit.file.originalUri ?? args.commit.file.uri,
},
rhs: {
// If the file is `?` (untracked), then this must be a stash, so get the ^3 commit to access the untracked file
sha: args.commit.file.status === '?' ? `${args.commit.sha}^3` : args.commit.sha || '',
uri: args.commit.file.uri,
},
line: args.line,
showOptions: args.showOptions,
}));
return;
}
gitUri = args.commit?.getGitUri();
} else {
gitUri = await GitUri.fromUri(uri);
}
// If we are in the right diff editor, we can't really trust the line number
// if (args.inDiffRightEditor && args.line !== 0) {
// // TODO@eamodio figure out how to tell where the line moved in the previous commit (if at all)
// }
try {
const diffUris = await this.container.git.getPreviousComparisonUris(
gitUri.repoPath!,
gitUri,
gitUri.sha,
// If we are in the right-side of the diff editor, we need to skip back 1 more revision
args.inDiffRightEditor ? 1 : 0,
);
if (diffUris == null || diffUris.previous == null) {
if (diffUris == null) {
void showCommitHasNoPreviousCommitWarningMessage();
return;
}
// If we have no previous and the current is the working file, just open the working file
if (diffUris.current.sha == null) {
void (await findOrOpenEditor(diffUris.current, args.showOptions));
return;
}
if (!diffUris.current.isUncommittedStaged) {
void showCommitHasNoPreviousCommitWarningMessage();
return;
}
// If we have no previous and the current is staged, then diff staged with missing
diffUris.previous = GitUri.fromFile(
diffUris.current.fileName,
diffUris.current.repoPath!,
GitRevision.deletedOrMissing,
);
}
void (await executeCommand<DiffWithCommandArgs>(Commands.DiffWith, {
repoPath: diffUris.current.repoPath,
lhs: {
sha: diffUris.previous.sha ?? '',
uri: diffUris.previous.documentUri(),
},
rhs: {
sha: diffUris.current.sha ?? '',
uri: diffUris.current.documentUri(),
},
line: args.line,
showOptions: args.showOptions,
}));
} catch (ex) {
Logger.error(
ex,
'DiffWithPreviousCommand',
`getPreviousDiffUris(${gitUri.repoPath}, ${gitUri.fsPath}, ${gitUri.sha})`,
);
void showGenericErrorMessage('Unable to open compare');
}
}
}