Skip to content

Commit c2c7ab5

Browse files
authored
add suggest setting WindowsExecutableExtensions, default values (#238155)
1 parent ff59377 commit c2c7ab5

File tree

3 files changed

+65
-5
lines changed

3 files changed

+65
-5
lines changed

extensions/terminal-suggest/src/helpers/executable.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
import { osIsWindows } from './os';
77
import * as fs from 'fs/promises';
88

9-
export async function isExecutable(filePath: string): Promise<boolean> {
9+
export async function isExecutable(filePath: string, configuredWindowsExecutableExtensions?: Object): Promise<boolean> {
1010
if (osIsWindows()) {
11-
return windowsExecutableExtensions.find(ext => filePath.endsWith(ext)) !== undefined;
11+
const resolvedWindowsExecutableExtensions = resolveWindowsExecutableExtensions(configuredWindowsExecutableExtensions);
12+
return resolvedWindowsExecutableExtensions.find(ext => filePath.endsWith(ext)) !== undefined;
1213
}
1314
try {
1415
const stats = await fs.stat(filePath);
@@ -19,7 +20,23 @@ export async function isExecutable(filePath: string): Promise<boolean> {
1920
return false;
2021
}
2122
}
22-
const windowsExecutableExtensions: string[] = [
23+
24+
function resolveWindowsExecutableExtensions(configuredWindowsExecutableExtensions?: Object): string[] {
25+
const resolvedWindowsExecutableExtensions: string[] = windowsDefaultExecutableExtensions;
26+
const excluded = new Set<string>();
27+
if (configuredWindowsExecutableExtensions) {
28+
for (const [key, value] of Object.entries(configuredWindowsExecutableExtensions)) {
29+
if (value === true) {
30+
resolvedWindowsExecutableExtensions.push(key);
31+
} else {
32+
excluded.add(key);
33+
}
34+
}
35+
}
36+
return Array.from(new Set(resolvedWindowsExecutableExtensions)).filter(ext => !excluded.has(ext));
37+
}
38+
39+
export const windowsDefaultExecutableExtensions: string[] = [
2340
'.exe', // Executable file
2441
'.bat', // Batch file
2542
'.cmd', // Command script

extensions/terminal-suggest/src/terminalSuggestMain.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import { isExecutable } from './helpers/executable';
1515

1616
const isWindows = osIsWindows();
1717
let cachedAvailableCommandsPath: string | undefined;
18+
let cachedWindowsExecutableExtensions: Object | undefined;
19+
const cachedWindowsExecutableExtensionsSettingId = 'terminal.integrated.suggest.windowsExecutableExtensions';
1820
let cachedAvailableCommands: Set<ICompletionResource> | undefined;
1921
const cachedBuiltinCommands: Map<string, ICompletionResource[] | undefined> = new Map();
2022

@@ -110,8 +112,18 @@ export async function activate(context: vscode.ExtensionContext) {
110112
return result.items;
111113
}
112114
}, '/', '\\'));
113-
}
114115

116+
if (isWindows) {
117+
cachedWindowsExecutableExtensions = vscode.workspace.getConfiguration(cachedWindowsExecutableExtensionsSettingId);
118+
context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(e => {
119+
if (e.affectsConfiguration(cachedWindowsExecutableExtensionsSettingId)) {
120+
cachedWindowsExecutableExtensions = vscode.workspace.getConfiguration(cachedWindowsExecutableExtensionsSettingId);
121+
cachedAvailableCommands = undefined;
122+
cachedAvailableCommandsPath = undefined;
123+
}
124+
}));
125+
}
126+
}
115127

116128
/**
117129
* Adjusts the current working directory based on a given prefix if it is a folder.
@@ -221,7 +233,7 @@ async function getCommandsInPath(env: { [key: string]: string | undefined } = pr
221233
const files = await vscode.workspace.fs.readDirectory(fileResource);
222234
for (const [file, fileType] of files) {
223235
const formattedPath = getFriendlyFilePath(vscode.Uri.joinPath(fileResource, file), pathSeparator);
224-
if (!labels.has(file) && fileType !== vscode.FileType.Unknown && fileType !== vscode.FileType.Directory && await isExecutable(formattedPath)) {
236+
if (!labels.has(file) && fileType !== vscode.FileType.Unknown && fileType !== vscode.FileType.Directory && await isExecutable(formattedPath), cachedWindowsExecutableExtensions) {
225237
executables.add({ label: file, path: formattedPath });
226238
labels.add(file);
227239
}

src/vs/workbench/contrib/terminalContrib/suggest/common/terminalSuggestConfiguration.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,29 @@ export const enum TerminalSuggestSettingId {
1515
RunOnEnter = 'terminal.integrated.suggest.runOnEnter',
1616
BuiltinCompletions = 'terminal.integrated.suggest.builtinCompletions',
1717
EnableExtensionCompletions = 'terminal.integrated.suggest.enableExtensionCompletions',
18+
WindowsExecutableExtensions = 'terminal.integrated.suggest.windowsExecutableExtensions',
1819
Providers = 'terminal.integrated.suggest.providers',
1920
}
2021

22+
export const windowsDefaultExecutableExtensions: string[] = [
23+
'exe', // Executable file
24+
'bat', // Batch file
25+
'cmd', // Command script
26+
'com', // Command file
27+
28+
'msi', // Windows Installer package
29+
30+
'ps1', // PowerShell script
31+
32+
'vbs', // VBScript file
33+
'js', // JScript file
34+
'jar', // Java Archive (requires Java runtime)
35+
'py', // Python script (requires Python interpreter)
36+
'rb', // Ruby script (requires Ruby interpreter)
37+
'pl', // Perl script (requires Perl interpreter)
38+
'sh', // Shell script (via WSL or third-party tools)
39+
];
40+
2141
export const terminalSuggestConfigSection = 'terminal.integrated.suggest';
2242

2343
export interface ITerminalSuggestConfiguration {
@@ -106,4 +126,15 @@ export const terminalSuggestConfiguration: IStringDictionary<IConfigurationPrope
106126
default: false,
107127
tags: ['experimental'],
108128
},
129+
[TerminalSuggestSettingId.WindowsExecutableExtensions]: {
130+
restricted: true,
131+
markdownDescription: localize("terminalWindowsExecutableSuggestionSetting", "A set of windows command executable extensions that will be included as suggestions in the terminal. For example, `exe` and `bat`.\n\nMany executables are included by default, listed below:\n\n{0}.\n\nTo exclude an extension, set it to `false`\n\n. To include one not in the list, add it and set it to `true`.",
132+
windowsDefaultExecutableExtensions.sort().map(extension => `- ${extension}`).join('\n'),
133+
),
134+
type: 'object',
135+
default: {},
136+
tags: ['experimental'],
137+
}
109138
};
139+
140+

0 commit comments

Comments
 (0)