浏览代码

Add "external diff" command to SCM groups and files

main
Chris Kaczor 7 年前
committed by Eric Amodio
父节点
当前提交
61e3708233
共有 9 个文件被更改,包括 165 次插入7 次删除
  1. +18
    -3
      package.json
  2. +1
    -0
      src/commands.ts
  3. +2
    -0
      src/commands/common.ts
  4. +115
    -0
      src/commands/externalDiff.ts
  5. +2
    -0
      src/extension.ts
  6. +11
    -0
      src/git/git.ts
  7. +3
    -1
      src/git/models/status.ts
  8. +7
    -3
      src/git/parsers/statusParser.ts
  9. +6
    -0
      src/gitService.ts

+ 18
- 3
package.json 查看文件

@ -1069,6 +1069,11 @@
}
},
{
"command": "gitlens.externalDiff",
"title": "Open Changes (with difftool)",
"category": "GitLens"
},
{
"command": "gitlens.resetSuppressedWarnings",
"title": "Reset Suppressed Warnings",
"category": "GitLens"
@ -1520,17 +1525,22 @@
{
"command": "gitlens.openChangedFiles",
"when": "gitlens:enabled",
"group": "1_gitlens@1"
"group": "2_gitlens@1"
},
{
"command": "gitlens.closeUnchangedFiles",
"when": "gitlens:enabled",
"group": "1_gitlens@2"
"group": "2_gitlens@2"
},
{
"command": "gitlens.externalDiff",
"when": "gitlens:enabled",
"group": "2_gitlens@3"
},
{
"command": "gitlens.stashSave",
"when": "gitlens:enabled",
"group": "2_gitlens@1"
"group": "3_gitlens@1"
}
],
"scm/resourceState/context": [
@ -1540,6 +1550,11 @@
"group": "navigation"
},
{
"command": "gitlens.externalDiff",
"when": "gitlens:enabled",
"group": "navigation"
},
{
"command": "gitlens.diffWithRevision",
"when": "gitlens:enabled",
"group": "1_gitlens@1"

+ 1
- 0
src/commands.ts 查看文件

@ -14,6 +14,7 @@ export * from './commands/diffWithNext';
export * from './commands/diffWithPrevious';
export * from './commands/diffWithRevision';
export * from './commands/diffWithWorking';
export * from './commands/externalDiff';
export * from './commands/openChangedFiles';
export * from './commands/openBranchesInRemote';
export * from './commands/openBranchInRemote';

+ 2
- 0
src/commands/common.ts 查看文件

@ -19,6 +19,7 @@ export type Commands =
'gitlens.diffWithRevision' |
'gitlens.diffWithWorking' |
'gitlens.diffLineWithWorking' |
'gitlens.externalDiff' |
'gitlens.openChangedFiles' |
'gitlens.openBranchesInRemote' |
'gitlens.openBranchInRemote' |
@ -61,6 +62,7 @@ export const Commands = {
DiffWithRevision: 'gitlens.diffWithRevision' as Commands,
DiffWithWorking: 'gitlens.diffWithWorking' as Commands,
DiffLineWithWorking: 'gitlens.diffLineWithWorking' as Commands,
ExternalDiff: 'gitlens.externalDiff' as Commands,
OpenChangedFiles: 'gitlens.openChangedFiles' as Commands,
OpenBranchesInRemote: 'gitlens.openBranchesInRemote' as Commands,
OpenBranchInRemote: 'gitlens.openBranchInRemote' as Commands,

+ 115
- 0
src/commands/externalDiff.ts 查看文件

@ -0,0 +1,115 @@
'use strict';
import { commands, SourceControlResourceState, Uri, window } from 'vscode';
import { Command, Commands } from './common';
import { BuiltInCommands } from '../constants';
import { CommandContext } from '../commands';
import { GitService } from '../gitService';
import { Logger } from '../logger';
import { Messages } from '../messages';
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 uri: Uri, public staged: boolean) {
}
}
export interface ExternalDiffCommandArgs {
files?: ExternalDiffFile[];
}
export class ExternalDiffCommand extends Command {
constructor(private git: GitService) {
super(Commands.ExternalDiff);
}
protected async preExecute(context: CommandContext, args: ExternalDiffCommandArgs = {}): Promise<any> {
if (context.type === 'scm-states') {
args = { ...args };
args.files = context.scmResourceStates.map<ExternalDiffFile>((_: Resource) => new ExternalDiffFile(_.resourceUri, _.resourceGroupType === ResourceGroupType.Index));
return this.execute(args);
} else if (context.type === 'scm-groups') {
const isModified = (status: Status): boolean => status === Status.BOTH_MODIFIED || status === Status.INDEX_MODIFIED || status === Status.MODIFIED;
args = { ...args };
args.files = context.scmResourceGroups[0].resourceStates.filter((_: Resource) => isModified(_.type)).map<ExternalDiffFile>((_: Resource) => new ExternalDiffFile(_.resourceUri, _.resourceGroupType === ResourceGroupType.Index));
return this.execute(args);
}
return this.execute(args);
}
async execute(args: ExternalDiffCommandArgs = {}) {
try {
const diffTool = await this.git.getConfig('diff.tool');
if (!diffTool) {
const result = await window.showWarningMessage(`Unable to open file compare because there is no Git diff tool 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'));
}
const repoPath = await this.git.getRepoPathFromUri(undefined);
if (!repoPath) return Messages.showNoRepositoryWarningMessage(`Unable to open changed files`);
if (!args.files) {
const status = await this.git.getStatusForRepo(repoPath);
if (status === undefined) return window.showWarningMessage(`Unable to open changed files`);
args.files = [];
for (const file of status.files) {
if (file.indexStatus === 'M') {
args.files.push(new ExternalDiffFile(file.Uri, true));
}
if (file.workTreeStatus === 'M') {
args.files.push(new ExternalDiffFile(file.Uri, false));
}
}
}
for (const file of args.files) {
this.git.openDiffTool(repoPath, file.uri, file.staged);
}
return undefined;
}
catch (ex) {
Logger.error(ex, 'ExternalDiffCommand');
return window.showErrorMessage(`Unable to open external diff. See output channel for more details`);
}
}
}

+ 2
- 0
src/extension.ts 查看文件

@ -3,6 +3,7 @@
import { commands, ExtensionContext, extensions, languages, window, workspace } from 'vscode';
import { AnnotationController } from './annotations/annotationController';
import { CloseUnchangedFilesCommand, OpenChangedFilesCommand } from './commands';
import { ExternalDiffCommand } from './commands';
import { OpenBranchesInRemoteCommand, OpenBranchInRemoteCommand, OpenCommitInRemoteCommand, OpenFileInRemoteCommand, OpenInRemoteCommand, OpenRepoInRemoteCommand } from './commands';
import { CopyMessageToClipboardCommand, CopyShaToClipboardCommand } from './commands';
import { DiffDirectoryCommand, DiffLineWithPreviousCommand, DiffLineWithWorkingCommand, DiffWithBranchCommand, DiffWithCommand, DiffWithNextCommand, DiffWithPreviousCommand, DiffWithRevisionCommand, DiffWithWorkingCommand } from './commands';
@ -99,6 +100,7 @@ export async function activate(context: ExtensionContext) {
context.subscriptions.push(commands.registerTextEditorCommand('gitlens.computingFileAnnotations', () => { }));
context.subscriptions.push(new CloseUnchangedFilesCommand(git));
context.subscriptions.push(new ExternalDiffCommand(git));
context.subscriptions.push(new OpenChangedFilesCommand(git));
context.subscriptions.push(new CopyMessageToClipboardCommand(git));
context.subscriptions.push(new CopyShaToClipboardCommand(git));

+ 11
- 0
src/git/git.ts 查看文件

@ -276,6 +276,17 @@ export class Git {
return gitCommand({ cwd: repoPath }, ...params);
}
static difftool_fileDiff(repoPath: string, fileName: string, staged: boolean) {
const params = [`difftool`, `--no-prompt`];
if (staged) {
params.push('--staged');
}
params.push('--');
params.push(fileName);
return gitCommand({ cwd: repoPath }, ...params);
}
static log(repoPath: string, sha?: string, maxCount?: number, reverse: boolean = false) {
const params = [...defaultLogParams, `-m`];
if (maxCount && !reverse) {

+ 3
- 1
src/git/models/status.ts 查看文件

@ -26,6 +26,8 @@ export interface IGitStatusFile {
status: GitStatusFileStatus;
fileName: string;
originalFileName?: string;
workTreeStatus: GitStatusFileStatus;
indexStatus: GitStatusFileStatus;
}
export interface IGitStatusFileWithCommit extends IGitStatusFile {
@ -36,7 +38,7 @@ export class GitStatusFile implements IGitStatusFile {
originalFileName?: string;
constructor(public repoPath: string, public status: GitStatusFileStatus, public fileName: string, public staged: boolean, originalFileName?: string) {
constructor(public repoPath: string, public status: GitStatusFileStatus, public workTreeStatus: GitStatusFileStatus, public indexStatus: GitStatusFileStatus, public fileName: string, public staged: boolean, originalFileName?: string) {
this.originalFileName = originalFileName;
}

+ 7
- 3
src/git/parsers/statusParser.ts 查看文件

@ -6,6 +6,8 @@ interface FileStatusEntry {
status: GitStatusFileStatus;
fileName: string;
originalFileName: string;
workTreeStatus: GitStatusFileStatus;
indexStatus: GitStatusFileStatus;
}
const aheadStatusV1Regex = /(?:ahead ([0-9]+))/;
@ -69,7 +71,7 @@ export class GitStatusParser {
else {
entry = this._parseFileEntry(rawStatus, fileName);
}
status.files.push(new GitStatusFile(repoPath, entry.status, entry.fileName, entry.staged, entry.originalFileName));
status.files.push(new GitStatusFile(repoPath, entry.status, entry.workTreeStatus, entry.indexStatus, entry.fileName, entry.staged, entry.originalFileName));
}
}
}
@ -117,7 +119,7 @@ export class GitStatusParser {
}
if (entry !== undefined) {
status.files.push(new GitStatusFile(repoPath, entry.status, entry.fileName, entry.staged, entry.originalFileName));
status.files.push(new GitStatusFile(repoPath, entry.status, entry.workTreeStatus, entry.indexStatus, entry.fileName, entry.staged, entry.originalFileName));
}
}
}
@ -131,7 +133,9 @@ export class GitStatusParser {
status: (indexStatus || workTreeStatus || '?') as GitStatusFileStatus,
fileName: fileName,
originalFileName: originalFileName,
staged: !!indexStatus
staged: !!indexStatus,
indexStatus: indexStatus,
workTreeStatus: workTreeStatus
} as FileStatusEntry;
}
}

+ 6
- 0
src/gitService.ts 查看文件

@ -1036,6 +1036,12 @@ export class GitService extends Disposable {
return !!result;
}
openDiffTool(repoPath: string, uri: Uri, staged: boolean) {
Logger.log(`openDiffTool('${repoPath}', '${uri}', ${staged})`);
return Git.difftool_fileDiff(repoPath, uri.fsPath, staged);
}
openDirectoryDiff(repoPath: string, sha1: string, sha2?: string) {
Logger.log(`openDirectoryDiff('${repoPath}', ${sha1}, ${sha2})`);

正在加载...
取消
保存