I'm trying to write completion functions for some custom functions I wrote, but seem to be really struggling with even the most basic ones. An example function is:function eb_instances() {    if [ $# -ne 2 ]; then        echo Usage eb_instances <aws profile name> <environment name>        echo e.g.:        echo  eb_instances production kraken-prod-api        return 1    fi    aws ec2 describe-instances --filters  Name=instance-state-name,Values=running   Name=tag:Name,Values=$2 --profile=$1 --output=json | jq -r .Reservations[].Instances[].PrivateIpAddress}This has two positional arguments, <aws profile name> and <environment name>I want the completion options for <aws profile name> to be dynamically available by running sed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' ', and the completions for <environment name> to be dynamically available by running another function I have called eb_names.I'm finding the documentation quite sparse and difficult to follow. I've also seen the zsh-completions repo for similar commands but can't seem to find something similar to what I need. Any help getting started would be much appreciated!UpdateBased on @cuonglm's answer, I used:#compdef ebinstances_ebinstances() {  local state  _arguments \    '1: :->aws_profile'\    '*: :->eb_name'  case $state in    (aws_profile) _arguments '1:profiles:($(sed -n -E s/\[([a-zA-Z0-9_\-]+)\]/\1/p ~/.aws/credentials | tr \\n  ))' ;;              (*) compadd $@ foo bar  esac}_ebinstances $@What I forgot to mention in the original question was, that I also wanted the completion of the second argument be dependent on the first one (both of which are dynamic based executing some code), for example:$ eb_instances <cursor>TABcuonglm  testgets the completions I want. Once I select say the first one, and try to auto complete:$ eb_instances cuonglm <cursor>TABI want to generate the completion options by executing eb_names cuonglm, and if possible, also, drilldown on the completions for example if the correct candidate was foo-bar,$ eb_instances cuonglm foo<cursor>TABI want to generate the completion options by executing eb_names cuonglm foo
Dynamic zsh autocomplete for custom commands
zsh;autocomplete
At the first time, zsh Completion System seems to be very complex and difficult to grasp. Let try an example.First thing you need to know, zsh completion system will load completion functions from $fpath. Make sure your completions directory appear in:print -rl -- $fpath(If you used oh-my-zsh, there's .oh-my-zsh/completions existed in $fpath, you can just create it and put your completion functions there)Now, you must create a completion file for your function, its name must start with underscore _, plus your function name. In your case, its name is _eb_instances.Add theses lines to _eb_instances file:#compdef eb_instances_eb_instances() {  local state  _arguments \    '1: :->aws_profile'\    '*: :->eb_name'  case $state in    (aws_profile) _arguments '1:profiles:(cuonglm test)' ;;              (*) compadd $@ prod staging dev  esac}_eb_instances $@You are done. Save the file and start new session to test completion. You will see some thing like this:$ eb_instances <cursor>TABcuonglm  test$ eb_instances cuonglm <cursor>TABdev      prod     stagingYou can read zsh completion system documentation about _arguments function, state variable. Also you need to change (cuonglm test) with your sed command and change prod staging dev to your eb_names function.If you want to generate the 2nd argument base on what 1st argument passed, you can use $words[2] variable:case $state in  (aws_profile) _arguments '1:profiles:(cuonglm test)' ;;            (*) compadd $@ $(echo $words[2]) ;;esacReplace echo with your real function, in your case, it's $(eb_names $words[2]).If you still feel hard to accomplish this, just define _eb_instances and eb_instances in your .zshrc then call completion as:compdef _eb_instances eb_instancesYou need to initialize completion system with:autoload -U compinitcompinit(If you used oh-my-zsh, it have been loaded)