Preenchimento automático zsh dinâmico para comandos personalizados

19

Estou tentando escrever funções de conclusão para algumas funções personalizadas que escrevi, mas parece estar realmente lutando com as mais básicas.

Um exemplo de função é:

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

Isso tem dois argumentos posicionais, <aws profile name>e<environment name>

Quero que as opções de conclusão <aws profile name>estejam disponíveis dinamicamente executando sed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' ', e as conclusões para <environment name>que estejam disponíveis dinamicamente executando outra função que chamei eb_names.

Estou achando a documentação bastante escassa e difícil de seguir. Também vi o repositório zsh-completions para comandos semelhantes, mas não consigo encontrar algo semelhante ao que eu preciso.

Qualquer ajuda para começar seria muito apreciada!

Atualizar

Com base na resposta de @ cuonglm , usei:

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

O que eu esqueci de mencionar na pergunta original era que eu também queria que a conclusão do segundo argumento dependesse do primeiro (ambos os quais são dinâmicos com base na execução de algum código), por exemplo:

$ eb_instances <cursor>TAB
cuonglm  test

obtém as conclusões que eu quero. Depois de selecionar, diga o primeiro e tente concluir automaticamente:

$ eb_instances cuonglm <cursor>TAB

Desejo gerar as opções de conclusão executando eb_names cuonglme, se possível, também uma pesquisa detalhada das conclusões, por exemplo, se o candidato correto foi foo-bar,

$ eb_instances cuonglm foo<cursor>TAB

Quero gerar as opções de conclusão executando eb_names cuonglm foo

zsquare
fonte

Respostas:

23

Na primeira vez, o zsh Completion System parece ser muito complexo e difícil de entender. Vamos tentar um exemplo.

A primeira coisa que você precisa saber é que o zshsistema de conclusão carregará as funções de conclusão $fpath. Verifique se o diretório de conclusões aparece em:

print -rl -- $fpath

(Se você usou oh-meu-zsh , não está .oh-my-zsh/completionsexistia em $fpath, você pode simplesmente criá-lo e colocar as suas funções de conclusão lá)

Agora, você deve criar um arquivo de conclusão para sua função, seu nome deve começar com sublinhado _, além do nome da sua função. No seu caso, o nome é _eb_instances.

Adicione estas linhas ao _eb_instancesarquivo:

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

Você terminou. Salve o arquivo e inicie uma nova sessão para testar a conclusão. Você verá algo assim:

$ eb_instances <cursor>TAB
cuonglm  test

$ eb_instances cuonglm <cursor>TAB
dev      prod     staging

Você pode ler a documentação do sistema de conclusão do zsh sobre a _argumentsfunção, statevariável. Você também precisa mudar (cuonglm test)com seu sedcomando e mudar prod staging devpara sua eb_namesfunção.

Se você deseja gerar a segunda base de argumentos com base no primeiro argumento passado, é possível usar a $words[2]variável:

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

Substitua echopor sua função real, no seu caso, é $(eb_names $words[2]).

Se você ainda estiver com dificuldade para fazer isso, basta definir _eb_instancese, eb_instancesem .zshrcseguida, conclua a chamada como:

compdef _eb_instances eb_instances

Você precisa inicializar o sistema de conclusão com:

autoload -U compinit
compinit

(Se você usou oh-my-zsh, ele foi carregado)

cuonglm
fonte
Muito obrigado pela resposta detalhada. O problema, porém, que eu não consigo encontrar uma maneira bem documentado que fazer, é o que se as minhas opções de conclusão são dinâmicos, ou provenientes de outras funções / scripts, ou seja, no seu exemplo, o que se eu queria cuonglm testvirsed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' '
ZSquare
@zsquare: Substitua (cuonglm test)por ($(sed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' ')), mude compadd "$@" prod staging devpara compadd "$@" $(eb_names).
#
isso pode ser um pouco complicado, mas, esqueci de mencionar, isso precisa passar eb_namespelo primeiro argumento, ou seja, productionou stagingcomo faço isso? Muito obrigado, já resolvi algumas coisas com isso.
Zsquare 2/11
Quero dizer, eu queria usar o primeiro argumento para passar para eb_names. Eu tentei fazer referência $1ou $2, mas nenhum dado.
Zsquare 2/11
2
Você é um bruxo, Harry.
cambunctious 23/08/19