Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 0 additions & 44 deletions extensions/terminal-suggest/src/env/pathExecutableCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import { osIsWindows } from '../helpers/os';
import type { ICompletionResource } from '../types';
import { getFriendlyResourcePath } from '../helpers/uri';
import { SettingsIds } from '../constants';
import * as filesystem from 'fs';
import * as path from 'path';
import { TerminalShellType } from '../terminalSuggestMain';

const isWindows = osIsWindows();
Expand Down Expand Up @@ -220,46 +218,4 @@ export class PathExecutableCache implements vscode.Disposable {
}
}

export async function watchPathDirectories(context: vscode.ExtensionContext, env: ITerminalEnvironment, pathExecutableCache: PathExecutableCache | undefined): Promise<void> {
const pathDirectories = new Set<string>();

const envPath = env.PATH;
if (envPath) {
envPath.split(path.delimiter).forEach(p => pathDirectories.add(p));
}

const activeWatchers = new Set<string>();

// Watch each directory
for (const dir of pathDirectories) {
try {
if (activeWatchers.has(dir)) {
// Skip if already watching or directory doesn't exist
continue;
}

const stat = await fs.stat(dir);
if (!stat.isDirectory()) {
continue;
}

const watcher = filesystem.watch(dir, { persistent: false }, () => {
if (pathExecutableCache) {
// Refresh cache when directory contents change
pathExecutableCache.refresh(dir);
}
});

activeWatchers.add(dir);

context.subscriptions.push(new vscode.Disposable(() => {
try {
watcher.close();
activeWatchers.delete(dir);
} catch { } { }
}));
} catch { }
}
}

export type ITerminalEnvironment = { [key: string]: string | undefined };
58 changes: 54 additions & 4 deletions extensions/terminal-suggest/src/terminalSuggestMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
*--------------------------------------------------------------------------------------------*/

import { ExecOptionsWithStringEncoding } from 'child_process';
import * as fs from 'fs';
import { basename, delimiter } from 'path';
import * as vscode from 'vscode';
import azdSpec from './completions/azd';
import cdSpec from './completions/cd';
Expand All @@ -17,7 +19,7 @@ import ghCompletionSpec from './completions/gh';
import npxCompletionSpec from './completions/npx';
import setLocationSpec from './completions/set-location';
import { upstreamSpecs } from './constants';
import { ITerminalEnvironment, PathExecutableCache, watchPathDirectories } from './env/pathExecutableCache';
import { ITerminalEnvironment, PathExecutableCache } from './env/pathExecutableCache';
import { executeCommand, executeCommandTimeout, IFigExecuteExternals } from './fig/execute';
import { getFigSuggestions } from './fig/figInterface';
import { createCompletionItem } from './helpers/completionItem';
Expand All @@ -30,8 +32,6 @@ import { getPwshGlobals } from './shell/pwsh';
import { getZshGlobals } from './shell/zsh';
import { defaultShellTypeResetChars, getTokenType, shellTypeResetChars, TokenType } from './tokens';
import type { ICompletionResource } from './types';
import { basename } from 'path';

export const enum TerminalShellType {
Bash = 'bash',
Fish = 'fish',
Expand Down Expand Up @@ -321,13 +321,63 @@ export async function activate(context: vscode.ExtensionContext) {
return result.items;
}
}, '/', '\\'));
await watchPathDirectories(context, currentTerminalEnv, pathExecutableCache);
watchPathDirectories(context, currentTerminalEnv, pathExecutableCache);

context.subscriptions.push(vscode.commands.registerCommand('terminal.integrated.suggest.clearCachedGlobals', () => {
cachedGlobals.clear();
}));
}

async function watchPathDirectories(context: vscode.ExtensionContext, env: ITerminalEnvironment, pathExecutableCache: PathExecutableCache | undefined): Promise<void> {
const pathDirectories = new Set<string>();

const envPath = env.PATH;
if (envPath) {
envPath.split(delimiter).forEach(p => pathDirectories.add(p));
}

const activeWatchers = new Set<string>();

let debounceTimer: NodeJS.Timeout | undefined; // debounce in case many file events fire at once
function handleChange() {
if (debounceTimer) {
clearTimeout(debounceTimer);
}
debounceTimer = setTimeout(() => {
pathExecutableCache?.refresh();
debounceTimer = undefined;
}, 300);
}

// Watch each directory
for (const dir of pathDirectories) {
if (activeWatchers.has(dir)) {
// Skip if already watching this directory
continue;
}

try {
const stat = await fs.promises.stat(dir);
if (!stat.isDirectory()) {
continue;
}
} catch {
// File not found
continue;
}

const watcher = vscode.workspace.createFileSystemWatcher(new vscode.RelativePattern(vscode.Uri.file(dir), '*'));
context.subscriptions.push(
watcher,
watcher.onDidCreate(() => handleChange()),
watcher.onDidChange(() => handleChange()),
watcher.onDidDelete(() => handleChange())
);

activeWatchers.add(dir);
}
}

/**
* Adjusts the current working directory based on a given current command string if it is a folder.
* @param currentCommandString - The current command string, which might contain a folder path prefix.
Expand Down
Loading