Thanks to Rick Howe, who answered and then emailed me the following script, we have a perfect solution for my question. Rick Howe's script highlights the longest common subsequence (LCS) in each line pair of two vimdiff buffers. When equal-length LCS matches are found, they are highlighted in different colors.
Credit
Rick Howe's wrote this script, I didn't. Rick's script is posted here with his permission.
I only added a couple of lines to suspend difference highlights so that LCS matches stand out more clearly. I also changed highlighting groups to choices that should work for the standard color scheme in vim and gvim on linux. Resulting colors aren't exactly pretty, but they work in cterm and gui with no need to fiddle them (you can change g:hlt
if you really want). Here's a vim (top) and gvim (bottom) screencap.
Usage
Save the script as lcs.vim
and put it in a folder included in the runtimepath
option list, then start vimdiff: vim -d +"runtime lcs.vim" A B
and press F4
to toggle highlighting LCS.
lcs.vim
nnoremap <silent> <F4> :call <SID>ToggleHighlightLCS()<CR>
" Cycle through these groups to highlight equal-length LCS in each line.
" You may change this choice but do not include Diff* groups, i.e., DiffAdd.
let g:hlt = ["MatchParen", "TabLineFill", "Error", "Folded"]
function! s:ToggleHighlightLCS()
if winnr('$') < 2 | echo "Need more windows" | return | endif
let win1 = winnr()
let win2 = win1 % winnr('$') + 1
if exists("t:mid")
for [w, mid] in t:mid
exec w . "wincmd w"
call map(mid, 'matchdelete(v:val)')
endfor
unlet t:mid
exec win1 . "wincmd w"
exec join(map(["Add","Text","Change","Delete"], '"hi! link Diff".v:val." NONE"'),"|")
return
endif
let ln1 = getbufline(winbufnr(win1), 1, '$')
let ln2 = getbufline(winbufnr(win2), 1, '$')
let lcs = map(range(min([len(ln1), len(ln2)])),
\'s:FindLCS(ln1[v:val], ln2[v:val])')
let t:mid = []
for w in [win1, win2]
exec w . "wincmd w"
let mid = []
for n in range(len(lcs))
let mid += map(map(copy(lcs[n]),
\'(&ic ? "\\c" : "\\C") .
\"\\V\\%" . (n + 1) . "l" .
\escape(v:val, "\\")'),
\'matchadd(g:hlt[v:key % len(g:hlt)], v:val)')
endfor
let t:mid += [[w, mid]]
endfor
exec win1 . "wincmd w"
exec join(map(["Add","Text","Change","Delete"], '"hi! link Diff".v:val." Normal"'),"|")
endfunction
function! s:FindLCS(str1, str2)
let [len1, len2] = [strchars(a:str1), strchars(a:str2)]
let [lng, sht, len] = (len1 >= len2) ?
\[a:str1, a:str2, len2] : [a:str2, a:str1, len1]
let idx = map(range(len + 1), 'byteidx(sht, v:val)')
for n in range(len, 1, -1)
let lcs = []
for p in range(0, len - n)
let s = sht[idx[p] : idx[p + n] - 1]
if !count(lcs, s, &ic) | let lcs += [s] | endif
endfor
call filter(lcs, 'lng =~ "\\V" . escape(v:val, "\\")')
if !empty(lcs) | break | endif
endfor
return lcs
endfunction