diff --git a/extensions/terminal-suggest/src/env/pathExecutableCache.ts b/extensions/terminal-suggest/src/env/pathExecutableCache.ts index 5113de9c17b..c7cb9f77d88 100644 --- a/extensions/terminal-suggest/src/env/pathExecutableCache.ts +++ b/extensions/terminal-suggest/src/env/pathExecutableCache.ts @@ -16,12 +16,23 @@ import { TerminalShellType } from '../terminalSuggestMain'; const isWindows = osIsWindows(); +export interface IExecutablesInPath { + completionResources: Set | undefined; + labels: Set | undefined; +} + export class PathExecutableCache implements vscode.Disposable { private _disposables: vscode.Disposable[] = []; private _cachedWindowsExeExtensions: { [key: string]: boolean | undefined } | undefined; private _cachedExes: Map | undefined> = new Map(); + private _inProgressRequest: { + env: ITerminalEnvironment; + shellType: TerminalShellType | undefined; + promise: Promise; + } | undefined; + constructor() { if (isWindows) { this._cachedWindowsExeExtensions = vscode.workspace.getConfiguration(SettingsIds.SuggestPrefix).get(SettingsIds.CachedWindowsExecutableExtensionsSuffixOnly); @@ -41,7 +52,6 @@ export class PathExecutableCache implements vscode.Disposable { } refresh(directory?: string): void { - console.trace('clear cache'); if (directory) { this._cachedExes.delete(directory); } else { @@ -49,7 +59,29 @@ export class PathExecutableCache implements vscode.Disposable { } } - async getExecutablesInPath(env: ITerminalEnvironment = process.env, shellType?: TerminalShellType): Promise<{ completionResources: Set | undefined; labels: Set | undefined } | undefined> { + async getExecutablesInPath(env: ITerminalEnvironment = process.env, shellType?: TerminalShellType): Promise { + if (this._inProgressRequest && + this._inProgressRequest.env === env && + this._inProgressRequest.shellType === shellType + ) { + return this._inProgressRequest.promise; + } + + const promise = this._doGetExecutablesInPath(env, shellType); + + this._inProgressRequest = { + env, + shellType, + promise, + }; + + await promise; + this._inProgressRequest = undefined; + + return promise; + } + + private async _doGetExecutablesInPath(env: ITerminalEnvironment, shellType?: TerminalShellType): Promise { // Create cache key let pathValue: string | undefined; if (shellType === TerminalShellType.GitBash) { @@ -84,7 +116,7 @@ export class PathExecutableCache implements vscode.Disposable { } } else { // Not cached, need to scan this directory - promises.push(this._getExecutablesInPath(pathDir, pathSeparator, labels)); + promises.push(this._getExecutablesInSinglePath(pathDir, pathSeparator, labels)); } } @@ -115,7 +147,7 @@ export class PathExecutableCache implements vscode.Disposable { return { completionResources: executables, labels }; } - private async _getExecutablesInPath(path: string, pathSeparator: string, labels: Set): Promise | undefined> { + private async _getExecutablesInSinglePath(path: string, pathSeparator: string, labels: Set): Promise | undefined> { try { const dirExists = await fs.stat(path).then(stat => stat.isDirectory()).catch(() => false); if (!dirExists) {