Czy mogę zobaczyć zmiany, zanim zapiszę plik w Vimie?


135

Używam Vima. Otwieram plik. Edytuję go i chcę zobaczyć, co edytowałem, zanim go zapiszę.

Jak mogę to zrobić w Vimie?

Odpowiedzi:


57

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

Oto funkcja i polecenie pozwalające zobaczyć różnicę między aktualnie edytowanym plikiem a jego niezmodyfikowaną wersją w systemie plików. Po prostu umieść to w swoim vimrc lub w katalogu wtyczek, otwórz plik, wprowadź modyfikacje bez ich zapisywania i zrób :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()

Aby wyjść z widoku różnic, możesz użyć :diffoffpolecenia.

Poniżej podobna funkcja, przystosowana do naśladowania 'cvs diff'polecenia ...


7
@ luc-hermitte Czy nie jest alternatywą :w !diff % -lepszą, gdy używasz vima na ciągle zmieniającej się i dużej liczbie pudełek, dla których nie możesz łatwo zmienić .vimrc? (Pod warunkiem, że mają zainstalowany diff.)
thomanski

1
Vim nie jest narzędziem ostatniej nadziei. Ten, który zadziała, gdy nic innego nie jest dostępne. To moje główne narzędzie pracy.
Luc Hermitte

12
Samo podanie linku nie jest tak naprawdę odpowiedzią
Skurpi,

3
Odpowiedź Chaosa jest lepsza, aw odpowiedzi Tobiasza wyjaśnienie jest kompletne.
Avi Cohen,

1
Czy możesz dodać treść zamiast tylko linku? Wytyczne SO ...
Błażej Michalik

160
:w !diff % -

4
Czy jest sposób, aby to zrobić za pomocą vimdiff? Próbowałem: w! Vimdiff% - ale bez powodzenia.
Joe J

14
Czy ktoś może to wyjaśnić? Nie rozumiem, co się dzieje. Rozumiem, że walczysz do diff. %odnosi się do aktualnie otwartej ścieżki do pliku. Dlaczego to wszystko jest argumentem dla :wpolecenia? W jaki sposób -zostaje przypisany do zawartości bufora roboczego? Czy w vimie jest to automatyczne, że zawartość bufora (a może określony zakres w buforze) jest przypisywana do stdin dla poleceń powłoki?
Nathan Wallace

9
@NathanWallace: To argument do, :wponieważ zapisujemy plik do polecenia (on stdin). W poleceniu -mówi mu, aby czytał stdin.
chaos

14
Lub użyj :w !git diff % -dla wersji kolorowanej, jeśli masz zainstalowany git!
Dergaczow

5
@Dergachev pojawia się błąd fatal: bad flag '-' used after filenamepodczas uruchamiania :w !git diff % -.
Skala szarości

100

Ponieważ niektórzy pytali o wyjaśnienie polecenia

:w !diff % -

Oto moja próba napisania bardziej szczegółowej odpowiedzi:

Jestem zakładając, że użytkownik pracuje w systemie z cati echozainstalowany (np prawie każdy GNU / Linux, Mac OS, BSD i innych systemów UNIX-like).

Powyższe polecenie działa w następujący sposób:

  1. Składnia zapisywania pliku w vimie to:

    :w <filename>
    
  2. Składnia wykonywania polecenia powłoki w vimie to:

    :!<command>
    
  3. Wewnątrz środowiska powłoki wydanego przez vima %zdarza się wskazać aktualną nazwę pliku. Możesz to sprawdzić, wykonując następujące czynności:

    :!echo %
    

    Powinno to wypisać nazwę pliku (lub błąd, jeśli vim został uruchomiony bez nazwy pliku).

    Używając cat możemy również wypisać zawartość pliku:

    :!cat %
    

    Powinno to zwrócić zawartość plików w ostatnim zapisanym stanie lub błąd, jeśli nigdy nie została zapisana.

  4. Program diff potrafi czytać ze standardowego wejścia (stdin). Jego strona podręcznika zawiera następujące informacje:

    [...] Jeśli PLIK jest „-”, czytaj standardowe wejście. […]

  5. Wykonanie polecenia zapisywania bez nazwy pliku, ale raczej polecenia powłoki za nim powoduje, że vim zapisuje zawartość plików na stdin powłoki zamiast zapisywać je w pliku fizycznym. Możesz to zweryfikować, wykonując

    :w !cat
    

    Powinno to zawsze drukować bieżącą zawartość plików (która zamiast tego została zapisana do pliku).

Składanie go razem (lub tl; dr): plik jest „zapisywany” na stdin, diff jest uruchamiany z nazwą pliku i standardowym wejściem jako wejściem.

Wiedząc o tym, można również porównać pliki z vimdiff robiąc coś takiego - to tylko pomysł, którego nie chcesz robić:

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

(Następnie otwórz tylko do odczytu i zamknij vimdiff za pomocą :qall)


Bardziej rozsądnym podejściem do używania vimdiff byłoby utworzenie skryptu powłoki zawierającego następujące elementy vim - -c ":vnew $1 |windo diffthis", uczynienie go wykonywalnym, zapisanie go w PATH, jak na przykład, vimdiffWithStdina następnie porównanie z następującym poleceniem w vimie::w !vimdiffWithStdin %
Tobias Heinicke

Jeszcze prostsze: :w !vimdiff % /dev/stdin. Nie wiem, czy podobna sztuczka dotyczy okien.
deft_code

12

Zawsze lubię różnice - ładne, proste, działa.


Działa to DUŻO lepiej niż opcje, które cieszą się większym uznaniem. Daje to możliwość przełączania go.
Steven Lu

1
@StevenLu - Meh ... co możesz zrobić? W każdym razie cieszę się, że ci się podoba. Uważam, że jest to bardziej praktyczne niż inne podejście.
Rook

Ja robię drugie @Steven, twoje sugerowane różnice są doskonałe. Dzięki!
AS

Można to również zainstalować jako wtyczkę od tego samego programisty: github.com/jmcantrell/vim-diffchanges
Sumanth Lingappa

fajna wtyczka, ale nie usuwa później tworzonej łatki? Edycja: mój błąd! To robi. Użyłem go w niewłaściwy sposób. Musiałem użyć :DiffChangesDiffToggle.
aderchox

10

z 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

... zgodnie z dokumentacją pod adresem vimdoc.sourceforge.net/htmldoc/diff.html#:DiffOrig . Zaletą tego powyższego w !diff % -jest to, że działa na zdalnych źródeł zbyt (na przykład: vim sftp://example.com/foo.txt)
Lekensteyn

1
Podoba mi się to lepiej, ponieważ widzimy różnicę bezpośrednio w samym buforze vim zamiast w terminalu
Niko Bellic,

Jak wrócisz do normalności po zbadaniu różnic?
Niko Bellic

Możesz pozbyć się klauzuli if, zastępując polecenie command! (patrz: h
E174

@NikoBellic Najpierw zamknij „stare” okno (oznaczone jako bufor magazynujący) za pomocą ': q'. Możesz przełączać się między oknami, dotykając dwukrotnie ctrl-W w trybie normalnym. Następnie możesz wyłączyć różnicę, pisząc: diffoff
brunch875

2

Skorzystaj z następującego źródła i użyj polecenia: 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

Nie jest to dokładnie to, czego szukasz, ale SCMDiff.vim jest naprawdę fajny. Jedno naciśnięcie klawisza i różnicuje bieżący plik z wersją główną w repozytorium kontroli źródła. Ma współpracować z wieloma systemami SCMS. Używam go z konieczności.



1

Mogę polecić histwin wtyczkę .

Chociaż nie różni się to od aktualnie zapisanej wersji pliku (podobnie jak inne odpowiedzi), może zmienić vimdiff od czasu rozpoczęcia edycji , a nawet odtworzyć zmiany w kolejności. Różnica pokazuje, czy oszczędzasz w międzyczasie.

Dodatkowo wyświetla listę wszystkich cofniętych gałęzi historii i umożliwia przełączanie lub różnicowanie między nimi.

PS: Chociaż wtyczka nie śledzi automatycznie momentów w historii edycji od każdej zmiany pliku, możesz jawnie „oznaczyć” moment, w którym zapisujesz plik, aby móc później z nim vimdiff, jeśli chcesz. Może można to zautomatyzować?


1

Jeśli chcesz użyć vim do porównania, tak jak w vimdiff, możesz zrobić coś takiego:

Edytuj swój plik .vimrc i dodaj:

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

Od tego momentu zobaczysz swoje zmiany i możesz wyjść z widoku różnic za pomocą qall podobnie jak w vimdiff, naciskając F8 w trybie poleceń. Zastąp F8 dowolnym kluczem.

Edycja: Dodano -M, aby zabronić jakiejkolwiek modyfikacji, ponieważ nie jest zapisywana.


To polecenie zaczyna działać dla mnie, pokazuje mi różnicę obok siebie. Jednak gdy tylko spróbuję coś edytować, okno Vima zwariuje. Zaczynam pisać, a za słowami w vimie po obu stronach ekranu pojawia się zachęta bash. Wygląda więc na to, że wyświetla różnice, ale potem vim ulega awarii. Dodatkowo otrzymuję ten błąd Vim: Error reading input, exiting...jakieś pomysły co tu jest nie tak?
Trevor,

@Trevor: Mogłem tylko zgadywać, jakie są problemy. Rzeczywiście, nie jest bezpieczne wprowadzanie jakichkolwiek modyfikacji w ten sposób. Dlatego dodałem parametr „-M”, aby całkowicie go zabronić. Przepraszam.
Tobias Heinicke

1

git obsługuje następujące polecenie

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

zamapuj go na polecenie, dodając następujący kod do pliku ~ / .vimrc

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

Teraz wykonanie :GitDiffstaje się poręcznym małym poleceniem do szybkiego pokazania różnic przed każdym zapisem.


0

Możesz sprawić, że vim utworzy ostatnią kopię zapasową i oryginalną kopię zapasową za pomocą:

:set backup
:set patchmode=.orig 

Następnie możesz je otworzyć w podziale:

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

A stamtąd:

:vimdiff in each buffer

Jeśli nie masz resztek, ale chcesz vimdiff, możesz również zrobić:

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

a następnie wykonaj: diffthis na każdym splicie


0

Zmiany właśnie edytowany [ bufor ], czyli tych, które różnią się od ostatniej zapisanej wersji (w pracy dir ectory), mogą się różnić z ostatniej wersji indeksu ( Git ). Zmapowałem oba:

" 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()

Przykład vimdiff vs Gdiff.

  • vimdiff: : vimdiff
  • Gdiff: Dokonując Gdiff zmian, widzisz tylko Gdiff, co może lub może mieć takie same zmiany jak vimdiff: zatwierdzając zmiany, widzisz tylko Gdiff, co może, a może NIE, mieć takie same zmiany jak vimdiff

Ponadto do łatwego vimdiffpliku homonimów w innej ścieżce:

    " 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
Można po prostu stworzyć jedną mapę, która będzie wykonywana: a Gdiffjeśli to możliwe, a inaczej (np. Nie projekt Git), a następnie wykonaj :vimdiff. Z try-catch-endtry. Ale w ten sposób :DiffWithSavedw projekcie Git brakuje.
Xopi García

-2

Postępuj zgodnie z powyższymi sugestiami, że używam git diff, który bardzo mi się podoba:

:w !git diff  % -
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.