git-svn-id: https://vimsuite.svn.sourceforge.net/svnroot/vimsuite/trunk@153 eb2d0018-73a3-4aeb-bfe9-1def61c9ec69
337 lines
9.5 KiB
VimL
337 lines
9.5 KiB
VimL
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
|
" svndiff (C) 2007 Ico Doornekamp
|
|
"
|
|
" This program is free software; you can redistribute it and/or modify it
|
|
" under the terms of the GNU General Public License as published by the Free
|
|
" Software Foundation; either version 2 of the License, or (at your option)
|
|
" any later version.
|
|
"
|
|
" This program is distributed in the hope that it will be useful, but WITHOUT
|
|
" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
" FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
" more details.
|
|
"
|
|
" Introduction
|
|
" ------------
|
|
"
|
|
" NOTE: This plugin is unix-only!
|
|
"
|
|
" An small vim 7.0 plugin for showing svn diff information in a file while
|
|
" editing. This plugin runs a diff between the current buffer and the original
|
|
" subversion file, and shows coloured signs indicating where the buffer
|
|
" differs from the original file from the subversion repository. The original
|
|
" text is not shown, only signs are used to indicate where changes were made.
|
|
"
|
|
" The following symbols and syntax highlight groups are used for the signs:
|
|
"
|
|
" > DiffAdd: Newly added lines. (default=blue)
|
|
"
|
|
" ! DiffChange: Lines which are changed from the original. (default=cyan)
|
|
"
|
|
" < DiffDel: Applied to the lines directly above and below a deleted block
|
|
" (default=magenta)
|
|
" Usage
|
|
" -----
|
|
"
|
|
" The plugin defines one function: Svndiff(). This function figures out the
|
|
" difference between the current buffer and it's subversion original, and adds
|
|
" the signs at the places where the buffer differs from the original file from
|
|
" subversion. You'll need to call this function after making changes to update
|
|
" the highlighting.
|
|
"
|
|
" The function takes one argument specifying an additional action to perform:
|
|
"
|
|
" "prev" : jump to the previous different block
|
|
" "next" : jump to the next different block
|
|
" "clear" : clean up all signs
|
|
"
|
|
" You might want to map some keys to run the Svndiff function. For
|
|
" example, add to your .vimrc:
|
|
"
|
|
" noremap <F3> :call Svndiff("prev")<CR>
|
|
" noremap <F4> :call Svndiff("next")<CR>
|
|
" noremap <F5> :call Svndiff("clear")<CR>
|
|
"
|
|
"
|
|
" Configuration
|
|
" -------------
|
|
"
|
|
" The following configuration variables are availabe:
|
|
"
|
|
" * g:svndiff_autoupdate
|
|
"
|
|
" If this variable is defined, svndiff will automatically update the signs
|
|
" when the user stops typing for a short while, and when leaving insert
|
|
" mode. This might slow things down on large files, so use with caution.
|
|
" The vim variable 'updatetime' can be used to set the auto-update intervar,
|
|
" but not that changing this variable other effects as well. (refer to the
|
|
" vim docs for more info)
|
|
" To use, add to your .vimrc:
|
|
"
|
|
" let g:svndiff_autoupdate = 1
|
|
"
|
|
" * g:svndiff_one_sign_delete
|
|
"
|
|
" Normally, two 'delete' signs are placed around the location where
|
|
" text was deleted. When this variable is defined, only one sign is
|
|
" placed, above the location of the deleted text.
|
|
" To use, add to your .vimrc:
|
|
"
|
|
" let g:svndiff_one_sign_delete = 1
|
|
"
|
|
" Colors
|
|
" ------
|
|
"
|
|
" Personally, I find the following colours more intuitive for diff colours:
|
|
" red=deleted, green=added, yellow=changed. If you want to use these colours,
|
|
" try adding the following lines to your .vimrc
|
|
"
|
|
" hi DiffAdd ctermfg=0 ctermbg=2 guibg='green'
|
|
" hi DiffDelete ctermfg=0 ctermbg=1 guibg='red'
|
|
" hi DiffChange ctermfg=0 ctermbg=3 guibg='yellow'
|
|
"
|
|
" Changelog
|
|
" ---------
|
|
"
|
|
" 1.0 2007-04-02 Initial version
|
|
"
|
|
" 1.1 2007-04-02 Added goto prev/next diffblock commands
|
|
"
|
|
" 1.2 2007-06-14 Updated diff arguments from -u0 (obsolete) to -U0
|
|
"
|
|
" 2.0 2007-08-16 Changed from syntax highlighting to using signs, thanks
|
|
" to Noah Spurrier for the idea. NOTE: the name of the
|
|
" function changed from Svndiff_show() to Svndiff(), so
|
|
" you might need to update your .vimrc mappings!
|
|
"
|
|
" 3.0 2008-02-02 Redesign with some ideas from Jan Bezdekovsky. The
|
|
" diff is only updated when the buffer actually changes,
|
|
" cleanup of signs is now done properly and some info
|
|
" about each diff block is printed in the status line.
|
|
"
|
|
" 3.1 2008-02-04 Fixed bug that broke plugin in non-english locales, thanks
|
|
" to Bernhard Walle for the patch
|
|
"
|
|
" 3.2 2008-02-27 The latest rewrite broke vim 6 compatiblity. The plugin
|
|
" is now simply disabled for older vim versions to avoid
|
|
" a lot of warnings when loading.
|
|
"
|
|
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
|
|
|
if v:version < 700
|
|
finish
|
|
endif
|
|
|
|
|
|
let s:sign_base = 200000 " Base for our sign id's, hoping to avoid colisions
|
|
let s:is_active = {} " dictionary with buffer names that have svndiff active
|
|
let s:diff_signs = {} " dict with list of ids of all signs, per file
|
|
let s:diff_blocks = {} " dict with list of ids of first line of each diff block, per file
|
|
let s:changedtick = {} " dict with changedticks of each buffer since last invocation
|
|
|
|
"
|
|
" Do the diff and update signs.
|
|
"
|
|
|
|
function s:Svndiff_update(...)
|
|
|
|
let fname = bufname("%")
|
|
|
|
if ! exists("s:is_active[fname]")
|
|
return 0
|
|
end
|
|
|
|
" Check if this file is managed by subversion, exit otherwise
|
|
|
|
let info = system("LANG=C svn info " . fname)
|
|
if match(info, "Path") == -1
|
|
echom "Svndiff: Warning, file " . fname . " is not managed by subversion, or error running svn."
|
|
unlet s:is_active[fname]
|
|
return 0
|
|
end
|
|
|
|
" Check if the changedticks changed since the last invocation of this
|
|
" function. If nothing changed, there's no need to update the signs.
|
|
|
|
if exists("s:changedtick[fname]") && s:changedtick[fname] == b:changedtick
|
|
return 1
|
|
end
|
|
let s:changedtick[fname] = b:changedtick
|
|
|
|
" The diff has changed since the last time, so we need to update the signs.
|
|
" This is where the magic happens: pipe the current buffer contents to a
|
|
" shell command calculating the diff in a friendly parsable format.
|
|
|
|
let contents = join(getbufline("%", 1, "$"), "\n")
|
|
let diff = system("diff -U0 <(svn cat " . fname . ") <(cat;echo)", contents)
|
|
|
|
" clear the old signs
|
|
|
|
call s:Svndiff_clear()
|
|
|
|
" Parse the output of the diff command and put signs at changed, added and
|
|
" removed lines
|
|
|
|
for line in split(diff, '\n')
|
|
|
|
let part = matchlist(line, '@@ -\([0-9]*\),*\([0-9]*\) +\([0-9]*\),*\([0-9]*\) @@')
|
|
|
|
if ! empty(part)
|
|
let old_from = part[1]
|
|
let old_count = part[2] == '' ? 1 : part[2]
|
|
let new_from = part[3]
|
|
let new_count = part[4] == '' ? 1 : part[4]
|
|
|
|
" Figure out if text was added, removed or changed.
|
|
|
|
if old_count == 0
|
|
let from = new_from
|
|
let to = new_from + new_count - 1
|
|
let name = 'svndiff_add'
|
|
let info = new_count . " lines added"
|
|
elseif new_count == 0
|
|
let from = new_from
|
|
let to = new_from
|
|
let name = 'svndiff_delete'
|
|
let info = old_count . " lines deleted"
|
|
if ! exists("g:svndiff_one_sign_delete")
|
|
let to += 1
|
|
endif
|
|
else
|
|
let from = new_from
|
|
let to = new_from + new_count - 1
|
|
let name = 'svndiff_change'
|
|
let info = new_count . " lines changed"
|
|
endif
|
|
|
|
let id = from + s:sign_base
|
|
let s:diff_blocks[fname] += [{ 'id': id, 'info': info }]
|
|
|
|
" Add signs to mark the changed lines
|
|
|
|
let line = from
|
|
while line <= to
|
|
let id = line + s:sign_base
|
|
exec 'sign place ' . id . ' line=' . line . ' name=' . name . ' file=' . fname
|
|
let s:diff_signs[fname] += [id]
|
|
let line = line + 1
|
|
endwhile
|
|
|
|
endif
|
|
endfor
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
"
|
|
" Remove all signs we placed earlier
|
|
"
|
|
|
|
function s:Svndiff_clear(...)
|
|
let fname = bufname("%")
|
|
if exists("s:diff_signs[fname]")
|
|
for id in s:diff_signs[fname]
|
|
exec 'sign unplace ' . id . ' file=' . fname
|
|
endfor
|
|
end
|
|
let s:diff_blocks[fname] = []
|
|
let s:diff_signs[fname] = []
|
|
endfunction
|
|
|
|
|
|
"
|
|
" Jump to previous diff block sign above the current line
|
|
"
|
|
|
|
function s:Svndiff_prev(...)
|
|
let fname = bufname("%")
|
|
let diff_blocks_reversed = reverse(copy(s:diff_blocks[fname]))
|
|
for block in diff_blocks_reversed
|
|
let line = block.id - s:sign_base
|
|
if line < line(".")
|
|
call setpos(".", [ 0, line, 1, 0 ])
|
|
echom 'svndiff: ' . block.info
|
|
return
|
|
endif
|
|
endfor
|
|
echom 'svndiff: no more diff blocks above cursor'
|
|
endfunction
|
|
|
|
|
|
"
|
|
" Jump to next diff block sign below the current line
|
|
"
|
|
|
|
function s:Svndiff_next(...)
|
|
let fname = bufname("%")
|
|
for block in s:diff_blocks[fname]
|
|
let line = block.id - s:sign_base
|
|
if line > line(".")
|
|
call setpos(".", [ 0, line, 1, 0 ])
|
|
echom 'svndiff: ' . block.info
|
|
return
|
|
endif
|
|
endfor
|
|
echom 'svndiff: no more diff blocks below cursor'
|
|
endfunction
|
|
|
|
|
|
"
|
|
" Wrapper function: Takes one argument, which is the action to perform:
|
|
" {next|prev|clear}
|
|
"
|
|
|
|
function Svndiff(...)
|
|
|
|
let cmd = exists("a:1") ? a:1 : ''
|
|
let fname = bufname("%")
|
|
if fname == ""
|
|
echom "Buffer has no file name, can not do a svn diff"
|
|
return
|
|
endif
|
|
|
|
if cmd == 'clear'
|
|
let s:changedtick[fname] = 0
|
|
if exists("s:is_active[fname]")
|
|
unlet s:is_active[fname]
|
|
endif
|
|
call s:Svndiff_clear()
|
|
end
|
|
|
|
if cmd == 'prev'
|
|
let s:is_active[fname] = 1
|
|
let ok = s:Svndiff_update()
|
|
if ok
|
|
call s:Svndiff_prev()
|
|
endif
|
|
endif
|
|
|
|
if cmd == 'next'
|
|
let s:is_active[fname] = 1
|
|
let ok = s:Svndiff_update()
|
|
if ok
|
|
call s:Svndiff_next()
|
|
endif
|
|
endif
|
|
|
|
endfunction
|
|
|
|
|
|
" Define sign characters and colors
|
|
|
|
sign define svndiff_add text=> texthl=diffAdd
|
|
sign define svndiff_delete text=< texthl=diffDelete
|
|
sign define svndiff_change text=! texthl=diffChange
|
|
|
|
|
|
" Define autocmds if autoupdate is enabled
|
|
|
|
if exists("g:svndiff_autoupdate")
|
|
autocmd CursorHold,CursorHoldI * call s:Svndiff_update()
|
|
autocmd InsertLeave * call s:Svndiff_update()
|
|
endif
|
|
|
|
" vi: ts=2 sw=2
|
|
|