mirror of
https://github.com/microsoft/vscode.git
synced 2025-12-20 02:08:47 +00:00
@@ -135,10 +135,18 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
const commands = [...commandsInPath.completionResources, ...builtinCommands];
|
||||
|
||||
const prefix = getPrefix(terminalContext.commandLine, terminalContext.cursorPosition);
|
||||
|
||||
const pathSeparator = isWindows ? '\\' : '/';
|
||||
const result = await getCompletionItemsFromSpecs(availableSpecs, terminalContext, commands, prefix, terminal.shellIntegration?.cwd, token);
|
||||
if (terminal.shellIntegration?.env) {
|
||||
const homeDirCompletion = result.items.find(i => i.label === '~');
|
||||
if (homeDirCompletion && terminal.shellIntegration.env.HOME) {
|
||||
homeDirCompletion.documentation = getFriendlyResourcePath(vscode.Uri.file(terminal.shellIntegration.env.HOME), pathSeparator, vscode.TerminalCompletionItemKind.Folder);
|
||||
homeDirCompletion.kind = vscode.TerminalCompletionItemKind.Folder;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.cwd && (result.filesRequested || result.foldersRequested)) {
|
||||
return new vscode.TerminalCompletionList(result.items, { filesRequested: result.filesRequested, foldersRequested: result.foldersRequested, cwd: result.cwd, pathSeparator: isWindows ? '\\' : '/' });
|
||||
return new vscode.TerminalCompletionList(result.items, { filesRequested: result.filesRequested, foldersRequested: result.foldersRequested, cwd: result.cwd, pathSeparator: isWindows ? '\\' : '/', env: terminal.shellIntegration?.env });
|
||||
}
|
||||
return result.items;
|
||||
}
|
||||
@@ -269,7 +277,7 @@ async function getCommandsInPath(env: { [key: string]: string | undefined } = pr
|
||||
const fileResource = vscode.Uri.file(path);
|
||||
const files = await vscode.workspace.fs.readDirectory(fileResource);
|
||||
for (const [file, fileType] of files) {
|
||||
const formattedPath = getFriendlyFilePath(vscode.Uri.joinPath(fileResource, file), pathSeparator);
|
||||
const formattedPath = getFriendlyResourcePath(vscode.Uri.joinPath(fileResource, file), pathSeparator);
|
||||
if (!labels.has(file) && fileType !== vscode.FileType.Unknown && fileType !== vscode.FileType.Directory && await isExecutable(formattedPath, cachedWindowsExecutableExtensions)) {
|
||||
executables.add({ label: file, detail: formattedPath });
|
||||
labels.add(file);
|
||||
@@ -539,12 +547,17 @@ function getFirstCommand(commandLine: string): string | undefined {
|
||||
return firstCommand;
|
||||
}
|
||||
|
||||
function getFriendlyFilePath(uri: vscode.Uri, pathSeparator: string): string {
|
||||
function getFriendlyResourcePath(uri: vscode.Uri, pathSeparator: string, kind?: vscode.TerminalCompletionItemKind): string {
|
||||
let path = uri.fsPath;
|
||||
// Ensure drive is capitalized on Windows
|
||||
if (pathSeparator === '\\' && path.match(/^[a-zA-Z]:\\/)) {
|
||||
path = `${path[0].toUpperCase()}:${path.slice(2)}`;
|
||||
}
|
||||
if (kind === vscode.TerminalCompletionItemKind.Folder) {
|
||||
if (!path.endsWith(pathSeparator)) {
|
||||
path += pathSeparator;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ export interface TerminalResourceRequestConfig {
|
||||
cwd?: URI;
|
||||
pathSeparator: string;
|
||||
shouldNormalizePrefix?: boolean;
|
||||
env?: { [key: string]: string | null | undefined };
|
||||
}
|
||||
|
||||
|
||||
@@ -246,6 +247,24 @@ export class TerminalCompletionService extends Disposable implements ITerminalCo
|
||||
|
||||
const lastWordFolderHasDotPrefix = lastWordFolder.match(/^\.\.?[\\\/]/);
|
||||
|
||||
const lastWordFolderHasTildePrefix = lastWordFolder.match(/^~[\\\/]/);
|
||||
if (lastWordFolderHasTildePrefix) {
|
||||
// Handle specially
|
||||
const resolvedFolder = resourceRequestConfig.env?.HOME ? URI.file(resourceRequestConfig.env.HOME) : undefined;
|
||||
if (resolvedFolder) {
|
||||
resourceCompletions.push({
|
||||
label: lastWordFolder,
|
||||
provider,
|
||||
kind: TerminalCompletionItemKind.Folder,
|
||||
isDirectory: true,
|
||||
isFile: false,
|
||||
detail: getFriendlyPath(resolvedFolder, resourceRequestConfig.pathSeparator),
|
||||
replacementIndex: cursorPosition - lastWord.length,
|
||||
replacementLength: lastWord.length
|
||||
});
|
||||
return resourceCompletions;
|
||||
}
|
||||
}
|
||||
// Add current directory. This should be shown at the top because it will be an exact match
|
||||
// and therefore highlight the detail, plus it improves the experience when runOnEnter is
|
||||
// used.
|
||||
|
||||
@@ -162,6 +162,20 @@ suite('TerminalCompletionService', () => {
|
||||
{ label: './../', detail: '/' },
|
||||
], { replacementIndex: 3, replacementLength: 3 });
|
||||
});
|
||||
test('cd ~/| should return home folder completions', async () => {
|
||||
const resourceRequestConfig: TerminalResourceRequestConfig = {
|
||||
cwd: URI.parse('file:///test/folder1'),// Updated to reflect home directory
|
||||
foldersRequested: true,
|
||||
pathSeparator,
|
||||
shouldNormalizePrefix: true,
|
||||
env: { HOME: '/test/' }
|
||||
};
|
||||
const result = await terminalCompletionService.resolveResources(resourceRequestConfig, 'cd ~/', 5, provider);
|
||||
|
||||
assertCompletions(result, [
|
||||
{ label: '~/', detail: '/test/' },
|
||||
], { replacementIndex: 3, replacementLength: 2 });
|
||||
});
|
||||
});
|
||||
|
||||
suite('resolveResources should handle file and folder completion requests correctly', () => {
|
||||
|
||||
@@ -128,5 +128,9 @@ declare module 'vscode' {
|
||||
* The path separator to use when constructing paths.
|
||||
*/
|
||||
pathSeparator: string;
|
||||
/**
|
||||
* Environment variables to use when constructing paths.
|
||||
*/
|
||||
env?: { [key: string]: string | null | undefined };
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user