Adicionar argumentos do comando anterior à conclusão do zsh

21

No zsh (assim como no bash), você pode usar algumas expansões de palavras do histórico para denotar argumentos de comandos anteriores.

Este exemplo mostra como obter o segundo parâmetro do comando anterior no histórico com !:#expansão:

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

Costumo esquecer exatamente o que # parâmetro é um argumento específico e a digitação !:#nem sempre é tão rápida quando me lembro qual é o argumento. Eu sei sobre meta-.substituir o último argumento, mas às vezes não é o último argumento que eu quero.

Eu gostaria de adicionar os argumentos do comando anterior como sugestões para concluir qualquer comando que eu estou digitando no zsh.

Consegui descobrir como criar uma função shell que pode criar uma matriz de argumentos (0..N) a partir do último comando e vinculá-la a um comando específico.

_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

Isto é o que parece para completar apenas onde eu apertei a tecla tab em <TAB>:

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

Isso funciona muito bem para a conclusão do comando "foo", mas eu gostaria que fossem opções em qualquer expansão zsh que eu faça. Eu acho que tem algo a ver com as coisas completas do zstyle, mas depois de algumas horas de hackers, percebi que estava fora do meu alcance.

Como posso obter os argumentos do meu comando anterior como conclusões sugeridas para qualquer comando no zsh?

Eu tenho meu arquivo completo de instalação do zshrc compartilhado no bitbucket, se isso ajudar. Muito disso é extraído de uma variedade de fontes e algumas delas foram hackeadas.

ATUALIZAR:

A resposta de @Julien Nicoulaud me aproximou, estou marcando-a como aceita como me levou aonde eu precisava chegar.

Com minha configuração específica, usando o sugerido:

zstyle ':completion:*' completer _last_command_args _complete

Não funcionou para mim, pois estava fazendo com que a conclusão da guia exibisse apenas a lista de argumentos do último comando (embora na verdade fosse concluída com nomes de arquivos, mas não apenas). Alterar a ordem para _complete _last_command_argsfazer o inverso. Seria exibir os nomes de arquivos normais, mas não last_command_args

Acho que isso tem algo a ver com a maneira como o completer funciona. Eu acho que apenas exibe a saída do primeiro método que retorna com êxito, mas estou tendo problemas para analisar a fonte zsh para entender completamente o que está acontecendo. Consegui ajustar meu método para incluir uma chamada para _completeque mostrasse os comandos do último argumento e o material de preenchimento automático regular. Não é tão separado, mas funciona bem o suficiente para mim.

Aqui está a função completa que usei, juntamente com as outras coisas do zstyle que tenho:

# 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 

Outras linhas do zstyle que eu tenho, não são necessárias para que isso funcione, mas podem afetar por que isso funciona para mim:

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

Agora, se eu estiver em um diretório com file1.txte file2.txt, e meu último comando foi echo foo bar baz, eu recebo isso para preenchimento automático, que é exatamente o que eu queria:

% ls
bar   baz   echo  foo 
- files -
file1.txt   file2.txt 
Ted Naleid
fonte
2
Essa é uma ideia espetacular
Michael Mrozek
2
Para complementar ^[ .( insert-last-word), eu gosto copy-earlier-word, que alterna entre as palavras da linha alcançada por insert-last-word. Para o seu .zshrc:autoload copy-earlier-word && zle -N copy-earlier-word && bindkey '^[,' copy-earlier-word
Gilles 'SO- stop be evil'
@Gilles thanks! Isso me aproxima da funcionalidade se eu não conseguir o preenchimento automático completo. ~ 80% do tempo, se não é o último argumento, é o penúltimo argumento que eu quero e C-. + C-, é muito bom.
Ted Naleid

Respostas:

6

Você pode adicionar seu completer à lista de finalizadores usados ​​por padrão:

zstyle ':completion:*' completer _last_command_args _complete
nicoulaj
fonte
1
Se houver alguma _last_command_argsconclusão, as outras não serão mostradas. Como você os consegue além dos habituais?
Gilles 'SO- stop be evil'
1
Obrigado pela resposta, isso me aproximou o suficiente para que algo funcionasse para mim, então estou aceitando. O que fiz de maneira diferente é anotado como uma atualização para a pergunta acima. Sua solução não imprimiu os argumentos do último comando, nem os arquivos, etc., do completor normal. Eu compus _completedentro da função que criei e funciona exatamente como eu queria.
precisa saber é o seguinte
Você está certo, minha resposta não está correta.
nicoulaj