##// END OF EJS Templates
contrib: patch review plugin for vim 7.0...
Manpreet Singh -
r2350:091d5556 default
parent child Browse files
Show More
@@ -0,0 +1,97 b''
1 *patchreview.txt* Vim global plugin for doing single or multipatch code reviews
2
3 Author: Manpreet Singh (junkblocker-CAT-yahoo-DOG-com)
4 (Replace -CAT- and -DOG- with @ and . first)
5 Copyright (C) 2006 by Manpreet Singh
6 License : This file is placed in the public domain.
7
8 =============================================================================
9
10 CONTENTS *patchreview* *patchreview-contents*
11
12 1. Contents.........................................: |patchreview-contents|
13 2. Introduction.....................................: |patchreview-intro|
14 3. PatchReview options..............................: |patchreview-options|
15 4. PatchReview Usage................................: |patchreview-usage|
16 4.1 PatchReview Usage............................: |:PatchReview|
17 4.2 PatchReview Usage............................: |:PatchReviewCleanup|
18
19 =============================================================================
20
21 PatchReview Introduction *patchreview-intro*
22
23 The Patch Review plugin allows single or multipatch code review to be done in
24 VIM. VIM provides the |:diffpatch| command to do single file reviews but can
25 not handle patch files containing multiple patches as is common with software
26 development projects. This plugin provides that missing functionality. It also
27 tries to improve on |:diffpatch|'s behaviour of creating the patched files in
28 the same directory as original file which can lead to project workspace
29 pollution.
30
31 =============================================================================
32
33 PatchReview Options *patchreview-options*
34
35 g:patchreview_filterdiff : Optional path to filterdiff binary. PatchReview
36 tries to locate filterdiff on system path
37 automatically. If the binary is not on system
38 path, this option tell PatchReview the full path
39 to the binary. This option, if specified,
40 overrides the default filterdiff binary on the
41 path.
42
43 examples:
44 (On Windows with Cygwin)
45
46 let g:patchreview_filterdiff = 'c:\\cygwin\\bin\\filterdiff.exe'
47
48 (On *nix systems)
49
50 let g:patchreview_filterdiff = '/usr/bin/filterdiff'
51
52 g:patchreview_patch : Optional path to patch binary. PatchReview tries
53 to locate patch on system path automatically. If
54 the binary is not on system path, this option
55 tell PatchReview the full path to the binary.
56 This option, if specified, overrides the default
57 patch binary on the path.
58
59 examples:
60 (On Windows with Cygwin)
61
62 let g:patchreview_patch = 'c:\\cygwin\\bin\\patch.exe'
63
64 (On *nix systems)
65
66 let g:patchreview_patch = '/usr/bin/gpatch'
67
68
69 g:patchreview_tmpdir : Optional path where the plugin can save temporary
70 files. If this is not specified, the plugin tries to
71 use TMP, TEMP and TMPDIR environment variables in
72 succession.
73
74 examples:
75 (On Windows) let g:patchreview_tmpdir = 'c:\\tmp'
76 (On *nix systems) let g:patchreview_tmpdir = '~/tmp'
77
78 =============================================================================
79
80 PatchReview Usage *patchreview-usage*
81 *:PatchReview*
82
83 :PatchReview patchfile_path [optional_source_directory]
84
85 Perform a patch review in the current directory based on the supplied
86 patchfile_path. If optional_source_directory is specified, patchreview is
87 done on that directory. Othewise, the current directory is assumed to be
88 the source directory.
89 *:PatchReviewCleanup*
90
91 :PatchReviewCleanup
92
93 After you are done using the :PatchReview command, you can cleanup the
94 temporary files in the temporary directory using this command.
95
96 =============================================================================
97 vim: ft=help:ts=2:sts=2:sw=2:tw=78:tw=78
@@ -0,0 +1,332 b''
1 " Vim global plugin for doing single or multipatch code reviews"{{{
2
3 " Version : 0.1 "{{{
4 " Last Modified : Thu 25 May 2006 10:15:11 PM PDT
5 " Author : Manpreet Singh (junkblocker AT yahoo DOT com)
6 " Copyright : 2006 by Manpreet Singh
7 " License : This file is placed in the public domain.
8 "
9 " History : 0.1 - First released
10 "}}}
11 " Documentation: "{{{
12 " ===========================================================================
13 " This plugin allows single or multipatch code reviews to be done in VIM. Vim
14 " has :diffpatch command to do single file reviews but can not handle patch
15 " files containing multiple patches. This plugin provides that missing
16 " functionality and doesn't require the original file to be open.
17 "
18 " Installing: "{{{
19 "
20 " For a quick start...
21 "
22 " Requirements: "{{{
23 "
24 " 1) (g)vim 7.0 or higher built with +diff option.
25 " 2) patch and patchutils ( http://cyberelk.net/tim/patchutils/ ) installed
26 " for your OS. For windows it is availble from Cygwin (
27 " http://www.cygwin.com ) or GnuWin32 ( http://gnuwin32.sourceforge.net/
28 " ).
29 ""}}}
30 " Install: "{{{
31 "
32 " 1) Extract this in your $VIM/vimfiles or $HOME/.vim directory and restart
33 " vim.
34 "
35 " 2) Make sure that you have filterdiff from patchutils and patch commands
36 " installed.
37 "
38 " 3) Optinally, specify the locations to filterdiff and patch commands and
39 " location of a temporary directory to use in your .vimrc.
40 "
41 " let g:patchreview_filterdiff = '/path/to/filterdiff'
42 " let g:patchreview_patch = '/path/to/patch'
43 " let g:patchreview_tmpdir = '/tmp/or/something'
44 "
45 " 4) Optionally, generate help tags to use help
46 "
47 " :helptags ~/.vim/doc
48 " or
49 " :helptags c:\vim\vimfiles\doc
50 ""}}}
51 ""}}}
52 " Usage: "{{{
53 "
54 " :PatchReview path_to_submitted_patchfile [optional_source_directory]
55 "
56 " after review is done
57 "
58 " :PatchReviewCleanup
59 "
60 " See :help patchreview for details after you've created help tags.
61 ""}}}
62 "}}}
63 " Code "{{{
64
65 " Enabled only during development "{{{
66 " unlet! g:loaded_patchreview " DEBUG
67 " unlet! g:patchreview_tmpdir " DEBUG
68 " unlet! g:patchreview_filterdiff " DEBUG
69 " unlet! g:patchreview_patch " DEBUG
70 "}}}
71
72 " load only once "{{{
73 if exists('g:loaded_patchreview')
74 finish
75 endif
76 let g:loaded_patchreview=1
77 let s:msgbufname = 'Patch Review Messages'
78 "}}}
79
80 function! <SID>PR_wipeMsgBuf() "{{{
81 let s:winnum = bufwinnr(s:msgbufname)
82 if s:winnum != -1 " If the window is already open, jump to it
83 let s:cur_winnr = winnr()
84 if winnr() != s:winnum
85 exe s:winnum . 'wincmd w'
86 exe 'bw'
87 exe s:cur_winnr . 'wincmd w'
88 endif
89 endif
90 endfunction
91 "}}}
92
93 function! <SID>PR_echo(...) "{{{
94 " Usage: PR_echo(msg, [return_to_original_window_flag])
95 " default return_to_original_window_flag = 0
96 "
97 let s:cur_winnr = winnr()
98 let s:winnum = bufwinnr(s:msgbufname)
99 if s:winnum != -1 " If the window is already open, jump to it
100 if winnr() != s:winnum
101 exe s:winnum . 'wincmd w'
102 endif
103 else
104 let s:bufnum = bufnr(s:msgbufname)
105 if s:bufnum == -1
106 let s:wcmd = s:msgbufname
107 else
108 let s:wcmd = '+buffer' . s:bufnum
109 endif
110 exe 'silent! botright 5split ' . s:wcmd
111 endif
112 setlocal modifiable
113 setlocal buftype=nofile
114 setlocal bufhidden=delete
115 setlocal noswapfile
116 setlocal nowrap
117 setlocal nobuflisted
118 if a:0 != 0
119 silent! $put =a:1
120 endif
121 exe ':$'
122 setlocal nomodifiable
123 if a:0 > 1 && a:2
124 exe s:cur_winnr . 'wincmd w'
125 endif
126 endfunction
127 "}}}
128
129 function! <SID>PR_checkBinary(BinaryName) "{{{
130 " Verify that BinaryName is specified or available
131 if ! exists('g:patchreview_' . a:BinaryName)
132 if executable(a:BinaryName)
133 let g:patchreview_{a:BinaryName} = a:BinaryName
134 return 1
135 else
136 call s:PR_echo('g:patchreview_' . a:BinaryName . ' is not defined and could not be found on path. Please define it in your .vimrc.')
137 return 0
138 endif
139 elseif ! executable(g:patchreview_{a:BinaryName})
140 call s:PR_echo('Specified g:patchreview_' . a:BinaryName . ' [' . g:patchreview_{a.BinaryName} . '] is not executable.')
141 return 0
142 else
143 return 1
144 endif
145 endfunction
146 "}}}
147
148 function! <SID>PR_GetTempDirLocation(Quiet) "{{{
149 if exists('g:patchreview_tmpdir')
150 if ! isdirectory(g:patchreview_tmpdir) || ! filewritable(g:patchreview_tmpdir)
151 if ! a:Quiet
152 call s:PR_echo('Temporary directory specified by g:patchreview_tmpdir [' . g:patchreview_tmpdir . '] is not accessible.')
153 return 0
154 endif
155 endif
156 elseif exists("$TMP") && isdirectory($TMP) && filewritable($TMP)
157 let g:patchreview_tmpdir = $TMP
158 elseif exists("$TEMP") && isdirectory($TEMP) && filewritable($TEMP)
159 let g:patchreview_tmpdir = $TEMP
160 elseif exists("$TMPDIR") && isdirectory($TMPDIR) && filewritable($TMPDIR)
161 let g:patchreview_tmpdir = $TMPDIR
162 else
163 if ! a:Quiet
164 call s:PR_echo('Could not figure out a temporary directory to use. Please specify g:patchreview_tmpdir in your .vimrc.')
165 return 0
166 endif
167 endif
168 let g:patchreview_tmpdir = g:patchreview_tmpdir . '/'
169 let g:patchreview_tmpdir = substitute(g:patchreview_tmpdir, '\\', '/', 'g')
170 let g:patchreview_tmpdir = substitute(g:patchreview_tmpdir, '/+$', '/', '')
171 if has('win32')
172 let g:patchreview_tmpdir = substitute(g:patchreview_tmpdir, '/', '\\', 'g')
173 endif
174 return 1
175 endfunction
176 "}}}
177
178 function! <SID>PatchReview(...) "{{{
179 " VIM 7+ required"{{{
180 if version < 700
181 call s:PR_echo('This plugin needs VIM 7 or higher')
182 return
183 endif
184 "}}}
185
186 let s:save_shortmess = &shortmess
187 set shortmess+=aW
188 call s:PR_wipeMsgBuf()
189
190 " Check passed arguments "{{{
191 if a:0 == 0
192 call s:PR_echo('PatchReview command needs at least one argument specifying a patchfile path.')
193 let &shortmess = s:save_shortmess
194 return
195 endif
196 if a:0 >= 1 && a:0 <= 2
197 let s:PatchFilePath = expand(a:1, ':p')
198 if ! filereadable(s:PatchFilePath)
199 call s:PR_echo('File [' . s:PatchFilePath . '] is not accessible.')
200 let &shortmess = s:save_shortmess
201 return
202 endif
203 if a:0 == 2
204 let s:SrcDirectory = expand(a:2, ':p')
205 if ! isdirectory(s:SrcDirectory)
206 call s:PR_echo('[' . s:SrcDirectory . '] is not a directory')
207 let &shortmess = s:save_shortmess
208 return
209 endif
210 try
211 exe 'cd ' . s:SrcDirectory
212 catch /^.*E344.*/
213 call s:PR_echo('Could not change to directory [' . s:SrcDirectory . ']')
214 let &shortmess = s:save_shortmess
215 return
216 endtry
217 endif
218 else
219 call s:PR_echo('PatchReview command needs at most two arguments: patchfile path and optional source directory path.')
220 let &shortmess = s:save_shortmess
221 return
222 endif
223 "}}}
224
225 " Verify that filterdiff and patch are specified or available "{{{
226 if ! s:PR_checkBinary('filterdiff') || ! s:PR_checkBinary('patch')
227 let &shortmess = s:save_shortmess
228 return
229 endif
230
231 let s:retval = s:PR_GetTempDirLocation(0)
232 if ! s:retval
233 let &shortmess = s:save_shortmess
234 return
235 endif
236 "}}}
237
238 " Requirements met, now execute "{{{
239 let s:PatchFilePath = fnamemodify(s:PatchFilePath, ':p')
240 call s:PR_echo('Patch file : ' . s:PatchFilePath)
241 call s:PR_echo('Source directory: ' . getcwd())
242 call s:PR_echo('------------------')
243 let s:theFilterDiffCommand = '' . g:patchreview_filterdiff . ' --list -s ' . s:PatchFilePath
244 let s:theFilesString = system(s:theFilterDiffCommand)
245 let s:theFilesList = split(s:theFilesString, '[\r\n]')
246 for s:filewithchangetype in s:theFilesList
247 if s:filewithchangetype !~ '^[!+-] '
248 call s:PR_echo('*** Skipping review generation due to understood change for [' . s:filewithchangetype . ']', 1)
249 continue
250 endif
251 unlet! s:RelativeFilePath
252 let s:RelativeFilePath = substitute(s:filewithchangetype, '^. ', '', '')
253 let s:RelativeFilePath = substitute(s:RelativeFilePath, '^[a-z][^\\\/]*[\\\/]' , '' , '')
254 if s:filewithchangetype =~ '^! '
255 let s:msgtype = 'Modification : '
256 elseif s:filewithchangetype =~ '^+ '
257 let s:msgtype = 'Addition : '
258 elseif s:filewithchangetype =~ '^- '
259 let s:msgtype = 'Deletion : '
260 endif
261 let s:bufnum = bufnr(s:RelativeFilePath)
262 if buflisted(s:bufnum) && getbufvar(s:bufnum, '&mod')
263 call s:PR_echo('Old buffer for file [' . s:RelativeFilePath . '] exists in modified state. Skipping review.', 1)
264 continue
265 endif
266 let s:tmpname = substitute(s:RelativeFilePath, '/', '_', 'g')
267 let s:tmpname = substitute(s:tmpname, '\\', '_', 'g')
268 let s:tmpname = g:patchreview_tmpdir . 'PatchReview.' . s:tmpname . '.' . strftime('%Y%m%d%H%M%S')
269 if has('win32')
270 let s:tmpname = substitute(s:tmpname, '/', '\\', 'g')
271 endif
272 if ! exists('s:patchreview_tmpfiles')
273 let s:patchreview_tmpfiles = []
274 endif
275 let s:patchreview_tmpfiles = s:patchreview_tmpfiles + [s:tmpname]
276
277 let s:filterdiffcmd = '!' . g:patchreview_filterdiff . ' -i ' . s:RelativeFilePath . ' ' . s:PatchFilePath . ' > ' . s:tmpname
278 silent! exe s:filterdiffcmd
279 if s:filewithchangetype =~ '^+ '
280 if has('win32')
281 let s:inputfile = 'nul'
282 else
283 let s:inputfile = '/dev/null'
284 endif
285 else
286 let s:inputfile = expand(s:RelativeFilePath, ':p')
287 endif
288 silent exe '!' . g:patchreview_patch . ' -o ' . s:tmpname . '.file ' . s:inputfile . ' < ' . s:tmpname
289 let s:origtabpagenr = tabpagenr()
290 silent! exe 'tabedit ' . s:RelativeFilePath
291 silent! exe 'vert diffsplit ' . s:tmpname . '.file'
292 if filereadable(s:tmpname . '.file.rej')
293 silent! exe 'topleft 5split ' . s:tmpname . '.file.rej'
294 call s:PR_echo(s:msgtype . '*** REJECTED *** ' . s:RelativeFilePath, 1)
295 else
296 call s:PR_echo(s:msgtype . ' ' . s:RelativeFilePath, 1)
297 endif
298 silent! exe 'tabn ' . s:origtabpagenr
299 endfor
300 call s:PR_echo('-----')
301 call s:PR_echo('Done.')
302 let &shortmess = s:save_shortmess
303 "}}}
304 endfunction
305 "}}}
306
307 function! <SID>PatchReviewCleanup() "{{{
308 let s:retval = s:PR_GetTempDirLocation(1)
309 if s:retval && exists('g:patchreview_tmpdir') && isdirectory(g:patchreview_tmpdir) && filewritable(g:patchreview_tmpdir)
310 let s:zefilestr = globpath(g:patchreview_tmpdir, 'PatchReview.*')
311 let s:theFilesList = split(s:zefilestr, '\m[\r\n]\+')
312 for s:thefile in s:theFilesList
313 call delete(s:thefile)
314 endfor
315 endif
316 endfunction
317 "}}}
318
319 " Commands "{{{
320 "============================================================================
321 " :PatchReview
322 command! -nargs=* -complete=file PatchReview call s:PatchReview (<f-args>)
323
324
325 " :PatchReviewCleanup
326 command! -nargs=0 PatchReviewCleanup call s:PatchReviewCleanup ()
327 "}}}
328 "}}}
329
330 " vim: textwidth=78 nowrap tabstop=2 shiftwidth=2 softtabstop=2 expandtab
331 " vim: filetype=vim encoding=latin1 fileformat=unix foldlevel=0 foldmethod=marker
332 "}}}
General Comments 0
You need to be logged in to leave comments. Login now