0

Basically I need to search only in areas marked red, not pink (in the default color scheme).

All I can find is how to search the unfolded areas. This is not very useful to me. I have long lines which sometimes differ only in a few characters. I need to search only in these characters.

I know how to make vimdiff unfold only lines with actual differences, but this is not enough either.

If it's possible to fold identical parts of lines, it would help somewhat. However the preferred solution would let me ignore identical parts in search without hiding them.

Perhaps a custom vim script can be written? Something along the lines of (pseudocode)

search pattern
while (found and not highlighted as diff)
       search pattern again
1
1

You can do that with some vimscript, I wrote a function doing just what you need:

function! ComparePos(p1, p2)
    let linediff = a:p2[0] - a:p1[0]
    let coldiff = a:p2[1] - a:p1[1]
    return linediff + (!linediff) * coldiff
endfunction

function! CurPos()
    return getpos('.')[1:2]
endfunction

function! DiffSearch(pattern, flags)
    if !&diff | return | endif

    let wrapped = 0

    let startpos = CurPos()
    let prevpos = startpos

    let winsave = winsaveview()

    while search(a:pattern, a:flags)
        let curpos = CurPos()

        if synIDattr(diff_hlID(line('.'), col('.')), "name") == 'DiffText'
            " We found a proper match!
            return
        endif
        if ComparePos(prevpos, curpos) < 0
            " We wrapped around the file
            let wrapped = 1
        endif
        if ComparePos(prevpos, curpos) == 0
            " We didn't move, there's no match in the file
            break
        endif
        if wrapped && ComparePos(startpos, curpos) > 0
            " We searched through the whole file but no match with appropriate
            " syngroup was found
            break
        endif
        let prevpos = curpos
    endwhile
    " No proper match found...
    echohl ErrorMsg | echo "Pattern not found: " . a:pattern | echohl None
    call winrestview(winsave)
endfunction

nnoremap <silent> n :if &diff<BAR>call DiffSearch(@/, '')<BAR>else<BAR>exe 'norm! n'<BAR>endif<CR>
nnoremap <silent> N :if &diff<BAR>call DiffSearch(@/, 'b')<BAR>else<BAR>exe 'norm! N'<BAR>endif<CR>

The function you'll be interested in is DiffSearch, you can use it exactly as you'd use the search function, except it only searches in the diff parts.

I also added some mapping on n and N for ease of use!

Tell me if anything's unclear!


Side note: The function currently searches for the DiffText syntax group, but we can use it with pretty much any syntax group with some tweaking

2
  • 1
    also looks like you don't use the synStack variable. I was looking at some code I had for comparing positions to see if yours could be simplified, but my function returns true iff pos1 is before pos2; you do more case analysis than that, so I'm not sure it would help – D. Ben Knoble Mar 15 at 14:42
  • Thanks for the synStack variable, I started using synstack before realizing that the diff colorations were not given... For the ComparePos function, I made it smaller. Not sure which version is better for readability though... – Zorzi Mar 15 at 16:25

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.