Zsh Autocomplete dinamis untuk perintah khusus

19

Saya mencoba menulis fungsi penyelesaian untuk beberapa fungsi kustom yang saya tulis, tetapi tampaknya benar-benar berjuang dengan yang paling dasar sekalipun.

Contoh fungsi adalah:

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

Ini memiliki dua argumen posisi, <aws profile name>dan<environment name>

Saya ingin opsi penyelesaian <aws profile name>tersedia secara dinamis dengan menjalankan sed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' ', dan penyelesaian untuk <environment name>tersedia secara dinamis dengan menjalankan fungsi lain yang saya panggil eb_names.

Saya menemukan dokumentasi sangat jarang dan sulit untuk diikuti. Saya juga melihat repo zsh-completions untuk perintah yang sama tetapi sepertinya tidak dapat menemukan sesuatu yang mirip dengan yang saya butuhkan.

Bantuan apa pun untuk memulai akan sangat dihargai!

Memperbarui

Berdasarkan jawaban @ cuonglm , saya menggunakan:

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

Apa yang saya lupa sebutkan dalam pertanyaan awal adalah, bahwa saya juga ingin penyelesaian argumen kedua bergantung pada yang pertama (keduanya bersifat dinamis yang menjalankan beberapa kode), misalnya:

$ eb_instances <cursor>TAB
cuonglm  test

mendapatkan penyelesaian yang saya inginkan. Setelah saya pilih ucapkan yang pertama, dan coba lengkapi secara otomatis:

$ eb_instances cuonglm <cursor>TAB

Saya ingin menghasilkan opsi penyelesaian dengan mengeksekusi eb_names cuonglm, dan jika memungkinkan, juga, menelusuri penyelesaian misalnya jika kandidat yang benar adalah foo-bar,

$ eb_instances cuonglm foo<cursor>TAB

Saya ingin menghasilkan opsi penyelesaian dengan mengeksekusi eb_names cuonglm foo

zsquare
sumber

Jawaban:

23

Pada awalnya, Sistem Penyelesaian zsh tampaknya sangat kompleks dan sulit untuk dipahami. Mari kita coba sebuah contoh.

Hal pertama yang perlu Anda ketahui, zshsistem penyelesaian akan memuat fungsi penyelesaian dari $fpath. Pastikan direktori penyelesaian Anda muncul di:

print -rl -- $fpath

(Jika Anda menggunakan oh-my-zsh , ada .oh-my-zsh/completionsada di $fpath, Anda hanya dapat membuat dan menempatkan fungsi selesai Anda ada)

Sekarang, Anda harus membuat file penyelesaian untuk fungsi Anda, namanya harus dimulai dengan garis bawah _, ditambah nama fungsi Anda. Dalam kasus Anda, namanya adalah _eb_instances.

Tambahkan baris tesis ke _eb_instancesfile:

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

Kamu selesai. Simpan file dan mulai sesi baru untuk menguji kelengkapan. Anda akan melihat beberapa hal seperti ini:

$ eb_instances <cursor>TAB
cuonglm  test

$ eb_instances cuonglm <cursor>TAB
dev      prod     staging

Anda dapat membaca dokumentasi sistem penyelesaian zsh tentang _argumentsfungsi, statevariabel. Anda juga perlu mengubah (cuonglm test)dengan sedperintah Anda dan mengubah fungsi prod staging devAnda eb_names.

Jika Anda ingin membuat argumen ke-2 berdasarkan argumen pertama yang dilewati, Anda dapat menggunakan $words[2]variabel:

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

Ganti echodengan fungsi asli Anda, dalam kasus Anda, itu $(eb_names $words[2]).

Jika Anda masih merasa sulit untuk mencapai hal ini, hanya mendefinisikan _eb_instancesdan eb_instancesdi Anda .zshrcpanggilan selesai kemudian sebagai:

compdef _eb_instances eb_instances

Anda perlu menginisialisasi sistem penyelesaian dengan:

autoload -U compinit
compinit

(Jika Anda menggunakan oh-my-zsh, itu telah dimuat)

cuonglm
sumber
Terima kasih banyak atas tanggapan terperinci. Masalahnya adalah bahwa saya sepertinya tidak dapat menemukan cara yang terdokumentasi dengan baik untuk dilakukan, adalah bagaimana jika opsi penyelesaian saya dinamis, atau berasal dari fungsi / skrip lain, yaitu, dalam contoh Anda, bagaimana jika saya ingin cuonglm testberasal darised -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' '
zsquare
@zsquare: Ganti saja (cuonglm test)dengan ($(sed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' ')), ubah compadd "$@" prod staging devke compadd "$@" $(eb_names).
cuonglm
ini mungkin sedikit melebar, tetapi, saya lupa menyebutkan, bahwa perlu melewati eb_namesargumen pertama, yaitu, productionatau staging, bagaimana saya melakukannya? Terima kasih banyak, saya sudah mendapatkan beberapa hal diurutkan dengan ini.
zsquare
Maksud saya, saya tidak ingin menggunakan argumen pertama untuk meneruskan ke eb_names. Saya mencoba referensi $1atau $2, tetapi tidak ada dadu.
zsquare
2
Anda seorang penyihir, Harry.
cambunctious