mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-27 12:36:14 +01:00
add completion generation for zsh (#137)
This commit is contained in:
parent
3d11b635d8
commit
723ff201f6
135
src/commands/completion.command.ts
Normal file
135
src/commands/completion.command.ts
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
import * as program from "commander";
|
||||||
|
import { Response } from "jslib/cli/models/response";
|
||||||
|
import { MessageResponse } from "jslib/cli/models/response/messageResponse";
|
||||||
|
|
||||||
|
type Option = {
|
||||||
|
long: string;
|
||||||
|
short: string;
|
||||||
|
description: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Command = {
|
||||||
|
commands?: Command[];
|
||||||
|
options?: Option[];
|
||||||
|
_name: string;
|
||||||
|
_description: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const zshCompletion = (rootName: string, rootCommand: Command) => {
|
||||||
|
const renderCommandBlock = (name: string, command: Command): string => {
|
||||||
|
const { commands = [], options = [] } = command;
|
||||||
|
const hasOptions = options.length > 0;
|
||||||
|
const hasCommands = commands.length > 0;
|
||||||
|
|
||||||
|
const _arguments = options
|
||||||
|
.map(({ long, short, description }) => {
|
||||||
|
const aliases = [short, long].filter(Boolean);
|
||||||
|
|
||||||
|
const OPTS = aliases.join(",");
|
||||||
|
|
||||||
|
const DESCRIPTION = `[${description.replace("'", `'"'"'`)}]`;
|
||||||
|
|
||||||
|
return aliases.length > 1
|
||||||
|
? `'(${aliases.join(" ")})'{${OPTS}}'${DESCRIPTION}'`
|
||||||
|
: `'${OPTS}${DESCRIPTION}'`;
|
||||||
|
})
|
||||||
|
.concat(
|
||||||
|
`'(-h --help)'{-h,--help}'[output usage information]'`,
|
||||||
|
hasCommands ? '"1: :->cmnds"' : null,
|
||||||
|
'"*::arg:->args"'
|
||||||
|
)
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
const commandBlockFunctionParts = [];
|
||||||
|
|
||||||
|
if (hasCommands) {
|
||||||
|
commandBlockFunctionParts.push("local -a commands");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasOptions) {
|
||||||
|
commandBlockFunctionParts.push(
|
||||||
|
`_arguments -C \\\n ${_arguments.join(` \\\n `)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasCommands) {
|
||||||
|
commandBlockFunctionParts.push(
|
||||||
|
`case $state in
|
||||||
|
cmnds)
|
||||||
|
commands=(
|
||||||
|
${commands
|
||||||
|
.map(({ _name, _description }) => `"${_name}:${_description}"`)
|
||||||
|
.join("\n ")}
|
||||||
|
)
|
||||||
|
_describe "command" commands
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$words[1]" in
|
||||||
|
${commands
|
||||||
|
.map(({ _name }) =>
|
||||||
|
[`${_name})`, `_${name}_${_name}`, ";;"].join("\n ")
|
||||||
|
)
|
||||||
|
.join("\n ")}
|
||||||
|
esac`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const commandBlocParts = [
|
||||||
|
`function _${name} {\n ${commandBlockFunctionParts.join(
|
||||||
|
"\n\n "
|
||||||
|
)}\n}`,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (hasCommands) {
|
||||||
|
commandBlocParts.push(
|
||||||
|
commands
|
||||||
|
.map((command) =>
|
||||||
|
renderCommandBlock(`${name}_${command._name}`, command)
|
||||||
|
)
|
||||||
|
.join("\n\n")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return commandBlocParts.join("\n\n");
|
||||||
|
};
|
||||||
|
|
||||||
|
const render = () => {
|
||||||
|
return [
|
||||||
|
`#compdef _${rootName} ${rootName}`,
|
||||||
|
"",
|
||||||
|
renderCommandBlock(rootName, rootCommand),
|
||||||
|
].join("\n");
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
render,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const validShells = ["zsh"];
|
||||||
|
|
||||||
|
export class CompletionCommand {
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
async run(cmd: program.Command) {
|
||||||
|
const shell: typeof validShells[number] = cmd.shell;
|
||||||
|
|
||||||
|
if (!shell) {
|
||||||
|
return Response.badRequest("`shell` was not provided!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validShells.includes(shell)) {
|
||||||
|
return Response.badRequest(`Unsupported shell!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let content = "";
|
||||||
|
|
||||||
|
if (shell === "zsh") {
|
||||||
|
content = zshCompletion("bw", cmd.parent).render();
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = new MessageResponse(content, null);
|
||||||
|
return Response.success(res);
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,8 @@ import { ShareCommand } from './commands/share.command';
|
|||||||
import { SyncCommand } from './commands/sync.command';
|
import { SyncCommand } from './commands/sync.command';
|
||||||
import { UnlockCommand } from './commands/unlock.command';
|
import { UnlockCommand } from './commands/unlock.command';
|
||||||
|
|
||||||
|
import { CompletionCommand } from './commands/completion.command';
|
||||||
|
|
||||||
import { LogoutCommand } from 'jslib/cli/commands/logout.command';
|
import { LogoutCommand } from 'jslib/cli/commands/logout.command';
|
||||||
import { UpdateCommand } from 'jslib/cli/commands/update.command';
|
import { UpdateCommand } from 'jslib/cli/commands/update.command';
|
||||||
|
|
||||||
@ -660,6 +662,26 @@ export class Program extends BaseProgram {
|
|||||||
this.processResponse(response);
|
this.processResponse(response);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
program
|
||||||
|
.command('completion')
|
||||||
|
.description('Generate shell completions.')
|
||||||
|
.option('--shell <shell>', 'Shell to generate completions for.')
|
||||||
|
.on('--help', () => {
|
||||||
|
writeLn('\n Notes:');
|
||||||
|
writeLn('');
|
||||||
|
writeLn(' Valid shells are `zsh`.')
|
||||||
|
writeLn('');
|
||||||
|
writeLn(' Examples:');
|
||||||
|
writeLn('');
|
||||||
|
writeLn(' bw completion --shell zsh');
|
||||||
|
writeLn('', true);
|
||||||
|
})
|
||||||
|
.action(async (cmd: program.Command) => {
|
||||||
|
const command = new CompletionCommand();
|
||||||
|
const response = await command.run(cmd);
|
||||||
|
this.processResponse(response);
|
||||||
|
})
|
||||||
|
|
||||||
program
|
program
|
||||||
.parse(process.argv);
|
.parse(process.argv);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user