Posso ver as alterações antes de salvar meu arquivo no Vim?


135

Eu uso o Vim. Eu abro um arquivo. Eu o edito e quero ver o que editei antes de salvá-lo.

Como posso fazer isso no Vim?

Respostas:


57

http://vim.wikia.com/wiki/Diff_current_buffer_and_the_original_file

Aqui está uma função e um comando para ver uma diferença entre o arquivo atualmente editado e sua versão não modificada no sistema de arquivos. Basta colocar isso no seu vimrc ou no diretório do plugin, abrir um arquivo, fazer algumas modificações sem salvá-las e fazer :DiffSaved.

function! s:DiffWithSaved()
  let filetype=&ft
  diffthis
  vnew | r # | normal! 1Gdd
  diffthis
  exe "setlocal bt=nofile bh=wipe nobl noswf ro ft=" . filetype
endfunction
com! DiffSaved call s:DiffWithSaved()

Para sair da exibição diff, você pode usar o :diffoffcomando

Abaixo está uma função semelhante, adaptada para imitar o 'cvs diff'comando ...


7
@ luc-hermitte A alternativa não é :w !diff % -superior quando você está usando o vim em um grande número de caixas sempre variável e que você não pode alterar facilmente o .vimrc? (Desde que tenham diff instalado.)
— thomanski

1
Vim não é a ferramenta da última esperança. Aquele que funcionará quando nada mais estiver disponível. É a minha principal ferramenta de trabalho.
— Luc Hermitte 11/01/12

12
Apenas fornecer um link não é realmente uma resposta
— Skurpi

3
A resposta do caos é superior e, na resposta de Tobias, a explicação está completa.
— Avi Cohen

1
Você pode adicionar algum conteúdo em vez de apenas um link? Orientações para SO ...
— Błażej Michalik

160
:w !diff % -

4
Existe uma maneira de fazer isso com o vimdiff? Eu tentei: w! Vimdiff% - mas sem sucesso.
— Joe J

14
Alguém pode explicar isso? Eu não entendo o que está acontecendo. Eu entendo que você está gastando muito diff. %refere-se ao caminho do arquivo aberto no momento. Por que tudo isso é um argumento para o :wcomando? Além disso, como é -atribuído ao conteúdo do buffer de trabalho? Isso é automático no vim, que o conteúdo do buffer (ou talvez um intervalo específico no buffer) seja atribuído ao stdin para comandos do shell?
— Nathan Wallace

9
@ NathanWallace: É um argumento :wporque estamos escrevendo o arquivo no comando (on stdin). No comando, -diz para ler stdin.
— 7283 caos

14
Ou use :w !git diff % -para uma versão colorida, se você tiver o git instalado!
— Dergachev

5
@ Dergachev Eu recebo o erro fatal: bad flag '-' used after filenamequando executo :w !git diff % -.
— Escala de cinza

100

Porque algumas pessoas perguntaram sobre uma explicação para o comando

:w !diff % -

Aqui está minha tentativa de escrever uma resposta mais detalhada:

Suponho que você esteja trabalhando em um sistema com cate echoinstalado (por exemplo, quase todos os sistemas GNU / Linux, Mac OS, BSD e outros sistemas similares ao UNIX).

O comando acima funciona da seguinte maneira:

  1. A sintaxe para salvar um arquivo no vim é:

    :w <filename>
    
  2. A sintaxe para executar um comando shell no vim é:

    :!<command>
    
  3. O ambiente do shell emitido pelo vim %aponta para o nome do arquivo atual. Você pode verificar isso executando o seguinte:

    :!echo %
    

    Isso deve gerar o nome do arquivo (ou um erro, se o vim foi executado sem um nome de arquivo).

    Usando cat, também podemos gerar o conteúdo do arquivo:

    :!cat %
    

    Isso deve retornar o conteúdo dos arquivos em seu último estado salvo ou um erro se nunca tiver sido salvo.

  4. O diff do programa pode ler da entrada padrão (stdin). Sua página de manual afirma o seguinte:

    [...] Se um ARQUIVO for '-', leia a entrada padrão. [...]

  5. A execução do comando save sem um nome de arquivo, mas um comando shell atrás dele faz com que o vim grave o conteúdo dos arquivos no stdin do shell, em vez de salvá-lo em um arquivo físico. Você pode verificar isso executando

    :w !cat
    

    Isso sempre deve imprimir o conteúdo atual dos arquivos (que seria gravado em um arquivo).

Reunindo (ou tl; dr): O arquivo é "salvo" no stdin, o diff é executado com o nome do arquivo e o stdin como entrada.

Saber que este também pode comparar arquivos com o vimdiff, fazendo algo assim - isso é apenas uma ideia de que você não deseja fazer isso:

:w !cat > /tmp/tempFile && vimdiff /tmp/tempFile % && rm /tmp/tempFile

(Em seguida, abra o modo somente leitura e feche o vimdiff usando :qall)


Uma abordagem mais sensata para uso vimdiff seria a criação de um shell script que contém o seguinte vim - -c ":vnew $1 |windo diffthis", tornando-executável, salvando-o no PATH como, por exemplo, vimdiffWithStdine em seguida, comparando com o seguinte comando no vim::w !vimdiffWithStdin %
— Tobias Heinicke

Ainda mais simples: :w !vimdiff % /dev/stdin. Não sei se existe um truque semelhante para o Windows.
— Deft_code

12

Eu sempre gostei de mudanças - agradável, simples, funciona.


Isso funciona MUITO melhor do que as opções mais votadas. Isso permite alternar.
— Steven Lu

1
@StevenLu - Meh ... o que você pode fazer? De qualquer forma, que bom que gostou. Acho mais prático que a outra abordagem.
— Rook

Eu, segundo, @ Steven, suas alterações sugeridas são excelentes. Obrigado!
— AS

Isso também pode ser instalado como um plugin do mesmo desenvolvedor: github.com/jmcantrell/vim-diffchanges
— Sumanth Lingappa

bom plugin, mas não exclui o patch que cria depois? Edit: Meu mal! Faz. Eu estava usando da maneira errada. Eu tive que usar :DiffChangesDiffToggle.
— aderchox

10

de vimrc_example.vim:

" Convenient command to see the difference between the current buffer and the
" file it was loaded from, thus the changes you made.
if !exists(":DiffOrig")
  command DiffOrig vert new | set bt=nofile | r # | 0d_ | diffthis
          \ | wincmd p | diffthis
endif

... conforme documentado em vimdoc.sourceforge.net/htmldoc/diff.html#:DiffOrig . Vantagem deste mais w !diff % -é que ele funciona fontes mais remotas também (por exemplo: vim sftp://example.com/foo.txt)
— Lekensteyn

1
I como este melhor porque vemos o direito diferença dentro do vim tampão em si, em vez de em um terminal
— Niko Bellic

Como você volta ao normal quando termina de examinar as diferenças?
— Niko Bellic

Você pode se livrar da cláusula if substituindo command por command! (consulte: h E174)
— elegível

@NikoBellic Primeiro feche a janela "antiga" (marcada como buffer temporário) com ': q'. Você pode alternar entre janelas tocando em ctrl-W duas vezes enquanto estiver no modo normal. Em seguida, você pode desativar o diff escrevendo: diffoff
— brunch875

2

Crie o seguinte e use: Comando DIFF

function! s:diff()
    let tmpa = tempname()
    let tmpb = tempname()
    earlier 100h
    exec 'w '.tmpa
    later 100h
    exec 'w '.tmpb
    update
    exec 'tabnew '.tmpa
    diffthis
    vert split
    exec 'edit '.tmpb
    diffthis
endfunction
command! -nargs=0 DIFF call <SID>diff()

2

Não é exatamente o que você está procurando, mas o SCMDiff.vim é muito legal. Um pressionamento de tecla e destaca o arquivo atual com a revisão principal em um repositório de controle de origem. Ele deve funcionar com muitos SCMS. Eu uso com força.



1

Eu posso recomendar o plugin histwin .

Embora não seja diferente da versão salva atual do arquivo (como as outras respostas), ela pode vimdiff as alterações desde que você começou a editar e até reproduzir as alterações em ordem. A diferença mostra se você salva intermediários.

Além disso, ele exibe uma lista de todas as ramificações do histórico de desfazer e permite alternar ou diferenciar entre elas.

PS: Embora o plug-in não rastreie automaticamente momentos no histórico de edição, pois todos os arquivos são alterados, você pode "marcar" explicitamente o momento em que salvar o arquivo, para depois poder vimdiff com ele, se desejar. Talvez isso possa ser automatizado?


1

Se você deseja usar o vim para comparação como no vimdiff, você pode fazer algo assim:

Edite seu arquivo .vimrc e adicione:

nmap <F8> :w !vim -M -R - -c ":vnew % \| windo diffthis"<CR><CR>

A partir daí, você verá suas alterações e poderá sair da visualização diff usando qallcomo no vimdiff pressionando F8 no modo de comando. Substitua F8 por qualquer tecla que desejar.

Edit: Adicionado -M para proibir qualquer modificação, porque não é salvo.


Esse comando começa a funcionar para mim, mostra o diff lado a lado. No entanto, assim que tento editar qualquer coisa, a janela do vim fica louca. Começo a digitar e recebo um prompt do bash por trás das palavras no vim em ambos os lados da tela. Parece exibir o diff, mas o vim trava. Além disso, recebo esse erro. Vim: Error reading input, exiting...Alguma idéia do que está errado aqui?
— Trevor

@ Trevor: Eu só conseguia adivinhar quais são os problemas. De fato, não é de graça fazer modificações enquanto estiver diferindo assim. Portanto, eu adicionei o parâmetro "-M" para desautorizá-lo completamente. Desculpe.
— Tobias Heinicke

1

O git suporta o seguinte comando

:w !git diff --no-index -- % -

mapeie-o para um comando adicionando o seguinte ao seu ~ / .vimrc

command GitDiff execute "w !git diff --no-index -- % -"

Agora, a execução :GitDiffse torna um pequeno comando útil para mostrar rapidamente o diff antes de cada salvamento.


0

Você pode fazer com que o vim crie um último backup e backup original com:

:set backup
:set patchmode=.orig 

Depois disso, você pode abri-los em uma divisão:

:vsp %:p~ or :vsp %:.orig

E a partir daí faça:

:vimdiff in each buffer

Se você estiver morto, sem sobras, mas quiser o vimdiff, também poderá:

ggVGy    # copy the whole buffer
:vnew    # open a split
CTRL-W w # switch to it
shift-P  # paste at start

e faça: diffthis em cada divisão


0

Alterações que você acabou de editar [ buffer ], ou seja, aquelas que diferem da última versão salva (no diretório de trabalho ), podem ser diferentes da última versão de índice ( Git ). Mapeei os dois:

" Find diff inbetween currrent buffer and ... A{last index version} vs B{last saved version in working directory}
"  - A{last index version}: the file as you last commited it
    " git diff to vimdiff against the index version of the file:
    nnoremap <leader>gd <Esc>:Gvdiff<CR><Esc>:echo "currentBuffer vs lastIndexVersion (last commited)"<CR>
"  - B{last saved version in working directory}: the file you last :w,
"   not neccesary commited it (not commited for sure if it is in NO git project)
    " https://vim.fandom.com/wiki/Diff_current_buffer_and_the_original_file
    nnoremap <leader>gd2 <Esc>:DiffSaved<CR><Esc>:echo "currentBuffer vs lastSaved (not neccesary equal to last commited)"<CR>
    function! s:DiffWithSaved()
        let filetype=&ft
        diffthis
        vnew | r # | normal! 1Gdd
        diffthis
        exe "setlocal bt=nofile bh=wipe nobl noswf ro ft=" . filetype
    endfunction
    com! DiffSaved call s:DiffWithSaved()

Exemplo de vimdiff vs Gdiff.

  • vimdiff: : vimdiff
  • Gdiff: Ao Gdiff realizar alterações, você vê apenas Gdiff, o que pode ou pode ter as mesmas alterações que o vimdiff: ao confirmar alterações, você vê apenas Gdiff, o que pode ou não ter as mesmas alterações que o vimdiff

Além disso, para facilitar o vimdiffarquivo homônimo em outro caminho:

    " vimdiff homonym file 
   nnoremap <leader>dh  <Esc>:vsplit %:p:h/../__/%:t <bar> :windo diffthis<Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left><Left>
        "E.g."$ vim /path01/proj02_pg064/processorder.php
        ":vsplit %:p:h/../proj01_pg05/%:t | :windo diffthis

1
Pode-se apenas fazer um mapa que seja executado: a Gdiffse possível e caso contrário (por exemplo, não um projeto Git), então execute a :vimdiff. Com try-catch-endtry. Mas dessa maneira, :DiffWithSavedem um projeto Git, não existe.
— Xopi García

-2

Siga o que precede sugere que eu uso git diff que eu gosto muito:

:w !git diff  % -
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.