@@ -44,6 +44,7 @@ type ShellGlobalsCacheEntry = {
4444
4545type ShellGlobalsCacheEntryWithMeta = ShellGlobalsCacheEntry & { timestamp : number } ;
4646const cachedGlobals : Map < string , ShellGlobalsCacheEntryWithMeta > = new Map ( ) ;
47+ const inflightRequests : Map < string , Promise < ICompletionResource [ ] | undefined > > = new Map ( ) ;
4748let pathExecutableCache : PathExecutableCache ;
4849const CACHE_KEY = 'terminalSuggestGlobalsCacheV2' ;
4950let globalStorageUri : vscode . Uri ;
@@ -122,30 +123,50 @@ async function fetchAndCacheShellGlobals(
122123 remoteAuthority ?: string ,
123124 background ?: boolean
124125) : Promise < ICompletionResource [ ] | undefined > {
125- try {
126- let execShellType = shellType ;
127- if ( shellType === TerminalShellType . GitBash ) {
128- execShellType = TerminalShellType . Bash ; // Git Bash is a bash shell
129- }
130- const options : ExecOptionsWithStringEncoding = { encoding : 'utf-8' , shell : execShellType , windowsHide : true } ;
131- const mixedCommands : ( string | ICompletionResource ) [ ] | undefined = await getShellSpecificGlobals . get ( shellType ) ?.( options , existingCommands ) ;
132- const normalizedCommands = mixedCommands ?. map ( command => typeof command === 'string' ? ( { label : command } ) : command ) ;
133- if ( machineId ) {
134- const cacheKey = getCacheKey ( machineId , remoteAuthority , shellType ) ;
135- cachedGlobals . set ( cacheKey , {
136- commands : normalizedCommands ,
137- existingCommands : existingCommands ? Array . from ( existingCommands ) : undefined ,
138- timestamp : Date . now ( )
139- } ) ;
140- await writeGlobalsCache ( ) ;
141- }
142- return normalizedCommands ;
143- } catch ( error ) {
144- if ( ! background ) {
145- console . error ( 'Error fetching builtin commands:' , error ) ;
146- }
147- return ;
126+ const cacheKey = getCacheKey ( machineId ?? 'no-machine-id' , remoteAuthority , shellType ) ;
127+
128+ // Check if there's already an in-flight request for this cache key
129+ const existingRequest = inflightRequests . get ( cacheKey ) ;
130+ if ( existingRequest ) {
131+ // Wait for the existing request to complete rather than spawning a new process
132+ return existingRequest ;
148133 }
134+
135+ // Create a new request and store it in the inflight map
136+ const requestPromise = ( async ( ) => {
137+ try {
138+ let execShellType = shellType ;
139+ if ( shellType === TerminalShellType . GitBash ) {
140+ execShellType = TerminalShellType . Bash ; // Git Bash is a bash shell
141+ }
142+ const options : ExecOptionsWithStringEncoding = { encoding : 'utf-8' , shell : execShellType , windowsHide : true } ;
143+ const mixedCommands : ( string | ICompletionResource ) [ ] | undefined = await getShellSpecificGlobals . get ( shellType ) ?.( options , existingCommands ) ;
144+ const normalizedCommands = mixedCommands ?. map ( command => typeof command === 'string' ? ( { label : command } ) : command ) ;
145+ if ( machineId ) {
146+ const cacheKey = getCacheKey ( machineId , remoteAuthority , shellType ) ;
147+ cachedGlobals . set ( cacheKey , {
148+ commands : normalizedCommands ,
149+ existingCommands : existingCommands ? Array . from ( existingCommands ) : undefined ,
150+ timestamp : Date . now ( )
151+ } ) ;
152+ await writeGlobalsCache ( ) ;
153+ }
154+ return normalizedCommands ;
155+ } catch ( error ) {
156+ if ( ! background ) {
157+ console . error ( 'Error fetching builtin commands:' , error ) ;
158+ }
159+ return ;
160+ } finally {
161+ // Always remove the promise from inflight requests when done
162+ inflightRequests . delete ( cacheKey ) ;
163+ }
164+ } ) ( ) ;
165+
166+ // Store the promise in the inflight map
167+ inflightRequests . set ( cacheKey , requestPromise ) ;
168+
169+ return requestPromise ;
149170}
150171
151172
0 commit comments