2012-05-08 12 views
16

Estoy construyendo un script de finalización de bash para una herramienta que comparte la semántica de carga de archivos con curl.Cómo evitar que la finalización de bash reemplace un carácter cuando se completa la pestaña

Con rizo, que puede hacer:

archivo rizo -F var = @

para cargar un archivo.

Mi aplicación tiene una semántica similar y deseo poder mostrar los archivos posibles después de presionar '@'. Desafortunadamente, esto está resultando difícil:

cur="${COMP_WORDS[COMP_CWORD]}" 
prev="${COMP_WORDS[COMP_CWORD-1]}" 
if [[ "$cur" == @* && "$prev" == '=' ]]; then 
    COMPREPLY=($(compgen -f ${cur:1})) 
    return 0 
fi 

Así que si un comando (hasta ahora) termina con:

[email protected] 

archivos en el directorio actual se mostrará.

[email protected]/usr/                              
/usr/bin  /usr/games 

Problema es si realmente presiono la pestaña para completar, ¡la '@' desaparece!

var=/usr/bin 

Parece que bash reemplaza toda la palabra actual con el COMPREPLY tabulado.

La única manera de evitar este ha sido el de hacer esto:

 COMPREPLY=($(compgen -f ${cur:1})) 
     for ((i=0; i<${#COMPREPLY[@]}; i++)); 
     do 
      COMPREPLY[$i]='@'${COMPREPLY[$i]} 
     done                              

Pero ahora la implementación del tabulador parece extraño por decir lo menos:

@/usr/bin  @/usr/games 

¿Hay alguna forma para mostrar un archivo normal completar la pestaña (sin el prefijo '@') pero conservar la '@' cuando se toca la pestaña?

+1

pregunta impresionante! Aprendí mucho respondiendo esto. – sanmiguel

Respuesta

5

Por lo tanto, esto me intrigó, así que he estado leyendo la fuente de finalización de bash (disponible en/etc/bash_completion).

Encontré esta variable: ${COMP_WORDBREAKS}, que parece permitir el control sobre qué caracteres se utilizan para delimitar palabras.

también me encontré con esta función, _get_cword y la complementaria _get_pword, tanto se recomienda su uso en lugar de ${COMP_WORDS[COMP_CWORD]} y ${COMP_WORDS[COMP_CWORD-1]} respectivamente.

lo tanto, poner todo esto junto, hice algunas pruebas y esto es lo que he llegado con: esto parece funcionar para mí, al menos, espero que para usted también:

# maintain the old value, so that we only affect ourselves with this 
OLD_COMP_WORDBREAKS=${COMP_WORDBREAKS} 
COMP_WORDBREAKS="${COMP_WORDBREAKS}@" 

cur="$(_get_cword)" 
prev="$(_get_pword)" 

if [[ "$cur" == '[email protected]' ]]; then 
    COMPREPLY=($(compgen -f ${cur:2})) 

    # restore the old value 
    COMP_WORDBREAKS=${OLD_COMP_WORDBREAKS} 
    return 0 
fi 

if [[ "$prev" == '[email protected]' ]]; then 
    COMPREPLY=($(compgen -f ${cur})) 

    # restore the old value 
    COMP_WORDBREAKS=${OLD_COMP_WORDBREAKS} 
    return 0 

fi 

Ahora , Admitiré que las cajas if están un poco sucias, definitivamente hay una mejor manera de hacerlo, pero necesito más cafeína.

Además, por lo que vale la pena también descubrí lo largo de la manera en que el argumento -P <prefix> a compgen, que le impida tener que bucle sobre la matriz $COMPREPLY[*]} después de llamar compgen, al igual que

COMPREPLY=($(compgen -P @ -f ${cur:1})) 

Eso es un poco redundante frente a una solución completa, sin embargo.

+1

Excelente investigación. Realmente me gusta a dónde vas con esto. Desde el aspecto de la secuencia de comandos, esto completará la pestaña como yo desee. Pero tengo una gran preocupación. Veo que restablece COMP_WORDBREAKS una vez que un usuario ha escrito los = @ caracteres. ¿Pero qué pasa si él nunca lo hace? Parece que bash siempre tendrá un COMP_WORDBREAKS modificado. Toda esta respuesta parece necesitar alguna forma garantizada de restablecer COMP_WORDBREAKS al valor original cuando el usuario finaliza la entrada de la línea. – UsAaR33

+0

Tiene razón: dejará COMP_WORDBREAKS en ese estado. Encontraré una solución y una actualización. – sanmiguel

+0

Como esta es la mejor respuesta hasta el momento, te daré la recompensa. Aceptará esto (o cualquier respuesta futura) cuando solucione el problema de restablecimiento de COMP_WODBREAKS. – UsAaR33

0

Prueba esto ....

function test 
{ 
    COMPREPLY=() 
    local cur="${COMP_WORDS[COMP_CWORD]}" 
    local opts="Whatever sort of tabbing options you want to have!" 
    COMPREPLY=($(compgen -W "${opts}" -- ${cur})) 
} 
complete -F "test" -o "default" "test" 
# complete -F "test" -o "nospace" "sd" ## Use this if you do not want a space after the completed word 
+0

¿Podría ampliar esto? Estás mostrando los conceptos básicos de un script de finalización de bash, pero ¿cómo se resuelve mi problema subyacente? – UsAaR33

Cuestiones relacionadas