-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement bash-completion script generation
- Loading branch information
1 parent
09ed999
commit fb935b5
Showing
15 changed files
with
372 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
#!/usr/bin/env bash | ||
# Bash completion script for docker | ||
# This file is automatically generated by running `docker generate-completions`. | ||
# Created with cli-er@0.13.0 on 2023-11-25 09:40 | ||
|
||
function indirect(){ | ||
if [[ -z $ZSH_VERSION ]]; then | ||
echo ${!1} | ||
else | ||
echo ${(P)1} | ||
fi | ||
} | ||
_docker() { | ||
# declare nestings | ||
local nestings=( | ||
"builder=build,prune" | ||
) | ||
# declare options by location ("o_" represents root) | ||
local opts_by_location=( | ||
"o_=--debug,--help,--version,--nodebug,--no-debug" | ||
"o_builder=" | ||
"o_build=--source,--add-host,--build-arg,--cache-from,--disable-content-trust,--file,--iidfile,--isolation,--label,--network,--no-cache,--output,--platform,--progress,--pull,--quiet,--secret,--ssh,--tag,--target" | ||
"o_prune=--all,--filter,--force,--keep-storage" | ||
) | ||
# Calculate keys for all available commands/namespaces | ||
local all_locations=($(echo "${opts_by_location[@]:1}" | sed 's/o_\([^=]*\)=[^ ]*/\1/g')) | ||
# initialize top-level definitions | ||
local top_defs=("${nestings[@]%%=*}") | ||
|
||
for d in "${nestings[@]}";do declare "$d";done | ||
for o in "${opts_by_location[@]}";do declare "$o";done | ||
|
||
# Obtain the location by removing the cli-name from the list of words | ||
local location=("${COMP_WORDS[@]:1:$COMP_CWORD-1}") | ||
# Initialize options with global values | ||
local opts=($(echo "${o_}" | tr "," "\n")) | ||
local initialized=false includeopts=false | ||
while [ ${#location[@]} -gt 0 ]; do | ||
local curr="${location[@]:0:1}" | ||
local ocurr="o_$curr" | ||
# Check for valid command/namespace | ||
if [[ " ${top_defs[@]} " =~ " ${curr} " ]] && [[ " ${all_locations[@]} " =~ " ${curr} " ]]; then | ||
top_defs=($(echo "$(indirect $curr)" | tr "," "\n")) | ||
location=(${location[@]:1}) | ||
opts+=($(echo "$(indirect $ocurr)" | tr "," "\n")) | ||
initialized=true | ||
# Check if element is a command to include options | ||
[[ ! " ${nestings[@]%%=*} " =~ " ${curr} " ]] && includeopts=true || includeopts=false | ||
else | ||
# if not valid location was found, empty the list | ||
[[ $initialized != true ]] && top_defs=() | ||
break | ||
fi | ||
done | ||
|
||
# Include options into top_defs | ||
[[ $includeopts == true ]] && top_defs+=("${opts[@]}") | ||
COMPREPLY=($(compgen -W "${top_defs[*]}" -- $2)) | ||
} | ||
|
||
complete -F _docker docker |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,6 @@ | |
"main": "docker.js", | ||
"author": "carloscortonc", | ||
"dependencies": { | ||
"cli-er": "0.12.0" | ||
"cli-er": "0.14.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import { DefinitionElement, isShortAlias } from "./cli-utils"; | ||
import { CliOptions, Definition, Kind } from "./types"; | ||
import { getClierVersion } from "./utils"; | ||
|
||
export function generateCompletions({ | ||
definition, | ||
cliOptions, | ||
}: { | ||
definition: Definition<DefinitionElement>; | ||
cliOptions: CliOptions; | ||
}) { | ||
const tab = (n: number = 1) => " ".repeat(2 * n); | ||
const getOptionsAliases = (e: DefinitionElement, filterFn?: (e: DefinitionElement) => boolean) => | ||
Object.values(e.options || {}) | ||
.filter(filterFn || (() => true)) | ||
.reduce((acc, curr) => acc.concat(...curr.aliases!.filter((a) => !isShortAlias(a))), [] as string[]) | ||
.join(","); | ||
// prettier-ignore | ||
const nestings: string[] = [], optionsByLocation: string[] = []; | ||
const populateLists = (def?: Definition<DefinitionElement>, loc = "") => { | ||
if (!def) return; | ||
const _currOptions = getOptionsAliases({ options: def }, (e) => e.kind === Kind.OPTION); | ||
optionsByLocation.push(`"o_${loc}=${_currOptions}"`); | ||
for (const el of Object.values(def)) { | ||
const currNesting = getOptionsAliases(el, (e) => [Kind.NAMESPACE, Kind.COMMAND].includes(e.kind as Kind)); | ||
if (el.kind === Kind.NAMESPACE) { | ||
nestings.push(`"${el.key}=${currNesting}"`); | ||
} | ||
populateLists(el.options, el.key); | ||
} | ||
}; | ||
populateLists(definition); | ||
const toFormattedList = (els: string[]) => | ||
[""] | ||
.concat(...els) | ||
.join(`\n${tab(2)}`) | ||
.concat(`\n${tab(1)}`); | ||
const str = Object.entries({ | ||
cliName: cliOptions.cliName, | ||
cliVersion: cliOptions.cliVersion, | ||
clierVersion: getClierVersion(), | ||
date: getLocalDate("YYYY-MM-DD HH:mm"), | ||
command: cliOptions.completion.command, | ||
nestings: toFormattedList(nestings), | ||
optionsByLocation: toFormattedList(optionsByLocation), | ||
}).reduce((acc, [k, v]) => acc.replace(new RegExp(`{{${k}}}`, "g"), v), defaultTemplate); | ||
|
||
process.stdout.write(str); | ||
} | ||
|
||
const getLocalDate = (template: string) => { | ||
const d = new Date(); | ||
return [ | ||
{ m: "getFullYear", n: "YYYY", p: 4 }, | ||
{ m: "getMonth", n: "MM", o: 1 }, | ||
{ m: "getDate", n: "DD" }, | ||
{ m: "getHours", n: "HH" }, | ||
{ m: "getMinutes", n: "mm" }, | ||
] | ||
.map((m) => ({ p: 2, o: 0, ...m })) | ||
.map(({ m, p, n, o }) => ({ v: ((d as any)[m]() + o).toString().padStart(p, "0"), n })) | ||
.reduce((acc, { v, n }) => acc.replace(new RegExp(n), v), template); | ||
}; | ||
|
||
const defaultTemplate = `#!/usr/bin/env bash | ||
# Bash completion script for {{cliName}} | ||
# This file is automatically generated by running \`{{cliName}} {{command}}\`. | ||
# Created with cli-er@{{clierVersion}} on {{date}} | ||
function indirect(){ | ||
if [[ -z $ZSH_VERSION ]]; then | ||
echo \${!1} | ||
else | ||
echo \${(P)1} | ||
fi | ||
} | ||
_{{cliName}}() { | ||
# declare nestings | ||
local nestings=({{nestings}}) | ||
# declare options by location ("o_" represents root) | ||
local opts_by_location=({{optionsByLocation}}) | ||
# Calculate keys for all available commands/namespaces | ||
local all_locations=($(echo "\${opts_by_location[@]:1}" | sed 's/o_\\([^=]*\\)=[^ ]*/\\1/g')) | ||
# initialize top-level definitions | ||
local top_defs=("\${nestings[@]%%=*}") | ||
for d in "\${nestings[@]}";do declare "$d";done | ||
for o in "\${opts_by_location[@]}";do declare "$o";done | ||
# Obtain the location by removing the cli-name from the list of words | ||
local location=("\${COMP_WORDS[@]:1:$COMP_CWORD-1}") | ||
# Initialize options with global values | ||
local opts=($(echo "\${o_}" | tr "," "\\n")) | ||
local initialized=false includeopts=false | ||
while [ \${#location[@]} -gt 0 ]; do | ||
local curr="\${location[@]:0:1}" | ||
local ocurr="o_$curr" | ||
# Check for valid command/namespace | ||
if [[ " \${top_defs[@]} " =~ " \${curr} " ]] && [[ " \${all_locations[@]} " =~ " \${curr} " ]]; then | ||
top_defs=($(echo "$(indirect $curr)" | tr "," "\\n")) | ||
location=(\${location[@]:1}) | ||
opts+=($(echo "$(indirect $ocurr)" | tr "," "\\n")) | ||
initialized=true | ||
# Check if element is a command to include options | ||
[[ ! " \${nestings[@]%%=*} " =~ " \${curr} " ]] && includeopts=true || includeopts=false | ||
else | ||
# if not valid location was found, empty the list | ||
[[ $initialized != true ]] && top_defs=() | ||
break | ||
fi | ||
done | ||
# Include options into top_defs | ||
[[ $includeopts == true ]] && top_defs+=("\${opts[@]}") | ||
COMPREPLY=($(compgen -W "\${top_defs[*]}" -- $2)) | ||
} | ||
complete -F _{{cliName}} {{cliName}} | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.