@@ -105,6 +105,17 @@ export async function resolveToSymbolicPath(path: string) {
105105 return path ;
106106}
107107
108+ /**
109+ * Checks whether a file exists, and the user has access to read it.
110+ * @param path The path of the file.
111+ * @returns Promise resolving to a boolean: TRUE => File exists, FALSE => File doesn't exist.
112+ */
113+ export function doesFileExist ( path : string ) {
114+ return new Promise < boolean > ( ( resolve ) => {
115+ fs . access ( path , fs . constants . R_OK , ( err ) => resolve ( err === null ) ) ;
116+ } ) ;
117+ }
118+
108119
109120/* General Methods */
110121
@@ -334,26 +345,38 @@ export function openExternalUrl(url: string, type: string = 'External URL'): The
334345 * Open a file within a repository in Visual Studio Code.
335346 * @param repo The repository the file is contained in.
336347 * @param filePath The relative path of the file within the repository.
348+ * @param hash An optional commit hash where the file is known to have existed.
349+ * @param dataSource An optional DataSource instance, that's used to check if the file has been renamed.
337350 * @param viewColumn An optional ViewColumn that the file should be opened in.
338351 * @returns A promise resolving to the ErrorInfo of the executed command.
339352 */
340- export function openFile ( repo : string , filePath : string , viewColumn : vscode . ViewColumn | null = null ) {
341- return new Promise < ErrorInfo > ( resolve => {
342- const p = path . join ( repo , filePath ) ;
343- fs . access ( p , fs . constants . R_OK , ( err ) => {
344- if ( err === null ) {
345- vscode . commands . executeCommand ( 'vscode.open' , vscode . Uri . file ( p ) , {
346- preview : true ,
347- viewColumn : viewColumn === null ? getConfig ( ) . openNewTabEditorGroup : viewColumn
348- } ) . then (
349- ( ) => resolve ( null ) ,
350- ( ) => resolve ( 'Visual Studio Code was unable to open ' + filePath + '.' )
351- ) ;
352- } else {
353- resolve ( 'The file ' + filePath + ' doesn\'t currently exist in this repository.' ) ;
353+ export async function openFile ( repo : string , filePath : string , hash : string | null = null , dataSource : DataSource | null = null , viewColumn : vscode . ViewColumn | null = null ) {
354+ let newFilePath = filePath ;
355+ let newAbsoluteFilePath = path . join ( repo , newFilePath ) ;
356+ let fileExists = await doesFileExist ( newAbsoluteFilePath ) ;
357+ if ( ! fileExists && hash !== null && dataSource !== null ) {
358+ const renamedFilePath = await dataSource . getNewPathOfRenamedFile ( repo , hash , filePath ) ;
359+ if ( renamedFilePath !== null ) {
360+ const renamedAbsoluteFilePath = path . join ( repo , renamedFilePath ) ;
361+ if ( await doesFileExist ( renamedAbsoluteFilePath ) ) {
362+ newFilePath = renamedFilePath ;
363+ newAbsoluteFilePath = renamedAbsoluteFilePath ;
364+ fileExists = true ;
354365 }
355- } ) ;
356- } ) ;
366+ }
367+ }
368+
369+ if ( fileExists ) {
370+ return vscode . commands . executeCommand ( 'vscode.open' , vscode . Uri . file ( newAbsoluteFilePath ) , {
371+ preview : true ,
372+ viewColumn : viewColumn === null ? getConfig ( ) . openNewTabEditorGroup : viewColumn
373+ } ) . then (
374+ ( ) => null ,
375+ ( ) => 'Visual Studio Code was unable to open ' + newFilePath + '.'
376+ ) ;
377+ } else {
378+ return 'The file ' + newFilePath + ' doesn\'t currently exist in this repository.' ;
379+ }
357380}
358381
359382/**
@@ -394,15 +417,27 @@ export function viewDiff(repo: string, fromHash: string, toHash: string, oldFile
394417 * @param repo The repository the file is contained in.
395418 * @param hash The revision of the left-side of the Diff View.
396419 * @param filePath The relative path of the file within the repository.
420+ * @param dataSource A DataSource instance, that's used to check if the file has been renamed.
397421 * @returns A promise resolving to the ErrorInfo of the executed command.
398422 */
399- export function viewDiffWithWorkingFile ( repo : string , hash : string , filePath : string ) {
400- return new Promise < ErrorInfo > ( ( resolve ) => {
401- const p = path . join ( repo , filePath ) ;
402- fs . access ( p , fs . constants . R_OK , ( err ) => {
403- resolve ( viewDiff ( repo , hash , UNCOMMITTED , filePath , filePath , err === null ? GitFileStatus . Modified : GitFileStatus . Deleted ) ) ;
404- } ) ;
405- } ) ;
423+ export async function viewDiffWithWorkingFile ( repo : string , hash : string , filePath : string , dataSource : DataSource ) {
424+ let newFilePath = filePath ;
425+ let fileExists = await doesFileExist ( path . join ( repo , newFilePath ) ) ;
426+ if ( ! fileExists ) {
427+ const renamedFilePath = await dataSource . getNewPathOfRenamedFile ( repo , hash , filePath ) ;
428+ if ( renamedFilePath !== null && await doesFileExist ( path . join ( repo , renamedFilePath ) ) ) {
429+ newFilePath = renamedFilePath ;
430+ fileExists = true ;
431+ }
432+ }
433+
434+ const type = fileExists
435+ ? filePath === newFilePath
436+ ? GitFileStatus . Modified
437+ : GitFileStatus . Renamed
438+ : GitFileStatus . Deleted ;
439+
440+ return viewDiff ( repo , hash , UNCOMMITTED , filePath , newFilePath , type ) ;
406441}
407442
408443/**
@@ -412,7 +447,7 @@ export function viewDiffWithWorkingFile(repo: string, hash: string, filePath: st
412447 * @param filePath The relative path of the file within the repository.
413448 * @returns A promise resolving to the ErrorInfo of the executed command.
414449 */
415- export async function viewFileAtRevision ( repo : string , hash : string , filePath : string ) {
450+ export function viewFileAtRevision ( repo : string , hash : string , filePath : string ) {
416451 const pathComponents = filePath . split ( '/' ) ;
417452 const title = abbrevCommit ( hash ) + ': ' + pathComponents [ pathComponents . length - 1 ] ;
418453
0 commit comments