1- import { Uri , window , workspace , WorkspaceFolder } from "vscode" ;
1+ import { FileType , Uri , window , workspace , WorkspaceFolder } from "vscode" ;
22import { getOnDiskWorkspaceFoldersObjects } from "../common/vscode/workspace-folders" ;
33import { extLogger } from "../common" ;
44import { tmpdir } from "../pure/files" ;
@@ -20,7 +20,7 @@ function getAncestors(uri: Uri): Uri[] {
2020 return ancestors ;
2121}
2222
23- function getRootWorkspaceDirectory ( ) : Uri | undefined {
23+ async function getRootWorkspaceDirectory ( ) : Promise < Uri | undefined > {
2424 // If there is a valid workspace file, just use its directory as the directory for the extensions
2525 const workspaceFile = workspace . workspaceFile ;
2626 if ( workspaceFile ?. scheme === "file" ) {
@@ -56,7 +56,7 @@ function getRootWorkspaceDirectory(): Uri | undefined {
5656 } , getAncestors ( workspaceFolders [ 0 ] . uri ) ) ;
5757
5858 if ( commonRoot . length === 0 ) {
59- return undefined ;
59+ return await findGitFolder ( workspaceFolders ) ;
6060 }
6161
6262 // The path closest to the workspace folders is the last element of the common root
@@ -65,12 +65,65 @@ function getRootWorkspaceDirectory(): Uri | undefined {
6565 // If we are at the root of the filesystem, we can't go up any further and there's something
6666 // wrong, so just return undefined
6767 if ( commonRootUri . fsPath === Uri . joinPath ( commonRootUri , ".." ) . fsPath ) {
68- return undefined ;
68+ return await findGitFolder ( workspaceFolders ) ;
6969 }
7070
7171 return commonRootUri ;
7272}
7373
74+ async function findGitFolder (
75+ workspaceFolders : WorkspaceFolder [ ] ,
76+ ) : Promise < Uri | undefined > {
77+ // Go through all workspace folders one-by-one and try to find the closest .git folder for each one
78+ const folders = await Promise . all (
79+ workspaceFolders . map ( async ( folder ) => {
80+ const ancestors = getAncestors ( folder . uri ) ;
81+
82+ // Reverse the ancestors so we're going from closest to furthest
83+ ancestors . reverse ( ) ;
84+
85+ const gitFoldersExists = await Promise . all (
86+ ancestors . map ( async ( uri ) => {
87+ const gitFolder = Uri . joinPath ( uri , ".git" ) ;
88+ try {
89+ const stat = await workspace . fs . stat ( gitFolder ) ;
90+ // Check whether it's a directory
91+ return ( stat . type & FileType . Directory ) !== 0 ;
92+ } catch ( e ) {
93+ return false ;
94+ }
95+ } ) ,
96+ ) ;
97+
98+ // Find the first ancestor that has a .git folder
99+ const ancestorIndex = gitFoldersExists . findIndex ( ( exists ) => exists ) ;
100+
101+ if ( ancestorIndex === - 1 ) {
102+ return undefined ;
103+ }
104+
105+ return [ ancestorIndex , ancestors [ ancestorIndex ] ] ;
106+ } ) ,
107+ ) ;
108+
109+ const validFolders = folders . filter (
110+ ( folder ) : folder is [ number , Uri ] => folder !== undefined ,
111+ ) ;
112+ if ( validFolders . length === 0 ) {
113+ return undefined ;
114+ }
115+
116+ // Find the .git folder which is closest to a workspace folder
117+ const closestFolder = validFolders . reduce ( ( closestFolder , folder ) => {
118+ if ( folder [ 0 ] < closestFolder [ 0 ] ) {
119+ return folder ;
120+ }
121+ return closestFolder ;
122+ } , validFolders [ 0 ] ) ;
123+
124+ return closestFolder ?. [ 1 ] ;
125+ }
126+
74127export async function autoPickExtensionsDirectory ( ) : Promise < Uri | undefined > {
75128 const workspaceFolders = getOnDiskWorkspaceFoldersObjects ( ) ;
76129
@@ -94,7 +147,7 @@ export async function autoPickExtensionsDirectory(): Promise<Uri | undefined> {
94147 }
95148
96149 // Get the root workspace directory, i.e. the common root directory of all workspace folders
97- const rootDirectory = getRootWorkspaceDirectory ( ) ;
150+ const rootDirectory = await getRootWorkspaceDirectory ( ) ;
98151 if ( ! rootDirectory ) {
99152 void extLogger . log ( "Unable to determine root workspace directory" ) ;
100153
0 commit comments