##// END OF EJS Templates
wireprotov2: declare command arguments richly...
wireprotov2: declare command arguments richly Previously, we declared command arguments with an example of their value. After this commit, we declare command arguments as a dict of metadata. This allows us to define the value type, whether the argument is required, and provide default values. This in turn allows us to have nice things, such as less boilerplate code in individual commands for validating input and assigning default values. It should also make command behavior more consistent as a result. Test output changed slightly because I realized that the "fields" argument wasn't being consistently defined as a set. Oops! Other test output changed because of slight differences in code performing type validation. Differential Revision: https://phab.mercurial-scm.org/D4615

File last commit:

r30332:318a24b5 default
r39835:0b61d21f default
Show More
patchreview.vim
868 lines | 26.7 KiB | text/x-vim | VimLexer
" 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 comparison
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 :