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_schemaNote
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 testUsing 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
--barYou 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 exampleYou'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.