The file get_cli_options.zsh parses a JSON structure and returns the relevant subcommands and flag options:
Note
This isn't a recursive implementation.
We stop at 4 levels deep.
The example.json file demonstrates what structure is required to
be passed to the get_cli_options
shell function.
This repository includes a schema.json
file which defines the expected
structure of the JSON file.
You can validate your JSON file (e.g. example.json
) against the schema by
running the following command:
make validate_schema
Note
This requires npx
to be available in your environment (which is included
with a standard Node.js installation).
This repository includes a test suite in test.zsh
to verify the behavior of
the get_cli_options.zsh
script. The tests ensure that the script correctly
parses the example.json
file and returns the expected commands and options for
various inputs, matching the examples shown in the "Example Output" section.
You can run the test suite with the following command:
make test
Using example.json
as our example structure, we should see the following
output:
# show the top-level commands
$ get_cli_options "example.json" ""
service
acl
# show the top-level/global flag options
$ get_cli_options "example.json" "--"
--help
--quiet
--verbose
# show subcommands and flags
$ get_cli_options "example.json" "acl"
--help-acl
create
list
# show command flags only
$ get_cli_options "example.json" "acl --"
--help-acl
# show subcommands and flags under a subcommand
$ get_cli_options "example.json" "acl list"
--json
third-level
# show subcommand flags only
$ get_cli_options "example.json" "acl list --"
--json
# show subcommands and flags under a third-level subcommand
$ get_cli_options "example.json" "acl list third-level"
--foo
--bar
fourth-level
# show third-level subcommand flags only
$ get_cli_options "example.json" "acl list third-level --"
--foo
--bar
You can plug this script into your zsh shell completion setup like so:
Note
The following example is for setting up autocomplete for a binary called
example
(which uses the example.json
from this repo as its structure). I
typically store these files in $HOME/.zsh/
, so in this case it would be
stored as $HOME/.zsh/_example
.
#compdef fastly
autoload -U compinit && compinit
autoload -U bashcompinit && bashcompinit
_example_bash_autocomplete() {
local cur opts input_str
COMPREPLY=()
# Current word being completed
cur="${COMP_WORDS[COMP_CWORD]}"
# Reconstruct the input arguments excluding the binary name
local input=("${COMP_WORDS[@]:1}")
# Join the array into a single string, trimming excess whitespace
input_str=$(echo "${input[*]}" | sed 's/ *$//')
# Debugging: Log the exact call to get_cli_options
# echo "Calling get_cli_options with input_str: '$input_str'" >> /tmp/autocomplete-debug.log
# Pass the reconstructed input string to get_cli_options
opts=$(get_cli_options "$HOME/.zsh/example.json" "$input_str")
# Log the result of get_cli_options
# echo "opts: $opts" >> /tmp/autocomplete-debug.log
# Generate completions based on opts
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
# Fall back to file completion if no matches are found
[[ $COMPREPLY ]] && return
compgen -f
return 0
}
complete -F _example_bash_autocomplete example
You'll then need to source the above _example
script:
dir_zsh="$HOME/.zsh"
path_example_completion="$dir_zsh/_example"
chmod +x $path_example_completion
source "$path_example_completion"
I'm not sure how you have your Zsh autocomplete setup, but I need to add this
custom directory to my fpath
:
fpath=($dir_zsh $fpath)
Tip
If you're looking for an example autocomplete setup, then view my dot files.