##// END OF EJS Templates
Updated contrib/vim/patchreview.* to version 0.2.1...
Manpreet Singh -
r10545:b9e4a673 stable
parent child Browse files
Show More
@@ -1,30 +1,38 b''
1 *patchreview.txt* Vim global plugin for doing single or multipatch code reviews
1 *patchreview.txt* Vim global plugin for doing single, multi-patch or diff code reviews
2 Version v0.2.1 (for Vim version 7.0 or higher)
2
3
3 Author: Manpreet Singh (junkblocker-CAT-yahoo-DOG-com)
4 Author: Manpreet Singh < junkblocker@yahoo.com >
4 (Replace -CAT- and -DOG- with @ and . first)
5 Copyright (C) 2006-2010 by Manpreet Singh
5 Copyright (C) 2006 by Manpreet Singh
6 License : This file is placed in the public domain.
6 License : This file is placed in the public domain.
7
7
8 =============================================================================
8 =============================================================================
9
9
10 CONTENTS *patchreview* *patchreview-contents*
10 CONTENTS *patchreview* *diffreview* *patchreview-contents*
11
11
12 1. Contents.........................................: |patchreview-contents|
12 1. Contents.........................................: |patchreview-contents|
13 2. Introduction.....................................: |patchreview-intro|
13 2. Introduction.....................................: |patchreview-intro|
14 3. PatchReview options..............................: |patchreview-options|
14 3. PatchReview options..............................: |patchreview-options|
15 4. PatchReview Usage................................: |patchreview-usage|
15 4. PatchReview Usage................................: |patchreview-usage|
16 4.1 PatchReview Usage............................: |:PatchReview|
16 4.1 DiffReview Usage.............................: |:DiffReview|
17 4.2 PatchReview Usage............................: |:PatchReviewCleanup|
17 4.2 PatchReview Usage............................: |:PatchReview|
18 4.3 DiffReviewCleanup Usage......................: |:DiffReviewCleanup|
19 4.4 PatchReviewCleanup Usage.....................: |:PatchReviewCleanup|
18
20
19 =============================================================================
21 =============================================================================
20
22
21 PatchReview Introduction *patchreview-intro*
23 PatchReview Introduction *patchreview-intro*
22
24
23 The Patch Review plugin allows single or multipatch code review to be done in
25 The Patch Review plugin allows easy single or multipatch code or diff reviews.
24 VIM. VIM provides the |:diffpatch| command to do single file reviews but can
26
25 not handle patch files containing multiple patches as is common with software
27 It opens each affected file in the patch or in a workspace diff in a diff view
26 development projects. This plugin provides that missing functionality. It also
28 in a separate tab.
27 tries to improve on |:diffpatch|'s behaviour of creating the patched files in
29
30 VIM provides the |:diffpatch| and related commands to do single file reviews
31 but can not handle patch files containing multiple patches as is common with
32 software development projects. This plugin provides that missing
33 functionality.
34
35 It also improves on |:diffpatch|'s behaviour of creating the patched files in
28 the same directory as original file which can lead to project workspace
36 the same directory as original file which can lead to project workspace
29 pollution.
37 pollution.
30
38
@@ -32,66 +40,81 b' pollution.'
32
40
33 PatchReview Options *patchreview-options*
41 PatchReview Options *patchreview-options*
34
42
35 g:patchreview_filterdiff : Optional path to filterdiff binary. PatchReview
43 g:patchreview_tmpdir = {string}
36 tries to locate filterdiff on system path
44 Optional path where the plugin can save temporary files. If this is not
37 automatically. If the binary is not on system
45 specified, the plugin tries to use TMP, TEMP and TMPDIR environment
38 path, this option tell PatchReview the full path
46 variables in succession.
39 to the binary. This option, if specified,
47
40 overrides the default filterdiff binary on the
48 examples:
49 (On Windows) >
50 let g:patchreview_tmpdir = 'c:\\tmp'
51 <
52 (On *nix systems) >
53 let g:patchreview_tmpdir = '~/tmp'
54 <
55
56 g:patchreview_filterdiff = {string}
57 Optional path to filterdiff binary. PatchReview tries to locate
58 filterdiff on system path automatically. If the binary is not on system
59 path, this option tell PatchReview the full path to the binary. This
60 option, if specified, overrides the default filterdiff binary on the
41 path.
61 path.
42
62
43 examples:
63 examples:
44 (On Windows with Cygwin)
64 (On Windows with Cygwin)
45
65 >
46 let g:patchreview_filterdiff = 'c:\\cygwin\\bin\\filterdiff.exe'
66 let g:patchreview_filterdiff = 'c:\\cygwin\\bin\\filterdiff.exe'
47
67 <
48 (On *nix systems)
68 (On *nix systems)
49
69 >
50 let g:patchreview_filterdiff = '/usr/bin/filterdiff'
70 let g:patchreview_filterdiff = '/usr/bin/filterdiff'
51
71 <
52 g:patchreview_patch : Optional path to patch binary. PatchReview tries
72 g:patchreview_patch = {string}
53 to locate patch on system path automatically. If
73 Optional path to patch binary. PatchReview tries to locate patch on
54 the binary is not on system path, this option
74 system path automatically. If the binary is not on system path, this
55 tell PatchReview the full path to the binary.
75 option tell PatchReview the full path to the binary. This option, if
56 This option, if specified, overrides the default
76 specified, overrides the default patch binary on the path.
57 patch binary on the path.
58
77
59 examples:
78 examples:
60 (On Windows with Cygwin)
79 (On Windows with Cygwin) >
61
62 let g:patchreview_patch = 'c:\\cygwin\\bin\\patch.exe'
80 let g:patchreview_patch = 'c:\\cygwin\\bin\\patch.exe'
63
81 <
64 (On *nix systems)
82 (On *nix systems) >
65
66 let g:patchreview_patch = '/usr/bin/gpatch'
83 let g:patchreview_patch = '/usr/bin/gpatch'
67
84 <
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
85
78 =============================================================================
86 =============================================================================
79
87
80 PatchReview Usage *patchreview-usage*
88 PatchReview Usage *patchreview-usage*
89 *:DiffReview*
90
91 :DiffReview
92
93 Perform a diff review in the current directory under version control.
94 Currently supports Mercurial (hg), Subversion (svn), CVS, Bazaar (bzr) and
95 Monotone.
96
81 *:PatchReview*
97 *:PatchReview*
82
98
83 :PatchReview patchfile_path [optional_source_directory]
99 :PatchReview patchfile_path [optional_source_directory]
84
100
85 Perform a patch review in the current directory based on the supplied
101 Perform a patch review in the current directory based on the supplied
86 patchfile_path. If optional_source_directory is specified, patchreview is
102 patchfile_path. If optional_source_directory is specified, patchreview is
87 done on that directory. Othewise, the current directory is assumed to be
103 done on that directory. Otherwise, the current directory is assumed to be
88 the source directory.
104 the source directory.
105
106 Only supports context or unified format patches.
107
108 *:DiffReviewCleanup*
89 *:PatchReviewCleanup*
109 *:PatchReviewCleanup*
90
110
111 :DiffReviewCleanup
91 :PatchReviewCleanup
112 :PatchReviewCleanup
92
113
93 After you are done using the :PatchReview command, you can cleanup the
114 After you are done using the :DiffReview or :PatchReview command, you can
94 temporary files in the temporary directory using this command.
115 cleanup the temporary files in the temporary directory using either of
116 these commands.
95
117
96 =============================================================================
118 ------------------------------------------------------------------------------
97 vim: ft=help:ts=2:sts=2:sw=2:tw=78:tw=78
119
120 vim: ft=help:ts=2:sts=2:sw=2:tw=78:norl:
This diff has been collapsed as it changes many lines, (934 lines changed) Show them Hide them
@@ -1,113 +1,148 b''
1 " Vim global plugin for doing single or multipatch code reviews"{{{
1 " VIM plugin for doing single, multi-patch or diff code reviews {{{
2 " Home: http://www.vim.org/scripts/script.php?script_id=1563
2
3
3 " Version : 0.1 "{{{
4 " Version : 0.2.1 "{{{
4 " Last Modified : Thu 25 May 2006 10:15:11 PM PDT
5 " Author : Manpreet Singh < junkblocker@yahoo.com >
5 " Author : Manpreet Singh (junkblocker AT yahoo DOT com)
6 " Copyright : 2006-2010 by Manpreet Singh
6 " Copyright : 2006 by Manpreet Singh
7 " License : This file is placed in the public domain.
7 " License : This file is placed in the public domain.
8 " No warranties express or implied. Use at your own risk.
8 "
9 "
9 " History : 0.1 - First released
10 " Changelog :
11 "
12 " 0.2.1 - Minor temp directory autodetection logic and cleanup
13 "
14 " 0.2 - Removed the need for filterdiff by implemeting it in pure vim script
15 " - Added DiffReview command for reverse (changed repository to
16 " pristine state) reviews.
17 " (PatchReview does pristine repository to patch review)
18 " - DiffReview does automatic detection and generation of diffs for
19 " various Source Control systems
20 " - Skip load if VIM 7.0 or higher unavailable
21 "
22 " 0.1 - First released
10 "}}}
23 "}}}
24
11 " Documentation: "{{{
25 " Documentation: "{{{
12 " ===========================================================================
26 " ===========================================================================
13 " This plugin allows single or multipatch code reviews to be done in VIM. Vim
27 " This plugin allows single or multiple, patch or diff based code reviews to
14 " has :diffpatch command to do single file reviews but can not handle patch
28 " be easily done in VIM. VIM has :diffpatch command to do single file reviews
15 " files containing multiple patches. This plugin provides that missing
29 " but a) can not handle patch files containing multiple patches or b) do
16 " functionality and doesn't require the original file to be open.
30 " automated diff generation for various version control systems. This plugin
31 " attempts to provide those functionalities. It opens each changed / added or
32 " removed file diff in new tabs.
17 "
33 "
18 " Installing: "{{{
34 " Installing:
19 "
35 "
20 " For a quick start...
36 " For a quick start...
21 "
37 "
22 " Requirements: "{{{
38 " Requirements:
39 "
40 " 1) VIM 7.0 or higher built with +diff option.
41 "
42 " 2) A gnu compatible patch command installed. This is the standard patch
43 " command on Linux, Mac OS X, *BSD, Cygwin or /usr/bin/gpatch on newer
44 " Solaris.
23 "
45 "
24 " 1) (g)vim 7.0 or higher built with +diff option.
46 " 3) Optional (but recommended for speed)
25 " 2) patch and patchutils ( http://cyberelk.net/tim/patchutils/ ) installed
47 "
26 " for your OS. For windows it is availble from Cygwin (
48 " Install patchutils ( http://cyberelk.net/tim/patchutils/ ) for your
27 " http://www.cygwin.com ) or GnuWin32 ( http://gnuwin32.sourceforge.net/
49 " OS. For windows it is availble from Cygwin
28 " ).
50 "
29 ""}}}
51 " http://www.cygwin.com
30 " Install: "{{{
52 "
53 " or GnuWin32
31 "
54 "
32 " 1) Extract this in your $VIM/vimfiles or $HOME/.vim directory and restart
55 " http://gnuwin32.sourceforge.net/
33 " vim.
56 "
57 " Install:
34 "
58 "
35 " 2) Make sure that you have filterdiff from patchutils and patch commands
59 " 1) Extract the zip in your $HOME/.vim or $VIM/vimfiles directory and
36 " installed.
60 " restart vim. The directory location relevant to your platform can be
61 " seen by running :help add-global-plugin in vim.
37 "
62 "
38 " 3) Optinally, specify the locations to filterdiff and patch commands and
63 " 2) Restart vim.
39 " location of a temporary directory to use in your .vimrc.
64 "
65 " Configuration:
40 "
66 "
41 " let g:patchreview_filterdiff = '/path/to/filterdiff'
67 " Optionally, specify the locations to these filterdiff and patch commands
42 " let g:patchreview_patch = '/path/to/patch'
68 " and location of a temporary directory to use in your .vimrc.
69 "
70 " let g:patchreview_patch = '/path/to/gnu/patch'
43 " let g:patchreview_tmpdir = '/tmp/or/something'
71 " let g:patchreview_tmpdir = '/tmp/or/something'
44 "
72 "
45 " 4) Optionally, generate help tags to use help
73 " " If you are using filterdiff
74 " let g:patchreview_filterdiff = '/path/to/filterdiff'
46 "
75 "
47 " :helptags ~/.vim/doc
48 " or
49 " :helptags c:\vim\vimfiles\doc
50 ""}}}
51 ""}}}
52 " Usage: "{{{
53 "
76 "
54 " :PatchReview path_to_submitted_patchfile [optional_source_directory]
55 "
77 "
56 " after review is done
78 " Usage:
57 "
79 "
58 " :PatchReviewCleanup
80 " Please see :help patchreview or :help diffreview for details.
59 "
81 "
60 " See :help patchreview for details after you've created help tags.
61 ""}}}
82 ""}}}
62 "}}}
63 " Code "{{{
64
83
65 " Enabled only during development "{{{
84 " Enabled only during development
66 " unlet! g:loaded_patchreview " DEBUG
85 " unlet! g:loaded_patchreview " DEBUG
67 " unlet! g:patchreview_tmpdir " DEBUG
86 " unlet! g:patchreview_tmpdir " DEBUG
87 " unlet! g:patchreview_patch " DEBUG
68 " unlet! g:patchreview_filterdiff " DEBUG
88 " unlet! g:patchreview_filterdiff " DEBUG
69 " unlet! g:patchreview_patch " DEBUG
89 " let g:patchreview_patch = 'patch' " DEBUG
70 "}}}
71
90
72 " load only once "{{{
91 if v:version < 700
73 if exists('g:loaded_patchreview')
92 finish
93 endif
94 if ! has('diff')
95 call confirm('patchreview.vim plugin needs (G)VIM built with +diff support to work.')
74 finish
96 finish
75 endif
97 endif
76 let g:loaded_patchreview=1
98
77 let s:msgbufname = 'Patch Review Messages'
99 " load only once
100 if (! exists('g:patchreview_debug') && exists('g:loaded_patchreview')) || &compatible
101 finish
102 endif
103 let g:loaded_patchreview="0.2.1"
104
105 let s:msgbufname = '-PatchReviewMessages-'
106
107 function! <SID>Debug(str) "{{{
108 if exists('g:patchreview_debug')
109 Pecho 'DEBUG: ' . a:str
110 endif
111 endfunction
112 command! -nargs=+ -complete=expression Debug call s:Debug(<args>)
78 "}}}
113 "}}}
79
114
80 function! <SID>PR_wipeMsgBuf() "{{{
115 function! <SID>PR_wipeMsgBuf() "{{{
81 let s:winnum = bufwinnr(s:msgbufname)
116 let winnum = bufwinnr(s:msgbufname)
82 if s:winnum != -1 " If the window is already open, jump to it
117 if winnum != -1 " If the window is already open, jump to it
83 let s:cur_winnr = winnr()
118 let cur_winnr = winnr()
84 if winnr() != s:winnum
119 if winnr() != winnum
85 exe s:winnum . 'wincmd w'
120 exe winnum . 'wincmd w'
86 exe 'bw'
121 exe 'bw'
87 exe s:cur_winnr . 'wincmd w'
122 exe cur_winnr . 'wincmd w'
88 endif
123 endif
89 endif
124 endif
90 endfunction
125 endfunction
91 "}}}
126 "}}}
92
127
93 function! <SID>PR_echo(...) "{{{
128 function! <SID>Pecho(...) "{{{
94 " Usage: PR_echo(msg, [return_to_original_window_flag])
129 " Usage: Pecho(msg, [return_to_original_window_flag])
95 " default return_to_original_window_flag = 0
130 " default return_to_original_window_flag = 0
96 "
131 "
97 let s:cur_winnr = winnr()
132 let cur_winnr = winnr()
98 let s:winnum = bufwinnr(s:msgbufname)
133 let winnum = bufwinnr(s:msgbufname)
99 if s:winnum != -1 " If the window is already open, jump to it
134 if winnum != -1 " If the window is already open, jump to it
100 if winnr() != s:winnum
135 if winnr() != winnum
101 exe s:winnum . 'wincmd w'
136 exe winnum . 'wincmd w'
102 endif
137 endif
103 else
138 else
104 let s:bufnum = bufnr(s:msgbufname)
139 let bufnum = bufnr(s:msgbufname)
105 if s:bufnum == -1
140 if bufnum == -1
106 let s:wcmd = s:msgbufname
141 let wcmd = s:msgbufname
107 else
142 else
108 let s:wcmd = '+buffer' . s:bufnum
143 let wcmd = '+buffer' . bufnum
109 endif
144 endif
110 exe 'silent! botright 5split ' . s:wcmd
145 exe 'silent! botright 5split ' . wcmd
111 endif
146 endif
112 setlocal modifiable
147 setlocal modifiable
113 setlocal buftype=nofile
148 setlocal buftype=nofile
@@ -121,9 +156,11 b' function! <SID>PR_echo(...) '
121 exe ':$'
156 exe ':$'
122 setlocal nomodifiable
157 setlocal nomodifiable
123 if a:0 > 1 && a:2
158 if a:0 > 1 && a:2
124 exe s:cur_winnr . 'wincmd w'
159 exe cur_winnr . 'wincmd w'
125 endif
160 endif
126 endfunction
161 endfunction
162
163 command! -nargs=+ -complete=expression Pecho call s:Pecho(<args>)
127 "}}}
164 "}}}
128
165
129 function! <SID>PR_checkBinary(BinaryName) "{{{
166 function! <SID>PR_checkBinary(BinaryName) "{{{
@@ -133,11 +170,12 b' function! <SID>PR_checkBinary(BinaryName'
133 let g:patchreview_{a:BinaryName} = a:BinaryName
170 let g:patchreview_{a:BinaryName} = a:BinaryName
134 return 1
171 return 1
135 else
172 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.')
173 Pecho 'g:patchreview_' . a:BinaryName . ' is not defined and ' . a:BinaryName . ' command could not be found on path.'
174 Pecho 'Please define it in your .vimrc.'
137 return 0
175 return 0
138 endif
176 endif
139 elseif ! executable(g:patchreview_{a:BinaryName})
177 elseif ! executable(g:patchreview_{a:BinaryName})
140 call s:PR_echo('Specified g:patchreview_' . a:BinaryName . ' [' . g:patchreview_{a.BinaryName} . '] is not executable.')
178 Pecho 'Specified g:patchreview_' . a:BinaryName . ' [' . g:patchreview_{a:BinaryName} . '] is not executable.'
141 return 0
179 return 0
142 else
180 else
143 return 1
181 return 1
@@ -149,7 +187,7 b' function! <SID>PR_GetTempDirLocation(Qui'
149 if exists('g:patchreview_tmpdir')
187 if exists('g:patchreview_tmpdir')
150 if ! isdirectory(g:patchreview_tmpdir) || ! filewritable(g:patchreview_tmpdir)
188 if ! isdirectory(g:patchreview_tmpdir) || ! filewritable(g:patchreview_tmpdir)
151 if ! a:Quiet
189 if ! a:Quiet
152 call s:PR_echo('Temporary directory specified by g:patchreview_tmpdir [' . g:patchreview_tmpdir . '] is not accessible.')
190 Pecho 'Temporary directory specified by g:patchreview_tmpdir [' . g:patchreview_tmpdir . '] is not accessible.'
153 return 0
191 return 0
154 endif
192 endif
155 endif
193 endif
@@ -160,14 +198,34 b' function! <SID>PR_GetTempDirLocation(Qui'
160 elseif exists("$TMPDIR") && isdirectory($TMPDIR) && filewritable($TMPDIR)
198 elseif exists("$TMPDIR") && isdirectory($TMPDIR) && filewritable($TMPDIR)
161 let g:patchreview_tmpdir = $TMPDIR
199 let g:patchreview_tmpdir = $TMPDIR
162 else
200 else
201 if has("unix")
202 if isdirectory("/tmp")
203 let g:patchreview_tmpdir = "/tmp"
204 elseif isdirectory(expand("~/tmp"))
205 let g:patchreview_tmpdir = expand("~/tmp")
206 endif
207 elseif has("win32")
208 if isdirectory('c:\\tmp')
209 let g:patchreview_tmpdir = 'c:\\tmp'
210 elseif isdirectory('c:\\temp')
211 let g:patchreview_tmpdir = 'c:\\temp'
212 elseif isdirectory('c:\\windows\\temp')
213 let g:patchreview_tmpdir = 'c:\\windows\\temp'
214 elseif isdirectory($USERPROFILE . '\Local Settings\Temp') # NOTE : No \ issue here
215 let g:patchreview_tmpdir = $USERPROFILE . '\Local Settings\Temp'
216 endif
217 endif
218 if !exists('g:patchreview_tmpdir')
163 if ! a:Quiet
219 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.')
220 Pecho 'Could not figure out a temporary directory to use. Please specify g:patchreview_tmpdir in your .vimrc.'
221 endif
165 return 0
222 return 0
166 endif
223 endif
167 endif
224 endif
225 let g:patchreview_tmpdir = expand(g:patchreview_tmpdir, ':p')
168 let g:patchreview_tmpdir = g:patchreview_tmpdir . '/'
226 let g:patchreview_tmpdir = g:patchreview_tmpdir . '/'
169 let g:patchreview_tmpdir = substitute(g:patchreview_tmpdir, '\\', '/', 'g')
227 let g:patchreview_tmpdir = substitute(g:patchreview_tmpdir, '\\', '/', 'g')
170 let g:patchreview_tmpdir = substitute(g:patchreview_tmpdir, '/+$', '/', '')
228 let g:patchreview_tmpdir = substitute(g:patchreview_tmpdir, '/\+$', '/', '')
171 if has('win32')
229 if has('win32')
172 let g:patchreview_tmpdir = substitute(g:patchreview_tmpdir, '/', '\\', 'g')
230 let g:patchreview_tmpdir = substitute(g:patchreview_tmpdir, '/', '\\', 'g')
173 endif
231 endif
@@ -175,158 +233,694 b' function! <SID>PR_GetTempDirLocation(Qui'
175 endfunction
233 endfunction
176 "}}}
234 "}}}
177
235
178 function! <SID>PatchReview(...) "{{{
236 function! <SID>ExtractDiffsNative(...) "{{{
179 " VIM 7+ required"{{{
237 " Sets g:patches = {'reason':'', 'patch':[
180 if version < 700
238 " {
181 call s:PR_echo('This plugin needs VIM 7 or higher')
239 " 'filename': filepath
240 " 'type' : '+' | '-' | '!'
241 " 'content' : patch text for this file
242 " },
243 " ...
244 " ]}
245 let g:patches = {'reason' : '', 'patch' : []}
246 " TODO : User pointers into lines list rather then use collect
247 if a:0 == 0
248 let g:patches['reason'] = "ExtractDiffsNative expects at least a patchfile argument"
249 return
250 endif
251 let patchfile = expand(a:1, ':p')
252 if a:0 > 1
253 let patch = a:2
254 endif
255 if ! filereadable(patchfile)
256 let g:patches['reason'] = "File " . patchfile . " is not readable"
182 return
257 return
183 endif
258 endif
259 unlet! filterdiffcmd
260 let filterdiffcmd = '' . g:patchreview_filterdiff . ' --list -s ' . patchfile
261 let fileslist = split(system(filterdiffcmd), '[\r\n]')
262 for filewithchangetype in fileslist
263 if filewithchangetype !~ '^[!+-] '
264 Pecho '*** Skipping review generation due to unknown change for [' . filewithchangetype . ']'
265 continue
266 endif
267
268 unlet! this_patch
269 let this_patch = {}
270
271 unlet! relpath
272 let relpath = substitute(filewithchangetype, '^. ', '', '')
273
274 let this_patch['filename'] = relpath
275
276 if filewithchangetype =~ '^! '
277 let this_patch['type'] = '!'
278 elseif filewithchangetype =~ '^+ '
279 let this_patch['type'] = '+'
280 elseif filewithchangetype =~ '^- '
281 let this_patch['type'] = '-'
282 endif
283
284 unlet! filterdiffcmd
285 let filterdiffcmd = '' . g:patchreview_filterdiff . ' -i ' . relpath . ' ' . patchfile
286 let this_patch['content'] = split(system(filterdiffcmd), '[\n\r]')
287 let g:patches['patch'] += [this_patch]
288 Debug "Patch collected for " . relpath
289 endfor
290 endfunction
184 "}}}
291 "}}}
185
292
186 let s:save_shortmess = &shortmess
293 function! <SID>ExtractDiffsPureVim(...) "{{{
187 set shortmess+=aW
294 " Sets g:patches = {'reason':'', 'patch':[
188 call s:PR_wipeMsgBuf()
295 " {
189
296 " 'filename': filepath
190 " Check passed arguments "{{{
297 " 'type' : '+' | '-' | '!'
298 " 'content' : patch text for this file
299 " },
300 " ...
301 " ]}
302 let g:patches = {'reason' : '', 'patch' : []}
303 " TODO : User pointers into lines list rather then use collect
191 if a:0 == 0
304 if a:0 == 0
192 call s:PR_echo('PatchReview command needs at least one argument specifying a patchfile path.')
305 let g:patches['reason'] = "ExtractDiffsPureVim expects at least a patchfile argument"
193 let &shortmess = s:save_shortmess
306 return
307 endif
308 let patchfile = expand(a:1, ':p')
309 if a:0 > 1
310 let patch = a:2
311 endif
312 if ! filereadable(patchfile)
313 let g:patches['reason'] = "File " . patchfile . " is not readable"
194 return
314 return
195 endif
315 endif
196 if a:0 >= 1 && a:0 <= 2
316 call s:PR_wipeMsgBuf()
197 let s:PatchFilePath = expand(a:1, ':p')
317 let collect = []
198 if ! filereadable(s:PatchFilePath)
318 let linum = 0
199 call s:PR_echo('File [' . s:PatchFilePath . '] is not accessible.')
319 let lines = readfile(patchfile)
200 let &shortmess = s:save_shortmess
320 let linescount = len(lines)
321 State 'START'
322 while linum < linescount
323 let line = lines[linum]
324 let linum += 1
325 if State() == 'START'
326 let mat = matchlist(line, '^--- \([^\t]\+\).*$')
327 if ! empty(mat) && mat[1] != ''
328 State 'MAYBE_UNIFIED_DIFF'
329 let p_first_file = mat[1]
330 let collect = [line]
331 Debug line . State()
332 continue
333 endif
334 let mat = matchlist(line, '^\*\*\* \([^\t]\+\).*$')
335 if ! empty(mat) && mat[1] != ''
336 State 'MAYBE_CONTEXT_DIFF'
337 let p_first_file = mat[1]
338 let collect = [line]
339 Debug line . State()
340 continue
341 endif
342 continue
343 elseif State() == 'MAYBE_CONTEXT_DIFF'
344 let mat = matchlist(line, '^--- \([^\t]\+\).*$')
345 if empty(mat) || mat[1] == ''
346 State 'START'
347 let linum -= 1
348 continue
349 Debug 'Back to square one ' . line()
350 endif
351 let p_second_file = mat[1]
352 if p_first_file == '/dev/null'
353 if p_second_file == '/dev/null'
354 let g:patches['reason'] = "Malformed diff found at line " . linum
201 return
355 return
202 endif
356 endif
203 if a:0 == 2
357 let p_type = '+'
204 let s:SrcDirectory = expand(a:2, ':p')
358 let filepath = p_second_file
205 if ! isdirectory(s:SrcDirectory)
359 else
206 call s:PR_echo('[' . s:SrcDirectory . '] is not a directory')
360 if p_second_file == '/dev/null'
207 let &shortmess = s:save_shortmess
361 let p_type = '-'
362 let filepath = p_first_file
363 else
364 let p_type = '!'
365 let filepath = p_first_file
366 endif
367 endif
368 State 'EXPECT_15_STARS'
369 let collect += [line]
370 Debug line . State()
371 elseif State() == 'EXPECT_15_STARS'
372 if line !~ '^*\{15}$'
373 State 'START'
374 let linum -= 1
375 Debug line . State()
376 continue
377 endif
378 State 'EXPECT_CONTEXT_CHUNK_HEADER_1'
379 let collect += [line]
380 Debug line . State()
381 elseif State() == 'EXPECT_CONTEXT_CHUNK_HEADER_1'
382 let mat = matchlist(line, '^\*\*\* \(\d\+,\)\?\(\d\+\) \*\*\*\*$')
383 if empty(mat) || mat[1] == ''
384 State 'START'
385 let linum -= 1
386 Debug line . State()
387 continue
388 endif
389 let collect += [line]
390 State 'SKIP_CONTEXT_STUFF_1'
391 Debug line . State()
392 continue
393 elseif State() == 'SKIP_CONTEXT_STUFF_1'
394 if line !~ '^[ !+].*$'
395 let mat = matchlist(line, '^--- \(\d\+\),\(\d\+\) ----$')
396 if ! empty(mat) && mat[1] != '' && mat[2] != ''
397 let goal_count = mat[2] - mat[1] + 1
398 let c_count = 0
399 State 'READ_CONTEXT_CHUNK'
400 let collect += [line]
401 Debug line . State() . " Goal count set to " . goal_count
402 continue
403 endif
404 State 'START'
405 let linum -= 1
406 Debug line . State()
407 continue
408 endif
409 let collect += [line]
410 continue
411 elseif State() == 'READ_CONTEXT_CHUNK'
412 let c_count += 1
413 if c_count == goal_count
414 let collect += [line]
415 State 'BACKSLASH_OR_CRANGE_EOF'
416 continue
417 else " goal not met yet
418 let mat = matchlist(line, '^\([\\!+ ]\).*$')
419 if empty(mat) || mat[1] == ''
420 let linum -= 1
421 State 'START'
422 Debug line . State()
423 continue
424 endif
425 let collect += [line]
426 continue
427 endif
428 elseif State() == 'BACKSLASH_OR_CRANGE_EOF'
429 if line =~ '^\\ No newline.*$' " XXX: Can we go to another chunk from here??
430 let collect += [line]
431 let this_patch = {}
432 let this_patch['filename'] = filepath
433 let this_patch['type'] = p_type
434 let this_patch['content'] = collect
435 let g:patches['patch'] += [this_patch]
436 Debug "Patch collected for " . filepath
437 State 'START'
438 continue
439 endif
440 if line =~ '^\*\{15}$'
441 let collect += [line]
442 State 'EXPECT_CONTEXT_CHUNK_HEADER_1'
443 Debug line . State()
444 continue
445 endif
446 let this_patch = {}
447 let this_patch['filename'] = filepath
448 let this_patch['type'] = p_type
449 let this_patch['content'] = collect
450 let g:patches['patch'] += [this_patch]
451 let linum -= 1
452 State 'START'
453 Debug "Patch collected for " . filepath
454 Debug line . State()
455 continue
456 elseif State() == 'MAYBE_UNIFIED_DIFF'
457 let mat = matchlist(line, '^+++ \([^\t]\+\).*$')
458 if empty(mat) || mat[1] == ''
459 State 'START'
460 let linum -= 1
461 Debug line . State()
462 continue
463 endif
464 let p_second_file = mat[1]
465 if p_first_file == '/dev/null'
466 if p_second_file == '/dev/null'
467 let g:patches['reason'] = "Malformed diff found at line " . linum
208 return
468 return
209 endif
469 endif
210 try
470 let p_type = '+'
211 exe 'cd ' . s:SrcDirectory
471 let filepath = p_second_file
212 catch /^.*E344.*/
472 else
213 call s:PR_echo('Could not change to directory [' . s:SrcDirectory . ']')
473 if p_second_file == '/dev/null'
214 let &shortmess = s:save_shortmess
474 let p_type = '-'
215 return
475 let filepath = p_first_file
216 endtry
476 else
477 let p_type = '!'
478 let filepath = p_first_file
479 endif
480 endif
481 State 'EXPECT_UNIFIED_RANGE_CHUNK'
482 let collect += [line]
483 Debug line . State()
484 continue
485 elseif State() == 'EXPECT_UNIFIED_RANGE_CHUNK'
486 let mat = matchlist(line, '^@@ -\(\d\+,\)\?\(\d\+\) +\(\d\+,\)\?\(\d\+\) @@$')
487 if ! empty(mat)
488 let old_goal_count = mat[2]
489 let new_goal_count = mat[4]
490 let o_count = 0
491 let n_count = 0
492 Debug "Goal count set to " . old_goal_count . ', ' . new_goal_count
493 State 'READ_UNIFIED_CHUNK'
494 let collect += [line]
495 Debug line . State()
496 continue
497 endif
498 State 'START'
499 Debug line . State()
500 continue
501 elseif State() == 'READ_UNIFIED_CHUNK'
502 if o_count == old_goal_count && n_count == new_goal_count
503 if line =~ '^\\.*$' " XXX: Can we go to another chunk from here??
504 let collect += [line]
505 let this_patch = {}
506 let this_patch['filename'] = filepath
507 let this_patch['type'] = p_type
508 let this_patch['content'] = collect
509 let g:patches['patch'] += [this_patch]
510 Debug "Patch collected for " . filepath
511 State 'START'
512 continue
513 endif
514 let mat = matchlist(line, '^@@ -\(\d\+,\)\?\(\d\+\) +\(\d\+,\)\?\(\d\+\) @@$')
515 if ! empty(mat)
516 let old_goal_count = mat[2]
517 let new_goal_count = mat[4]
518 let o_count = 0
519 let n_count = 0
520 Debug "Goal count set to " . old_goal_count . ', ' . new_goal_count
521 let collect += [line]
522 Debug line . State()
523 continue
524 endif
525 let this_patch = {}
526 let this_patch['filename'] = filepath
527 let this_patch['type'] = p_type
528 let this_patch['content'] = collect
529 let g:patches['patch'] += [this_patch]
530 Debug "Patch collected for " . filepath
531 let linum -= 1
532 State 'START'
533 Debug line . State()
534 continue
535 else " goal not met yet
536 let mat = matchlist(line, '^\([\\+ -]\).*$')
537 if empty(mat) || mat[1] == ''
538 let linum -= 1
539 State 'START'
540 continue
541 endif
542 let chr = mat[1]
543 if chr == '+'
544 let n_count += 1
545 endif
546 if chr == ' '
547 let o_count += 1
548 let n_count += 1
549 endif
550 if chr == '-'
551 let o_count += 1
552 endif
553 let collect += [line]
554 Debug line . State()
555 continue
217 endif
556 endif
218 else
557 else
219 call s:PR_echo('PatchReview command needs at most two arguments: patchfile path and optional source directory path.')
558 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>"
220 let &shortmess = s:save_shortmess
221 return
559 return
222 endif
560 endif
561 endwhile
562 "Pecho State()
563 if (State() == 'READ_CONTEXT_CHUNK' && c_count == goal_count) || (State() == 'READ_UNIFIED_CHUNK' && n_count == new_goal_count && o_count == old_goal_count)
564 let this_patch = {}
565 let this_patch['filename'] = filepath
566 let this_patch['type'] = p_type
567 let this_patch['content'] = collect
568 let g:patches['patch'] += [this_patch]
569 Debug "Patch collected for " . filepath
570 endif
571 return
572 endfunction
573 "}}}
574
575 function! State(...) " For easy manipulation of diff extraction state "{{{
576 if a:0 != 0
577 let s:STATE = a:1
578 else
579 if ! exists('s:STATE')
580 let s:STATE = 'START'
581 endif
582 return s:STATE
583 endif
584 endfunction
585 com! -nargs=+ -complete=expression State call State(<args>)
223 "}}}
586 "}}}
224
587
225 " Verify that filterdiff and patch are specified or available "{{{
588 function! <SID>PatchReview(...) "{{{
226 if ! s:PR_checkBinary('filterdiff') || ! s:PR_checkBinary('patch')
589 let s:save_shortmess = &shortmess
590 let s:save_aw = &autowrite
591 let s:save_awa = &autowriteall
592 set shortmess=aW
593 call s:PR_wipeMsgBuf()
594 let s:reviewmode = 'patch'
595 call s:_GenericReview(a:000)
596 let &autowriteall = s:save_awa
597 let &autowrite = s:save_aw
227 let &shortmess = s:save_shortmess
598 let &shortmess = s:save_shortmess
599 endfunction
600 "}}}
601
602 function! <SID>_GenericReview(argslist) "{{{
603 " diff mode:
604 " arg1 = patchfile
605 " arg2 = strip count
606 " patch mode:
607 " arg1 = patchfile
608 " arg2 = strip count
609 " arg3 = directory
610
611 " VIM 7+ required
612 if version < 700
613 Pecho 'This plugin needs VIM 7 or higher'
228 return
614 return
229 endif
615 endif
230
616
231 let s:retval = s:PR_GetTempDirLocation(0)
617 " +diff required
232 if ! s:retval
618 if ! has('diff')
233 let &shortmess = s:save_shortmess
619 Pecho 'This plugin needs VIM built with +diff feature.'
620 return
621 endif
622
623
624 if s:reviewmode == 'diff'
625 let patch_R_option = ' -t -R '
626 elseif s:reviewmode == 'patch'
627 let patch_R_option = ''
628 else
629 Pecho 'Fatal internal error in patchreview.vim plugin'
630 return
631 endif
632
633 " Check passed arguments
634 if len(a:argslist) == 0
635 Pecho 'PatchReview command needs at least one argument specifying a patchfile path.'
636 return
637 endif
638 let StripCount = 0
639 if len(a:argslist) >= 1 && ((s:reviewmode == 'patch' && len(a:argslist) <= 3) || (s:reviewmode == 'diff' && len(a:argslist) == 2))
640 let PatchFilePath = expand(a:argslist[0], ':p')
641 if ! filereadable(PatchFilePath)
642 Pecho 'File [' . PatchFilePath . '] is not accessible.'
643 return
644 endif
645 if len(a:argslist) >= 2 && s:reviewmode == 'patch'
646 let s:SrcDirectory = expand(a:argslist[1], ':p')
647 if ! isdirectory(s:SrcDirectory)
648 Pecho '[' . s:SrcDirectory . '] is not a directory'
234 return
649 return
235 endif
650 endif
236 "}}}
651 try
652 " Command line has already escaped the path
653 exe 'cd ' . s:SrcDirectory
654 catch /^.*E344.*/
655 Pecho 'Could not change to directory [' . s:SrcDirectory . ']'
656 return
657 endtry
658 endif
659 if s:reviewmode == 'diff'
660 " passed in by default
661 let StripCount = eval(a:argslist[1])
662 elseif s:reviewmode == 'patch'
663 let StripCount = 1
664 " optional strip count
665 if len(a:argslist) == 3
666 let StripCount = eval(a:argslist[2])
667 endif
668 endif
669 else
670 if s:reviewmode == 'patch'
671 Pecho 'PatchReview command needs at most three arguments: patchfile path, optional source directory path and optional strip count.'
672 elseif s:reviewmode == 'diff'
673 Pecho 'DiffReview command accepts no arguments.'
674 endif
675 return
676 endif
237
677
238 " Requirements met, now execute "{{{
678 " Verify that patch command and temporary directory are available or specified
239 let s:PatchFilePath = fnamemodify(s:PatchFilePath, ':p')
679 if ! s:PR_checkBinary('patch')
240 call s:PR_echo('Patch file : ' . s:PatchFilePath)
680 return
241 call s:PR_echo('Source directory: ' . getcwd())
681 endif
242 call s:PR_echo('------------------')
682
243 let s:theFilterDiffCommand = '' . g:patchreview_filterdiff . ' --list -s ' . s:PatchFilePath
683 let retval = s:PR_GetTempDirLocation(0)
244 let s:theFilesString = system(s:theFilterDiffCommand)
684 if ! retval
245 let s:theFilesList = split(s:theFilesString, '[\r\n]')
685 return
246 for s:filewithchangetype in s:theFilesList
686 endif
247 if s:filewithchangetype !~ '^[!+-] '
687
248 call s:PR_echo('*** Skipping review generation due to understood change for [' . s:filewithchangetype . ']', 1)
688 " Requirements met, now execute
689 let PatchFilePath = fnamemodify(PatchFilePath, ':p')
690 if s:reviewmode == 'patch'
691 Pecho 'Patch file : ' . PatchFilePath
692 endif
693 Pecho 'Source directory: ' . getcwd()
694 Pecho '------------------'
695 if s:PR_checkBinary('filterdiff')
696 Debug "Using filterdiff"
697 call s:ExtractDiffsNative(PatchFilePath)
698 else
699 Debug "Using own diff extraction (slower)"
700 call s:ExtractDiffsPureVim(PatchFilePath)
701 endif
702 for patch in g:patches['patch']
703 if patch.type !~ '^[!+-]$'
704 Pecho '*** Skipping review generation due to unknown change [' . patch.type . ']', 1
249 continue
705 continue
250 endif
706 endif
251 unlet! s:RelativeFilePath
707 unlet! relpath
252 let s:RelativeFilePath = substitute(s:filewithchangetype, '^. ', '', '')
708 let relpath = patch.filename
253 let s:RelativeFilePath = substitute(s:RelativeFilePath, '^[a-z][^\\\/]*[\\\/]' , '' , '')
709 " XXX: svn diff and hg diff produce different kind of outputs, one requires
254 if s:filewithchangetype =~ '^! '
710 " XXX: stripping but the other doesn't. We need to take care of that
255 let s:msgtype = 'Modification : '
711 let stripmore = StripCount
256 elseif s:filewithchangetype =~ '^+ '
712 let StrippedRelativeFilePath = relpath
257 let s:msgtype = 'Addition : '
713 while stripmore > 0
258 elseif s:filewithchangetype =~ '^- '
714 " strip one
259 let s:msgtype = 'Deletion : '
715 let StrippedRelativeFilePath = substitute(StrippedRelativeFilePath, '^[^\\\/]\+[^\\\/]*[\\\/]' , '' , '')
716 let stripmore -= 1
717 endwhile
718 if patch.type == '!'
719 if s:reviewmode == 'patch'
720 let msgtype = 'Patch modifies file: '
721 elseif s:reviewmode == 'diff'
722 let msgtype = 'File has changes: '
260 endif
723 endif
261 let s:bufnum = bufnr(s:RelativeFilePath)
724 elseif patch.type == '+'
262 if buflisted(s:bufnum) && getbufvar(s:bufnum, '&mod')
725 if s:reviewmode == 'patch'
263 call s:PR_echo('Old buffer for file [' . s:RelativeFilePath . '] exists in modified state. Skipping review.', 1)
726 let msgtype = 'Patch adds file : '
727 elseif s:reviewmode == 'diff'
728 let msgtype = 'New file : '
729 endif
730 elseif patch.type == '-'
731 if s:reviewmode == 'patch'
732 let msgtype = 'Patch removes file : '
733 elseif s:reviewmode == 'diff'
734 let msgtype = 'Removed file : '
735 endif
736 endif
737 let bufnum = bufnr(relpath)
738 if buflisted(bufnum) && getbufvar(bufnum, '&mod')
739 Pecho 'Old buffer for file [' . relpath . '] exists in modified state. Skipping review.', 1
264 continue
740 continue
265 endif
741 endif
266 let s:tmpname = substitute(s:RelativeFilePath, '/', '_', 'g')
742 let tmpname = substitute(relpath, '/', '_', 'g')
267 let s:tmpname = substitute(s:tmpname, '\\', '_', 'g')
743 let tmpname = substitute(tmpname, '\\', '_', 'g')
268 let s:tmpname = g:patchreview_tmpdir . 'PatchReview.' . s:tmpname . '.' . strftime('%Y%m%d%H%M%S')
744 let tmpname = g:patchreview_tmpdir . 'PatchReview.' . 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')
745 if has('win32')
281 let s:inputfile = 'nul'
746 let tmpname = substitute(tmpname, '/', '\\', 'g')
747 endif
748
749 " write patch for patch.filename into tmpname
750 call writefile(patch.content, tmpname)
751 if patch.type == '+' && s:reviewmode == 'patch'
752 let inputfile = ''
753 let patchcmd = '!' . g:patchreview_patch . patch_R_option . ' -o "' . tmpname . '.file" "' . inputfile . '" < "' . tmpname . '"'
754 elseif patch.type == '+' && s:reviewmode == 'diff'
755 let inputfile = ''
756 unlet! patchcmd
282 else
757 else
283 let s:inputfile = '/dev/null'
758 let inputfile = expand(StrippedRelativeFilePath, ':p')
284 endif
759 let patchcmd = '!' . g:patchreview_patch . patch_R_option . ' -o "' . tmpname . '.file" "' . inputfile . '" < "' . tmpname . '"'
285 else
286 let s:inputfile = expand(s:RelativeFilePath, ':p')
287 endif
760 endif
288 silent exe '!' . g:patchreview_patch . ' -o ' . s:tmpname . '.file ' . s:inputfile . ' < ' . s:tmpname
761 if exists('patchcmd')
762 let v:errmsg = ''
763 Debug patchcmd
764 silent exe patchcmd
765 if v:errmsg != '' || v:shell_error
766 Pecho 'ERROR: Could not execute patch command.'
767 Pecho 'ERROR: ' . patchcmd
768 Pecho 'ERROR: ' . v:errmsg
769 Pecho 'ERROR: Diff skipped.'
770 continue
771 endif
772 endif
289 let s:origtabpagenr = tabpagenr()
773 let s:origtabpagenr = tabpagenr()
290 silent! exe 'tabedit ' . s:RelativeFilePath
774 silent! exe 'tabedit ' . StrippedRelativeFilePath
291 silent! exe 'vert diffsplit ' . s:tmpname . '.file'
775 if exists('patchcmd')
292 if filereadable(s:tmpname . '.file.rej')
776 silent! exe 'vert diffsplit ' . tmpname . '.file'
293 silent! exe 'topleft 5split ' . s:tmpname . '.file.rej'
294 call s:PR_echo(s:msgtype . '*** REJECTED *** ' . s:RelativeFilePath, 1)
295 else
777 else
296 call s:PR_echo(s:msgtype . ' ' . s:RelativeFilePath, 1)
778 silent! exe 'vnew'
779 endif
780 if filereadable(tmpname . '.file.rej')
781 silent! exe 'topleft 5split ' . tmpname . '.file.rej'
782 Pecho msgtype . '*** REJECTED *** ' . relpath, 1
783 else
784 Pecho msgtype . ' ' . relpath, 1
297 endif
785 endif
298 silent! exe 'tabn ' . s:origtabpagenr
786 silent! exe 'tabn ' . s:origtabpagenr
299 endfor
787 endfor
300 call s:PR_echo('-----')
788 Pecho '-----'
301 call s:PR_echo('Done.')
789 Pecho 'Done.'
302 let &shortmess = s:save_shortmess
790
303 "}}}
304 endfunction
791 endfunction
305 "}}}
792 "}}}
306
793
307 function! <SID>PatchReviewCleanup() "{{{
794 function! <SID>PatchReviewCleanup() "{{{
308 let s:retval = s:PR_GetTempDirLocation(1)
795 let retval = s:PR_GetTempDirLocation(1)
309 if s:retval && exists('g:patchreview_tmpdir') && isdirectory(g:patchreview_tmpdir) && filewritable(g:patchreview_tmpdir)
796 if retval && exists('g:patchreview_tmpdir') && isdirectory(g:patchreview_tmpdir) && filewritable(g:patchreview_tmpdir)
310 let s:zefilestr = globpath(g:patchreview_tmpdir, 'PatchReview.*')
797 let zefilestr = globpath(g:patchreview_tmpdir, 'PatchReview.*')
311 let s:theFilesList = split(s:zefilestr, '\m[\r\n]\+')
798 let fileslist = split(zefilestr, '\m[\r\n]\+')
312 for s:thefile in s:theFilesList
799 for thefile in fileslist
313 call delete(s:thefile)
800 call delete(thefile)
314 endfor
801 endfor
315 endif
802 endif
316 endfunction
803 endfunction
317 "}}}
804 "}}}
318
805
319 " Commands "{{{
806 function! <SID>DiffReview(...) "{{{
807 let s:save_shortmess = &shortmess
808 set shortmess=aW
809 call s:PR_wipeMsgBuf()
810
811 let vcsdict = {
812 \'Mercurial' : {'dir' : '.hg', 'binary' : 'hg', 'diffargs' : 'diff' , 'strip' : 1},
813 \'Bazaar-NG' : {'dir' : '.bzr', 'binary' : 'bzr', 'diffargs' : 'diff' , 'strip' : 0},
814 \'monotone' : {'dir' : '_MTN', 'binary' : 'mtn', 'diffargs' : 'diff --unified', 'strip' : 0},
815 \'Subversion' : {'dir' : '.svn', 'binary' : 'svn', 'diffargs' : 'diff' , 'strip' : 0},
816 \'cvs' : {'dir' : 'CVS', 'binary' : 'cvs', 'diffargs' : '-q diff -u' , 'strip' : 0},
817 \}
818
819 unlet! s:theDiffCmd
820 unlet! l:vcs
821 if ! exists('g:patchreview_diffcmd')
822 for key in keys(vcsdict)
823 if isdirectory(vcsdict[key]['dir'])
824 if ! s:PR_checkBinary(vcsdict[key]['binary'])
825 Pecho 'Current directory looks like a ' . vcsdict[key] . ' repository but ' . vcsdist[key]['binary'] . ' command was not found on path.'
826 let &shortmess = s:save_shortmess
827 return
828 else
829 let s:theDiffCmd = vcsdict[key]['binary'] . ' ' . vcsdict[key]['diffargs']
830 let strip = vcsdict[key]['strip']
831
832 Pecho 'Using [' . s:theDiffCmd . '] to generate diffs for this ' . key . ' review.'
833 let &shortmess = s:save_shortmess
834 let l:vcs = vcsdict[key]['binary']
835 break
836 endif
837 else
838 continue
839 endif
840 endfor
841 else
842 let s:theDiffCmd = g:patchreview_diffcmd
843 let strip = 0
844 endif
845 if ! exists('s:theDiffCmd')
846 Pecho 'Please define g:patchreview_diffcmd and make sure you are in a VCS controlled top directory.'
847 let &shortmess = s:save_shortmess
848 return
849 endif
850
851 let retval = s:PR_GetTempDirLocation(0)
852 if ! retval
853 Pecho 'DiffReview aborted.'
854 let &shortmess = s:save_shortmess
855 return
856 endif
857 let outfile = g:patchreview_tmpdir . 'PatchReview.diff.' . strftime('%Y%m%d%H%M%S')
858 let cmd = '!' . s:theDiffCmd . ' > "' . outfile . '"'
859 let v:errmsg = ''
860 silent exe cmd
861 if v:errmsg == '' && exists('l:vcs') && l:vcs == 'cvs' && v:shell_error == 1
862 " Ignoring CVS non-error
863 elseif v:errmsg != '' || v:shell_error
864 Pecho 'Could not execute [' . s:theDiffCmd . ']'
865 Pecho v:errmsg
866 Pecho 'Diff review aborted.'
867 let &shortmess = s:save_shortmess
868 return
869 endif
870 let s:reviewmode = 'diff'
871 call s:_GenericReview([outfile, strip])
872 let &shortmess = s:save_shortmess
873 endfunction
874 "}}}
875
876 " End user commands "{{{
320 "============================================================================
877 "============================================================================
321 " :PatchReview
878 " :PatchReview
322 command! -nargs=* -complete=file PatchReview call s:PatchReview (<f-args>)
879 command! -nargs=* -complete=file PatchReview call s:PatchReview (<f-args>)
323
880
881 " :DiffReview
882 command! -nargs=0 DiffReview call s:DiffReview()
324
883
325 " :PatchReviewCleanup
884 " :PatchReviewCleanup
326 command! -nargs=0 PatchReviewCleanup call s:PatchReviewCleanup ()
885 command! -nargs=0 PatchReviewCleanup call s:PatchReviewCleanup ()
327 "}}}
886 command! -nargs=0 DiffReviewCleanup call s:PatchReviewCleanup ()
328 "}}}
887 "}}}
329
888
330 " vim: textwidth=78 nowrap tabstop=2 shiftwidth=2 softtabstop=2 expandtab
889 " Development "{{{
331 " vim: filetype=vim encoding=latin1 fileformat=unix foldlevel=0 foldmethod=marker
890 if exists('g:patchreview_debug')
891 " Tests
892 function! <SID>PRExtractTestNative(...)
893 "let patchfiles = glob(expand(a:1) . '/?*')
894 "for fname in split(patchfiles)
895 call s:PR_wipeMsgBuf()
896 let fname = a:1
897 call s:ExtractDiffsNative(fname)
898 for patch in g:patches['patch']
899 for line in patch.content
900 Pecho line
901 endfor
902 endfor
903 "endfor
904 endfunction
905
906 function! <SID>PRExtractTestVim(...)
907 "let patchfiles = glob(expand(a:1) . '/?*')
908 "for fname in split(patchfiles)
909 call s:PR_wipeMsgBuf()
910 let fname = a:1
911 call s:ExtractDiffsPureVim(fname)
912 for patch in g:patches['patch']
913 for line in patch.content
914 Pecho line
915 endfor
916 endfor
917 "endfor
918 endfunction
919
920 command! -nargs=+ -complete=file PRTestVim call s:PRExtractTestVim(<f-args>)
921 command! -nargs=+ -complete=file PRTestNative call s:PRExtractTestNative(<f-args>)
922 endif
332 "}}}
923 "}}}
924
925 " modeline
926 " vim: set et fdl=0 fdm=marker fenc=latin ff=unix ft=vim sw=2 sts=0 ts=2 textwidth=78 nowrap :
General Comments 0
You need to be logged in to leave comments. Login now