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

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)


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.