(Vim)diff two subroutines in same file

2019-01-21 13:00发布

问题:

Is it possible to diff or even vimdiff two almost similar subroutines which occur in the same file? If so, how?

I can think of copying the two subroutines in two separate files and then diff them, but is there a way to do it within the original file?

Thanks!

回答1:

You cannot do this within the original file, but you can do this without using separate files, only separate buffers. This should work if you copied one subroutine in register a (for example, with "ay typed in visual mode) and other subroutine in register b:

enew | call setline(1, split(@a, "\n")) | diffthis | vnew | call setline(1, split(@b, "\n")) | diffthis

To automate:

let g:diffed_buffers=[]
function DiffText(a, b, diffed_buffers)
    enew
    setlocal buftype=nowrite
    call add(a:diffed_buffers, bufnr('%'))
    call setline(1, split(a:a, "\n"))
    diffthis
    vnew
    setlocal buftype=nowrite
    call add(a:diffed_buffers, bufnr('%'))
    call setline(1, split(a:b, "\n"))
    diffthis
endfunction
function WipeOutDiffs(diffed_buffers)
    for buffer in a:diffed_buffers
        execute 'bwipeout! '.buffer
    endfor
endfunction
nnoremap <special> <F7> :call DiffText(@a, @b, g:diffed_buffers)<CR>
nnoremap <special> <F8> :call WipeOutDiffs(g:diffed_buffers) | let g:diffed_buffers=[]<CR>

Note that you may want to set hidden option if Vim refuses to abandon changed file (see :h abandon).



回答2:

Plugin linediff.vim : Perform an interactive diff on two blocks of text is similar to the one pointed ou by Vincent with some additional features:

  • has a command to close the opened buffer
  • seems to work without GUI
  • insert some visual indication on the original file(s) being diffed.

To use it you perform a visual selection on the first block to diff, enter command :Linediff, and repeat it to the second block. To quit, :LineDiffReset

I've found the followings maps helpful:

noremap \ldt :Linediff<CR>
noremap \ldo :LinediffReset<CR>


回答3:

You can write those two parts/subroutines/sections to two files and then use vimdiff to see the difference.

    :1, 39 write part1          //any line range or marks can be used
    :40, 79 write part2
    :!vimdiff part1 part2

If you aren't comfortable with using line numbers, you can keep the cursor at start of the section , press v and select till the end of the section and then press : . it will show :'<,'>. Then type write and then file name in the command line itself. Press enter. Similary, do for second one also. Then you can execute vimdiff command as stated above.

(Write command saves the part to a new file.) Writing a new file may not be a good idea, but that helps me. Especially when we had to go through the comparison several times.

This is one of the simplest way without using plugin or if you aren't concerned about memory.



回答4:

I really like ZyX's answer, but needed to make two modifications for it to work seamlessly:

  1. As implemented, <F7> replaces the active buffer with the vertically split diff display. Then, while <F8> closes the diff, it does not reload the original buffer. To fix this, I changed enew on the third line to execute 'tab split | enew'.

  2. In order to minimize side-effects, I added call remove(a:diffed_buffers, 0, -1) just before the end of WipeOutDiffs().

HTH, - Stu



回答5:

I've been using this command:

vimdiff <(cat file.foo | sed -n 10,15p) <(cat file.foo | sed -n 20,25p)

Where the numbers fed to sed are the line number I want to diff in the file. <(*) means evaluate and redirect as input.



回答6:

you can try Block diff vim plugin, it will make 2 new buffer in a new tab to show the differences.



标签: vim diff vimdiff