Agregue argumentos del comando anterior para completar zsh

22

En zsh (así como bash) puede usar algunas expansiones de palabras del historial para denotar argumentos de comandos anteriores.

Este ejemplo muestra cómo obtener el segundo parámetro del comando anterior en el historial con !:#expansión:

% echo foo bar baz
foo bar baz
% echo !:2
echo bar
bar

A menudo olvido exactamente qué parámetro # es un argumento en particular y escribir !:#no siempre es tan rápido cuando recuerdo qué argumento es. Sé a punto meta-.de reemplazar el último argumento, pero a veces no es el último argumento que quiero.

Me gustaría agregar los argumentos del comando anterior como sugerencias para completar cualquier comando que estoy escribiendo en zsh.

Pude descubrir cómo crear una función de shell que pueda crear una matriz de argumentos (0..N) desde el último comando y vincularlo a un comando en particular.

_last_command_args() {
    last_command=$history[$[HISTCMD-1]]
    last_command_array=("${(s/ /)last_command}") 
    _sep_parts last_command_array
}

# trying to get last_command_args to be suggested for any command, this just works for foo
compdef _last_command_args foo

Esto es lo que parece completar solo foo donde presioné la tecla tab en <TAB>:

% echo bar baz qux
bar baz qux
% foo <TAB>
bar   baz   echo  qux 

Esto funciona muy bien para completar el comando "foo", pero me gustaría que sean opciones en cualquier expansión de zsh que haga. Creo que tiene algo que ver con las cosas completadoras de zstyle, pero después de unas horas de pirateo me di cuenta de que estaba fuera de mi alcance.

¿Cómo puedo obtener los argumentos de mi comando anterior como finalizaciones sugeridas para cualquier comando en zsh?

Tengo mi archivo completo de compilación zshrc compartido en bitbucket si eso ayuda. Mucho de esto se basa en una variedad de fuentes y algunas de ellas las he pirateado yo mismo.

ACTUALIZAR:

La respuesta de @Julien Nicoulaud me acercó, lo marqué como aceptado ya que me llevó a donde necesitaba llegar.

Con mi configuración particular, usando lo sugerido:

zstyle ':completion:*' completer _last_command_args _complete

No funcionó para mí, ya que estaba causando que la finalización de la pestaña solo mostrara la lista de argumentos del último comando (aunque en realidad también se completaría con los nombres de los archivos, pero no los mostraría). Cambiar el orden a _complete _last_command_argshizo lo contrario. Mostraría los nombres de archivo normales, pero no last_command_args

Supongo que esto tiene algo que ver con la forma en que funciona el completer. Creo que solo muestra la salida del primer método que regresa con éxito, pero tengo problemas para analizar la fuente zsh para comprender completamente lo que está sucediendo. Pude ajustar mi método para incluir una llamada para _completeque mostrara tanto los últimos comandos de argumento como las cosas de autocompletar normales. No tan separados, pero funciona lo suficientemente bien para mí.

Aquí está la función completa que utilicé junto con otras cosas de zstyle que tengo:

# adds the arguments from the last commadn to the autocomplete list
# I wasn't able to get this to work standalone and still print out both regular
# completion plus the last args, but this works well enough.
_complete_plus_last_command_args() {
    last_command=$history[$[HISTCMD-1]]
    last_command_array=("${(s/ /)last_command}") 
    _sep_parts last_command_array
    _complete 
}


_force_rehash() {
  (( CURRENT == 1 )) && rehash
  return 1  # Because we didn't really complete anything
}

zstyle ':completion:::::' completer _force_rehash _complete_plus_last_command_args _approximate 

Otras líneas de zstyle que tengo, no son necesarias para que esto funcione, pero podrían afectar por qué esto funciona para mí:

zstyle -e ':completion:*:approximate:*' max-errors 'reply=( $(( ($#PREFIX + $#SUFFIX) / 3 )) )'
zstyle ':completion:*:descriptions' format "- %d -"
zstyle ':completion:*:corrections' format "- %d - (errors %e})"
zstyle ':completion:*:default' list-prompt '%S%M matches%s'
zstyle ':completion:*' group-name ''
zstyle ':completion:*:manuals' separate-sections true
zstyle ':completion:*' menu select
zstyle ':completion:*' verbose yes

Ahora, si estoy en un directorio con file1.txty file2.txt, y mi último comando fue echo foo bar baz, obtengo esto para autocompletar, que es justo lo que quería:

% ls
bar   baz   echo  foo 
- files -
file1.txt   file2.txt 
Ted Naleid
fuente
2
Esta es una idea espectacular
Michael Mrozek
2
Para complementar ^[ .( insert-last-word), me gusta copy-earlier-word, que alterna entre las palabras de la línea alcanzada por insert-last-word. Para su .zshrc:autoload copy-earlier-word && zle -N copy-earlier-word && bindkey '^[,' copy-earlier-word
Gilles 'SO- deja de ser malvado'
@Gilles gracias! Eso me acerca a la funcionalidad si no puedo obtener el autocompletado completo. ~ 80% del tiempo, si no es el último argumento, es el segundo al último argumento que quiero y C-. + C-, es bastante bueno.
Ted Naleid

Respuestas:

6

Puede agregar su completer a la lista de completers utilizados por defecto:

zstyle ':completion:*' completer _last_command_args _complete
nicoulaj
fuente
1
Si hay alguna _last_command_argsfinalización, las demás no se muestran. ¿Cómo se obtienen además de los habituales?
Gilles 'SO- deja de ser malvado'
1
Gracias por la respuesta, esto me acercó lo suficiente como para que algo funcionara para mí, así que lo acepto. Lo que hice de manera diferente se observa como una actualización de la pregunta anterior. Su solución no imprimió tanto los argumentos del último comando como los archivos, etc. del finalizador normal. Compuse _completedentro de la función que creé y funciona exactamente como quería.
Ted Naleid
Tienes razón, mi respuesta no es correcta.
nicoulaj