Dynamische automatische Vervollständigung für benutzerdefinierte Befehle

18

Ich versuche, Vervollständigungsfunktionen für einige benutzerdefinierte Funktionen zu schreiben, die ich geschrieben habe, aber es scheint, als würde ich selbst mit den grundlegendsten Schwierigkeiten haben.

Eine Beispielfunktion ist:

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

Dies hat zwei Positionsargumente <aws profile name>und<environment name>

Ich möchte, dass die Vervollständigungsoptionen <aws profile name>durch Ausführen dynamisch verfügbar sed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' 'sind und die Vervollständigungsoptionen <environment name>durch Ausführen einer anderen von mir aufgerufenen Funktion dynamisch verfügbar sind eb_names.

Ich finde die Dokumentation recht spärlich und schwer zu befolgen. Ich habe auch das Repo von zsh-completions für ähnliche Befehle gesehen, kann aber anscheinend nicht das finden, was ich brauche.

Jede Hilfe, die anfängt, wäre sehr dankbar!

Aktualisieren

Basierend auf der Antwort von @ cuonglm habe ich Folgendes verwendet:

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

Was ich in der ursprünglichen Frage vergessen habe, war, dass ich auch wollte, dass die Vervollständigung des zweiten Arguments vom ersten abhängig ist (beide basieren auf der dynamischen Ausführung von Code), zum Beispiel:

$ eb_instances <cursor>TAB
cuonglm  test

bekommt die Vervollständigungen, die ich will. Sobald ich ausgewählt habe, sage ich die erste und versuche, sie automatisch zu vervollständigen:

$ eb_instances cuonglm <cursor>TAB

Ich möchte die Vervollständigungsoptionen generieren, indem ich einen eb_names cuonglmDrilldown für die Vervollständigungen durchführe , wenn beispielsweise der richtige Kandidat war foo-bar.

$ eb_instances cuonglm foo<cursor>TAB

Ich möchte die Vervollständigungsoptionen durch Ausführen von generieren eb_names cuonglm foo

zsquare
quelle

Antworten:

21

Auf den ersten Blick scheint das zsh Completion System sehr komplex und schwer zu verstehen zu sein. Lassen Sie uns ein Beispiel versuchen.

Als erstes müssen Sie wissen, dass das zshVervollständigungssystem Vervollständigungsfunktionen von lädt $fpath. Stellen Sie sicher, dass Ihr Vervollständigungsverzeichnis in folgenden Verzeichnissen angezeigt wird:

print -rl -- $fpath

(Wenn Sie oh-my-zsh verwendet haben , existiert .oh-my-zsh/completionses in $fpath, Sie können es einfach erstellen und Ihre Vervollständigungsfunktionen dort platzieren.)

Jetzt müssen Sie eine Vervollständigungsdatei für Ihre Funktion erstellen. Der Name muss mit einem Unterstrich _sowie dem Funktionsnamen beginnen. In Ihrem Fall lautet der Name _eb_instances.

Füge diese Zeilen zur _eb_instancesDatei hinzu:

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

Du bist fertig. Speichern Sie die Datei und starten Sie eine neue Sitzung, um den Abschluss zu testen. Sie werden so etwas sehen:

$ eb_instances <cursor>TAB
cuonglm  test

$ eb_instances cuonglm <cursor>TAB
dev      prod     staging

Sie können die Dokumentation zum zsh-Vervollständigungssystem über _argumentsFunktion, stateVariable lesen . Sie müssen sich auch (cuonglm test)mit Ihrem sedBefehl ändern und prod staging devzu Ihrer eb_namesFunktion wechseln .

Wenn Sie das 2. Argument basierend auf dem übergebenen 1. Argument generieren möchten, können Sie die $words[2]Variable verwenden:

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

Ersetzen Sie echodurch Ihre eigentliche Funktion, in Ihrem Fall ist es $(eb_names $words[2]).

Wenn Sie dies immer noch nicht erreichen können, definieren Sie _eb_instancesund rufen Sie eb_instancesin Ihrem .zshrcThen Completion Folgendes auf:

compdef _eb_instances eb_instances

Sie müssen das Vervollständigungssystem initialisieren mit:

autoload -U compinit
compinit

(Wenn Sie verwendet haben oh-my-zsh, wurde es geladen)

cuonglm
quelle
Vielen Dank für die ausführliche Antwort. Das Problem, das ich anscheinend nicht finden kann, ist, dass meine Vervollständigungsoptionen dynamisch sind oder von anderen Funktionen / Skripten stammen, dh in Ihrem Beispiel, was ist, wenn ich cuonglm testvonsed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' '
zsquare
@zsquare: Ersetzen Sie einfach (cuonglm test)mit ($(sed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' ')), ändern compadd "$@" prod staging devzu compadd "$@" $(eb_names).
2.
das mag ein wenig anstrengend sein, aber ich habe vergessen zu erwähnen, dass eb_namesdas erste Argument überholt werden muss, dh productionoder stagingwie mache ich das? Vielen Dank, ich habe einige Dinge damit sortiert.
Zsquare
Ich wollte nicht das erste Argument verwenden, um an eb_names zu übergeben. Ich habe versucht, $1oder zu referenzieren $2, aber keine Würfel.
Zsquare
1
Du bist ein Zauberer Harry.
kambunctious