How to diff two lines in an open file in vim?

An alternative to @sehe's approach would not require the use of temp files:

funct! DiffTwoTexts(text1, text2)
  new
  put =a:text1
  normal ggdd
  diffthis
  new
  put =a:text2
  normal ggdd
  diffthis
endfunct

funct! DiffTwoLines(line1, line2)
  let text1 = getline(a:line1)
  let text2 = getline(a:line2)
  call DiffTwoTexts(text1, text2)
endfunct

comma! DiffWithNext call DiffTwoLines('.', line('.') + 1)

This will still be pretty hard to read, since it keeps everything on a single line, so I came up with this modification:

funct! EvalTextPreprocessor(expr, text)
  let text = a:text
  return eval(a:expr)
endfunct

comma! -nargs=1 DiffWithNextPre call DiffTwoTexts(
      \ EvalTextPreprocessor(<q-args>, getline('.')),
      \ EvalTextPreprocessor(<q-args>, getline(line('.') + 1)))

This new command takes a vimscript expression as its argument, wherein the variable text refers to whichever line is being preprocessed. So you can call, e.g.

DiffWithNextPre split(text, '[(,)]\zs')

For your sample data, this gives the two buffers

AVeryLongReturnType* MyLongClassName:hasAnEvenLongerFunction(
That *is,
 Overloaded *with,
 Multiple *different,
 Parameter *lists)
;

and

AVeryLongReturnType* MyLongClassName:hasAnEvenLongerFunction(
That *is,
 Overloaded *with,
 Multiple *different,
 Parameter *1ists)
;

Only the lines that start with Parameter are highlighted.

You can even build up from there, creating a command

comma! DiffTwoCFunctionSigs DiffWithNextPre split(text, '[(,)]\s*\zs')

Notice that I modified the regexp a bit so that it will keep trailing spaces at the end of lines. You could get it to ignore them entirely by moving the \s* to after the \zs. See :help /\zs if you're unfamiliar with what that vim-specific RE atom does.

A nicety would be to make the command take a range (see :help command-range), which you could use by diffing the first line of the range with the last line. So then you just visual-select from the first line to the second and call the command.


That is not a feature, however it is easily scripted, e.g. in your vimrc:

function! DiffLineWithNext()
    let f1=tempname()
    let f2=tempname()

    exec ".write " . f1
    exec ".+1write " . f2

    exec "tabedit " . f1
    exec "vert diffsplit " . f2
endfunction

This will open the current and next lines in vertical split in another tab. Note that this code is a sample

  • it doesn't check whether next line exists (there are any following lines)
  • it doesn't cleanup the tempfiles created
  • a nice improvement would be to take a range, or use the '' mark to select the other line

You can leave off the 'vert' in order to have a horizontal split

Map it to something fancy so you don't have to :call it manually:

:nnoremap <F10> :call DiffLineWithNext()^M

I used linediff.vim.

This plugin provides a simple command, ":Linediff", which is used to diff two separate blocks of text.


A quick and dirty solution is to just select both lines and sort them while removing duplicates:

  • select lines
  • ":sort u"
  • if only one line remains, both were equal
  • if both remain, there most be some difference

An undo recovers everything again.

Tags:

Vim