1+ 'use strict' ;
2+ import { commands , SourceControlResourceState , Uri , window } from 'vscode' ;
3+ import { Command , Commands } from './common' ;
4+ import { BuiltInCommands } from '../constants' ;
5+ import { CommandContext } from '../commands' ;
6+ import { GitService } from '../gitService' ;
7+ import { Logger } from '../logger' ;
8+ import { Messages } from '../messages' ;
9+
10+ enum Status {
11+ INDEX_MODIFIED ,
12+ INDEX_ADDED ,
13+ INDEX_DELETED ,
14+ INDEX_RENAMED ,
15+ INDEX_COPIED ,
16+
17+ MODIFIED ,
18+ DELETED ,
19+ UNTRACKED ,
20+ IGNORED ,
21+
22+ ADDED_BY_US ,
23+ ADDED_BY_THEM ,
24+ DELETED_BY_US ,
25+ DELETED_BY_THEM ,
26+ BOTH_ADDED ,
27+ BOTH_DELETED ,
28+ BOTH_MODIFIED
29+ }
30+
31+ enum ResourceGroupType {
32+ Merge ,
33+ Index ,
34+ WorkingTree
35+ }
36+
37+ interface Resource extends SourceControlResourceState {
38+ readonly resourceGroupType : ResourceGroupType ;
39+ readonly type : Status ;
40+ }
41+
42+ class ExternalDiffFile {
43+ constructor ( public uri : Uri , public staged : boolean ) {
44+ }
45+ }
46+
47+ export interface ExternalDiffCommandArgs {
48+ files ?: ExternalDiffFile [ ] ;
49+ }
50+
51+ export class ExternalDiffCommand extends Command {
52+ constructor ( private git : GitService ) {
53+ super ( Commands . ExternalDiff ) ;
54+ }
55+
56+ protected async preExecute ( context : CommandContext , args : ExternalDiffCommandArgs = { } ) : Promise < any > {
57+ if ( context . type === 'scm-states' ) {
58+ args = { ...args } ;
59+ args . files = context . scmResourceStates . map < ExternalDiffFile > ( ( _ : Resource ) => new ExternalDiffFile ( _ . resourceUri , _ . resourceGroupType === ResourceGroupType . Index ) ) ;
60+
61+ return this . execute ( args ) ;
62+ } else if ( context . type === 'scm-groups' ) {
63+ const isModified = ( status : Status ) : boolean => status === Status . BOTH_MODIFIED || status === Status . INDEX_MODIFIED || status === Status . MODIFIED ;
64+
65+ args = { ...args } ;
66+ args . files = context . scmResourceGroups [ 0 ] . resourceStates . filter ( ( _ : Resource ) => isModified ( _ . type ) ) . map < ExternalDiffFile > ( ( _ : Resource ) => new ExternalDiffFile ( _ . resourceUri , _ . resourceGroupType === ResourceGroupType . Index ) ) ;
67+
68+ return this . execute ( args ) ;
69+ }
70+
71+ return this . execute ( args ) ;
72+ }
73+
74+ async execute ( args : ExternalDiffCommandArgs = { } ) {
75+ try {
76+ const diffTool = await this . git . getConfig ( 'diff.tool' ) ;
77+ if ( ! diffTool ) {
78+ const result = await window . showWarningMessage ( `Unable to open file compare because there is no Git diff tool configured` , 'View Git Docs' ) ;
79+ if ( ! result ) return undefined ;
80+
81+ return commands . executeCommand ( BuiltInCommands . Open , Uri . parse ( 'https://git-scm.com/docs/git-config#git-config-difftool' ) ) ;
82+ }
83+
84+ const repoPath = await this . git . getRepoPathFromUri ( undefined ) ;
85+ if ( ! repoPath ) return Messages . showNoRepositoryWarningMessage ( `Unable to open changed files` ) ;
86+
87+ if ( ! args . files ) {
88+ const status = await this . git . getStatusForRepo ( repoPath ) ;
89+ if ( status === undefined ) return window . showWarningMessage ( `Unable to open changed files` ) ;
90+
91+ args . files = [ ] ;
92+
93+ for ( const file of status . files ) {
94+ if ( file . indexStatus === 'M' ) {
95+ args . files . push ( new ExternalDiffFile ( file . Uri , true ) ) ;
96+ }
97+
98+ if ( file . workTreeStatus === 'M' ) {
99+ args . files . push ( new ExternalDiffFile ( file . Uri , false ) ) ;
100+ }
101+ }
102+ }
103+
104+ for ( const file of args . files ) {
105+ this . git . openDiffTool ( repoPath , file . uri , file . staged ) ;
106+ }
107+
108+ return undefined ;
109+ }
110+ catch ( ex ) {
111+ Logger . error ( ex , 'ExternalDiffCommand' ) ;
112+ return window . showErrorMessage ( `Unable to open external diff. See output channel for more details` ) ;
113+ }
114+ }
115+ }
0 commit comments