Como alterar a granularidade de desfazer no Vim?

11

Em algum momento, meu Vim desfiz uma palavra inteira quando eu batesse u.

[i]typing some words[C-c][u]

Resultaria em

typing some

No entanto, a granularidade de desfazer parece ter sido alterada para excluir uma letra de cada vez.

[i]typing some words[C-c][u]

Resulta em

typing some word

Lembro-me de ler algo sobre como personalizar a granularidade de desfazer no Practical Vim, mas não consigo me lembrar de como controlá-lo. Qualquer ajuda apreciada!

Dan Prince
fonte
2
Provavelmente existe algo no seu vimrc que faz isso. Não consigo replicá-lo e não consigo encontrar nada nos :helparquivos sobre ele ... Consulte: Como depuro meu arquivo vimrc? ... Além disso, usando <C-c>para sair do modo de inserção pode ter efeitos colaterais ( ver este ) e pode ser parte do problema ... Eu sugiro usar Escou <C-[>( ver este )
Martin Tournoij

Respostas:

11

Quebrando manualmente a sequência de desfazer

Você pode interromper manualmente a sequência de desfazer no modo Inserir com <C-G>u. Da ajuda :

CTRL-G u        break undo sequence, start new change

Exemplo

iHello<C-G>u world!<Esc>u

Isso deixará você com o texto

Hello

Divisão de comandos

i                           " Enter Insert mode
 Hello                      " Type 'Hello'
      <C-G>u                " Break the undo sequence
             world!         " Type ' world!'
                   <Esc>    " Return to Normal mode
                        u   " Undo

Solução automática

Controle de nível inferior de granulação mais fina

Aqui está um pequeno trecho do VimScript usado <C-G>upara criar quebras de desfazer quando você começa a excluir texto e também quando você começa a inserir texto novamente após uma exclusão.

function! s:start_delete(key)
    let l:result = a:key
    if !s:deleting
        let l:result = "\<C-G>u".l:result
    endif
    let s:deleting = 1
    return l:result
endfunction

function! s:check_undo_break(char)
    if s:deleting
        let s:deleting = 0
        call feedkeys("\<BS>\<C-G>u".a:char, 'n')
    endif
endfunction

augroup smartundo
    autocmd!
    autocmd InsertEnter * let s:deleting = 0
    autocmd InsertCharPre * call s:check_undo_break(v:char)
augroup END

inoremap <expr> <BS> <SID>start_delete("\<BS>")
inoremap <expr> <C-W> <SID>start_delete("\<C-W>")
inoremap <expr> <C-U> <SID>start_delete("\<C-U>")

Notas

Isto irá funcionar para <BS>, <C-W>(excluir uma palavra), e <C-U>(excluir para o início da linha). Se houver mais maneiras de excluir no modo Inserir, elas poderão ser suportadas adicionando inoremapchamadas adicionais no final.

tommcdo
fonte
4
O único problema é que você não prevê que irá desfazer mais tarde (caso contrário, não o fará em primeiro lugar). Então você geralmente acaba com uma situação em que gostaria de ter usado <C-G>u, que já é tarde demais.
Shahbaz
4
Sim. Na verdade, algo que eu sinto falta de mim mesmo é isso. Às vezes, faço isso iseguido de uma frase longa seguida de backspace para remover parte do que escrevi (tudo no modo de inserção). Então percebo que não deveria ter retrocedido e que o que eu escrevi estava bem. Desfazer, mas todo o texto inserido será desfeito. Então, ou eu fiquei com nenhuma frase longa ou a parte que não é retrocedida. É impossível recuperar a parte posterior. Existe uma maneira de dizer ao vim para quebrar a sequência de desfazer no backspace? (Agora que eu digo, o mapbackspace é uma opção, é claro).
Shahbaz
2
Para futuros visitantes, também adicionei, inoremap <CR> <C-G>u<CR>para que cada desfazer seja contido em uma única linha (não desfaz mais o parágrafo inteiro que você estava digitando sem parar).
Shahbaz
11
@Shahbaz, absolutamente :)
tommcdo
11
@ Shahbaz "Posso copiar?" Veja o link na parte inferior da página: "contribuições de usuários licenciadas sob cc by-sa 3.0 com atribuição necessária"