Autocompletado dinámico de zsh para comandos personalizados


19

Estoy tratando de escribir funciones de finalización para algunas funciones personalizadas que escribí, pero parece que estoy luchando incluso con las más básicas.

Una función de ejemplo es:

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

Esto tiene dos argumentos posicionales, <aws profile name>y<environment name>

Quiero que las opciones de finalización <aws profile name>estén disponibles dinámicamente ejecutando sed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' ', y las finalizaciones para <environment name>que estén disponibles dinámicamente ejecutando otra función que he llamado eb_names.

La documentación me parece bastante escasa y difícil de seguir. También he visto el repositorio zsh-completions para comandos similares, pero parece que no puedo encontrar algo similar a lo que necesito.

¡Cualquier ayuda para comenzar sería muy apreciada!

Actualizar

Basado en la respuesta de @ cuonglm , usé:

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

Lo que olvidé mencionar en la pregunta original fue que también quería que la finalización del segundo argumento dependiera del primero (ambos basados ​​en la ejecución dinámica de algún código), por ejemplo:

$ eb_instances <cursor>TAB
cuonglm  test

obtiene las terminaciones que quiero. Una vez que selecciono decir el primero, e intento completar automáticamente:

$ eb_instances cuonglm <cursor>TAB

Quiero generar las opciones de finalización ejecutando eb_names cuonglmy, si es posible, también, profundizar en las finalizaciones, por ejemplo, si el candidato correcto era foo-bar,

$ eb_instances cuonglm foo<cursor>TAB

Quiero generar las opciones de finalización ejecutando eb_names cuonglm foo

Respuestas:


23

Por primera vez, zsh Completion System parece ser muy complejo y difícil de comprender. Vamos a probar un ejemplo.

Lo primero que debe saber es que el zshsistema de finalización cargará las funciones de finalización $fpath. Asegúrese de que su directorio de finalizaciones aparezca en:

print -rl -- $fpath

(Si ha utilizado oh-my-zsh , hay .oh-my-zsh/completionsexistía en $fpath, sólo puede crear y poner sus funciones de completado allí)

Ahora, debe crear un archivo de finalización para su función, su nombre debe comenzar con un guión bajo _, más el nombre de su función. En su caso, su nombre es _eb_instances.

Agregue estas líneas al _eb_instancesarchivo:

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

Estás listo. Guarde el archivo e inicie una nueva sesión para probar la finalización. Verás algo como esto:

$ eb_instances <cursor>TAB
cuonglm  test

$ eb_instances cuonglm <cursor>TAB
dev      prod     staging

Puede leer la documentación del sistema de finalización zsh sobre la _argumentsfunción, statevariable. También debe cambiar (cuonglm test)con su sedcomando y cambiar prod staging deva su eb_namesfunción.

Si desea generar la segunda base de argumentos sobre la que pasó el primer argumento, puede usar la $words[2]variable:

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

Reemplace echocon su función real, en su caso, es $(eb_names $words[2]).

Si aún se siente difícil de lograr esto, simplemente defina _eb_instancesy complete eb_instancessu .zshrcllamada como:

compdef _eb_instances eb_instances

Debe inicializar el sistema de finalización con:

autoload -U compinit
compinit

(Si lo usó oh-my-zsh, se ha cargado)


Muchas gracias por la respuesta detallada. El problema sin embargo, que me parece que no puede encontrar una manera bien documentado que hacer, es lo que mis opciones de finalización son dinámicas, o vienen de otras funciones / scripts, es decir, en el ejemplo, lo que si quería cuonglm testvenir desed -n -E 's/\[([a-zA-Z0-9_\-]+)\]/\1/p' ~/.aws/credentials | tr \\n ' '
ZSquare

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

esto puede estar estirándolo un poco, pero, olvidé mencionar, que necesito pasar eb_namesel primer argumento, es decir, productiono staging¿cómo hago eso? Muchas gracias, he ordenado algunas cosas con esto.
zsquare

Quiero decir, no quería usar el primer argumento para pasar a eb_names. Intenté hacer referencia $1o $2, pero no dados.
zsquare

2
Eres un mago Harry.
desagradable el
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.