Skip to content

Commit 92467d7

Browse files
committed
Only refresh cached path results for changes dirs
Fixes microsoft#259342
1 parent 9eedc68 commit 92467d7

File tree

1 file changed

+42
-23
lines changed

1 file changed

+42
-23
lines changed

extensions/terminal-suggest/src/env/pathExecutableCache.ts

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,16 @@ const isWindows = osIsWindows();
1919
export class PathExecutableCache implements vscode.Disposable {
2020
private _disposables: vscode.Disposable[] = [];
2121

22-
private _cachedPathValue: string | undefined;
2322
private _cachedWindowsExeExtensions: { [key: string]: boolean | undefined } | undefined;
24-
private _cachedExes: { completionResources: Set<ICompletionResource> | undefined; labels: Set<string> | undefined } | undefined;
23+
private _cachedExes: Map<string, Set<ICompletionResource> | undefined> = new Map();
2524

2625
constructor() {
2726
if (isWindows) {
2827
this._cachedWindowsExeExtensions = vscode.workspace.getConfiguration(SettingsIds.SuggestPrefix).get(SettingsIds.CachedWindowsExecutableExtensionsSuffixOnly);
2928
this._disposables.push(vscode.workspace.onDidChangeConfiguration(e => {
3029
if (e.affectsConfiguration(SettingsIds.CachedWindowsExecutableExtensions)) {
3130
this._cachedWindowsExeExtensions = vscode.workspace.getConfiguration(SettingsIds.SuggestPrefix).get(SettingsIds.CachedWindowsExecutableExtensionsSuffixOnly);
32-
this._cachedExes = undefined;
31+
this._cachedExes.clear();
3332
}
3433
}));
3534
}
@@ -41,9 +40,13 @@ export class PathExecutableCache implements vscode.Disposable {
4140
}
4241
}
4342

44-
refresh(): void {
45-
this._cachedExes = undefined;
46-
this._cachedPathValue = undefined;
43+
refresh(directory?: string): void {
44+
console.trace('clear cache');
45+
if (directory) {
46+
this._cachedExes.delete(directory);
47+
} else {
48+
this._cachedExes.clear();
49+
}
4750
}
4851

4952
async getExecutablesInPath(env: ITerminalEnvironment = process.env, shellType?: TerminalShellType): Promise<{ completionResources: Set<ICompletionResource> | undefined; labels: Set<string> | undefined } | undefined> {
@@ -65,35 +68,51 @@ export class PathExecutableCache implements vscode.Disposable {
6568
return;
6669
}
6770

68-
// Check cache
69-
if (this._cachedExes && this._cachedPathValue === pathValue) {
70-
return this._cachedExes;
71-
}
72-
7371
// Extract executables from PATH
7472
const paths = pathValue.split(isWindows ? ';' : ':');
7573
const pathSeparator = isWindows ? '\\' : '/';
7674
const promises: Promise<Set<ICompletionResource> | undefined>[] = [];
7775
const labels: Set<string> = new Set<string>();
78-
for (const path of paths) {
79-
promises.push(this._getExecutablesInPath(path, pathSeparator, labels));
76+
77+
for (const pathDir of paths) {
78+
// Check if this directory is already cached
79+
const cachedExecutables = this._cachedExes.get(pathDir);
80+
if (cachedExecutables) {
81+
for (const executable of cachedExecutables) {
82+
const labelText = typeof executable.label === 'string' ? executable.label : executable.label.label;
83+
labels.add(labelText);
84+
}
85+
} else {
86+
// Not cached, need to scan this directory
87+
promises.push(this._getExecutablesInPath(pathDir, pathSeparator, labels));
88+
}
89+
}
90+
91+
// Process uncached directories
92+
if (promises.length > 0) {
93+
const resultSets = await Promise.all(promises);
94+
let uncachedPathIndex = 0;
95+
96+
for (const pathDir of paths) {
97+
if (!this._cachedExes.has(pathDir)) {
98+
const resultSet = resultSets[uncachedPathIndex++];
99+
this._cachedExes.set(pathDir, resultSet || new Set());
100+
}
101+
}
80102
}
81103

82-
// Merge all results
104+
// Merge all results from all directories
83105
const executables = new Set<ICompletionResource>();
84-
const resultSets = await Promise.all(promises);
85-
for (const resultSet of resultSets) {
86-
if (resultSet) {
87-
for (const executable of resultSet) {
106+
for (const pathDir of paths) {
107+
const dirExecutables = this._cachedExes.get(pathDir);
108+
if (dirExecutables) {
109+
for (const executable of dirExecutables) {
88110
executables.add(executable);
89111
}
90112
}
91113
}
92114

93-
// Return
94-
this._cachedPathValue = pathValue;
95-
this._cachedExes = { completionResources: executables, labels };
96-
return this._cachedExes;
115+
return { completionResources: executables, labels };
97116
}
98117

99118
private async _getExecutablesInPath(path: string, pathSeparator: string, labels: Set<string>): Promise<Set<ICompletionResource> | undefined> {
@@ -190,7 +209,7 @@ export async function watchPathDirectories(context: vscode.ExtensionContext, env
190209
const watcher = filesystem.watch(dir, { persistent: false }, () => {
191210
if (pathExecutableCache) {
192211
// Refresh cache when directory contents change
193-
pathExecutableCache.refresh();
212+
pathExecutableCache.refresh(dir);
194213
}
195214
});
196215

0 commit comments

Comments
 (0)