|
|
- 'use strict';
- import { commands, SourceControlResourceState, Uri, window } from 'vscode';
- import { BuiltInCommands, GlyphChars } from '../constants';
- import { Container } from '../container';
- import { GitService, GitUri } from '../git/gitService';
- import { Logger } from '../logger';
- import { Messages } from '../messages';
- import { Arrays } from '../system';
- import {
- Command,
- CommandContext,
- Commands,
- getRepoPathOrPrompt,
- isCommandViewContextWithFileCommit,
- isCommandViewContextWithFileRefs
- } from './common';
-
- enum Status {
- INDEX_MODIFIED,
- INDEX_ADDED,
- INDEX_DELETED,
- INDEX_RENAMED,
- INDEX_COPIED,
-
- MODIFIED,
- DELETED,
- UNTRACKED,
- IGNORED,
-
- ADDED_BY_US,
- ADDED_BY_THEM,
- DELETED_BY_US,
- DELETED_BY_THEM,
- BOTH_ADDED,
- BOTH_DELETED,
- BOTH_MODIFIED
- }
-
- enum ResourceGroupType {
- Merge,
- Index,
- WorkingTree
- }
-
- interface Resource extends SourceControlResourceState {
- readonly resourceGroupType: ResourceGroupType;
- readonly type: Status;
- }
-
- class ExternalDiffFile {
- constructor(
- public readonly uri: Uri,
- public readonly staged: boolean,
- public readonly ref1?: string,
- public readonly ref2?: string
- ) {}
- }
-
- export interface ExternalDiffCommandArgs {
- files?: ExternalDiffFile[];
- }
-
- export class ExternalDiffCommand extends Command {
- constructor() {
- super([Commands.ExternalDiff, Commands.ExternalDiffAll]);
- }
-
- protected async preExecute(context: CommandContext, args: ExternalDiffCommandArgs = {}): Promise<any> {
- if (isCommandViewContextWithFileCommit(context)) {
- args = { ...args };
-
- const ref1 = GitService.isUncommitted(context.node.commit.previousFileSha)
- ? ''
- : context.node.commit.previousFileSha;
- const ref2 = context.node.commit.isUncommitted ? '' : context.node.commit.sha;
-
- args.files = [
- new ExternalDiffFile(
- GitUri.fromFile(context.node.file, context.node.file.repoPath || context.node.repoPath),
- context.node.commit.isStagedUncommitted || context.node.file.indexStatus !== undefined,
- ref1,
- ref2
- )
- ];
-
- return this.execute(args);
- }
-
- if (isCommandViewContextWithFileRefs(context)) {
- args = { ...args };
-
- args.files = [
- new ExternalDiffFile(
- GitUri.fromFile(context.node.file, context.node.file.repoPath || context.node.repoPath),
- context.node.file.indexStatus !== undefined,
- context.node.ref1,
- context.node.ref2
- )
- ];
-
- return this.execute(args);
- }
-
- if (args.files === undefined) {
- if (context.type === 'scm-states') {
- args = { ...args };
- args.files = context.scmResourceStates.map(
- r =>
- new ExternalDiffFile(
- r.resourceUri,
- (r as Resource).resourceGroupType === ResourceGroupType.Index
- )
- );
- }
- else if (context.type === 'scm-groups') {
- args = { ...args };
- args.files = Arrays.filterMap(
- context.scmResourceGroups[0].resourceStates,
- r =>
- this.isModified(r)
- ? new ExternalDiffFile(
- r.resourceUri,
- (r as Resource).resourceGroupType === ResourceGroupType.Index
- )
- : undefined
- );
- }
- }
-
- if (context.command === Commands.ExternalDiffAll) {
- if (args.files === undefined) {
- const repoPath = await getRepoPathOrPrompt(
- undefined,
- `Open changes from which repository${GlyphChars.Ellipsis}`
- );
- if (!repoPath) return undefined;
-
- const status = await Container.git.getStatusForRepo(repoPath);
- if (status === undefined) {
- return window.showInformationMessage("The repository doesn't have any changes");
- }
-
- args.files = [];
-
- for (const file of status.files) {
- if (file.indexStatus === 'M') {
- args.files.push(new ExternalDiffFile(file.uri, true));
- }
-
- if (file.workingTreeStatus === 'M') {
- args.files.push(new ExternalDiffFile(file.uri, false));
- }
- }
- }
- }
-
- return this.execute(args);
- }
-
- private isModified(resource: SourceControlResourceState) {
- const status = (resource as Resource).type;
- return status === Status.BOTH_MODIFIED || status === Status.INDEX_MODIFIED || status === Status.MODIFIED;
- }
-
- async execute(args: ExternalDiffCommandArgs = {}) {
- try {
- let repoPath;
- if (args.files === undefined) {
- const editor = window.activeTextEditor;
- if (editor === undefined) return undefined;
-
- repoPath = await Container.git.getRepoPathOrActive(undefined, editor);
- if (!repoPath) return undefined;
-
- const uri = editor.document.uri;
- const status = await Container.git.getStatusForFile(repoPath, uri.fsPath);
- if (status === undefined) {
- return window.showInformationMessage("The current file doesn't have any changes");
- }
-
- args.files = [];
- if (status.indexStatus === 'M') {
- args.files.push(new ExternalDiffFile(status.uri, true));
- }
-
- if (status.workingTreeStatus === 'M') {
- args.files.push(new ExternalDiffFile(status.uri, false));
- }
- }
- else {
- repoPath = await Container.git.getRepoPath(args.files[0].uri.fsPath);
- if (!repoPath) return undefined;
- }
-
- const tool = await Container.git.getDiffTool(repoPath);
- if (tool === undefined) {
- const result = await window.showWarningMessage(
- `Unable to open changes in diff tool. No Git diff tool is configured`,
- 'View Git Docs'
- );
- if (!result) return undefined;
-
- return commands.executeCommand(
- BuiltInCommands.Open,
- Uri.parse('https://git-scm.com/docs/git-config#git-config-difftool')
- );
- }
-
- for (const file of args.files) {
- void Container.git.openDiffTool(repoPath, file.uri, {
- ref1: file.ref1,
- ref2: file.ref2,
- staged: file.staged,
- tool: tool
- });
- }
-
- return undefined;
- }
- catch (ex) {
- Logger.error(ex, 'ExternalDiffCommand');
- return Messages.showGenericErrorMessage('Unable to open changes in diff tool');
- }
- }
- }
|