7

I need to compute a "XOR"-like of two lines to find every char that differs between the two lines. I know the vim-diff feature can easily achieve that, but for comparing two lines I wanted to keep everything in the same buffer.

e.g.

1wYT4SH8f8VjRA25u8AItlrTdAY4Y7n-g8if8VjRA3q25u8AItlrTdwTbv8if8VjRA3q25u8AItlrTdJjMY
1wYT4SH8f8VjRA25u8AItlrTdAY4Y7n-g8if8VjRA3q25u8AIt1rTdwTbv8if8VjRA3q25u8AItlrTdJjMY
                                                  1

How can it be done ?

13

This solution doesn't show the difference between the two lines but highlight them and allow you to navigate through them with n and N like this:

Screen cast of the function

To do so add this function to your .vimrc:

function! CompareLines(line1, line2)
    let l1 = getline(a:line1)
    let l2 = getline(a:line2)
    let pattern = ""

    for i in range(strlen(l1))
        if strpart(l1, i, 1) != strpart(l2, i, 1)
            if pattern != ""
                let pattern = pattern . "\\|"
            endif
            let pattern = pattern . "\\%" . a:line1 . "l" . "\\%" . ( i+1 ) . "c"
            let pattern = pattern . "\\|" . "\\%" . a:line2 . "l" . "\\%" . ( i+1 ) . "c"
        endif
    endfor

    execute "let @/='" . pattern . "'"
    set hlsearch
    normal n
endfunction

You can call the function with :call CompareLines(1, 2) where the arguments are the numbers of the lines to compare.

To add a bit more details about how the function works:

  • The first lines gets the lines to compare in some variables.
  • The loop iterates through these strings. Each characters of the strings are compared and when they don't match a pattern of the form \%Xl\%Yc is added to the variable pattern where X and Y are the line and the column of a character.

    (See :h /ordinary-atom and especially the last lines which explains that the pattern \%23l allows to match the 23rd line and \%23c the 23rd column)

  • Once the pattern is build it is injected in the search register (let @/= allow to define the content of the register and the pattern has to be quoted).

  • Finally set hlsearch is used to highlight all the matches of the pattern and normal n brings the cursor to the first different character.

Note 1 The function will change your search history.

Note 2 The part which uses the pattern to make the search could probably be greatly improved.

And as a bonus Add this line to your .vimrc to create a command which will faster the call of the function:

command! -nargs=* CompLines call CompareLines(<f-args>)

This way you can simple use :CompLines 1 2 to compares two lines.


EDIT And here is an improved version of the function and of the command. The difference is that you can call it in 3 different ways:

  • :CL will diff the current line and the following one
  • :CL 23 will diff the current line and the line 23
  • :CL 23 42 will diff the lines 23 and 42

Here is the code:

command! -nargs=* CL call CompareLines(<f-args>)

function! CompareLines(...)

    " Check the number of arguments
    " And get lines numbers
    if len(a:000) == 0
        let l1=line(".")
        let l2=line(".")+1
    elseif len(a:000) == 1
        let l1 =line(".")
        let l2 =a:1
    elseif len(a:000) == 2
        let l1 = a:1
        let l2 = a:2
    else
        echom "bad number of arguments"
        return;
    endif

    " Get the content of the lines
    let line1 = getline(l1)
    let line2 = getline(l2)

    let pattern = ""

    " Compare lines and create pattern of diff
    for i in range(strlen(line1))
        if strpart(line1, i, 1) != strpart(line2, i, 1)
            if pattern != ""
                let pattern = pattern . "\\|"
            endif
            let pattern = pattern . "\\%" . l1 . "l" . "\\%" . ( i+1 ) . "c"
            let pattern = pattern . "\\|" . "\\%" . l2 . "l" . "\\%" . ( i+1 ) . "c"
        endif
    endfor

    " Search and highlight the diff
    execute "let @/='" . pattern . "'"
    set hlsearch
    normal n
endfunction

EDIT 2 I made it a plugin. You can install it with a regular plugin manager with (e.g.):

Plug 'statox/vim-compare-lines'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.