/contrib/vim/patchreview.vim
Vim Script | 868 lines | 665 code | 38 blank | 165 comment | 195 complexity | 87ba632e4c666b94a8443a0a1292e89e MD5 | raw file
Possible License(s): GPL-2.0
- " VIM plugin for doing single, multi-patch or diff code reviews {{{
- " Home: http://www.vim.org/scripts/script.php?script_id=1563
- " Version : 0.2.2 "{{{
- " Author : Manpreet Singh < junkblocker@yahoo.com >
- " Copyright : 2006-2010 by Manpreet Singh
- " License : This file is placed in the public domain.
- " No warranties express or implied. Use at your own risk.
- "
- " Changelog :
- "
- " 0.2.2 - Security fixes by removing custom tempfile creation
- " - Removed need for DiffReviewCleanup/PatchReviewCleanup
- " - Better command execution error detection and display
- " - Improved diff view and folding by ignoring modelines
- " - Improved tab labels display
- "
- " 0.2.1 - Minor temp directory autodetection logic and cleanup
- "
- " 0.2 - Removed the need for filterdiff by implementing it in pure vim script
- " - Added DiffReview command for reverse (changed repository to
- " pristine state) reviews.
- " (PatchReview does pristine repository to patch review)
- " - DiffReview does automatic detection and generation of diffs for
- " various Source Control systems
- " - Skip load if VIM 7.0 or higher unavailable
- "
- " 0.1 - First released
- "}}}
- " Documentation: "{{{
- " ===========================================================================
- " This plugin allows single or multiple, patch or diff based code reviews to
- " be easily done in VIM. VIM has :diffpatch command to do single file reviews
- " but a) can not handle patch files containing multiple patches or b) do
- " automated diff generation for various version control systems. This plugin
- " attempts to provide those functionalities. It opens each changed / added or
- " removed file diff in new tabs.
- "
- " Installing:
- "
- " For a quick start, unzip patchreview.zip into your ~/.vim directory and
- " restart Vim.
- "
- " Details:
- "
- " Requirements:
- "
- " 1) VIM 7.0 or higher built with +diff option.
- "
- " 2) A gnu compatible patch command installed. This is the standard patch
- " command on Linux, Mac OS X, *BSD, Cygwin or /usr/bin/gpatch on newer
- " Solaris.
- "
- " 3) Optional (but recommended for speed)
- "
- " Install patchutils ( http://cyberelk.net/tim/patchutils/ ) for your
- " OS. For windows it is available from Cygwin
- "
- " http://www.cygwin.com
- "
- " or GnuWin32
- "
- " http://gnuwin32.sourceforge.net/
- "
- " Install:
- "
- " 1) Extract the zip in your $HOME/.vim or $VIM/vimfiles directory and
- " restart vim. The directory location relevant to your platform can be
- " seen by running :help add-global-plugin in vim.
- "
- " 2) Restart vim.
- "
- " Configuration:
- "
- " Optionally, specify the locations to these filterdiff and patch commands
- " and location of a temporary directory to use in your .vimrc.
- "
- " let g:patchreview_patch = '/path/to/gnu/patch'
- "
- " " If you are using filterdiff
- " let g:patchreview_filterdiff = '/path/to/filterdiff'
- "
- "
- " Usage:
- "
- " Please see :help patchreview or :help diffreview for details.
- "
- ""}}}
- " Enabled only during development
- " unlet! g:loaded_patchreview " DEBUG
- " unlet! g:patchreview_patch " DEBUG
- " unlet! g:patchreview_filterdiff " DEBUG
- " let g:patchreview_patch = 'patch' " DEBUG
- if v:version < 700
- finish
- endif
- if ! has('diff')
- call confirm('patchreview.vim plugin needs (G)VIM built with +diff support to work.')
- finish
- endif
- " load only once
- if (! exists('g:patchreview_debug') && exists('g:loaded_patchreview')) || &compatible
- finish
- endif
- let g:loaded_patchreview="0.2.2"
- let s:msgbufname = '-PatchReviewMessages-'
- function! <SID>Debug(str) "{{{
- if exists('g:patchreview_debug')
- Pecho 'DEBUG: ' . a:str
- endif
- endfunction
- command! -nargs=+ -complete=expression Debug call s:Debug(<args>)
- "}}}
- function! <SID>PR_wipeMsgBuf() "{{{
- let winnum = bufwinnr(s:msgbufname)
- if winnum != -1 " If the window is already open, jump to it
- let cur_winnr = winnr()
- if winnr() != winnum
- exe winnum . 'wincmd w'
- exe 'bw'
- exe cur_winnr . 'wincmd w'
- endif
- endif
- endfunction
- "}}}
- function! <SID>Pecho(...) "{{{
- " Usage: Pecho(msg, [return_to_original_window_flag])
- " default return_to_original_window_flag = 0
- "
- let cur_winnr = winnr()
- let winnum = bufwinnr(s:msgbufname)
- if winnum != -1 " If the window is already open, jump to it
- if winnr() != winnum
- exe winnum . 'wincmd w'
- endif
- else
- let bufnum = bufnr(s:msgbufname)
- if bufnum == -1
- let wcmd = s:msgbufname
- else
- let wcmd = '+buffer' . bufnum
- endif
- exe 'silent! botright 5split ' . wcmd
- endif
- setlocal modifiable
- setlocal buftype=nofile
- setlocal bufhidden=delete
- setlocal noswapfile
- setlocal nowrap
- setlocal nobuflisted
- if a:0 != 0
- silent! $put =a:1
- endif
- exe ':$'
- setlocal nomodifiable
- if a:0 > 1 && a:2
- exe cur_winnr . 'wincmd w'
- endif
- endfunction
- command! -nargs=+ -complete=expression Pecho call s:Pecho(<args>)
- "}}}
- function! <SID>PR_checkBinary(BinaryName) "{{{
- " Verify that BinaryName is specified or available
- if ! exists('g:patchreview_' . a:BinaryName)
- if executable(a:BinaryName)
- let g:patchreview_{a:BinaryName} = a:BinaryName
- return 1
- else
- Pecho 'g:patchreview_' . a:BinaryName . ' is not defined and ' . a:BinaryName . ' command could not be found on path.'
- Pecho 'Please define it in your .vimrc.'
- return 0
- endif
- elseif ! executable(g:patchreview_{a:BinaryName})
- Pecho 'Specified g:patchreview_' . a:BinaryName . ' [' . g:patchreview_{a:BinaryName} . '] is not executable.'
- return 0
- else
- return 1
- endif
- endfunction
- "}}}
- function! <SID>ExtractDiffsNative(...) "{{{
- " Sets g:patches = {'reason':'', 'patch':[
- " {
- " 'filename': filepath
- " 'type' : '+' | '-' | '!'
- " 'content' : patch text for this file
- " },
- " ...
- " ]}
- let g:patches = {'reason' : '', 'patch' : []}
- " TODO : User pointers into lines list rather then use collect
- if a:0 == 0
- let g:patches['reason'] = "ExtractDiffsNative expects at least a patchfile argument"
- return
- endif
- let patchfile = expand(a:1, ':p')
- if a:0 > 1
- let patch = a:2
- endif
- if ! filereadable(patchfile)
- let g:patches['reason'] = "File " . patchfile . " is not readable"
- return
- endif
- unlet! filterdiffcmd
- let filterdiffcmd = '' . g:patchreview_filterdiff . ' --list -s ' . patchfile
- let fileslist = split(system(filterdiffcmd), '[\r\n]')
- for filewithchangetype in fileslist
- if filewithchangetype !~ '^[!+-] '
- Pecho '*** Skipping review generation due to unknown change for [' . filewithchangetype . ']'
- continue
- endif
- unlet! this_patch
- let this_patch = {}
- unlet! relpath
- let relpath = substitute(filewithchangetype, '^. ', '', '')
- let this_patch['filename'] = relpath
- if filewithchangetype =~ '^! '
- let this_patch['type'] = '!'
- elseif filewithchangetype =~ '^+ '
- let this_patch['type'] = '+'
- elseif filewithchangetype =~ '^- '
- let this_patch['type'] = '-'
- endif
- unlet! filterdiffcmd
- let filterdiffcmd = '' . g:patchreview_filterdiff . ' -i ' . relpath . ' ' . patchfile
- let this_patch['content'] = split(system(filterdiffcmd), '[\n\r]')
- let g:patches['patch'] += [this_patch]
- Debug "Patch collected for " . relpath
- endfor
- endfunction
- "}}}
- function! <SID>ExtractDiffsPureVim(...) "{{{
- " Sets g:patches = {'reason':'', 'patch':[
- " {
- " 'filename': filepath
- " 'type' : '+' | '-' | '!'
- " 'content' : patch text for this file
- " },
- " ...
- " ]}
- let g:patches = {'reason' : '', 'patch' : []}
- " TODO : User pointers into lines list rather then use collect
- if a:0 == 0
- let g:patches['reason'] = "ExtractDiffsPureVim expects at least a patchfile argument"
- return
- endif
- let patchfile = expand(a:1, ':p')
- if a:0 > 1
- let patch = a:2
- endif
- if ! filereadable(patchfile)
- let g:patches['reason'] = "File " . patchfile . " is not readable"
- return
- endif
- call s:PR_wipeMsgBuf()
- let collect = []
- let linum = 0
- let lines = readfile(patchfile)
- let linescount = len(lines)
- State 'START'
- while linum < linescount
- let line = lines[linum]
- let linum += 1
- if State() == 'START'
- let mat = matchlist(line, '^--- \([^\t]\+\).*$')
- if ! empty(mat) && mat[1] != ''
- State 'MAYBE_UNIFIED_DIFF'
- let p_first_file = mat[1]
- let collect = [line]
- Debug line . State()
- continue
- endif
- let mat = matchlist(line, '^\*\*\* \([^\t]\+\).*$')
- if ! empty(mat) && mat[1] != ''
- State 'MAYBE_CONTEXT_DIFF'
- let p_first_file = mat[1]
- let collect = [line]
- Debug line . State()
- continue
- endif
- continue
- elseif State() == 'MAYBE_CONTEXT_DIFF'
- let mat = matchlist(line, '^--- \([^\t]\+\).*$')
- if empty(mat) || mat[1] == ''
- State 'START'
- let linum -= 1
- continue
- Debug 'Back to square one ' . line()
- endif
- let p_second_file = mat[1]
- if p_first_file == '/dev/null'
- if p_second_file == '/dev/null'
- let g:patches['reason'] = "Malformed diff found at line " . linum
- return
- endif
- let p_type = '+'
- let filepath = p_second_file
- else
- if p_second_file == '/dev/null'
- let p_type = '-'
- let filepath = p_first_file
- else
- let p_type = '!'
- let filepath = p_first_file
- endif
- endif
- State 'EXPECT_15_STARS'
- let collect += [line]
- Debug line . State()
- elseif State() == 'EXPECT_15_STARS'
- if line !~ '^*\{15}$'
- State 'START'
- let linum -= 1
- Debug line . State()
- continue
- endif
- State 'EXPECT_CONTEXT_CHUNK_HEADER_1'
- let collect += [line]
- Debug line . State()
- elseif State() == 'EXPECT_CONTEXT_CHUNK_HEADER_1'
- let mat = matchlist(line, '^\*\*\* \(\d\+,\)\?\(\d\+\) \*\*\*\*$')
- if empty(mat) || mat[1] == ''
- State 'START'
- let linum -= 1
- Debug line . State()
- continue
- endif
- let collect += [line]
- State 'SKIP_CONTEXT_STUFF_1'
- Debug line . State()
- continue
- elseif State() == 'SKIP_CONTEXT_STUFF_1'
- if line !~ '^[ !+].*$'
- let mat = matchlist(line, '^--- \(\d\+\),\(\d\+\) ----$')
- if ! empty(mat) && mat[1] != '' && mat[2] != ''
- let goal_count = mat[2] - mat[1] + 1
- let c_count = 0
- State 'READ_CONTEXT_CHUNK'
- let collect += [line]
- Debug line . State() . " Goal count set to " . goal_count
- continue
- endif
- State 'START'
- let linum -= 1
- Debug line . State()
- continue
- endif
- let collect += [line]
- continue
- elseif State() == 'READ_CONTEXT_CHUNK'
- let c_count += 1
- if c_count == goal_count
- let collect += [line]
- State 'BACKSLASH_OR_CRANGE_EOF'
- continue
- else " goal not met yet
- let mat = matchlist(line, '^\([\\!+ ]\).*$')
- if empty(mat) || mat[1] == ''
- let linum -= 1
- State 'START'
- Debug line . State()
- continue
- endif
- let collect += [line]
- continue
- endif
- elseif State() == 'BACKSLASH_OR_CRANGE_EOF'
- if line =~ '^\\ No newline.*$' " XXX: Can we go to another chunk from here??
- let collect += [line]
- let this_patch = {}
- let this_patch['filename'] = filepath
- let this_patch['type'] = p_type
- let this_patch['content'] = collect
- let g:patches['patch'] += [this_patch]
- Debug "Patch collected for " . filepath
- State 'START'
- continue
- endif
- if line =~ '^\*\{15}$'
- let collect += [line]
- State 'EXPECT_CONTEXT_CHUNK_HEADER_1'
- Debug line . State()
- continue
- endif
- let this_patch = {}
- let this_patch['filename'] = filepath
- let this_patch['type'] = p_type
- let this_patch['content'] = collect
- let g:patches['patch'] += [this_patch]
- let linum -= 1
- State 'START'
- Debug "Patch collected for " . filepath
- Debug line . State()
- continue
- elseif State() == 'MAYBE_UNIFIED_DIFF'
- let mat = matchlist(line, '^+++ \([^\t]\+\).*$')
- if empty(mat) || mat[1] == ''
- State 'START'
- let linum -= 1
- Debug line . State()
- continue
- endif
- let p_second_file = mat[1]
- if p_first_file == '/dev/null'
- if p_second_file == '/dev/null'
- let g:patches['reason'] = "Malformed diff found at line " . linum
- return
- endif
- let p_type = '+'
- let filepath = p_second_file
- else
- if p_second_file == '/dev/null'
- let p_type = '-'
- let filepath = p_first_file
- else
- let p_type = '!'
- let filepath = p_first_file
- endif
- endif
- State 'EXPECT_UNIFIED_RANGE_CHUNK'
- let collect += [line]
- Debug line . State()
- continue
- elseif State() == 'EXPECT_UNIFIED_RANGE_CHUNK'
- let mat = matchlist(line, '^@@ -\(\d\+,\)\?\(\d\+\) +\(\d\+,\)\?\(\d\+\) @@$')
- if ! empty(mat)
- let old_goal_count = mat[2]
- let new_goal_count = mat[4]
- let o_count = 0
- let n_count = 0
- Debug "Goal count set to " . old_goal_count . ', ' . new_goal_count
- State 'READ_UNIFIED_CHUNK'
- let collect += [line]
- Debug line . State()
- continue
- endif
- State 'START'
- Debug line . State()
- continue
- elseif State() == 'READ_UNIFIED_CHUNK'
- if o_count == old_goal_count && n_count == new_goal_count
- if line =~ '^\\.*$' " XXX: Can we go to another chunk from here??
- let collect += [line]
- let this_patch = {}
- let this_patch['filename'] = filepath
- let this_patch['type'] = p_type
- let this_patch['content'] = collect
- let g:patches['patch'] += [this_patch]
- Debug "Patch collected for " . filepath
- State 'START'
- continue
- endif
- let mat = matchlist(line, '^@@ -\(\d\+,\)\?\(\d\+\) +\(\d\+,\)\?\(\d\+\) @@$')
- if ! empty(mat)
- let old_goal_count = mat[2]
- let new_goal_count = mat[4]
- let o_count = 0
- let n_count = 0
- Debug "Goal count set to " . old_goal_count . ', ' . new_goal_count
- let collect += [line]
- Debug line . State()
- continue
- endif
- let this_patch = {}
- let this_patch['filename'] = filepath
- let this_patch['type'] = p_type
- let this_patch['content'] = collect
- let g:patches['patch'] += [this_patch]
- Debug "Patch collected for " . filepath
- let linum -= 1
- State 'START'
- Debug line . State()
- continue
- else " goal not met yet
- let mat = matchlist(line, '^\([\\+ -]\).*$')
- if empty(mat) || mat[1] == ''
- let linum -= 1
- State 'START'
- continue
- endif
- let chr = mat[1]
- if chr == '+'
- let n_count += 1
- endif
- if chr == ' '
- let o_count += 1
- let n_count += 1
- endif
- if chr == '-'
- let o_count += 1
- endif
- let collect += [line]
- Debug line . State()
- continue
- endif
- else
- let g:patches['reason'] = "Internal error: Do not use the plugin anymore and if possible please send the diff or patch file you tried it with to Manpreet Singh <junkblocker@yahoo.com>"
- return
- endif
- endwhile
- "Pecho State()
- if (State() == 'READ_CONTEXT_CHUNK' && c_count == goal_count) || (State() == 'READ_UNIFIED_CHUNK' && n_count == new_goal_count && o_count == old_goal_count)
- let this_patch = {}
- let this_patch['filename'] = filepath
- let this_patch['type'] = p_type
- let this_patch['content'] = collect
- let g:patches['patch'] += [this_patch]
- Debug "Patch collected for " . filepath
- endif
- return
- endfunction
- "}}}
- function! State(...) " For easy manipulation of diff extraction state "{{{
- if a:0 != 0
- let s:STATE = a:1
- else
- if ! exists('s:STATE')
- let s:STATE = 'START'
- endif
- return s:STATE
- endif
- endfunction
- com! -nargs=+ -complete=expression State call State(<args>)
- "}}}
- function! <SID>PatchReview(...) "{{{
- let s:save_shortmess = &shortmess
- let s:save_aw = &autowrite
- let s:save_awa = &autowriteall
- set shortmess=aW
- call s:PR_wipeMsgBuf()
- let s:reviewmode = 'patch'
- call s:_GenericReview(a:000)
- let &autowriteall = s:save_awa
- let &autowrite = s:save_aw
- let &shortmess = s:save_shortmess
- endfunction
- "}}}
- function! <SID>_GenericReview(argslist) "{{{
- " diff mode:
- " arg1 = patchfile
- " arg2 = strip count
- " patch mode:
- " arg1 = patchfile
- " arg2 = strip count
- " arg3 = directory
- " VIM 7+ required
- if version < 700
- Pecho 'This plugin needs VIM 7 or higher'
- return
- endif
- " +diff required
- if ! has('diff')
- Pecho 'This plugin needs VIM built with +diff feature.'
- return
- endif
- if s:reviewmode == 'diff'
- let patch_R_option = ' -t -R '
- elseif s:reviewmode == 'patch'
- let patch_R_option = ''
- else
- Pecho 'Fatal internal error in patchreview.vim plugin'
- return
- endif
- " Check passed arguments
- if len(a:argslist) == 0
- Pecho 'PatchReview command needs at least one argument specifying a patchfile path.'
- return
- endif
- let StripCount = 0
- if len(a:argslist) >= 1 && ((s:reviewmode == 'patch' && len(a:argslist) <= 3) || (s:reviewmode == 'diff' && len(a:argslist) == 2))
- let PatchFilePath = expand(a:argslist[0], ':p')
- if ! filereadable(PatchFilePath)
- Pecho 'File [' . PatchFilePath . '] is not accessible.'
- return
- endif
- if len(a:argslist) >= 2 && s:reviewmode == 'patch'
- let s:SrcDirectory = expand(a:argslist[1], ':p')
- if ! isdirectory(s:SrcDirectory)
- Pecho '[' . s:SrcDirectory . '] is not a directory'
- return
- endif
- try
- " Command line has already escaped the path
- exe 'cd ' . s:SrcDirectory
- catch /^.*E344.*/
- Pecho 'Could not change to directory [' . s:SrcDirectory . ']'
- return
- endtry
- endif
- if s:reviewmode == 'diff'
- " passed in by default
- let StripCount = eval(a:argslist[1])
- elseif s:reviewmode == 'patch'
- let StripCount = 1
- " optional strip count
- if len(a:argslist) == 3
- let StripCount = eval(a:argslist[2])
- endif
- endif
- else
- if s:reviewmode == 'patch'
- Pecho 'PatchReview command needs at most three arguments: patchfile path, optional source directory path and optional strip count.'
- elseif s:reviewmode == 'diff'
- Pecho 'DiffReview command accepts no arguments.'
- endif
- return
- endif
- " Verify that patch command and temporary directory are available or specified
- if ! s:PR_checkBinary('patch')
- return
- endif
- " Requirements met, now execute
- let PatchFilePath = fnamemodify(PatchFilePath, ':p')
- if s:reviewmode == 'patch'
- Pecho 'Patch file : ' . PatchFilePath
- endif
- Pecho 'Source directory: ' . getcwd()
- Pecho '------------------'
- if s:PR_checkBinary('filterdiff')
- Debug "Using filterdiff"
- call s:ExtractDiffsNative(PatchFilePath)
- else
- Debug "Using own diff extraction (slower)"
- call s:ExtractDiffsPureVim(PatchFilePath)
- endif
- for patch in g:patches['patch']
- if patch.type !~ '^[!+-]$'
- Pecho '*** Skipping review generation due to unknown change [' . patch.type . ']', 1
- continue
- endif
- unlet! relpath
- let relpath = patch.filename
- " XXX: svn diff and hg diff produce different kind of outputs, one requires
- " XXX: stripping but the other doesn't. We need to take care of that
- let stripmore = StripCount
- let StrippedRelativeFilePath = relpath
- while stripmore > 0
- " strip one
- let StrippedRelativeFilePath = substitute(StrippedRelativeFilePath, '^[^\\\/]\+[^\\\/]*[\\\/]' , '' , '')
- let stripmore -= 1
- endwhile
- if patch.type == '!'
- if s:reviewmode == 'patch'
- let msgtype = 'Patch modifies file: '
- elseif s:reviewmode == 'diff'
- let msgtype = 'File has changes: '
- endif
- elseif patch.type == '+'
- if s:reviewmode == 'patch'
- let msgtype = 'Patch adds file : '
- elseif s:reviewmode == 'diff'
- let msgtype = 'New file : '
- endif
- elseif patch.type == '-'
- if s:reviewmode == 'patch'
- let msgtype = 'Patch removes file : '
- elseif s:reviewmode == 'diff'
- let msgtype = 'Removed file : '
- endif
- endif
- let bufnum = bufnr(relpath)
- if buflisted(bufnum) && getbufvar(bufnum, '&mod')
- Pecho 'Old buffer for file [' . relpath . '] exists in modified state. Skipping review.', 1
- continue
- endif
- let tmpname = tempname()
- " write patch for patch.filename into tmpname
- call writefile(patch.content, tmpname)
- if patch.type == '+' && s:reviewmode == 'patch'
- let inputfile = ''
- let patchcmd = '!' . g:patchreview_patch . patch_R_option . ' -o "' . tmpname . '.file" "' . inputfile . '" < "' . tmpname . '"'
- elseif patch.type == '+' && s:reviewmode == 'diff'
- let inputfile = ''
- unlet! patchcmd
- else
- let inputfile = expand(StrippedRelativeFilePath, ':p')
- let patchcmd = '!' . g:patchreview_patch . patch_R_option . ' -o "' . tmpname . '.file" "' . inputfile . '" < "' . tmpname . '"'
- endif
- if exists('patchcmd')
- let v:errmsg = ''
- Debug patchcmd
- silent exe patchcmd
- if v:errmsg != '' || v:shell_error
- Pecho 'ERROR: Could not execute patch command.'
- Pecho 'ERROR: ' . patchcmd
- Pecho 'ERROR: ' . v:errmsg
- Pecho 'ERROR: Diff skipped.'
- continue
- endif
- endif
- call delete(tmpname)
- let s:origtabpagenr = tabpagenr()
- silent! exe 'tabedit ' . StrippedRelativeFilePath
- if exists('patchcmd')
- " modelines in loaded files mess with diff comparision
- let s:keep_modeline=&modeline
- let &modeline=0
- silent! exe 'vert diffsplit ' . tmpname . '.file'
- setlocal buftype=nofile
- setlocal noswapfile
- setlocal syntax=none
- setlocal bufhidden=delete
- setlocal nobuflisted
- setlocal modifiable
- setlocal nowrap
- " Remove buffer name
- silent! 0f
- " Switch to original to get a nice tab title
- silent! wincmd p
- let &modeline=s:keep_modeline
- else
- silent! exe 'vnew'
- endif
- if filereadable(tmpname . '.file.rej')
- silent! exe 'topleft 5split ' . tmpname . '.file.rej'
- Pecho msgtype . '*** REJECTED *** ' . relpath, 1
- else
- Pecho msgtype . ' ' . relpath, 1
- endif
- silent! exe 'tabn ' . s:origtabpagenr
- endfor
- Pecho '-----'
- Pecho 'Done.'
- endfunction
- "}}}
- function! <SID>DiffReview(...) "{{{
- let s:save_shortmess = &shortmess
- set shortmess=aW
- call s:PR_wipeMsgBuf()
- let vcsdict = {
- \'Mercurial' : {'dir' : '.hg', 'binary' : 'hg', 'diffargs' : 'diff' , 'strip' : 1},
- \'Bazaar-NG' : {'dir' : '.bzr', 'binary' : 'bzr', 'diffargs' : 'diff' , 'strip' : 0},
- \'monotone' : {'dir' : '_MTN', 'binary' : 'mtn', 'diffargs' : 'diff --unified', 'strip' : 0},
- \'Subversion' : {'dir' : '.svn', 'binary' : 'svn', 'diffargs' : 'diff' , 'strip' : 0},
- \'cvs' : {'dir' : 'CVS', 'binary' : 'cvs', 'diffargs' : '-q diff -u' , 'strip' : 0},
- \}
- unlet! s:theDiffCmd
- unlet! l:vcs
- if ! exists('g:patchreview_diffcmd')
- for key in keys(vcsdict)
- if isdirectory(vcsdict[key]['dir'])
- if ! s:PR_checkBinary(vcsdict[key]['binary'])
- Pecho 'Current directory looks like a ' . vcsdict[key] . ' repository but ' . vcsdist[key]['binary'] . ' command was not found on path.'
- let &shortmess = s:save_shortmess
- return
- else
- let s:theDiffCmd = vcsdict[key]['binary'] . ' ' . vcsdict[key]['diffargs']
- let strip = vcsdict[key]['strip']
- Pecho 'Using [' . s:theDiffCmd . '] to generate diffs for this ' . key . ' review.'
- let &shortmess = s:save_shortmess
- let l:vcs = vcsdict[key]['binary']
- break
- endif
- else
- continue
- endif
- endfor
- else
- let s:theDiffCmd = g:patchreview_diffcmd
- let strip = 0
- endif
- if ! exists('s:theDiffCmd')
- Pecho 'Please define g:patchreview_diffcmd and make sure you are in a VCS controlled top directory.'
- let &shortmess = s:save_shortmess
- return
- endif
- let outfile = tempname()
- let cmd = s:theDiffCmd . ' > "' . outfile . '"'
- let v:errmsg = ''
- let cout = system(cmd)
- if v:errmsg == '' && exists('l:vcs') && l:vcs == 'cvs' && v:shell_error == 1
- " Ignoring CVS non-error
- elseif v:errmsg != '' || v:shell_error
- Pecho v:errmsg
- Pecho 'Could not execute [' . s:theDiffCmd . ']'
- Pecho 'Error code: ' . v:shell_error
- Pecho cout
- Pecho 'Diff review aborted.'
- let &shortmess = s:save_shortmess
- return
- endif
- let s:reviewmode = 'diff'
- call s:_GenericReview([outfile, strip])
- let &shortmess = s:save_shortmess
- endfunction
- "}}}
- " End user commands "{{{
- "============================================================================
- " :PatchReview
- command! -nargs=* -complete=file PatchReview call s:PatchReview (<f-args>)
- " :DiffReview
- command! -nargs=0 DiffReview call s:DiffReview()
- "}}}
- " Development "{{{
- if exists('g:patchreview_debug')
- " Tests
- function! <SID>PRExtractTestNative(...)
- "let patchfiles = glob(expand(a:1) . '/?*')
- "for fname in split(patchfiles)
- call s:PR_wipeMsgBuf()
- let fname = a:1
- call s:ExtractDiffsNative(fname)
- for patch in g:patches['patch']
- for line in patch.content
- Pecho line
- endfor
- endfor
- "endfor
- endfunction
- function! <SID>PRExtractTestVim(...)
- "let patchfiles = glob(expand(a:1) . '/?*')
- "for fname in split(patchfiles)
- call s:PR_wipeMsgBuf()
- let fname = a:1
- call s:ExtractDiffsPureVim(fname)
- for patch in g:patches['patch']
- for line in patch.content
- Pecho line
- endfor
- endfor
- "endfor
- endfunction
- command! -nargs=+ -complete=file PRTestVim call s:PRExtractTestVim(<f-args>)
- command! -nargs=+ -complete=file PRTestNative call s:PRExtractTestNative(<f-args>)
- endif
- "}}}
- " modeline
- " vim: set et fdl=0 fdm=marker fenc=latin ff=unix ft=vim sw=2 sts=0 ts=2 textwidth=78 nowrap :