How to ‘diff’ two subroutines in the same file in Vim?

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).


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>

Tags:

Vim

Diff

Vimdiff