Monday, August 30, 2010

Re: vimdiff-like highlighting within the same file?

>> I'm still hacking on my "highlight only" version, but it's slow going.
>
> Please share!

I don't really have anything useful to share at this point, but I can
tell you where I'm at. I'll start at the beginning so folks can join
in even if they've missed earlier posts in this thread.

I want improved syntax highlighting for unified diff/patch files in
Vim. I've mentioned this in various forms earlier, but I think that
statement hits it more accurately and succinctly.

I'm trying to use Vim script identify areas in unified diffs showing
changes in lines (as opposed to additions or deletions) and use a more
striking highlighting mode to point out, say, when a single letter or
space changes in a line. This is quite difficult to spot visually in a
unified diff. Vimdiff finds and highlights these types of changes
quite nicely, emacs diff mode does as well, and "git diff
--color-words" (now called --word-diff, I think) also does a great
job. I think I need to use or emulate the intra-line difference
location algorithm(s) from those tools. I deliberately left out wdiff,
whose output I don't particularly like. Of those listed, only emacs
diff mode actually does the intra-line word difference highlighting
for a single unified diff file (the others require both the old and
new files).

Once I've identified changes in hunks, I plan on using something like
the following snippet to highlight specific parts of lines (thanks to
bairui on #vim for the pointer on \%v):

:highlight DiffRegion ctermbg=red guibg=red
:let m = matchadd("DiffRegion", '\%6l\%9v.*\%14v')
:let n = matchadd("DiffRegion", '\%7l\%9v.*\%16v')

I'm stuck trying to identify changes in words or spaces.

I started by writing a line-by-line scanner ( http://pastey.net/140210
) that would detect when it started seeing the "old" ('^-') and "new"
('^+') parts of a change hunk, but then I realized that I'd rather
just manipulate pointers to those different parts of hunks and walk
through the parts in parallel... and I'm kinda lost here.

Another approach I played with a little was using a regex (
http://pastey.net/140211 ) to get to each hunk, something like this:

'\nindex.*\n--- .*\n+++ .*\n@@.*@@.*$'

And this is about the point that I've decided it's going to be quite a
tricky task to actually get all the use cases covered for intra-line
differences.

Here's sort of a collection of use cases, in one unified diff.

tmp.diff: http://pastey.net/140214
old : http://pastey.net/140212
new : http://pastey.net/140213

To see how other tools highlight stuff, I've been doing stuff like:

- vimdiff old new
- git diff old new
- git diff --color-words old new
- emacs tmp.diff (then ALT-n once emacs starts up)

Anyway, I'm probably going to set this stuff down for a while. It
would be fun to have a little in-person hack session on this,
especially with someone at least mildly talented in Vim script and/or
general scanning/parsing algorithms. Vim script might not even be
what's blocking me... for some reason I'm also really getting stuck
breaking down/identifying/solving the problem about how to identify
which parts of a line have changed. Tokenizing/scanning/whatever you
call it is partly subjective--see the new "git --word-diff-regex"
command line argument, and discussion around same on the git mailing
list. In fact, the git solution might be the most elegant and flexible
algorithm to emulate.

That's all for now, cheers,
-Adam

--
You received this message from the "vim_use" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

No comments: