Динамическое автозаполнение Zsh для пользовательских команд

19

Я пытаюсь написать функции завершения для некоторых пользовательских функций, которые я написал, но, похоже, действительно борется даже с самыми простыми.

Пример функции:

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

Это имеет два позиционных аргумента, <aws profile name>и<environment name>

Я хочу, чтобы параметры завершения <aws profile name>были динамически доступны при запуске sed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' ', а завершения <environment name>- динамически доступны при запуске другой функции, которую я вызвал eb_names.

Я нахожу документацию довольно редкой и трудной для следования. Я также видел репозиторий zsh-дополнений для похожих команд, но не могу найти что-то похожее на то, что мне нужно.

Любая помощь с самого начала будет высоко ценится!

Обновить

Основываясь на ответе @ cuonglm , я использовал:

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

Что я забыл упомянуть в исходном вопросе, так это то, что я также хотел, чтобы завершение второго аргумента зависело от первого (оба из которых основаны на динамическом выполнении некоторого кода), например:

$ eb_instances <cursor>TAB
cuonglm  test

получает завершения, которые я хочу. Как только я выбираю произнесите первый, и попробуйте выполнить автоматически:

$ eb_instances cuonglm <cursor>TAB

Я хочу сгенерировать варианты завершения, выполнив eb_names cuonglm, и, если возможно, также детализацию завершений, например, если правильный кандидат был foo-bar,

$ eb_instances cuonglm foo<cursor>TAB

Я хочу создать варианты завершения, выполнив eb_names cuonglm foo

zsquare
источник

Ответы:

23

В первый раз zsh Completion System кажется очень сложной и трудной для понимания. Давай попробуем пример.

Первое, что вам нужно знать, zshсистема завершения будет загружать функции завершения $fpath. Убедитесь, что ваш каталог завершений находится в:

print -rl -- $fpath

(Если вы использовали о-мой-ЗШ , там .oh-my-zsh/completionsсуществовали $fpath, вы можете просто создать его и поместить свои функции завершения там)

Теперь вы должны создать файл завершения для своей функции, его имя должно начинаться с подчеркивания _, плюс имя вашей функции. В вашем случае его зовут _eb_instances.

Добавьте тезисные строки в _eb_instancesфайл:

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

Вы сделали. Сохраните файл и начните новый сеанс для проверки завершения. Вы увидите что-то вроде этого:

$ eb_instances <cursor>TAB
cuonglm  test

$ eb_instances cuonglm <cursor>TAB
dev      prod     staging

Вы можете прочитать документацию системы завершения zsh о _argumentsфункции, stateпеременной. Также вам нужно изменить (cuonglm test)с помощью вашей sedкоманды и перейти prod staging devк вашей eb_namesфункции.

Если вы хотите сгенерировать 2-й аргумент на основе переданного 1-го аргумента, вы можете использовать $words[2]переменную:

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

Замените echoна вашу реальную функцию, в вашем случае это $(eb_names $words[2]).

Если вам все еще трудно это сделать, просто определите _eb_instancesи eb_instancesв вашем .zshrcвызове завершение как:

compdef _eb_instances eb_instances

Вам необходимо инициализировать систему завершения:

autoload -U compinit
compinit

(Если вы использовали oh-my-zsh, он был загружен)

cuonglm
источник
Большое спасибо за подробный ответ. Проблема, однако, в том, что я не могу найти хорошо документированный способ сделать то, что, если мои варианты завершения являются динамическими или исходят из других функций / сценариев, то есть, в вашем примере, что, если я хочу cuonglm testприйтиsed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' '
zsquare
@zsquare: Просто замените (cuonglm test)с ($(sed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' ')), изменения compadd "$@" prod staging devв compadd "$@" $(eb_names).
Cuonglm
это может немного растягивать, но я забыл упомянуть, что нужно передать eb_namesпервый аргумент, т. е. productionили staging, как мне это сделать? Большое спасибо, я получил несколько вещей, отсортированных с этим.
zsquare
Я имею в виду, я не хотел использовать первый аргумент, чтобы передать eb_names. Я пытался ссылаться $1или $2, но не кости.
zsquare
2
Ты волшебник Гарри.
cambuncious