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.