Add custom path support for cli/tui in terminal config
This commit is contained in:
@@ -23,6 +23,7 @@ import {
|
||||
existsSync,
|
||||
readFileSync,
|
||||
appendFileSync,
|
||||
mkdirSync,
|
||||
} from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
@@ -193,7 +194,7 @@ export function generateFishCompletions(binName: string): string {
|
||||
return loadAndProcessTemplate("fish.fish", binName);
|
||||
}
|
||||
|
||||
type ShellType = "bash" | "zsh" | "fish";
|
||||
export type ShellType = "bash" | "zsh" | "fish";
|
||||
|
||||
const generators: Record<ShellType, (binName: string) => string> = {
|
||||
bash: generateBashCompletions,
|
||||
@@ -202,51 +203,74 @@ const generators: Record<ShellType, (binName: string) => string> = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Shell config file paths and eval commands for each shell type.
|
||||
* Shell config file paths and startup commands for each shell type.
|
||||
*/
|
||||
const shellConfigs: Record<
|
||||
ShellType,
|
||||
{ configFile: string; evalCommand: (binName: string) => string }
|
||||
{
|
||||
configFile: string;
|
||||
configDirCommand: string;
|
||||
configDirPattern: RegExp;
|
||||
evalCommand: (binName: string) => string;
|
||||
}
|
||||
> = {
|
||||
bash: {
|
||||
configFile: join(homedir(), ".bashrc"),
|
||||
configDirCommand: 'export XO_CONFIG_DIR="${XO_CONFIG_DIR:-$HOME/.config/xo-cli}"',
|
||||
configDirPattern: /^\s*(?:export\s+)?XO_CONFIG_DIR=/m,
|
||||
evalCommand: (binName) => `eval "$(${binName} completions bash)"`,
|
||||
},
|
||||
zsh: {
|
||||
configFile: join(homedir(), ".zshrc"),
|
||||
configDirCommand: 'export XO_CONFIG_DIR="${XO_CONFIG_DIR:-$HOME/.config/xo-cli}"',
|
||||
configDirPattern: /^\s*(?:export\s+)?XO_CONFIG_DIR=/m,
|
||||
evalCommand: (binName) => `eval "$(${binName} completions zsh)"`,
|
||||
},
|
||||
fish: {
|
||||
configFile: join(homedir(), ".config", "fish", "config.fish"),
|
||||
configDirCommand:
|
||||
'set -q XO_CONFIG_DIR; or set -gx XO_CONFIG_DIR "$HOME/.config/xo-cli"',
|
||||
configDirPattern: /^\s*set\b[^\n]*\bXO_CONFIG_DIR\b/m,
|
||||
evalCommand: (binName) => `${binName} completions fish | source`,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Installs completions to the user's shell config file.
|
||||
* Adds the eval command if not already present.
|
||||
* Adds a default config directory and the eval command if not already present.
|
||||
* @param shell - The shell type
|
||||
* @param binName - The CLI binary name
|
||||
* @returns true if installed, false if already present
|
||||
*/
|
||||
function installCompletions(shell: ShellType, binName: string): boolean {
|
||||
const config = shellConfigs[shell];
|
||||
export function installCompletions(
|
||||
shell: ShellType,
|
||||
binName: string,
|
||||
configFile: string = shellConfigs[shell].configFile,
|
||||
): boolean {
|
||||
const config = { ...shellConfigs[shell], configFile };
|
||||
const evalCommand = config.evalCommand(binName);
|
||||
|
||||
// Check if config file exists and already has the completion line
|
||||
let existingContent = "";
|
||||
if (existsSync(config.configFile)) {
|
||||
existingContent = readFileSync(config.configFile, "utf8");
|
||||
if (existingContent.includes(evalCommand)) {
|
||||
return false; // Already installed
|
||||
}
|
||||
}
|
||||
|
||||
// Append the completion line
|
||||
const commands: string[] = [];
|
||||
if (!config.configDirPattern.test(existingContent)) {
|
||||
commands.push(config.configDirCommand);
|
||||
}
|
||||
if (!existingContent.includes(evalCommand)) {
|
||||
commands.push(evalCommand);
|
||||
}
|
||||
if (commands.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const newLine =
|
||||
existingContent.endsWith("\n") || existingContent === "" ? "" : "\n";
|
||||
const completionBlock = `${newLine}\n# ${binName} shell completions\n${evalCommand}\n`;
|
||||
const completionBlock = `${newLine}\n# ${binName} shell completions\n${commands.join("\n")}\n`;
|
||||
|
||||
mkdirSync(dirname(config.configFile), { recursive: true });
|
||||
appendFileSync(config.configFile, completionBlock);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,19 @@ __xo_complete() {
|
||||
[[ -n "${__xo_complete_bin}" ]] && "${__xo_complete_bin}" "$@" 2>/dev/null
|
||||
}
|
||||
|
||||
# @description
|
||||
# Lists mnemonic aliases directly from the config directory without starting
|
||||
# the dynamic Node helper.
|
||||
__xo_complete_mnemonics() {
|
||||
local config_dir="${XO_CONFIG_DIR:-${HOME}/.config/xo-cli}"
|
||||
local file mnemonic
|
||||
for file in "${config_dir}"/mnemonics/mnemonic-*; do
|
||||
[[ -f "${file}" ]] || continue
|
||||
mnemonic="${file##*/}"
|
||||
[[ "${mnemonic}" == "$1"* ]] && printf '%s\n' "${mnemonic}"
|
||||
done
|
||||
}
|
||||
|
||||
# @description
|
||||
# Main completion dispatcher invoked by bash's `complete -F`.
|
||||
# It determines context (command/subcommand/argument position) and then mixes:
|
||||
@@ -39,10 +52,10 @@ _{{FUNC_NAME}}_completions() {
|
||||
_init_completion || return
|
||||
|
||||
# If the previous token is `-m/--mnemonic-file`, this argument expects a
|
||||
# mnemonic file alias/path. Ask the helper for mnemonic suggestions.
|
||||
# mnemonic file alias/path. List mnemonic aliases directly from disk.
|
||||
if [[ "${prev}" == "-m" || "${prev}" == "--mnemonic-file" ]]; then
|
||||
local mnemonics
|
||||
mnemonics=$(__xo_complete mnemonics "${cur}")
|
||||
mnemonics=$(__xo_complete_mnemonics "${cur}")
|
||||
if [[ -n "${mnemonics}" ]]; then
|
||||
while IFS= read -r line; do
|
||||
COMPREPLY+=("$line")
|
||||
|
||||
@@ -28,6 +28,21 @@ function __{{FUNC_NAME}}_complete_dynamic
|
||||
end
|
||||
end
|
||||
|
||||
# @description
|
||||
# Lists mnemonic aliases directly from the config directory without starting
|
||||
# the dynamic Node helper.
|
||||
function __{{FUNC_NAME}}_complete_mnemonics
|
||||
set -l config_dir "$XO_CONFIG_DIR"
|
||||
if test -z "$config_dir"
|
||||
set config_dir "$HOME/.config/xo-cli"
|
||||
end
|
||||
for file in $config_dir/mnemonics/mnemonic-*
|
||||
if test -f "$file"
|
||||
string replace -r '.*/' '' "$file"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Global option flags available across top-level command contexts.
|
||||
complete -c {{BIN_NAME}} -s h -d "Show help"
|
||||
complete -c {{BIN_NAME}} -l help -d "Show help"
|
||||
@@ -37,8 +52,8 @@ complete -c {{BIN_NAME}} -s o -d "Output file"
|
||||
complete -c {{BIN_NAME}} -l output -d "Output file"
|
||||
complete -c {{BIN_NAME}} -l currency -d "Set fiat display currency"
|
||||
|
||||
# Dynamic completion for `-m/--mnemonic-file`.
|
||||
complete -c {{BIN_NAME}} -s m -l mnemonic-file -xa '(__{{FUNC_NAME}}_complete_dynamic mnemonics)'
|
||||
# Shell-native completion for `-m/--mnemonic-file`.
|
||||
complete -c {{BIN_NAME}} -s m -l mnemonic-file -xa '(__{{FUNC_NAME}}_complete_mnemonics)'
|
||||
|
||||
# Top-level command registrations inserted by template expansion.
|
||||
{{TOP_LEVEL_COMMANDS}}
|
||||
|
||||
@@ -25,6 +25,19 @@ __xo_complete() {
|
||||
[[ -n "${__xo_complete_bin}" ]] && "${__xo_complete_bin}" "$@" 2>/dev/null
|
||||
}
|
||||
|
||||
# @description
|
||||
# Lists mnemonic aliases directly from the config directory without starting
|
||||
# the dynamic Node helper.
|
||||
__xo_complete_mnemonics() {
|
||||
local config_dir="${XO_CONFIG_DIR:-${HOME}/.config/xo-cli}"
|
||||
local file mnemonic
|
||||
for file in "${config_dir}"/mnemonics/mnemonic-*(N); do
|
||||
[[ -f "${file}" ]] || continue
|
||||
mnemonic="${file:t}"
|
||||
[[ "${mnemonic}" == "$1"* ]] && print -r -- "${mnemonic}"
|
||||
done
|
||||
}
|
||||
|
||||
# @description
|
||||
# Main zsh completion dispatcher registered via `compdef`.
|
||||
# It resolves command context from `$words`/`$CURRENT` and serves:
|
||||
@@ -38,7 +51,7 @@ _{{FUNC_NAME}}_completions() {
|
||||
# If previous token is `-m/--mnemonic-file`, complete mnemonic sources.
|
||||
if [[ "${words[CURRENT-1]}" == "-m" || "${words[CURRENT-1]}" == "--mnemonic-file" ]]; then
|
||||
local mnemonics
|
||||
mnemonics=("${(@f)$(__xo_complete mnemonics "${words[CURRENT]}")}")
|
||||
mnemonics=("${(@f)$(__xo_complete_mnemonics "${words[CURRENT]}")}")
|
||||
if [[ ${#mnemonics[@]} -gt 0 ]]; then
|
||||
compadd -- "${mnemonics[@]}"
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user