Vim Diff
February 21, 2008 – 9:00 pmFor a long time now I’ve wanted to have the current diff of my working copy highlighted in vim. This would help a lot when you’re working in complicated code and want your modifications to pop out in case you’ve missed something. Unfortunately none of the existing tools do exactly what I want, so with the advice of some co-workers I’ve hacked up the svndiff vim script and made it work with git just like I wanted. Now I can turn on or refresh the highlights with Ctl-D and diff against a different branch with “:D <branch>”.

gitdiff.vim
—————
if exists(”loaded_gitdiff”) || &cp
finish
endif
let loaded_gitdiff = 1
map <C-d> :call <SID>Gitdiff()<CR>
map <C-g> :set nodiff<CR>
noremap <unique> <script> <plug>Dh :call <SID>Gitdiff(”h”)<CR>
com! -bar -nargs=? D :call s:Gitdiff(<f-args>)
let g:gitdiff_rev = ”
function! s:Gitdiff(…)
if a:0 == 1
if a:1 == “none”
let g:gitdiff_rev = ”
else
let g:gitdiff_rev = a:1
endif
endif
let ftype = &filetype
let tmpfile = tempname()
let cmd = “cat ” . bufname(”%”) . ” > ” . tmpfile
let cmd_output = system(cmd)
let tmpdiff = tempname()
let cmd = “git diff ” . g:gitdiff_rev . ” ” . bufname(”%”) . ” > ” . tmpdiff
let cmd_output = system(cmd)
if v:shell_error && cmd_output != “”
echohl WarningMsg | echon cmd_output
return
endif
let cmd = “patch -R -p0 ” . tmpfile . ” ” . tmpdiff
let cmd_output = system(cmd)
if v:shell_error && cmd_output != “”
echohl WarningMsg | echon cmd_output
return
endif
if exists(”s:killbuffs”)
2,9999 bdelete
endif
let s:killbuffs = 1
if a:0 > 0 && a:1 == “h”
exe “diffsplit” . tmpfile
else
exe “vert diffsplit” . tmpfile
endif
exe “set filetype=” . ftype
hide
set foldcolumn=0
set foldlevel=100
set diffopt= ” removed filler so we don’t show deleted lines
highlight DiffAdd ctermbg=black ctermfg=DarkGreen
highlight DiffChange ctermbg=black ctermfg=DarkGreen
highlight DiffText ctermbg=black ctermfg=DarkGreen cterm=underline
highlight DiffDelete ctermbg=red ctermfg=white
endfunction
“autocmd CursorHold * call s:Gitdiff()
—————
Tags: vimdiff git
21 Responses to “Vim Diff”
This doesn’t work for me. What am I doing wrong?
Error detected while processing /home/james/.vim/plugin/gitdiff.vim:
line 1:
E15: Invalid expression: ”loaded_gitdiff”) || &cp
E116: Invalid arguments for function exists(”loaded_gitdiff”) || &cp
E15: Invalid expression: exists(”loaded_gitdiff”) || &cp
line 11:
E15: Invalid expression: ”
E15: Invalid expression: ”
line 13:
E125: Illegal argument: …)
line 64:
E492: Not an editor command: “autocmd CursorHold * call s:Gitdiff()
By James Sadler on Mar 24, 2008
Ah, I think the double-quote characters have been mangled by the blog engine you use.
By James Sadler on Mar 24, 2008
unicode wins again
By barkmadley on Mar 24, 2008
eh, sorry about that it was a quick cut/paste job. I can post the original file for you and others to download if you like.
By shire on Mar 24, 2008
Nice. Can you upload the script to http://www.vim.org/login.php?add_script.php ?
By Nico on Mar 25, 2008
A s/git/svn/g makes it work with svn, too. Very slick.
By ak on Mar 25, 2008
I took the liberty of posting a modified version that allows using any SCM with standardized ’scm diff’ output (svn, git, and Mercurial all work).
http://www.vim.org/scripts/script.php?script_id=2201
Thanks for this, it’s quite useful.
By James Longstreet on Mar 25, 2008
I’d suggest removing those bindings and list them as an example on that page. I actually use Ctrl-G pretty often.
It was easy enough to fix for myself, but not something I’d like to remember to do each time I installed or upgraded the script.
By fred on Mar 25, 2008
Not to sound ungrateful, Thanks. :)
By fred on Mar 25, 2008
Happy to see you all found it useful, and thanks for modifying it and uploading it to vim.org! I was hoping to enhance it for SVN but hadn’t gotten to it yet. Hopefully it’ll be useful to a wider range of people now.
By shire on Mar 25, 2008
Hey,
I took the modified SCMdiff version from vim.org and made even more mods.
You can find my version here:
http://playground.audioscrobbler.com/jonty/scmdiff.vim
It:
- Removes the ctrl-g keybinding and makes ctrl-d a toggle
- Resets the viewport when pressing ctrl-d the first time (no more scrolling, yay!)
- Has indentation ;)
I also camelCased all the vars, as I’m a picky bastard…
Hope that’s useful to you.
By Jonty on Mar 26, 2008
Thank you Shire for the original post
and thank you Jonty for the viewport tweaks!
By josh on Mar 26, 2008
Thanks for a great script!
I had to make a few tweaks to Jonty’s script. Removed this line:
let b:scmDiffOn = 1
and changed this line:
if b:scmDiffOn == 1
to:
if exists(’b:scmDiffOn’) && b:scmDiffOn == 1
Also changed the “map …” to “map “.
Is there any way of getting rid of the “2,9999 bdelete” and the left over buffer? I normally use a lot of buffers and just closing all of them like that is not very nice, IMHO.
By Jonas on Mar 26, 2008
Oh noes, my angle brackets were eaten by the interwebs.
Also changed the “map [C-d] …” to “map [silent] [C-d] …”.
By Jonas on Mar 26, 2008
Jonas, what?! If you do that you won’t be able to toggle it off again?
By Jonty on Mar 27, 2008
Jonas, thanks for the silent tweak, applied to the version I linked above.
Still have no idea what you’re on about with the scmDiffOn var though ;)
By Jonty on Mar 27, 2008
Sorry, manual diffs from (lack of) memory aren’t very reliable. There are two “let b:scmDiffOn = 0″ (not “= 1″ as I said before), I removed the first one so there are only two places where it sets that variable. My problem was that for some reason it barfed in s:scmDiff() since that variable wasn’t set (hence the if exists()).
By Jonas on Mar 27, 2008
Jonas, aha, now you make sense! Odd that it died for you - what version of vim are you using?
(I’ll fix it in the linked version tomorrow morning)
By Jonty on Mar 27, 2008
7.1.138. But it might be due to the fact that I’m normally using multiple buffers, and the plugin is only run once so it won’t set the variable in all buffers, AFAIK.
By Jonas on Mar 27, 2008
Aha! That’ll be it, I only tested it in a single buffer instance. More fool me.
By Jonty on Mar 27, 2008
Anyone made a version that would work with multiple buffers open (not closing unrelated buffers)? I really like this script, but it’s usually unusable for me when it behaves this way. I’m using MacVim BTW if that’s relevant.
By Lars on Jun 28, 2008