Skip to content

Commit

Permalink
feat: cd directory only autocomplete
Browse files Browse the repository at this point in the history
  • Loading branch information
JoelEinbinder committed Apr 29, 2024
1 parent 3dc9620 commit e5e8127
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 4 deletions.
12 changes: 8 additions & 4 deletions src/shellCompleter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ registry.set('sudo', async (shell, line, abortSignal) => {
};
});

registry.set('cd', async (shell, line, abortSignal) => {
return fileCompleter(shell, line, { directoriesOnly: true });
});

export function makeShellCompleter(shell: Shell): Completer {
return async (line: string, abortSignal: AbortSignal) => {
const {getAutocompletePrefix} = await import('../slug/shjs/transform');
Expand All @@ -29,7 +33,7 @@ export function makeShellCompleter(shell: Shell): Completer {
const prefixText = line.slice(prefix.start, prefix.end);
if (prefixText === '' || (prefix.isSh && !prefixText.includes(' '))) {
if (line.includes('/'))
result = await fileCompleter(shell, line, true);
result = await fileCompleter(shell, line, {executablesOnly: true});
else
result = await commandCompleter(shell, line);
return {
Expand All @@ -52,7 +56,7 @@ export function makeShellCompleter(shell: Shell): Completer {
if (!result && registry.has(command))
result = await registry.get(command)(shell, prefixText, abortSignal);
if (!result)
result = await fileCompleter(shell, prefixText, false);
result = await fileCompleter(shell, prefixText);
return {
anchor: prefix.start + result.anchor,
suggestions: result.suggestions,
Expand Down Expand Up @@ -122,13 +126,13 @@ async function commandCompleter(shell: Shell, line: string) {
}
}

async function fileCompleter(shell: Shell, line: string, executablesOnly: boolean): ReturnType<Completer> {
async function fileCompleter(shell: Shell, line: string, {executablesOnly, directoriesOnly}: {executablesOnly?: boolean, directoriesOnly?: boolean} = {}): ReturnType<Completer> {
const pathStart = lastIndexIgnoringEscapes(line, ' ') + 1;
const path = line.substring(pathStart);
const anchor = path.lastIndexOf('/') + 1 + pathStart;
const prefix = path.substring(0, anchor - pathStart);
const files = await parseCompletions(!executablesOnly ? `__file_completions all ${prefix}` : `__file_completions executable ${prefix}`);
const directories = new Set(await parseCompletions(`__file_completions directory ${prefix}`));
const files = directoriesOnly ? [...directories] : await parseCompletions(!executablesOnly ? `__file_completions all ${prefix}` : `__file_completions executable ${prefix}`);
const suggestions: Suggestion[] = [];
if (!path || path === '.')
files.push('.');
Expand Down
8 changes: 8 additions & 0 deletions tests/shell.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ test('sees aliases in autocomplete', async ({ shell }) => {
expect((await shell.serialize()).prompt.autocomplete).toEqual(['my_alias_for_test']);
});

test('has only directories in cd autocomplete', async ({ shell, workingDir }) => {
await shell.runCommand(`cd ${workingDir}; mkdir a b c; touch d e f; mkdir a/sub_a`);
await shell.typeInPrompt('cd ');
expect((await shell.serialize()).prompt.autocomplete).toEqual(['', 'a', 'b', 'c', '.']);
await shell.typeInPrompt('a/');
expect((await shell.serialize()).prompt.autocomplete).toEqual(['', 'sub_a']);
});

test('sees filter autocomplete properly', async ({ shell }) => {
await shell.runCommand('export FOO_BAR=123; export FOO_BAZ=456; export NOT_THIS=789;');
await shell.typeInPrompt('echo $FOO_');
Expand Down

0 comments on commit e5e8127

Please sign in to comment.