Динамічне автозаповнення 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

Відповіді:


23

У перший час система завершення zsh здається дуже складною і важкою для розуміння. Спробуй приклад.

Перше, що вам потрібно знати, zshсистема завершення завантажить з нього функції завершення $fpath. Переконайтеся, що ваш каталог заповнень відображається в:

print -rl -- $fpath

(Якщо ви використовували oh-my-zsh , він .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 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
Ти чарівник, Гаррі.
cambunvolu
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.