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
1 change: 1 addition & 0 deletions extensions/terminal-suggest/src/fig/figInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ export async function collectCompletionItemResult(
}
if (parsedArguments.suggestionFlags & SuggestionFlag.Options) {
await addSuggestions(parsedArguments.completionObj.options, vscode.TerminalCompletionItemKind.Flag, parsedArguments);
await addSuggestions(parsedArguments.completionObj.persistentOptions, vscode.TerminalCompletionItemKind.Flag, parsedArguments);
}

return { showFiles, showFolders, fileExtensions };
Expand Down
50 changes: 50 additions & 0 deletions extensions/terminal-suggest/src/test/fig.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,56 @@ export const figGenericTestSuites: ISuiteSpec[] = [
{ input: 'foo b|', expectedCompletions: ['b', 'foo'] },
{ input: 'foo c|', expectedCompletions: ['c', 'foo'] },
]
},
{
name: 'Fig persistent options',
completionSpecs: [
{
name: 'foo',
description: 'Foo',
options: [
{ name: '--help', description: 'Show help', isPersistent: true },
{ name: '--docs', description: 'Show docs' },
{ name: '--version', description: 'Version info', isPersistent: false }
],
subcommands: [
{
name: 'bar',
description: 'Bar subcommand',
options: [
{ name: '--local', description: 'Local option' }
]
},
{
name: 'baz',
description: 'Baz subcommand',
options: [
{ name: '--another', description: 'Another option' }
],
subcommands: [
{
name: 'nested',
description: 'Nested subcommand'
}
]
}
]
}
],
availableCommands: 'foo',
testSpecs: [
// Top-level should show all options including persistent
{ input: 'foo |', expectedCompletions: ['--help', '--docs', '--version', 'bar', 'baz'] },
// First-level subcommand should only inherit persistent options (not --docs or --version)
{ input: 'foo bar |', expectedCompletions: ['--help', '--local'] },
// Another first-level subcommand should also inherit only persistent options
{ input: 'foo baz |', expectedCompletions: ['--help', '--another', 'nested'] },
// Nested subcommand should inherit persistent options from top level
{ input: 'foo baz nested |', expectedCompletions: ['--help'] },
// Persistent options should be available even after using local options
{ input: 'foo bar --local |', expectedCompletions: ['--help'] },
]
}
];


Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,16 @@ const compareCompletionsFn = (leadingLineContent: string, a: TerminalCompletionI
if ((b.completion.kind === TerminalCompletionItemKind.Method || b.completion.kind === TerminalCompletionItemKind.Alias) && (a.completion.kind !== TerminalCompletionItemKind.Method && a.completion.kind !== TerminalCompletionItemKind.Alias)) {
return 1; // Methods and aliases should come first
}
if ((a.completion.kind === TerminalCompletionItemKind.File || a.completion.kind === TerminalCompletionItemKind.Folder) && (b.completion.kind !== TerminalCompletionItemKind.File && b.completion.kind !== TerminalCompletionItemKind.Folder)) {
if (a.completion.kind === TerminalCompletionItemKind.Argument && b.completion.kind !== TerminalCompletionItemKind.Argument) {
return -1; // Arguments should come before other kinds
}
if (b.completion.kind === TerminalCompletionItemKind.Argument && a.completion.kind !== TerminalCompletionItemKind.Argument) {
return 1; // Arguments should come before other kinds
}
if (isResourceKind(a.completion.kind) && !isResourceKind(b.completion.kind)) {
return 1; // Resources should come last
}
if ((b.completion.kind === TerminalCompletionItemKind.File || b.completion.kind === TerminalCompletionItemKind.Folder) && (a.completion.kind !== TerminalCompletionItemKind.File && a.completion.kind !== TerminalCompletionItemKind.Folder)) {
if (isResourceKind(b.completion.kind) && !isResourceKind(a.completion.kind)) {
return -1; // Resources should come last
}
}
Expand All @@ -143,6 +149,12 @@ const compareCompletionsFn = (leadingLineContent: string, a: TerminalCompletionI
return a.labelLow.localeCompare(b.labelLow, undefined, { ignorePunctuation: true });
};

const isResourceKind = (kind: TerminalCompletionItemKind | undefined) =>
kind === TerminalCompletionItemKind.File ||
kind === TerminalCompletionItemKind.Folder ||
kind === TerminalCompletionItemKind.SymbolicLinkFile ||
kind === TerminalCompletionItemKind.SymbolicLinkFolder;

// TODO: This should be based on the process OS, not the local OS
// File score boosts for specific file extensions on Windows. This only applies when the file is the
// _first_ part of the command line.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -360,4 +360,35 @@ suite('TerminalCompletionModel', function () {
assertItems(model, ['main', 'master', 'dev']);
});
});

suite('mixed kind sorting', () => {
test('should sort arguments before flags and options', () => {
const items = [
createItem({ kind: TerminalCompletionItemKind.Flag, label: '--verbose' }),
createItem({ kind: TerminalCompletionItemKind.Option, label: '--config' }),
createItem({ kind: TerminalCompletionItemKind.Argument, label: 'value2' }),
createItem({ kind: TerminalCompletionItemKind.Argument, label: 'value1' }),
createItem({ kind: TerminalCompletionItemKind.Flag, label: '--all' }),
];
const model = new TerminalCompletionModel(items, new LineContext('cmd ', 0));
assertItems(model, ['value1', 'value2', '--all', '--config', '--verbose']);
});

test('should sort by kind hierarchy: methods/aliases, arguments, others, files/folders', () => {
const items = [
createItem({ kind: TerminalCompletionItemKind.File, label: 'file.txt' }),
createItem({ kind: TerminalCompletionItemKind.Flag, label: '--flag' }),
createItem({ kind: TerminalCompletionItemKind.Argument, label: 'arg' }),
createItem({ kind: TerminalCompletionItemKind.Method, label: 'method' }),
createItem({ kind: TerminalCompletionItemKind.Folder, label: 'folder/' }),
createItem({ kind: TerminalCompletionItemKind.Option, label: '--option' }),
createItem({ kind: TerminalCompletionItemKind.Alias, label: 'alias' }),
createItem({ kind: TerminalCompletionItemKind.SymbolicLinkFile, label: 'file2.txt' }),
createItem({ kind: TerminalCompletionItemKind.SymbolicLinkFolder, label: 'folder2/' }),
];
const model = new TerminalCompletionModel(items, new LineContext('', 0));
assertItems(model, ['alias', 'method', 'arg', '--flag', '--option', 'file2.txt', 'file.txt', 'folder/', 'folder2/']);
});
});
});

Loading