Add ~/ completion (#238727)

part of #234352
This commit is contained in:
Megan Rogge
2025-01-24 16:24:25 -06:00
committed by GitHub
parent 7cb0aa04f2
commit eefe484351
4 changed files with 54 additions and 4 deletions

View File

@@ -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;
}

View File

@@ -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.

View File

@@ -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', () => {

View File

@@ -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 };
}
}