Saisie semi-automatique zsh dynamique pour les commandes personnalisées

19

J'essaie d'écrire des fonctions de complétion pour certaines fonctions personnalisées que j'ai écrites, mais semble vraiment avoir du mal avec les plus élémentaires.

Un exemple de fonction est:

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"
}

Cela a deux arguments de position, <aws profile name>et<environment name>

Je veux que les options de complétion <aws profile name>soient dynamiquement disponibles en exécutant sed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' 'et que les compléments <environment name>soient dynamiquement disponibles en exécutant une autre fonction que j'ai appelée eb_names.

Je trouve la documentation assez clairsemée et difficile à suivre. J'ai également vu le dépôt zsh-complétions pour des commandes similaires, mais je n'arrive pas à trouver quelque chose de similaire à ce dont j'ai besoin.

Toute aide pour commencer serait très appréciée!

Mise à jour

Sur la base de la réponse de @ cuonglm , j'ai utilisé:

#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 "$@"

Ce que j'ai oublié de mentionner dans la question d'origine, c'est que je voulais aussi que l'achèvement du deuxième argument dépende du premier (qui sont tous deux basés sur l'exécution dynamique de code), par exemple:

$ eb_instances <cursor>TAB
cuonglm  test

obtient les finitions que je veux. Une fois que j'ai sélectionné, dites le premier et essayez de terminer automatiquement:

$ eb_instances cuonglm <cursor>TAB

Je souhaite générer les options de complétion en exécutant eb_names cuonglm, et si possible, également, une analyse détaillée des compléments, par exemple si le bon candidat était foo-bar,

$ eb_instances cuonglm foo<cursor>TAB

Je veux générer les options de complétion en exécutant eb_names cuonglm foo

zsquare
la source

Réponses:

23

À la première fois, zsh Completion System semble être très complexe et difficile à saisir. Essayons un exemple.

Première chose que vous devez savoir, le zshsystème d'achèvement chargera les fonctions d'achèvement à partir de $fpath. Assurez-vous que votre répertoire d'achèvement apparaît dans:

print -rl -- $fpath

(Si vous avez utilisé oh-my-zsh , il en .oh-my-zsh/completionsexiste un $fpath, vous pouvez simplement le créer et y mettre vos fonctions de complétion)

Maintenant, vous devez créer un fichier d'achèvement pour votre fonction, son nom doit commencer par un trait de soulignement _, plus le nom de votre fonction. Dans votre cas, son nom est _eb_instances.

Ajoutez ces lignes au _eb_instancesfichier:

#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 "$@"

Vous avez terminé. Enregistrez le fichier et démarrez une nouvelle session pour tester la fin. Vous verrez quelque chose comme ça:

$ eb_instances <cursor>TAB
cuonglm  test

$ eb_instances cuonglm <cursor>TAB
dev      prod     staging

Vous pouvez lire la documentation du système de complétion zsh sur la _argumentsfonction, la statevariable. Vous devez également modifier (cuonglm test)votre sedcommande et passer prod staging devà votre eb_namesfonction.

Si vous souhaitez générer la 2e base d'arguments sur la base de ce 1er argument, vous pouvez utiliser la $words[2]variable:

case $state in
  (aws_profile) _arguments '1:profiles:(cuonglm test)' ;;
            (*) compadd "$@" $(echo $words[2]) ;;
esac

Remplacez echopar votre vraie fonction, dans votre cas, c'est $(eb_names $words[2]).

Si vous vous sentez toujours difficile d'accomplir cela, définissez simplement _eb_instanceset eb_instancesdans votre .zshrcappel, puis complétez comme:

compdef _eb_instances eb_instances

Vous devez initialiser le système d'achèvement avec:

autoload -U compinit
compinit

(Si vous l'avez utilisé oh-my-zsh, il a été chargé)

cuonglm
la source
Merci beaucoup pour la réponse détaillée. Le problème cependant que je n'arrive pas à trouver une manière bien documentée de faire, c'est que si mes options de complétion sont dynamiques, ou proviennent d'autres fonctions / scripts, c'est-à-dire, dans votre exemple, que faire si je voulais cuonglm testvenirsed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' '
zsquare
@zsquare: remplacez simplement (cuonglm test)par ($(sed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' ')), changez compadd "$@" prod staging deven compadd "$@" $(eb_names).
cuonglm
cela l'étire peut-être un peu, mais, j'ai oublié de mentionner, qu'il faut passer eb_namesle premier argument, c'est-à-dire, productionou stagingcomment faire? Merci beaucoup, j'ai obtenu pas mal de choses triées avec ça.
zsquare
Je veux dire que je ne voulais pas utiliser le premier argument pour passer à eb_names. J'ai essayé de référencer $1ou $2, mais pas de dés.
zsquare
2
Tu es un sorcier Harry.
cambunctious