@@ -5,13 +5,14 @@ import type { Container } from '../container';
55import type { GitCommit } from '../git/models/commit' ;
66import { isCommit } from '../git/models/commit' ;
77import { deletedOrMissing } from '../git/models/revision' ;
8- import { isShaWithOptionalRevisionSuffix , isUncommitted , shortenRevision } from '../git/utils/revision.utils' ;
8+ import { isShaWithParentSuffix , isUncommitted , shortenRevision } from '../git/utils/revision.utils' ;
99import { showGenericErrorMessage } from '../messages' ;
1010import { command } from '../system/-webview/command' ;
1111import { openDiffEditor } from '../system/-webview/vscode/editors' ;
1212import { createMarkdownCommandLink } from '../system/commands' ;
1313import { Logger } from '../system/logger' ;
1414import { basename } from '../system/path' ;
15+ import { getSettledValue } from '../system/promise' ;
1516import { GlCommandBase } from './commandBase' ;
1617
1718export interface DiffWithCommandArgsRevision {
@@ -25,6 +26,7 @@ export interface DiffWithCommandArgs {
2526 rhs : DiffWithCommandArgsRevision ;
2627 repoPath : string | undefined ;
2728
29+ fromComparison ?: boolean ;
2830 line ?: number ;
2931 showOptions ?: TextDocumentShowOptions ;
3032}
@@ -45,28 +47,16 @@ export class DiffWithCommand extends GlCommandBase {
4547 if ( commit . isUncommitted ) {
4648 args = {
4749 repoPath : commit . repoPath ,
48- lhs : {
49- sha : 'HEAD' ,
50- uri : commit . file . uri ,
51- } ,
52- rhs : {
53- sha : '' ,
54- uri : commit . file . uri ,
55- } ,
50+ lhs : { sha : 'HEAD' , uri : commit . file . uri } ,
51+ rhs : { sha : '' , uri : commit . file . uri } ,
5652 line : line ,
5753 } ;
5854 } else {
5955 args = {
6056 repoPath : commit . repoPath ,
61- lhs : {
62- // Don't need to worry about verifying the previous sha, as the DiffWith command will
63- sha : commit . unresolvedPreviousSha ,
64- uri : commit . file . originalUri ?? commit . file . uri ,
65- } ,
66- rhs : {
67- sha : commit . sha ,
68- uri : commit . file . uri ,
69- } ,
57+ // Don't need to worry about verifying the previous sha, as the DiffWith command will
58+ lhs : { sha : commit . unresolvedPreviousSha , uri : commit . file . originalUri ?? commit . file . uri } ,
59+ rhs : { sha : commit . sha , uri : commit . file . uri } ,
7060 line : line ,
7161 } ;
7262 }
@@ -84,111 +74,107 @@ export class DiffWithCommand extends GlCommandBase {
8474 async execute ( args ?: DiffWithCommandArgs ) : Promise < any > {
8575 if ( args ?. lhs == null || args ?. rhs == null ) return ;
8676
87- args = {
88- ...args ,
89- lhs : { ...args . lhs } ,
90- rhs : { ...args . rhs } ,
91- showOptions : args . showOptions == null ? undefined : { ...args . showOptions } ,
92- } ;
93-
94- if ( args . repoPath == null ) return ;
77+ const repo = args . repoPath ? this . container . git . getRepository ( args . repoPath ) : undefined ;
78+ if ( repo == null ) return ;
9579
9680 try {
97- let lhsSha = args . lhs . sha ;
98- let rhsSha = args . rhs . sha ;
99-
100- [ args . lhs . sha , args . rhs . sha ] = await Promise . all ( [
101- await this . container . git . refs ( args . repoPath ) . resolveReference ( args . lhs . sha , args . lhs . uri , {
102- // If the ref looks like a sha, don't wait too long, since it should work
103- timeout : isShaWithOptionalRevisionSuffix ( args . lhs . sha ) ? 100 : undefined ,
104- } ) ,
105- await this . container . git . refs ( args . repoPath ) . resolveReference ( args . rhs . sha , args . rhs . uri , {
106- // If the ref looks like a sha, don't wait too long, since it should work
107- timeout : isShaWithOptionalRevisionSuffix ( args . rhs . sha ) ? 100 : undefined ,
108- } ) ,
81+ let {
82+ lhs : { sha : lhsSha , uri : lhsUri , title : lhsTitle } ,
83+ rhs : { sha : rhsSha , uri : rhsUri , title : rhsTitle } ,
84+ } = args ;
85+ const showOptions = { viewColumn : ViewColumn . Active , ...args . showOptions } ;
86+
87+ let [ lhsResolvedResult , rhsResolvedResult ] = await Promise . allSettled ( [
88+ repo . git . revision ( ) . resolveRevision ( lhsSha , lhsUri ) ,
89+ repo . git . revision ( ) . resolveRevision ( rhsSha , rhsUri ) ,
10990 ] ) ;
11091
111- if ( args . lhs . sha !== deletedOrMissing ) {
112- lhsSha = args . lhs . sha ;
113- }
92+ let lhsResolved = getSettledValue ( lhsResolvedResult ) ! ;
93+ let rhsResolved = getSettledValue ( rhsResolvedResult ) ! ;
11494
115- if ( args . rhs . sha && args . rhs . sha !== deletedOrMissing ) {
116- // Ensure that the file still exists in this commit
117- const status = await this . container . git
118- . commits ( args . repoPath )
119- . getCommitFileStatus ( args . rhs . uri , args . rhs . sha ) ;
120- if ( status ?. status === 'D' ) {
121- args . rhs . sha = deletedOrMissing ;
122- } else {
123- rhsSha = args . rhs . sha ;
124- }
95+ // If both are missing, check for renames by swapping the paths
96+ if ( lhsResolved . sha === deletedOrMissing && rhsResolved . sha === deletedOrMissing ) {
97+ [ lhsResolvedResult , rhsResolvedResult ] = await Promise . allSettled ( [
98+ repo ?. git . revision ( ) . resolveRevision ( lhsSha , rhsUri ) ,
99+ repo ?. git . revision ( ) . resolveRevision ( rhsSha , lhsUri ) ,
100+ ] ) ;
125101
126- if ( status ?. status === 'A' && args . lhs . sha . endsWith ( '^' ) ) {
127- args . lhs . sha = deletedOrMissing ;
102+ lhsResolved = getSettledValue ( lhsResolvedResult ) ! ;
103+ rhsResolved = getSettledValue ( rhsResolvedResult ) ! ;
104+
105+ if ( lhsResolved . sha !== deletedOrMissing || rhsResolved . sha !== deletedOrMissing ) {
106+ [ lhsTitle , rhsTitle ] = [ rhsTitle , lhsTitle ] ;
107+ [ lhsUri , rhsUri ] = [ rhsUri , lhsUri ] ;
128108 }
129109 }
130110
131- const [ lhs , rhs ] = await Promise . all ( [
132- this . container . git . getBestRevisionUri ( args . repoPath , args . lhs . uri . fsPath , args . lhs . sha ) ,
133- this . container . git . getBestRevisionUri ( args . repoPath , args . rhs . uri . fsPath , args . rhs . sha ) ,
111+ if ( rhsResolved . status === 'D' ) {
112+ rhsResolved . sha = deletedOrMissing ;
113+ } else if ( rhsResolved . status === 'R' || rhsResolved . status === 'C' ) {
114+ rhsUri = this . container . git . getAbsoluteUri ( rhsResolved . path ! , args . repoPath ) ;
115+ } else if ( rhsResolved . status === 'A' && isShaWithParentSuffix ( lhsResolved . sha ) ) {
116+ lhsResolved . sha = deletedOrMissing ;
117+ }
118+
119+ const [ lhsResult , rhsResult ] = await Promise . allSettled ( [
120+ repo . git . getBestRevisionUri ( lhsUri . fsPath , lhsResolved . sha ) ,
121+ repo . git . getBestRevisionUri ( rhsUri . fsPath , rhsResolved . sha ) ,
134122 ] ) ;
135123
136- let rhsSuffix = shortenRevision ( rhsSha , { strings : { uncommitted : 'Working Tree' } } ) ;
124+ const lhs = getSettledValue ( lhsResult ) ;
125+ const rhs = getSettledValue ( rhsResult ) ;
126+
127+ let rhsSuffix = shortenRevision ( rhsResolved . revision ) ;
137128 if ( rhs == null ) {
138- if ( isUncommitted ( args . rhs . sha ) ) {
139- rhsSuffix = 'deleted ' ;
140- } else if ( rhsSuffix . length === 0 && args . rhs . sha === deletedOrMissing ) {
141- rhsSuffix = 'not in Working Tree' ;
129+ if ( isUncommitted ( rhsResolved . sha ) ) {
130+ rhsSuffix = 'Deleted ' ;
131+ } else if ( ! rhsSuffix && rhsResolved . sha === deletedOrMissing ) {
132+ rhsSuffix = 'Not in Working Tree' ;
142133 } else {
143- rhsSuffix = `deleted ${ rhsSuffix . length === 0 ? '' : ` in ${ rhsSuffix } ` } ` ;
134+ rhsSuffix = `${ args . fromComparison ? 'Missing' : 'Deleted' } ${ ! rhsSuffix ? '' : ` in ${ rhsSuffix } ` } ` ;
144135 }
145136 } else if ( lhs == null ) {
146- rhsSuffix = `added${ rhsSuffix . length === 0 ? '' : ` in ${ rhsSuffix } ` } ` ;
137+ if ( ! args . fromComparison ) {
138+ rhsSuffix = `Added${ ! rhsSuffix ? '' : ` in ${ rhsSuffix } ` } ` ;
139+ }
147140 }
148141
149- let lhsSuffix = args . lhs . sha !== deletedOrMissing ? shortenRevision ( lhsSha ) : '' ;
150- if ( lhs == null && args . rhs . sha . length === 0 ) {
142+ let lhsSuffix = shortenRevision ( lhsResolved . revision ) ;
143+ if ( lhsResolved . sha === deletedOrMissing ) {
144+ lhsSuffix = args . fromComparison ? `Missing${ ! lhsSuffix ? '' : ` in ${ lhsSuffix } ` } ` : '' ;
145+ }
146+ if ( lhs == null && ! rhsResolved . sha ) {
151147 if ( rhs != null ) {
152- lhsSuffix = lhsSuffix . length === 0 ? '' : `not in ${ lhsSuffix } ` ;
148+ lhsSuffix = ! lhsSuffix ? '' : `Not in ${ lhsSuffix } ` ;
153149 rhsSuffix = '' ;
154150 } else {
155- lhsSuffix = `deleted ${ lhsSuffix . length === 0 ? '' : ` in ${ lhsSuffix } ` } ` ;
151+ lhsSuffix = `${ args . fromComparison ? 'Missing' : 'Deleted' } ${ ! lhsSuffix ? '' : ` in ${ lhsSuffix } ` } ` ;
156152 }
157153 }
158154
159- if ( args . lhs . title == null && ( lhs != null || lhsSuffix . length !== 0 ) ) {
160- args . lhs . title = `${ basename ( args . lhs . uri . fsPath ) } ${ lhsSuffix ? ` (${ lhsSuffix } )` : '' } ` ;
161- }
162- if ( args . rhs . title == null ) {
163- args . rhs . title = `${ basename ( args . rhs . uri . fsPath ) } ${ rhsSuffix ? ` (${ rhsSuffix } )` : '' } ` ;
155+ if ( lhsTitle == null && ( lhs != null || lhsSuffix ) ) {
156+ lhsTitle = `${ basename ( args . lhs . uri . fsPath ) } ${ lhsSuffix ? ` (${ lhsSuffix } )` : '' } ` ;
164157 }
158+ rhsTitle ??= `${ basename ( args . rhs . uri . fsPath ) } ${ rhsSuffix ? ` (${ rhsSuffix } )` : '' } ` ;
165159
166160 const title =
167- args . lhs . title != null && args . rhs . title != null
168- ? `${ args . lhs . title } ${ GlyphChars . ArrowLeftRightLong } ${ args . rhs . title } `
169- : args . lhs . title ?? args . rhs . title ;
170-
171- if ( args . showOptions == null ) {
172- args . showOptions = { } ;
173- }
174-
175- if ( args . showOptions . viewColumn == null ) {
176- args . showOptions . viewColumn = ViewColumn . Active ;
177- }
161+ lhsTitle != null && rhsTitle != null
162+ ? `${ lhsTitle } ${ GlyphChars . ArrowLeftRightLong } ${ rhsTitle } `
163+ : lhsTitle ?? rhsTitle ;
178164
179- if ( args . line != null && args . line !== 0 ) {
180- args . showOptions . selection = new Range ( args . line , 0 , args . line , 0 ) ;
165+ if ( args . line ) {
166+ showOptions . selection = new Range ( args . line , 0 , args . line , 0 ) ;
181167 }
182168
183169 await openDiffEditor (
184- lhs ?? this . container . git . getRevisionUri ( args . repoPath , deletedOrMissing , args . lhs . uri . fsPath ) ,
185- rhs ?? this . container . git . getRevisionUri ( args . repoPath , deletedOrMissing , args . rhs . uri . fsPath ) ,
170+ lhs ?? repo . git . getRevisionUri ( deletedOrMissing , args . lhs . uri . fsPath ) ,
171+ rhs ?? repo . git . getRevisionUri ( deletedOrMissing , args . rhs . uri . fsPath ) ,
186172 title ,
187173 args . showOptions ,
188174 ) ;
189175 } catch ( ex ) {
190- Logger . error ( ex , 'DiffWithCommand' , 'getVersionedFile' ) ;
191- void showGenericErrorMessage ( 'Unable to open compare ' ) ;
176+ Logger . error ( ex , 'DiffWithCommand' ) ;
177+ void showGenericErrorMessage ( 'Unable to open comparison ' ) ;
192178 }
193179 }
194180}
0 commit comments