Completamento automatico zsh dinamico per comandi personalizzati


19

Sto cercando di scrivere funzioni di completamento per alcune funzioni personalizzate che ho scritto, ma sembra che stia davvero lottando con anche le più elementari.

Una funzione di esempio è:

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

Questo ha due argomenti posizionali, <aws profile name>e<environment name>

Voglio che le opzioni di completamento <aws profile name>siano disponibili dinamicamente eseguendo sed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' ', mentre i completamenti <environment name>siano dinamicamente disponibili eseguendo un'altra funzione che ho chiamato eb_names.

Sto trovando la documentazione abbastanza scarsa e difficile da seguire. Ho anche visto il repository di completamenti zsh per comandi simili ma non riesco a trovare qualcosa di simile a quello di cui ho bisogno.

Qualsiasi aiuto per iniziare sarebbe molto apprezzato!

Aggiornare

Sulla base della risposta di @ cuonglm , ho usato:

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

Quello che ho dimenticato di menzionare nella domanda originale era che volevo anche che il completamento del secondo argomento dipendesse dal primo (entrambi i quali sono dinamici in base all'esecuzione di un codice), ad esempio:

$ eb_instances <cursor>TAB
cuonglm  test

ottiene i completamenti che desidero. Una volta selezionato dì il primo e provo a completare automaticamente:

$ eb_instances cuonglm <cursor>TAB

Voglio generare le opzioni di completamento eseguendo eb_names cuonglme, se possibile, anche il drill-down dei completamenti, ad esempio se il candidato corretto fosse foo-bar,

$ eb_instances cuonglm foo<cursor>TAB

Voglio generare le opzioni di completamento eseguendo eb_names cuonglm foo

Risposte:


23

Per la prima volta, il sistema di completamento zsh sembra essere molto complesso e difficile da comprendere. Facciamo un esempio.

Prima cosa che devi sapere, il zshsistema di completamento caricherà le funzioni di completamento da $fpath. Assicurati che la directory dei completamenti appaia in:

print -rl -- $fpath

(Se hai usato oh-my-zsh , .oh-my-zsh/completionsesiste in $fpath, puoi semplicemente crearlo e inserire lì le tue funzioni di completamento)

Ora, devi creare un file di completamento per la tua funzione, il suo nome deve iniziare con un trattino basso _, più il nome della tua funzione. Nel tuo caso, il suo nome è _eb_instances.

Aggiungi queste righe al _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 "$@"

Hai fatto. Salvare il file e avviare una nuova sessione per testare il completamento. Vedrai qualcosa del genere:

$ eb_instances <cursor>TAB
cuonglm  test

$ eb_instances cuonglm <cursor>TAB
dev      prod     staging

Puoi leggere la documentazione del sistema di completamento zsh sulla _argumentsfunzione, statevariabile. Inoltre devi cambiare (cuonglm test)con il tuo sedcomando e passare prod staging devalla tua eb_namesfunzione.

Se si desidera generare il 2 ° argomento in base al 1 ° argomento passato, è possibile utilizzare la $words[2]variabile:

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

Sostituisci echocon la tua vera funzione, nel tuo caso, lo è $(eb_names $words[2]).

Se ti senti ancora difficile da raggiungere, basta definire _eb_instancese eb_instancesnel tuo .zshrcquindi chiamare il completamento come:

compdef _eb_instances eb_instances

È necessario inizializzare il sistema di completamento con:

autoload -U compinit
compinit

(Se l'hai usato oh-my-zsh, è stato caricato)


Grazie mille per la risposta dettagliata. Il problema però che non riesco a trovare un modo ben documentato di fare, è cosa succede se le mie opzioni di completamento sono dinamiche o provengono da altre funzioni / script, ovvero, nel tuo esempio, e se volessi cuonglm testvenire dased -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' '
zsquare

@zsquare: basta sostituire (cuonglm test)con ($(sed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' ')), cambiare compadd "$@" prod staging devin compadd "$@" $(eb_names).
cuonglm,

questo potrebbe allungarlo un po ', ma, ho dimenticato di menzionare, che è necessario passare eb_namesil primo argomento, ovvero, productiono stagingcome posso farlo? Grazie mille, ho ottenuto parecchie cose risolte con questo.
zsquare,

Voglio dire, non volevo usare il primo argomento in per passare a eb_names. Ho provato a fare riferimento $1o $2, ma nessun dado.
zsquare,

2
Sei un mago Harry.
generoso
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.