Dynamiczne autouzupełnianie zsh dla poleceń niestandardowych

19

Próbuję napisać funkcje uzupełniania dla niektórych niestandardowych funkcji, które napisałem, ale wydaje mi się, że naprawdę mam problemy z nawet najbardziej podstawowymi.

Przykładowa funkcja to:

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

Ma to dwa argumenty pozycyjne <aws profile name>i<environment name>

Chcę, aby opcje uzupełniania <aws profile name>były dynamicznie dostępne po uruchomieniu sed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' ', a uzupełnienia <environment name>były dynamicznie dostępne po uruchomieniu innej funkcji, którą wywołałem eb_names.

Uważam, że dokumentacja jest dość rzadka i trudna do naśladowania. Widziałem też repozytorium zsh-uzupełniające dla podobnych poleceń, ale nie mogę znaleźć czegoś podobnego do tego, czego potrzebuję.

Każda pomoc na początku byłaby mile widziana!

Aktualizacja

Na podstawie odpowiedzi @ cuonglm użyłem:

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

W pierwotnym pytaniu zapomniałem wspomnieć, że chciałem, aby uzupełnienie drugiego argumentu zależało od pierwszego (oba są oparte na dynamice i wykonują jakiś kod), na przykład:

$ eb_instances <cursor>TAB
cuonglm  test

otrzymuje uzupełnienia, które chcę. Po wybraniu powiedz pierwszy i spróbuj wykonać automatycznie:

$ eb_instances cuonglm <cursor>TAB

Chcę wygenerować opcje ukończenia, wykonując eb_names cuonglm, a jeśli to możliwe, również drążenie w szczegółach, na przykład jeśli prawidłowym kandydatem był foo-bar,

$ eb_instances cuonglm foo<cursor>TAB

Chcę wygenerować opcje zakończenia, wykonując eb_names cuonglm foo

zsquare
źródło

Odpowiedzi:

23

Po raz pierwszy system uzupełniania zsh wydaje się być bardzo złożony i trudny do uchwycenia. Spróbujmy przykładu.

Pierwszą rzeczą, którą musisz wiedzieć, zshsystem uzupełniania załaduje funkcje uzupełniania $fpath. Upewnij się, że katalog uzupełnień znajduje się w:

print -rl -- $fpath

(Jeśli użyłeś oh-my-zsh , jest.oh-my-zsh/completions istniał $fpath, można po prostu stworzyć i umieścić swoje funkcje uzupełniania tam)

Teraz musisz utworzyć plik zakończenia dla swojej funkcji, jego nazwa musi zaczynać się od podkreślenia _ oraz nazwą twojej funkcji. W twoim przypadku jego nazwa to _eb_instances.

Dodaj te linie do _eb_instancespliku:

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

Gotowe. Zapisz plik i rozpocznij nową sesję, aby zakończyć test. Zobaczysz coś takiego:

$ eb_instances <cursor>TAB
cuonglm  test

$ eb_instances cuonglm <cursor>TAB
dev      prod     staging

Możesz przeczytać dokumentację systemu uzupełniania zsh o _argumentsfunkcji, statezmiennej. Musisz także zmienić za (cuonglm test)pomocą swojego sedpolecenia i zmienićprod staging dev do swojej eb_namesfunkcji.

Jeśli chcesz wygenerować drugi argument na podstawie przekazanego pierwszego argumentu, możesz użyć $words[2]zmiennej:

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

Zastąpić echo swoją prawdziwą funkcją, w twoim przypadku jest to $(eb_names $words[2]).

Jeśli nadal czujesz trudno tego dokonać, wystarczy zdefiniować _eb_instancesi eb_instancesw swojej .zshrcnastępnie zakończenia połączenia jak:

compdef _eb_instances eb_instances

Musisz zainicjować system uzupełniania za pomocą:

autoload -U compinit
compinit

(Jeśli używałeś oh-my-zsh, został załadowany)

Cuonglm
źródło
Bardzo dziękuję za szczegółową odpowiedź. Problemem, który wydaje mi się, że nie mogę znaleźć dobrze udokumentowanego sposobu, jest to, że jeśli moje opcje uzupełniania są dynamiczne lub pochodzą z innych funkcji / skryptów, tj. W twoim przykładzie, co jeśli chciałbym cuonglm testpochodzićsed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' '
zsquare
@zsquare: Wystarczy wymienić (cuonglm test)z ($(sed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' ')), zmiany compadd "$@" prod staging devdo compadd "$@" $(eb_names).
cuonglm,
może to być rozciąganie to trochę, ale zapomniałem wspomnieć, że trzeba przekazać eb_namespierwszy argument, to znaczy, productionczy staging, jak to zrobić? Wielkie dzięki, udało mi się uporządkować kilka rzeczy.
zsquare
To znaczy, nie chciałem użyć pierwszego argumentu, aby przejść do eb_names. Próbowałem nawiązać do $1lub $2, ale nie kości.
zsquare
2
Jesteś czarodziejem Harry.
kambuzowy