@oclif/plugin-autocomplete
Version:
autocomplete plugin for oclif
244 lines (235 loc) • 8.89 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
const fs = require("fs-extra");
const bash_1 = require("../../autocomplete/bash");
const zsh_1 = require("../../autocomplete/zsh");
const powershell_1 = require("../../autocomplete/powershell");
const bash_spaces_1 = require("../../autocomplete/bash-spaces");
const base_1 = require("../../base");
const debug = require('debug')('autocomplete:create');
function sanitizeDescription(description) {
if (description === undefined) {
return '';
}
return description
.replace(/([`"])/g, '\\\\\\$1') // backticks and double-quotes require triple-backslashes
// eslint-disable-next-line no-useless-escape
.replace(/([\[\]])/g, '\\\\$1') // square brackets require double-backslashes
.split('\n')[0]; // only use the first line
}
class Create extends base_1.AutocompleteBase {
async run() {
// 1. ensure needed dirs
await this.ensureDirs();
// 2. save (generated) autocomplete files
await this.createFiles();
}
async ensureDirs() {
// ensure autocomplete cache dir
await fs.ensureDir(this.autocompleteCacheDir);
// ensure autocomplete bash function dir
await fs.ensureDir(this.bashFunctionsDir);
// ensure autocomplete zsh function dir
await fs.ensureDir(this.zshFunctionsDir);
// ensure autocomplete powershell function dir
await fs.ensureDir(this.pwshFunctionsDir);
}
async createFiles() {
await fs.writeFile(this.bashSetupScriptPath, this.bashSetupScript);
await fs.writeFile(this.bashCompletionFunctionPath, this.bashCompletionFunction);
await fs.writeFile(this.zshSetupScriptPath, this.zshSetupScript);
// zsh
const supportSpaces = this.config.topicSeparator === ' ';
if (process.env.OCLIF_AUTOCOMPLETE_TOPIC_SEPARATOR === 'colon' || !supportSpaces) {
await fs.writeFile(this.zshCompletionFunctionPath, this.zshCompletionFunction);
}
else {
const zshCompWithSpaces = new zsh_1.default(this.config);
await fs.writeFile(this.zshCompletionFunctionPath, zshCompWithSpaces.generate());
const pwshComp = new powershell_1.default(this.config);
await fs.writeFile(this.pwshCompletionFunctionPath, pwshComp.generate());
}
}
get bashSetupScriptPath() {
// <cachedir>/autocomplete/bash_setup
return path.join(this.autocompleteCacheDir, 'bash_setup');
}
get zshSetupScriptPath() {
// <cachedir>/autocomplete/zsh_setup
return path.join(this.autocompleteCacheDir, 'zsh_setup');
}
get pwshFunctionsDir() {
// <cachedir>/autocomplete/functions/powershell
return path.join(this.autocompleteCacheDir, 'functions', 'powershell');
}
get bashFunctionsDir() {
// <cachedir>/autocomplete/functions/bash
return path.join(this.autocompleteCacheDir, 'functions', 'bash');
}
get zshFunctionsDir() {
// <cachedir>/autocomplete/functions/zsh
return path.join(this.autocompleteCacheDir, 'functions', 'zsh');
}
get pwshCompletionFunctionPath() {
// <cachedir>/autocomplete/functions/powershell/<bin>.ps1
return path.join(this.pwshFunctionsDir, `${this.cliBin}.ps1`);
}
get bashCompletionFunctionPath() {
// <cachedir>/autocomplete/functions/bash/<bin>.bash
return path.join(this.bashFunctionsDir, `${this.cliBin}.bash`);
}
get zshCompletionFunctionPath() {
// <cachedir>/autocomplete/functions/zsh/_<bin>
return path.join(this.zshFunctionsDir, `_${this.cliBin}`);
}
get bashSetupScript() {
const setup = path.join(this.bashFunctionsDir, `${this.cliBin}.bash`);
const bin = this.cliBinEnvVar;
/* eslint-disable-next-line no-useless-escape */
return `${bin}_AC_BASH_COMPFUNC_PATH=${setup} && test -f \$${bin}_AC_BASH_COMPFUNC_PATH && source \$${bin}_AC_BASH_COMPFUNC_PATH;
`;
}
get zshSetupScript() {
return `
fpath=(
${this.zshFunctionsDir}
$fpath
);
autoload -Uz compinit;
compinit;\n`;
}
get commands() {
if (this._commands)
return this._commands;
const plugins = this.config.plugins;
const cmds = [];
plugins.forEach(p => {
p.commands.forEach(c => {
try {
if (c.hidden)
return;
const description = sanitizeDescription(c.summary || c.description || '');
const flags = c.flags;
cmds.push({
id: c.id,
description,
flags,
});
c.aliases.forEach(a => {
cmds.push({
id: a,
description,
flags,
});
});
}
catch (error) {
debug(`Error creating zsh flag spec for command ${c.id}`);
debug(error.message);
this.writeLogFile(error.message);
}
});
});
this._commands = cmds;
return this._commands;
}
genZshFlagSpecs(Klass) {
return Object.keys(Klass.flags || {})
.filter(flag => Klass.flags && !Klass.flags[flag].hidden)
.map(flag => {
const f = (Klass.flags && Klass.flags[flag]) || { description: '' };
const isBoolean = f.type === 'boolean';
const isOption = f.type === 'option';
const name = isBoolean ? flag : `${flag}=-`;
const multiple = isOption && f.multiple ? '*' : '';
const valueCmpl = isBoolean ? '' : ':';
const completion = `${multiple}--${name}[${sanitizeDescription(f.summary || f.description)}]${valueCmpl}`;
return `"${completion}"`;
})
.join('\n');
}
/* eslint-disable no-useless-escape */
get genAllCommandsMetaString() {
return this.commands.map(c => {
return `\"${c.id.replace(/:/g, '\\:')}:${c.description}\"`;
}).join('\n');
}
/* eslint-enable no-useless-escape */
get genCaseStatementForFlagsMetaString() {
// command)
// _command_flags=(
// "--boolean[bool descr]"
// "--value=-[value descr]:"
// )
// ;;
return this.commands.map(c => {
return `${c.id})
_command_flags=(
${this.genZshFlagSpecs(c)}
)
;;\n`;
}).join('\n');
}
genCmdPublicFlags(Command) {
const Flags = Command.flags || {};
return Object.keys(Flags)
.filter(flag => !Flags[flag].hidden)
.map(flag => `--${flag}`)
.join(' ');
}
get bashCommandsWithFlagsList() {
return this.commands.map(c => {
const publicFlags = this.genCmdPublicFlags(c).trim();
return `${c.id} ${publicFlags}`;
}).join('\n');
}
get bashCompletionFunction() {
var _a, _b;
const cliBin = this.cliBin;
const supportSpaces = this.config.topicSeparator === ' ';
const bashScript = (process.env.OCLIF_AUTOCOMPLETE_TOPIC_SEPARATOR === 'colon' || !supportSpaces) ? bash_1.default : bash_spaces_1.default;
return bashScript
.concat(...((_b = (_a = this.config.binAliases) === null || _a === void 0 ? void 0 : _a.map(alias => `complete -F _<CLI_BIN>_autocomplete ${alias}`).join('\n')) !== null && _b !== void 0 ? _b : []))
.replace(/<CLI_BIN>/g, cliBin)
.replace(/<BASH_COMMANDS_WITH_FLAGS_LIST>/g, this.bashCommandsWithFlagsList);
}
get zshCompletionFunction() {
const cliBin = this.cliBin;
const allCommandsMeta = this.genAllCommandsMetaString;
const caseStatementForFlagsMeta = this.genCaseStatementForFlagsMetaString;
return `#compdef ${cliBin}
_${cliBin} () {
local _command_id=\${words[2]}
local _cur=\${words[CURRENT]}
local -a _command_flags=()
## public cli commands & flags
local -a _all_commands=(
${allCommandsMeta}
)
_set_flags () {
case $_command_id in
${caseStatementForFlagsMeta}
esac
}
## end public cli commands & flags
_complete_commands () {
_describe -t all-commands "all commands" _all_commands
}
if [ $CURRENT -gt 2 ]; then
if [[ "$_cur" == -* ]]; then
_set_flags
else
_path_files
fi
fi
_arguments -S '1: :_complete_commands' \\
$_command_flags
}
_${cliBin}
`;
}
}
exports.default = Create;
Create.hidden = true;
Create.description = 'create autocomplete setup scripts and completion functions';