mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 09:08:48 +01:00
address terminal completion provider API feedback (#270249)
commit api feedback
This commit is contained in:
@@ -50,7 +50,7 @@ const postProcessRemoteBranches: Fig.Generator["postProcess"] = (out) => {
|
||||
return {
|
||||
name,
|
||||
description: "Branch",
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.Branch}`,
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.ScmBranch}`,
|
||||
priority: 75,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -89,7 +89,7 @@ const postProcessBranches =
|
||||
name: branch.replace("*", "").trim(),
|
||||
description: "Current branch",
|
||||
priority: 100,
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.Branch}`
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.ScmBranch}`
|
||||
};
|
||||
} else if (parts[0] === "+") {
|
||||
// Branch checked out in another worktree.
|
||||
@@ -112,7 +112,7 @@ const postProcessBranches =
|
||||
return {
|
||||
name,
|
||||
description,
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.Branch}`,
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.ScmBranch}`,
|
||||
priority: 75,
|
||||
};
|
||||
})
|
||||
@@ -148,7 +148,7 @@ export const gitGenerators = {
|
||||
return lines.map((line) => {
|
||||
return {
|
||||
name: line.substring(0, hashLength),
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.Commit}`,
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.ScmCommit}`,
|
||||
description: line.substring(descriptionStart),
|
||||
};
|
||||
});
|
||||
@@ -194,7 +194,7 @@ export const gitGenerators = {
|
||||
return output.split("\n").map((line) => {
|
||||
return {
|
||||
name: line.substring(0, 7),
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.Commit}`,
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.ScmCommit}`,
|
||||
description: line.substring(7),
|
||||
};
|
||||
});
|
||||
@@ -217,7 +217,7 @@ export const gitGenerators = {
|
||||
// account for conventional commit messages
|
||||
name: file.split(":").slice(2).join(":"),
|
||||
insertValue: file.split(":")[0],
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.Stash}`,
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.ScmStash}`,
|
||||
};
|
||||
});
|
||||
},
|
||||
@@ -329,7 +329,7 @@ export const gitGenerators = {
|
||||
return Object.keys(remoteURLs).map((remote) => {
|
||||
return {
|
||||
name: remote,
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.Remote}`,
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.ScmRemote}`,
|
||||
description: "Remote",
|
||||
};
|
||||
});
|
||||
@@ -347,7 +347,7 @@ export const gitGenerators = {
|
||||
postProcess: function (output) {
|
||||
return output.split("\n").map((tag) => ({
|
||||
name: tag,
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.Tag}`
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.ScmTag}`
|
||||
}));
|
||||
},
|
||||
} satisfies Fig.Generator,
|
||||
@@ -8117,7 +8117,7 @@ const completionSpec: Fig.Spec = {
|
||||
{
|
||||
name: "-",
|
||||
description: "Switch to the last used branch",
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.Branch}`
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.ScmBranch}`
|
||||
},
|
||||
{
|
||||
name: "--",
|
||||
@@ -9283,7 +9283,7 @@ const completionSpec: Fig.Spec = {
|
||||
{
|
||||
name: "-",
|
||||
description: "Switch to the last used branch",
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.Branch}`
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.ScmBranch}`
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -20,8 +20,8 @@ import { asArray, availableSpecs } from '../terminalSuggestMain';
|
||||
import { IFigExecuteExternals } from './execute';
|
||||
|
||||
export interface IFigSpecSuggestionsResult {
|
||||
filesRequested: boolean;
|
||||
foldersRequested: boolean;
|
||||
showFiles: boolean;
|
||||
showFolders: boolean;
|
||||
fileExtensions?: string[];
|
||||
hasCurrentArg: boolean;
|
||||
items: vscode.TerminalCompletionItem[];
|
||||
@@ -29,7 +29,7 @@ export interface IFigSpecSuggestionsResult {
|
||||
|
||||
export async function getFigSuggestions(
|
||||
specs: Fig.Spec[],
|
||||
terminalContext: { commandLine: string; cursorPosition: number },
|
||||
terminalContext: { commandLine: string; cursorIndex: number },
|
||||
availableCommands: ICompletionResource[],
|
||||
currentCommandAndArgString: string,
|
||||
tokenType: TokenType,
|
||||
@@ -40,8 +40,8 @@ export async function getFigSuggestions(
|
||||
token?: vscode.CancellationToken,
|
||||
): Promise<IFigSpecSuggestionsResult> {
|
||||
const result: IFigSpecSuggestionsResult = {
|
||||
filesRequested: false,
|
||||
foldersRequested: false,
|
||||
showFiles: false,
|
||||
showFolders: false,
|
||||
hasCurrentArg: false,
|
||||
items: [],
|
||||
};
|
||||
@@ -75,7 +75,7 @@ export async function getFigSuggestions(
|
||||
if (availableCommand.kind !== vscode.TerminalCompletionItemKind.Alias) {
|
||||
const description = getFixSuggestionDescription(spec);
|
||||
result.items.push(createCompletionItem(
|
||||
terminalContext.cursorPosition,
|
||||
terminalContext.cursorIndex,
|
||||
currentCommandAndArgString,
|
||||
{
|
||||
label: { label: specLabel, description },
|
||||
@@ -106,8 +106,8 @@ export async function getFigSuggestions(
|
||||
const completionItemResult = await getFigSpecSuggestions(actualSpec, terminalContext, currentCommandAndArgString, shellIntegrationCwd, env, name, executeExternals, token);
|
||||
result.hasCurrentArg ||= !!completionItemResult?.hasCurrentArg;
|
||||
if (completionItemResult) {
|
||||
result.filesRequested ||= completionItemResult.filesRequested;
|
||||
result.foldersRequested ||= completionItemResult.foldersRequested;
|
||||
result.showFiles ||= completionItemResult.showFiles;
|
||||
result.showFolders ||= completionItemResult.showFolders;
|
||||
result.fileExtensions ||= completionItemResult.fileExtensions;
|
||||
if (completionItemResult.items) {
|
||||
result.items = result.items.concat(completionItemResult.items);
|
||||
@@ -120,7 +120,7 @@ export async function getFigSuggestions(
|
||||
|
||||
async function getFigSpecSuggestions(
|
||||
spec: Fig.Spec,
|
||||
terminalContext: { commandLine: string; cursorPosition: number },
|
||||
terminalContext: { commandLine: string; cursorIndex: number },
|
||||
prefix: string,
|
||||
shellIntegrationCwd: vscode.Uri | undefined,
|
||||
env: Record<string, string>,
|
||||
@@ -128,11 +128,11 @@ async function getFigSpecSuggestions(
|
||||
executeExternals: IFigExecuteExternals,
|
||||
token?: vscode.CancellationToken,
|
||||
): Promise<IFigSpecSuggestionsResult | undefined> {
|
||||
let filesRequested = false;
|
||||
let foldersRequested = false;
|
||||
let showFiles = false;
|
||||
let showFolders = false;
|
||||
let fileExtensions: string[] | undefined;
|
||||
|
||||
const command = getCommand(terminalContext.commandLine, {}, terminalContext.cursorPosition);
|
||||
const command = getCommand(terminalContext.commandLine, {}, terminalContext.cursorIndex);
|
||||
if (!command || !shellIntegrationCwd) {
|
||||
return;
|
||||
}
|
||||
@@ -153,14 +153,14 @@ async function getFigSpecSuggestions(
|
||||
}
|
||||
|
||||
if (completionItemResult) {
|
||||
filesRequested = completionItemResult.filesRequested;
|
||||
foldersRequested = completionItemResult.foldersRequested;
|
||||
showFiles = completionItemResult.showFiles;
|
||||
showFolders = completionItemResult.showFolders;
|
||||
fileExtensions = completionItemResult.fileExtensions;
|
||||
}
|
||||
|
||||
return {
|
||||
filesRequested,
|
||||
foldersRequested,
|
||||
showFiles: showFiles,
|
||||
showFolders: showFolders,
|
||||
fileExtensions,
|
||||
hasCurrentArg: !!parsedArguments.currentArg,
|
||||
items,
|
||||
@@ -173,14 +173,14 @@ export async function collectCompletionItemResult(
|
||||
command: Command,
|
||||
parsedArguments: ArgumentParserResult,
|
||||
prefix: string,
|
||||
terminalContext: { commandLine: string; cursorPosition: number },
|
||||
terminalContext: { commandLine: string; cursorIndex: number },
|
||||
shellIntegrationCwd: vscode.Uri | undefined,
|
||||
env: Record<string, string>,
|
||||
items: vscode.TerminalCompletionItem[],
|
||||
executeExternals: IFigExecuteExternals
|
||||
): Promise<{ filesRequested: boolean; foldersRequested: boolean; fileExtensions: string[] | undefined } | undefined> {
|
||||
let filesRequested = false;
|
||||
let foldersRequested = false;
|
||||
): Promise<{ showFiles: boolean; showFolders: boolean; fileExtensions: string[] | undefined } | undefined> {
|
||||
let showFiles = false;
|
||||
let showFolders = false;
|
||||
let fileExtensions: string[] | undefined;
|
||||
|
||||
const addSuggestions = async (specArgs: SpecArg[] | Record<string, SpecArg> | undefined, kind: vscode.TerminalCompletionItemKind, parsedArguments?: ArgumentParserResult) => {
|
||||
@@ -188,7 +188,7 @@ export async function collectCompletionItemResult(
|
||||
const generators = parsedArguments.currentArg.generators;
|
||||
const initialFigState: FigState = {
|
||||
buffer: terminalContext.commandLine,
|
||||
cursorLocation: terminalContext.cursorPosition,
|
||||
cursorLocation: terminalContext.cursorIndex,
|
||||
cwd: shellIntegrationCwd?.fsPath ?? null,
|
||||
processUserIsIn: null,
|
||||
sshContextString: null,
|
||||
@@ -222,12 +222,12 @@ export async function collectCompletionItemResult(
|
||||
for (const generatorResult of generatorResults) {
|
||||
for (const item of (await generatorResult?.request) ?? []) {
|
||||
if (item.type === 'file') {
|
||||
filesRequested = true;
|
||||
foldersRequested = true;
|
||||
showFiles = true;
|
||||
showFolders = true;
|
||||
fileExtensions = item._internal?.fileExtensions as string[] | undefined;
|
||||
}
|
||||
if (item.type === 'folder') {
|
||||
foldersRequested = true;
|
||||
showFolders = true;
|
||||
}
|
||||
|
||||
if (!item.name) {
|
||||
@@ -239,7 +239,7 @@ export async function collectCompletionItemResult(
|
||||
}
|
||||
for (const label of suggestionLabels) {
|
||||
items.push(createCompletionItem(
|
||||
terminalContext.cursorPosition,
|
||||
terminalContext.cursorIndex,
|
||||
prefix,
|
||||
{ label },
|
||||
item.displayName,
|
||||
@@ -256,16 +256,16 @@ export async function collectCompletionItemResult(
|
||||
const templates = Array.isArray(generator.template) ? generator.template : [generator.template];
|
||||
for (const template of templates) {
|
||||
if (template === 'filepaths') {
|
||||
filesRequested = true;
|
||||
showFiles = true;
|
||||
} else if (template === 'folders') {
|
||||
foldersRequested = true;
|
||||
showFolders = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!specArgs) {
|
||||
return { filesRequested, foldersRequested };
|
||||
return { showFiles, showFolders };
|
||||
}
|
||||
const flagsToExclude = kind === vscode.TerminalCompletionItemKind.Flag ? parsedArguments?.passedOptions.map(option => option.name).flat() : undefined;
|
||||
|
||||
@@ -304,7 +304,7 @@ export async function collectCompletionItemResult(
|
||||
|
||||
items.push(
|
||||
createCompletionItem(
|
||||
terminalContext.cursorPosition,
|
||||
terminalContext.cursorIndex,
|
||||
prefix,
|
||||
{
|
||||
label: detail ? { label, detail } : label
|
||||
@@ -343,7 +343,7 @@ export async function collectCompletionItemResult(
|
||||
await addSuggestions(parsedArguments.completionObj.options, vscode.TerminalCompletionItemKind.Flag, parsedArguments);
|
||||
}
|
||||
|
||||
return { filesRequested, foldersRequested, fileExtensions };
|
||||
return { showFiles, showFolders, fileExtensions };
|
||||
}
|
||||
|
||||
function convertEnvRecordToArray(env: Record<string, string>): EnvironmentVariable[] {
|
||||
@@ -372,11 +372,11 @@ export function getFigSuggestionLabel(spec: Fig.Spec | Fig.Arg | Fig.Suggestion
|
||||
|
||||
function convertIconToKind(icon: string | undefined): vscode.TerminalCompletionItemKind | undefined {
|
||||
switch (icon) {
|
||||
case 'vscode://icon?type=10': return vscode.TerminalCompletionItemKind.Commit;
|
||||
case 'vscode://icon?type=11': return vscode.TerminalCompletionItemKind.Branch;
|
||||
case 'vscode://icon?type=12': return vscode.TerminalCompletionItemKind.Tag;
|
||||
case 'vscode://icon?type=13': return vscode.TerminalCompletionItemKind.Stash;
|
||||
case 'vscode://icon?type=14': return vscode.TerminalCompletionItemKind.Remote;
|
||||
case 'vscode://icon?type=10': return vscode.TerminalCompletionItemKind.ScmCommit;
|
||||
case 'vscode://icon?type=11': return vscode.TerminalCompletionItemKind.ScmBranch;
|
||||
case 'vscode://icon?type=12': return vscode.TerminalCompletionItemKind.ScmTag;
|
||||
case 'vscode://icon?type=13': return vscode.TerminalCompletionItemKind.ScmStash;
|
||||
case 'vscode://icon?type=14': return vscode.TerminalCompletionItemKind.ScmRemote;
|
||||
case 'vscode://icon?type=15': return vscode.TerminalCompletionItemKind.PullRequest;
|
||||
case 'vscode://icon?type=16': return vscode.TerminalCompletionItemKind.PullRequestDone;
|
||||
default: return undefined;
|
||||
|
||||
@@ -274,7 +274,7 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
}
|
||||
// Order is important here, add shell globals first so they are prioritized over path commands
|
||||
const commands = [...shellGlobals, ...commandsInPath.completionResources];
|
||||
const currentCommandString = getCurrentCommandAndArgs(terminalContext.commandLine, terminalContext.cursorPosition, terminalShellType);
|
||||
const currentCommandString = getCurrentCommandAndArgs(terminalContext.commandLine, terminalContext.cursorIndex, terminalShellType);
|
||||
const pathSeparator = isWindows ? '\\' : '/';
|
||||
const tokenType = getTokenType(terminalContext, terminalShellType);
|
||||
const result = await Promise.race([
|
||||
@@ -305,11 +305,11 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
}
|
||||
|
||||
const cwd = result.cwd ?? terminal.shellIntegration?.cwd;
|
||||
if (cwd && (result.filesRequested || result.foldersRequested)) {
|
||||
if (cwd && (result.showFiles || result.showFolders)) {
|
||||
const globPattern = createFileGlobPattern(result.fileExtensions);
|
||||
return new vscode.TerminalCompletionList(result.items, {
|
||||
filesRequested: result.filesRequested,
|
||||
foldersRequested: result.foldersRequested,
|
||||
showFiles: result.showFiles,
|
||||
showDirectories: result.showFolders,
|
||||
globPattern,
|
||||
cwd,
|
||||
});
|
||||
@@ -370,7 +370,7 @@ export async function resolveCwdFromCurrentCommandString(currentCommandString: s
|
||||
|
||||
// Retrurns the string that represents the current command and its arguments up to the cursor position.
|
||||
// Uses shell specific separators to determine the current command and its arguments.
|
||||
export function getCurrentCommandAndArgs(commandLine: string, cursorPosition: number, shellType: TerminalShellType | undefined): string {
|
||||
export function getCurrentCommandAndArgs(commandLine: string, cursorIndex: number, shellType: TerminalShellType | undefined): string {
|
||||
|
||||
// Return an empty string if the command line is empty after trimming
|
||||
if (commandLine.trim() === '') {
|
||||
@@ -378,12 +378,12 @@ export function getCurrentCommandAndArgs(commandLine: string, cursorPosition: nu
|
||||
}
|
||||
|
||||
// Check if cursor is not at the end and there's non-whitespace after the cursor
|
||||
if (cursorPosition < commandLine.length && /\S/.test(commandLine[cursorPosition])) {
|
||||
if (cursorIndex < commandLine.length && /\S/.test(commandLine[cursorIndex])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Extract the part of the line up to the cursor position
|
||||
const beforeCursor = commandLine.slice(0, cursorPosition);
|
||||
const beforeCursor = commandLine.slice(0, cursorIndex);
|
||||
|
||||
const resetChars = shellType ? shellTypeResetChars.get(shellType) ?? defaultShellTypeResetChars : defaultShellTypeResetChars;
|
||||
// Find the last reset character before the cursor
|
||||
@@ -419,10 +419,10 @@ export async function getCompletionItemsFromSpecs(
|
||||
name: string,
|
||||
token?: vscode.CancellationToken,
|
||||
executeExternals?: IFigExecuteExternals,
|
||||
): Promise<{ items: vscode.TerminalCompletionItem[]; filesRequested: boolean; foldersRequested: boolean; fileExtensions?: string[]; cwd?: vscode.Uri }> {
|
||||
): Promise<{ items: vscode.TerminalCompletionItem[]; showFiles: boolean; showFolders: boolean; fileExtensions?: string[]; cwd?: vscode.Uri }> {
|
||||
let items: vscode.TerminalCompletionItem[] = [];
|
||||
let filesRequested = false;
|
||||
let foldersRequested = false;
|
||||
let showFiles = false;
|
||||
let showFolders = false;
|
||||
let hasCurrentArg = false;
|
||||
let fileExtensions: string[] | undefined;
|
||||
|
||||
@@ -455,8 +455,8 @@ export async function getCompletionItemsFromSpecs(
|
||||
const result = await getFigSuggestions(specs, terminalContext, availableCommands, currentCommandString, tokenType, shellIntegrationCwd, env, name, executeExternalsWithFallback, token);
|
||||
if (result) {
|
||||
hasCurrentArg ||= result.hasCurrentArg;
|
||||
filesRequested ||= result.filesRequested;
|
||||
foldersRequested ||= result.foldersRequested;
|
||||
showFiles ||= result.showFiles;
|
||||
showFolders ||= result.showFolders;
|
||||
fileExtensions = result.fileExtensions;
|
||||
if (result.items) {
|
||||
items = items.concat(result.items);
|
||||
@@ -472,7 +472,7 @@ export async function getCompletionItemsFromSpecs(
|
||||
const labelWithoutExtension = isWindows ? commandTextLabel.replace(/\.[^ ]+$/, '') : commandTextLabel;
|
||||
if (!labels.has(labelWithoutExtension)) {
|
||||
items.push(createCompletionItem(
|
||||
terminalContext.cursorPosition,
|
||||
terminalContext.cursorIndex,
|
||||
currentCommandString,
|
||||
command,
|
||||
command.detail,
|
||||
@@ -491,23 +491,23 @@ export async function getCompletionItemsFromSpecs(
|
||||
existingItem.detail ??= command.detail;
|
||||
}
|
||||
}
|
||||
filesRequested = true;
|
||||
foldersRequested = true;
|
||||
showFiles = true;
|
||||
showFolders = true;
|
||||
}
|
||||
// For arguments when no fig suggestions are found these are fallback suggestions
|
||||
else if (!items.length && !filesRequested && !foldersRequested && !hasCurrentArg) {
|
||||
else if (!items.length && !showFiles && !showFolders && !hasCurrentArg) {
|
||||
if (terminalContext.allowFallbackCompletions) {
|
||||
filesRequested = true;
|
||||
foldersRequested = true;
|
||||
showFiles = true;
|
||||
showFolders = true;
|
||||
}
|
||||
}
|
||||
|
||||
let cwd: vscode.Uri | undefined;
|
||||
if (shellIntegrationCwd && (filesRequested || foldersRequested)) {
|
||||
if (shellIntegrationCwd && (showFiles || showFolders)) {
|
||||
cwd = await resolveCwdFromCurrentCommandString(currentCommandString, shellIntegrationCwd);
|
||||
}
|
||||
|
||||
return { items, filesRequested, foldersRequested, fileExtensions, cwd };
|
||||
return { items, showFiles: showFiles, showFolders: showFolders, fileExtensions, cwd };
|
||||
}
|
||||
|
||||
function getEnvAsRecord(shellIntegrationEnv: ITerminalEnvironment): Record<string, string> {
|
||||
@@ -564,7 +564,7 @@ export function sanitizeProcessEnvironment(env: Record<string, string>, ...prese
|
||||
});
|
||||
}
|
||||
|
||||
function createFileGlobPattern(fileExtensions?: string[]): vscode.GlobPattern | undefined {
|
||||
function createFileGlobPattern(fileExtensions?: string[]): string | undefined {
|
||||
if (!fileExtensions || fileExtensions.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -91,11 +91,11 @@ suite('Terminal Suggest', () => {
|
||||
}
|
||||
test(`'${testSpec.input}' -> ${expectedString}`, async () => {
|
||||
const commandLine = testSpec.input.split('|')[0];
|
||||
const cursorPosition = testSpec.input.indexOf('|');
|
||||
const currentCommandString = getCurrentCommandAndArgs(commandLine, cursorPosition, undefined);
|
||||
const filesRequested = testSpec.expectedResourceRequests?.type === 'files' || testSpec.expectedResourceRequests?.type === 'both';
|
||||
const foldersRequested = testSpec.expectedResourceRequests?.type === 'folders' || testSpec.expectedResourceRequests?.type === 'both';
|
||||
const terminalContext = { commandLine, cursorPosition, allowFallbackCompletions: true };
|
||||
const cursorIndex = testSpec.input.indexOf('|');
|
||||
const currentCommandString = getCurrentCommandAndArgs(commandLine, cursorIndex, undefined);
|
||||
const showFiles = testSpec.expectedResourceRequests?.type === 'files' || testSpec.expectedResourceRequests?.type === 'both';
|
||||
const showFolders = testSpec.expectedResourceRequests?.type === 'folders' || testSpec.expectedResourceRequests?.type === 'both';
|
||||
const terminalContext = { commandLine, cursorIndex, allowFallbackCompletions: true };
|
||||
const result = await getCompletionItemsFromSpecs(
|
||||
completionSpecs,
|
||||
terminalContext,
|
||||
@@ -118,8 +118,8 @@ suite('Terminal Suggest', () => {
|
||||
}).sort(),
|
||||
(testSpec.expectedCompletions ?? []).sort()
|
||||
);
|
||||
strictEqual(result.filesRequested, filesRequested, 'Files requested different than expected, got: ' + result.filesRequested);
|
||||
strictEqual(result.foldersRequested, foldersRequested, 'Folders requested different than expected, got: ' + result.foldersRequested);
|
||||
strictEqual(result.showFiles, showFiles, 'Show files different than expected, got: ' + result.showFiles);
|
||||
strictEqual(result.showFolders, showFolders, 'Show folders different than expected, got: ' + result.showFolders);
|
||||
if (testSpec.expectedResourceRequests?.cwd) {
|
||||
strictEqual(result.cwd?.fsPath, testSpec.expectedResourceRequests.cwd.fsPath, 'Non matching cwd');
|
||||
}
|
||||
|
||||
@@ -10,91 +10,91 @@ import { TerminalShellType } from '../terminalSuggestMain';
|
||||
|
||||
suite('Terminal Suggest', () => {
|
||||
test('simple command', () => {
|
||||
strictEqual(getTokenType({ commandLine: 'echo', cursorPosition: 'echo'.length }, undefined), TokenType.Command);
|
||||
strictEqual(getTokenType({ commandLine: 'echo', cursorIndex: 'echo'.length }, undefined), TokenType.Command);
|
||||
});
|
||||
test('simple argument', () => {
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello', cursorPosition: 'echo hello'.length }, undefined), TokenType.Argument);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello', cursorIndex: 'echo hello'.length }, undefined), TokenType.Argument);
|
||||
});
|
||||
test('simple command, cursor mid text', () => {
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello', cursorPosition: 'echo'.length }, undefined), TokenType.Command);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello', cursorIndex: 'echo'.length }, undefined), TokenType.Command);
|
||||
});
|
||||
test('simple argument, cursor mid text', () => {
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello', cursorPosition: 'echo hel'.length }, undefined), TokenType.Argument);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello', cursorIndex: 'echo hel'.length }, undefined), TokenType.Argument);
|
||||
});
|
||||
suite('reset to command', () => {
|
||||
test('|', () => {
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello | ', cursorPosition: 'echo hello | '.length }, undefined), TokenType.Command);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello | ', cursorIndex: 'echo hello | '.length }, undefined), TokenType.Command);
|
||||
});
|
||||
test(';', () => {
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello; ', cursorPosition: 'echo hello; '.length }, undefined), TokenType.Command);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello; ', cursorIndex: 'echo hello; '.length }, undefined), TokenType.Command);
|
||||
});
|
||||
test('&&', () => {
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && ', cursorPosition: 'echo hello && '.length }, undefined), TokenType.Command);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && ', cursorIndex: 'echo hello && '.length }, undefined), TokenType.Command);
|
||||
});
|
||||
test('||', () => {
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello || ', cursorPosition: 'echo hello || '.length }, undefined), TokenType.Command);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello || ', cursorIndex: 'echo hello || '.length }, undefined), TokenType.Command);
|
||||
});
|
||||
});
|
||||
suite('pwsh', () => {
|
||||
test('simple command', () => {
|
||||
strictEqual(getTokenType({ commandLine: 'Write-Host', cursorPosition: 'Write-Host'.length }, TerminalShellType.PowerShell), TokenType.Command);
|
||||
strictEqual(getTokenType({ commandLine: 'Write-Host', cursorIndex: 'Write-Host'.length }, TerminalShellType.PowerShell), TokenType.Command);
|
||||
});
|
||||
test('simple argument', () => {
|
||||
strictEqual(getTokenType({ commandLine: 'Write-Host hello', cursorPosition: 'Write-Host hello'.length }, TerminalShellType.PowerShell), TokenType.Argument);
|
||||
strictEqual(getTokenType({ commandLine: 'Write-Host hello', cursorIndex: 'Write-Host hello'.length }, TerminalShellType.PowerShell), TokenType.Argument);
|
||||
});
|
||||
test('reset char', () => {
|
||||
strictEqual(getTokenType({ commandLine: `Write-Host hello -and `, cursorPosition: `Write-Host hello -and `.length }, TerminalShellType.PowerShell), TokenType.Command);
|
||||
strictEqual(getTokenType({ commandLine: `Write-Host hello -and `, cursorIndex: `Write-Host hello -and `.length }, TerminalShellType.PowerShell), TokenType.Command);
|
||||
});
|
||||
test('arguments after reset char', () => {
|
||||
strictEqual(getTokenType({ commandLine: `Write-Host hello -and $true `, cursorPosition: `Write-Host hello -and $true `.length }, TerminalShellType.PowerShell), TokenType.Argument);
|
||||
strictEqual(getTokenType({ commandLine: `Write-Host hello -and $true `, cursorIndex: `Write-Host hello -and $true `.length }, TerminalShellType.PowerShell), TokenType.Argument);
|
||||
});
|
||||
test('; reset char', () => {
|
||||
strictEqual(getTokenType({ commandLine: `Write-Host hello; `, cursorPosition: `Write-Host hello; `.length }, TerminalShellType.PowerShell), TokenType.Command);
|
||||
strictEqual(getTokenType({ commandLine: `Write-Host hello; `, cursorIndex: `Write-Host hello; `.length }, TerminalShellType.PowerShell), TokenType.Command);
|
||||
});
|
||||
suite('multiple commands on the line', () => {
|
||||
test('multiple commands, cursor at end', () => {
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world', cursorPosition: 'echo hello && ech'.length }, undefined), TokenType.Command);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world', cursorIndex: 'echo hello && ech'.length }, undefined), TokenType.Command);
|
||||
// Bash
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world', cursorPosition: 'echo hello && ech'.length }, TerminalShellType.Bash), TokenType.Command);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world', cursorIndex: 'echo hello && ech'.length }, TerminalShellType.Bash), TokenType.Command);
|
||||
// Zsh
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world', cursorPosition: 'echo hello && ech'.length }, TerminalShellType.Zsh), TokenType.Command);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world', cursorIndex: 'echo hello && ech'.length }, TerminalShellType.Zsh), TokenType.Command);
|
||||
// Fish (use ';' as separator)
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello; echo world', cursorPosition: 'echo hello; ech'.length }, TerminalShellType.Fish), TokenType.Command);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello; echo world', cursorIndex: 'echo hello; ech'.length }, TerminalShellType.Fish), TokenType.Command);
|
||||
// PowerShell (use ';' as separator)
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello; echo world', cursorPosition: 'echo hello; ech'.length }, TerminalShellType.PowerShell), TokenType.Command);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello; echo world', cursorIndex: 'echo hello; ech'.length }, TerminalShellType.PowerShell), TokenType.Command);
|
||||
});
|
||||
test('multiple commands, cursor mid text', () => {
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world', cursorPosition: 'echo hello && echo w'.length }, undefined), TokenType.Argument);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world', cursorIndex: 'echo hello && echo w'.length }, undefined), TokenType.Argument);
|
||||
// Bash
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world', cursorPosition: 'echo hello && echo w'.length }, TerminalShellType.Bash), TokenType.Argument);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world', cursorIndex: 'echo hello && echo w'.length }, TerminalShellType.Bash), TokenType.Argument);
|
||||
// Zsh
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world', cursorPosition: 'echo hello && echo w'.length }, TerminalShellType.Zsh), TokenType.Argument);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world', cursorIndex: 'echo hello && echo w'.length }, TerminalShellType.Zsh), TokenType.Argument);
|
||||
// Fish (use ';' as separator)
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello; echo world', cursorPosition: 'echo hello; echo w'.length }, TerminalShellType.Fish), TokenType.Argument);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello; echo world', cursorIndex: 'echo hello; echo w'.length }, TerminalShellType.Fish), TokenType.Argument);
|
||||
// PowerShell (use ';' as separator)
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello; echo world', cursorPosition: 'echo hello; echo w'.length }, TerminalShellType.PowerShell), TokenType.Argument);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello; echo world', cursorIndex: 'echo hello; echo w'.length }, TerminalShellType.PowerShell), TokenType.Argument);
|
||||
});
|
||||
test('multiple commands, cursor at end with reset char', () => {
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world; ', cursorPosition: 'echo hello && echo world; '.length }, undefined), TokenType.Command);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world; ', cursorIndex: 'echo hello && echo world; '.length }, undefined), TokenType.Command);
|
||||
// Bash
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world; ', cursorPosition: 'echo hello && echo world; '.length }, TerminalShellType.Bash), TokenType.Command);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world; ', cursorIndex: 'echo hello && echo world; '.length }, TerminalShellType.Bash), TokenType.Command);
|
||||
// Zsh
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world; ', cursorPosition: 'echo hello && echo world; '.length }, TerminalShellType.Zsh), TokenType.Command);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world; ', cursorIndex: 'echo hello && echo world; '.length }, TerminalShellType.Zsh), TokenType.Command);
|
||||
// Fish (use ';' as separator)
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello; echo world; ', cursorPosition: 'echo hello; echo world; '.length }, TerminalShellType.Fish), TokenType.Command);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello; echo world; ', cursorIndex: 'echo hello; echo world; '.length }, TerminalShellType.Fish), TokenType.Command);
|
||||
// PowerShell (use ';' as separator)
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello; echo world; ', cursorPosition: 'echo hello; echo world; '.length }, TerminalShellType.PowerShell), TokenType.Command);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello; echo world; ', cursorIndex: 'echo hello; echo world; '.length }, TerminalShellType.PowerShell), TokenType.Command);
|
||||
});
|
||||
test('multiple commands, cursor mid text with reset char', () => {
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world; ', cursorPosition: 'echo hello && echo worl'.length }, undefined), TokenType.Argument);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world; ', cursorIndex: 'echo hello && echo worl'.length }, undefined), TokenType.Argument);
|
||||
// Bash
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world; ', cursorPosition: 'echo hello && echo worl'.length }, TerminalShellType.Bash), TokenType.Argument);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world; ', cursorIndex: 'echo hello && echo worl'.length }, TerminalShellType.Bash), TokenType.Argument);
|
||||
// Zsh
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world; ', cursorPosition: 'echo hello && echo worl'.length }, TerminalShellType.Zsh), TokenType.Argument);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello && echo world; ', cursorIndex: 'echo hello && echo worl'.length }, TerminalShellType.Zsh), TokenType.Argument);
|
||||
// Fish (use ';' as separator)
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello; echo world; ', cursorPosition: 'echo hello; echo worl'.length }, TerminalShellType.Fish), TokenType.Argument);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello; echo world; ', cursorIndex: 'echo hello; echo worl'.length }, TerminalShellType.Fish), TokenType.Argument);
|
||||
// PowerShell (use ';' as separator)
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello; echo world; ', cursorPosition: 'echo hello; echo worl'.length }, TerminalShellType.PowerShell), TokenType.Argument);
|
||||
strictEqual(getTokenType({ commandLine: 'echo hello; echo world; ', cursorIndex: 'echo hello; echo worl'.length }, TerminalShellType.PowerShell), TokenType.Argument);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -19,9 +19,9 @@ export const shellTypeResetChars = new Map<TerminalShellType, string[]>([
|
||||
|
||||
export const defaultShellTypeResetChars = shellTypeResetChars.get(TerminalShellType.Bash)!;
|
||||
|
||||
export function getTokenType(ctx: { commandLine: string; cursorPosition: number }, shellType: TerminalShellType | undefined): TokenType {
|
||||
export function getTokenType(ctx: { commandLine: string; cursorIndex: number }, shellType: TerminalShellType | undefined): TokenType {
|
||||
const commandLine = ctx.commandLine;
|
||||
const cursorPosition = ctx.cursorPosition;
|
||||
const cursorPosition = ctx.cursorIndex;
|
||||
const commandResetChars = shellType === undefined ? defaultShellTypeResetChars : shellTypeResetChars.get(shellType) ?? defaultShellTypeResetChars;
|
||||
|
||||
// Check for reset char before the current word
|
||||
|
||||
Reference in New Issue
Block a user