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.