Могу ли я увидеть изменения перед сохранением файла в Vim?


135

Я использую Vim. Я открываю файл. Я редактирую его и хочу посмотреть, что я отредактировал, прежде чем сохранить его.

Как я могу сделать это в Vim?

Ответы:


57

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

Вот функция и команда, чтобы увидеть разницу между текущим отредактированным файлом и его неизмененной версией в файловой системе. Просто поместите это в ваш vimrc или в каталог плагинов, откройте файл, внесите некоторые изменения, не сохраняя их, и сделайте :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()

Чтобы выйти из режима просмотра различий, вы можете использовать :diffoffкоманду.

Ниже приведена аналогичная функция, адаптированная для имитации 'cvs diff'команды ...


7
@ luc-hermitte Не является ли альтернатива :w !diff % -превосходной, когда вы используете vim для постоянно меняющегося и большого количества ящиков, для которых вы не можете легко изменить .vimrc? (При условии, что у них установлен diff.)
Томански

1
Вим не инструмент последней надежды. Тот, который будет работать, когда ничего больше не доступно. Это мой основной рабочий инструмент.
Люк Эрмита

12
Просто
указание

3
Ответ Хаоса выше, и в ответе Тобиаса объяснение завершено.
Ави Коэн

1
Можете ли вы добавить контент вместо ссылки? ТАК руководящие принципы ...
Błażej Michalik

160
:w !diff % -

4
Есть ли способ сделать это с vimdiff? Я попробовал: w! Vimdiff% - но безуспешно.
Джо Дж

14
Может кто-нибудь объяснить это? Я не понимаю, что происходит. Я понимаю, что вы обстреливаете diff. %ссылается на текущий открытый путь к файлу. Почему все это аргумент :wкоманды? Кроме того, как -присваивается содержимое рабочего буфера? Является ли это автоматическим в vim, что содержимое буфера (или, возможно, определенный диапазон в буфере) назначается stdin для команд оболочки?
Натан Уоллес

9
@NathanWallace: это аргумент, :wпотому что мы записываем файл в команду (on stdin). В команде, -говорит это читать stdin.
хаос

14
Или используйте :w !git diff % -для раскрашенной версии, если у вас установлен git!
Дергачев

5
@Dergachev Я получаю ошибку fatal: bad flag '-' used after filenameпри запуске :w !git diff % -.
Оттенки серого

100

Потому что некоторые люди спрашивали об объяснении команды

:w !diff % -

Вот моя попытка написать более подробный ответ:

Я предполагаю , что вы работаете в системе с catи echoустановлен (например , практически любой GNU / Linux, Mac OS, BSD и других UNIX-подобных систем).

Вышеприведенная команда работает следующим образом:

  1. Синтаксис для сохранения файла в vim:

    :w <filename>
    
  2. Синтаксис для выполнения команды оболочки в vim:

    :!<command>
    
  3. Внутри оболочки, выдаваемой vim %, указывается на текущее имя файла. Вы можете убедиться в этом, выполнив следующее:

    :!echo %
    

    Это должно вывести имя файла (или ошибку, если vim был запущен без имени файла).

    Используя cat, мы также можем вывести содержимое файла:

    :!cat %
    

    Это должно вернуть содержимое файла в его последнее сохраненное состояние или сообщение об ошибке, если оно никогда не было сохранено.

  4. Программа diff умеет читать со стандартного ввода (stdin). На его странице руководства говорится следующее:

    [...] Если ФАЙЛ - '-', прочитайте стандартный ввод. [...]

  5. Выполнение команды save без имени файла, а скорее команды оболочки позади него, приводит к тому, что vim записывает содержимое файла на стандартный ввод оболочки вместо сохранения его в физическом файле. Вы можете проверить это, выполнив

    :w !cat
    

    Это должно всегда печатать файлы текущего содержимого (которые были бы записаны в файл вместо этого).

Собираем его вместе (или tl; dr): файл "сохраняется" в stdin, diff запускается с именем файла и stdin в качестве ввода.

Зная это, можно также сравнить файлы с vimdiff, выполняющим что-то вроде этого - это просто идея, которую вы не хотите делать следующим образом:

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

(Затем откройте readonly и закройте vimdiff, используя :qall)


Более разумный подход к использованию vimdiff - создать сценарий оболочки, содержащий следующее vim - -c ":vnew $1 |windo diffthis", сделать его исполняемым, сохранить его в PATH, например, vimdiffWithStdinи затем сравнить со следующей командой в vim::w !vimdiffWithStdin %
Tobias Heinicke

Еще проще: :w !vimdiff % /dev/stdin. Я не знаю, существует ли подобная уловка для окон.
deft_code

12

Мне всегда нравятся различия - красиво, просто, работает.


Это работает НАМНОГО лучше, чем более высокооплачиваемые варианты. Это дает возможность переключать его.
Стивен Лу

1
@StevenLu - Мех ... что ты можешь сделать? В любом случае, рад, что тебе понравилось. Я считаю это более практичным, чем другой подход.
Ладья

Я делаю второй @Steven, ваши предложенные различия отлично. Спасибо!
AS

Это также может быть установлено как плагин от того же разработчика: github.com/jmcantrell/vim-diffchanges
Sumanth Lingappa

хороший плагин, но он не удаляет патч, который создает потом? Редактировать: мой плохой! Оно делает. Я использовал это неправильно. Я должен был использовать :DiffChangesDiffToggle.
aderchox

10

из 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

... как описано в vimdoc.sourceforge.net/htmldoc/diff.html#:DiffOrig . Преимущество над этим в w !diff % -том , что она работает над удаленными источниками тоже (например: vim sftp://example.com/foo.txt)
Lekensteyn

1
Мне это нравится больше, потому что мы видим разницу прямо в самом буфере vim, а не в терминале
Нико Беллик

Как вы вернетесь к нормальному состоянию, как только закончите, изучая различия?
Нико Беллик

Вы можете избавиться от предложения if, подставив команду команде! (см .: h E174)
Элиг

@NikoBellic Сначала закройте «старое» окно (помеченное как «чистый буфер») с помощью «: q». Вы можете переключаться между окнами, дважды нажав Ctrl-W в обычном режиме. Затем вы можете отключить diff, написав: diffoff
brunch875

2

Исходя из следующего и используйте: 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

Не совсем то, что вы ищете, но SCMDiff.vim действительно классный. Одно нажатие клавиши, и она выделяет ваш текущий файл с ревизией головы в репозитории с исходным кодом. Он предназначен для работы со многими SCMS. Я использую это с исполнением.


2

Здесь есть плагин, основанный на разных ответах: https://github.com/gangleri/vim-diffsaved

Это обеспечивает :w !diff % -метод и более вовлеченный diffthis.

Кроме того, это не разрешено и для недопустимого дерева , но также и для гораздо большего (различия между различными контрольными точками отмены). Похоже на Gundo .


1

Я могу порекомендовать плагин Histwin .

Хотя он не отличается от текущей сохраненной версии файла (как и другие ответы), он может изменять изменения с момента начала редактирования и даже воспроизводить изменения по порядку. Разница показывает, сохраняете ли вы промежуточно.

Кроме того, он отображает список всех ветвей истории отмены и позволяет вам переключаться между ними.

PS: хотя плагин не отслеживает автоматически моменты в истории редактирования с момента каждого изменения файла, вы можете явно «пометить» момент, когда вы сохраните файл, чтобы позже вы могли с ним vimdiff, если хотите. Может быть, это может быть автоматизировано?


1

Если вы хотите использовать vim для сравнения, как в vimdiff, вы можете сделать что-то вроде этого:

Отредактируйте ваш .vimrc и добавьте:

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

Оттуда вы увидите ваши изменения и можете выйти из qallрежима сравнения, используя, как в vimdiff, нажав F8 в командном режиме. Замените F8 на любую понравившуюся клавишу.

Редактировать: Добавлена ​​опция -M, чтобы запретить любые изменения, потому что они не сохраняются.


Эта команда начинает работать для меня, она показывает мне разницу рядом. Однако, как только я пытаюсь что-то редактировать, окно vim сходит с ума. Я начинаю печатать и получаю подсказку bash за словами в vim с обеих сторон экрана. Так что, похоже, отображает diff, но затем vim вылетает. Кроме того, я получаю эту ошибку Vim: Error reading input, exiting...какие-либо идеи, что здесь происходит не так?
Тревор

@Trevor: я мог только догадываться, в чем проблемы. Это действительно не спасение, чтобы вносить какие-либо изменения во время различий, как это. Поэтому я добавил параметр "-M", чтобы полностью запретить его. Сожалею.
Тобиас Хейнике

1

git поддерживает следующую команду

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

сопоставьте его с командой, добавив следующее в ваш ~ / .vimrc

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

Теперь выполнение :GitDiffстановится удобной маленькой командой для быстрого отображения различий перед каждым сохранением.


0

Вы можете сделать Vim создать последнюю резервную копию и оригинальную резервную копию с:

:set backup
:set patchmode=.orig 

После этого вы можете открыть их в сплит:

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

И оттуда сделать:

:vimdiff in each buffer

Если вы не имеете никаких остатков, но хотите vimdiff, вы также можете сделать:

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

а затем сделайте: diffthis на каждом разделении


0

Изменения, которые вы только что отредактировали [ буфер ], то есть те, которые отличаются от последней сохраненной версии (в рабочем каталоге), могут отличаться от последней версии индекса ( Git ). Я сопоставил оба:

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

Пример vimdiff против Gdiff.

  • vimdiff: : vimdiff
  • Gdiff: фиксируя Gdiff изменения, вы видите только Gdiff, что может или может иметь те же изменения, что и vimdiff: фиксируя изменения, вы видите только Gdiff, что может или не может иметь те же изменения, что и vimdiff

Кроме того, чтобы легко vimdiffнайти файл омонима по другому пути:

    " 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
Можно просто сделать 1 карту, которая выполняется: Gdiffесли возможно, и иначе (например, не проект Git), затем выполните a :vimdiff. С try-catch-endtry. Но этот путь :DiffWithSavedв Git-проекте отсутствует.
Ксопи Гарсия

-2

Следуйте вышесказанному, я предлагаю использовать git diff, который мне очень нравится:

:w !git diff  % -
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.