Mercurial > hg
view contrib/vim/patchreview.vim @ 30769:e520f0f4b1cf
help: merge revsets.txt into revisions.txt
Selecting single and multiple revisions is closely related, so let's
put it in one place, so users can easily find it. We actually did not
even point to "hg help revsets" from "hg help revisions", but now that
they're on a single page, that won't be necessary.
author | Martin von Zweigbergk <martinvonz@google.com> |
---|---|
date | Wed, 11 Jan 2017 11:37:38 -0800 |
parents | 318a24b52eeb |
children |
line wrap: on
line source
" 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 :