Posso repetir o último comando da interface do usuário?

17

Eu sei que posso usar .para repetir o último comando de edição.

Existe uma maneira de repetir o último comando de manipulação da interface do usuário? Por exemplo, eu posso escrever 10<C-W>-para reduzir uma janela por dez linhas. Seria bom para ser capaz de imprensa ⟨ alguma chave ⟩ repetir facilmente este comando se eu quiser reduzi-lo mais.

wchargin
fonte
Relacionado: stackoverflow.com/q/6952636/2072269 (nenhuma resposta dada pode ser usada depois que você redimensionou).
Muru
@uru: legal, mas é para este caso específico. E se eu fiz algo parecido fze depois 10;? Que tal :tabm +1? Todos estes terão que ser de caixa especial?
Whargin
Eu acho que você me entendeu mal. Estou dizendo que o post vinculado tem respostas inúteis (antes que alguém venha e o sugira).
Muru
ah! Ok, então nós estamos na mesma página @muru :)
wchargin

Respostas:

12

O comando dot .funciona porque o Vim "acompanha" os comandos que alteram o conteúdo dos buffers. Se você executar :echo b:changedtick, você o verá incrementando a cada alteração no buffer atual.

Mas o Vim não "acompanha" os comandos que não são de edição. Portanto, não, o que você está pedindo não pode ser feito.

lcd047
fonte
8

Por padrão, não há como fazer isso no vim porque o vim não controla o wincmd executado anteriormente. No entanto, é possível fazer isso através de alguns mapeamentos inteligentes:

function! s:Wincmd(count, key)
    " If count is not zero, use the original count.  If otherwise, don't
    " include a count.
    let if_count = a:count ? a:count : ""
    " This builds a wincmd from the given key, and saves it so
    " it can be repeated.
    let g:last_wincmd = "wincmd " . nr2char(a:key)
    " Execute the built wincmd
    execute if_count . g:last_wincmd
endfunction

function! s:WincmdRepeat(count)
    " If no wincmd has been executed yet, don't do anything
    if !exists('g:last_wincmd') | return | endif
    " If a count is given, repeat the last wincmd that amount of times.
    " If otherwise, just repeat once.
    let if_count = a:count ? a:count : ""
    execute if_count . g:last_wincmd
endfunction

" Overwrite the default <C-w> mapping so that the last wincmd can be kept
" track of.  The getchar function is what captures the key pressed
" directly afterwards.  The <C-u> is to remove any cmdline range that vim
" automatically inserted.
nnoremap <silent> <C-w> :<C-u>call <SID>Wincmd(v:count, getchar())<CR>

" This just calls the function which repeats the previous wincmd.  It
" does accept a count, which is the number of times it should repeat the
" previous wincmd.  You can also replace Q with whatever key you want. 
nnoremap <silent> Q :<C-u> call <SID>WincmdRepeat(v:count)<CR>

Observe que, se você tiver algum mapeamento em uso, <C-w>ele só poderá ser repetido se não for da norevariedade. Quaisquer wincmds emitidos usando :wincmdnão serão repetidos. Além disso, quaisquer wincmds que contenham mais de um caractere não podem ser executados (como <C-w>gf) .

Tópicos de ajuda relevantes

  • :help v:count
  • :help getchar()
  • :help nr2char()
  • :help expr1
  • :help :wincmd
  • :help :execute
  • :help :for
  • :help :map-<silent>
  • :help c_CTRL-U
  • :help <SID>
EvergreenTree
fonte
1
Isso é ótimo e um excelente exemplo de VimScript bem escrito! Algum feedback menor (talvez exigente): esse comando de repetição se comportaria diferente da maneira como o built-in .se comporta com uma contagem. Quando uma contagem é fornecida ., a contagem anterior é ignorada. Então, 2ddseguido por 3.excluiria 2 linhas e depois 3 linhas; por outro lado, com os seus mapeamentos, 2<C-w>-seguido por 3Qdiminuiria a janela por 2 linhas e depois por 6 (= 2x3) linhas. Esse comportamento é bom, mas é bom usar comandos Vim internos análogos ao escolher como um comando personalizado deve se comportar.
21415 TommyCdo:
Obrigado! Além disso, entendo o que você quer dizer com como a contagem funciona. Eu posso mudar para que funcione dessa maneira.
EvergreenTree
4

O plugin submode pode ajudar com isso. Você pode definir um "submodo" digitado digitando <C-W>-, no qual você definiu -(e talvez +) para continuar redimensionando a janela.

tommcdo
fonte
2

Há outro plugin chamado repmo.vim ("repetir movimentos") que pode fazer o que você deseja.

Mas você precisará especificar quais movimentos (ou ações em geral) você deseja repetir. O meu está atualmente configurado assim:

let g:repmo_mapmotions = "j|k h|l zh|zl g;|g, <C-w>w|<C-w>W"
let g:repmo_mapmotions .= " <C-w>+|<C-w>- <C-w>>|<C-w><"
let g:repmo_key = ";" 
let g:repmo_revkey = "," 

Então, depois de fazer 5 CTRL-W +, posso clicar ;para repeti-lo quantas vezes quiser.

O plug-in funciona criando mapeamentos para cada uma das chaves especificadas.

Quando fou tsão usados, os mapeamentos ;e ,são limpos de volta ao seu comportamento padrão.

Acho o mapeamento g;especialmente útil para voltar a um ponto de edição anterior. g; ; ; ;

joeytwiddle
fonte
@albfan Não sei se entendi sua pergunta, mas, para mim, pressionar ,age imediatamente e 5,também funciona conforme o esperado. É possível que você tiver definido o mapleaderque ,?
joeytwiddle