Show More
@@ -1,97 +1,120 b'' | |||
|
1 |
*patchreview.txt* Vim global plugin for doing single |
|
|
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 |
|
|
4 | (Replace -CAT- and -DOG- with @ and . first) | |
|
5 | Copyright (C) 2006 by Manpreet Singh | |
|
4 | Author: Manpreet Singh < junkblocker@yahoo.com > | |
|
5 | Copyright (C) 2006-2010 by Manpreet Singh | |
|
6 | 6 | License : This file is placed in the public domain. |
|
7 | 7 | |
|
8 | 8 | ============================================================================= |
|
9 | 9 | |
|
10 |
CONTENTS |
|
|
10 | CONTENTS *patchreview* *diffreview* *patchreview-contents* | |
|
11 | 11 | |
|
12 | 12 | 1. Contents.........................................: |patchreview-contents| |
|
13 | 13 | 2. Introduction.....................................: |patchreview-intro| |
|
14 | 14 | 3. PatchReview options..............................: |patchreview-options| |
|
15 | 15 | 4. PatchReview Usage................................: |patchreview-usage| |
|
16 |
4.1 |
|
|
17 |
4.2 PatchReview Usage............................: |:PatchReview |
|
|
16 | 4.1 DiffReview Usage.............................: |:DiffReview| | |
|
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 | 23 | PatchReview Introduction *patchreview-intro* |
|
22 | 24 | |
|
23 |
The Patch Review plugin allows single or multipatch code review |
|
|
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 | |
|
25 | The Patch Review plugin allows easy single or multipatch code or diff reviews. | |
|
26 | ||
|
27 | It opens each affected file in the patch or in a workspace diff in a diff view | |
|
28 | in a separate tab. | |
|
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 | 36 | the same directory as original file which can lead to project workspace |
|
29 | 37 | pollution. |
|
30 | 38 | |
|
31 | 39 | ============================================================================= |
|
32 | 40 | |
|
33 | 41 | PatchReview Options *patchreview-options* |
|
34 | 42 | |
|
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. | |
|
43 | g:patchreview_tmpdir = {string} | |
|
44 | Optional path where the plugin can save temporary files. If this is not | |
|
45 | specified, the plugin tries to use TMP, TEMP and TMPDIR environment | |
|
46 | variables in succession. | |
|
47 | ||
|
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 | |
|
61 | path. | |
|
42 | 62 | |
|
43 | 63 | examples: |
|
44 | 64 | (On Windows with Cygwin) |
|
45 | ||
|
65 | > | |
|
46 | 66 | let g:patchreview_filterdiff = 'c:\\cygwin\\bin\\filterdiff.exe' |
|
47 | ||
|
67 | < | |
|
48 | 68 | (On *nix systems) |
|
49 | ||
|
69 | > | |
|
50 | 70 | 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 |
|
|
|
55 |
|
|
|
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. | |
|
71 | < | |
|
72 | g:patchreview_patch = {string} | |
|
73 | Optional path to patch binary. PatchReview tries to locate patch on | |
|
74 | system path automatically. If the binary is not on system path, this | |
|
75 | option tell PatchReview the full path to the binary. This option, if | |
|
76 | specified, overrides the default patch binary on the path. | |
|
73 | 77 | |
|
74 | 78 | examples: |
|
75 | (On Windows) let g:patchreview_tmpdir = 'c:\\tmp' | |
|
76 | (On *nix systems) let g:patchreview_tmpdir = '~/tmp' | |
|
79 | (On Windows with Cygwin) > | |
|
80 | let g:patchreview_patch = 'c:\\cygwin\\bin\\patch.exe' | |
|
81 | < | |
|
82 | (On *nix systems) > | |
|
83 | let g:patchreview_patch = '/usr/bin/gpatch' | |
|
84 | < | |
|
77 | 85 | |
|
78 | 86 | ============================================================================= |
|
79 | 87 | |
|
80 | 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 | 97 | *:PatchReview* |
|
82 | 98 | |
|
83 | 99 | :PatchReview patchfile_path [optional_source_directory] |
|
84 | 100 | |
|
85 | 101 | Perform a patch review in the current directory based on the supplied |
|
86 | 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 | 104 | the source directory. |
|
105 | ||
|
106 | Only supports context or unified format patches. | |
|
107 | ||
|
108 | *:DiffReviewCleanup* | |
|
89 | 109 | *:PatchReviewCleanup* |
|
90 | 110 | |
|
111 | :DiffReviewCleanup | |
|
91 | 112 | :PatchReviewCleanup |
|
92 | 113 | |
|
93 |
After you are done using the :PatchReview command, you can |
|
|
94 |
temporary files in the temporary directory using |
|
|
114 | After you are done using the :DiffReview or :PatchReview command, you can | |
|
115 | cleanup the temporary files in the temporary directory using either of | |
|
116 | these commands. | |
|
95 | 117 | |
|
96 | ============================================================================= | |
|
97 | vim: ft=help:ts=2:sts=2:sw=2:tw=78:tw=78 | |
|
118 | ------------------------------------------------------------------------------ | |
|
119 | ||
|
120 | vim: ft=help:ts=2:sts=2:sw=2:tw=78:norl: |
This diff has been collapsed as it changes many lines, (952 lines changed) Show them Hide them | |||
@@ -1,332 +1,926 b'' | |||
|
1 |
" V |
|
|
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 | " 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 | |
|
4 | " Version : 0.2.1 "{{{ | |
|
5 | " Author : Manpreet Singh < junkblocker@yahoo.com > | |
|
6 | " Copyright : 2006-2010 by Manpreet Singh | |
|
7 | 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 | 25 |
|
|
12 | 26 | " =========================================================================== |
|
13 |
" This plugin allows single or multipatch code reviews to |
|
|
14 |
" has :diffpatch command to do single file reviews |
|
|
15 | " files containing multiple patches. This plugin provides that missing | |
|
16 | " functionality and doesn't require the original file to be open. | |
|
27 | " This plugin allows single or multiple, patch or diff based code reviews to | |
|
28 | " be easily done in VIM. VIM has :diffpatch command to do single file reviews | |
|
29 | " but a) can not handle patch files containing multiple patches or b) do | |
|
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. | |
|
33 | " | |
|
34 | " Installing: | |
|
17 | 35 | " |
|
18 | " Installing: "{{{ | |
|
36 | " For a quick start... | |
|
37 | " | |
|
38 | " Requirements: | |
|
39 | " | |
|
40 | " 1) VIM 7.0 or higher built with +diff option. | |
|
19 | 41 | " |
|
20 | " For a quick start... | |
|
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. | |
|
21 | 45 | " |
|
22 | " Requirements: "{{{ | |
|
46 | " 3) Optional (but recommended for speed) | |
|
23 | 47 | " |
|
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: "{{{ | |
|
48 | " Install patchutils ( http://cyberelk.net/tim/patchutils/ ) for your | |
|
49 | " OS. For windows it is availble from Cygwin | |
|
50 | " | |
|
51 | " http://www.cygwin.com | |
|
52 | " | |
|
53 | " or GnuWin32 | |
|
54 | " | |
|
55 | " http://gnuwin32.sourceforge.net/ | |
|
56 | " | |
|
57 | " Install: | |
|
31 | 58 | " |
|
32 |
" 1) Extract th |
|
|
33 | " vim. | |
|
59 | " 1) Extract the zip in your $HOME/.vim or $VIM/vimfiles directory and | |
|
60 | " restart vim. The directory location relevant to your platform can be | |
|
61 | " seen by running :help add-global-plugin in vim. | |
|
34 | 62 | " |
|
35 | " 2) Make sure that you have filterdiff from patchutils and patch commands | |
|
36 | " installed. | |
|
63 | " 2) Restart vim. | |
|
37 | 64 | " |
|
38 | " 3) Optinally, specify the locations to filterdiff and patch commands and | |
|
39 | " location of a temporary directory to use in your .vimrc. | |
|
65 | " Configuration: | |
|
40 | 66 | " |
|
41 | " let g:patchreview_filterdiff = '/path/to/filterdiff' | |
|
42 | " let g:patchreview_patch = '/path/to/patch' | |
|
67 | " Optionally, specify the locations to these filterdiff and patch commands | |
|
68 | " and location of a temporary directory to use in your .vimrc. | |
|
69 | " | |
|
70 | " let g:patchreview_patch = '/path/to/gnu/patch' | |
|
43 | 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 | 85 | " unlet! g:loaded_patchreview " DEBUG |
|
67 | 86 | " unlet! g:patchreview_tmpdir " DEBUG |
|
87 | " unlet! g:patchreview_patch " DEBUG | |
|
68 | 88 | " unlet! g:patchreview_filterdiff " DEBUG |
|
69 |
" |
|
|
70 | "}}} | |
|
89 | " let g:patchreview_patch = 'patch' " DEBUG | |
|
71 | 90 | |
|
72 | " load only once "{{{ | |
|
73 | if exists('g:loaded_patchreview') | |
|
91 | if v:version < 700 | |
|
92 | finish | |
|
93 | endif | |
|
94 | if ! has('diff') | |
|
95 | call confirm('patchreview.vim plugin needs (G)VIM built with +diff support to work.') | |
|
96 | finish | |
|
97 | endif | |
|
98 | ||
|
99 | " load only once | |
|
100 | if (! exists('g:patchreview_debug') && exists('g:loaded_patchreview')) || &compatible | |
|
74 | 101 | finish |
|
75 | 102 | endif |
|
76 | let g:loaded_patchreview=1 | |
|
77 | let s:msgbufname = 'Patch Review Messages' | |
|
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() "{{{ | |
|
81 |
let |
|
|
82 |
if |
|
|
83 |
let |
|
|
84 |
if winnr() != |
|
|
85 |
exe |
|
|
115 | function! <SID>PR_wipeMsgBuf() "{{{ | |
|
116 | let winnum = bufwinnr(s:msgbufname) | |
|
117 | if winnum != -1 " If the window is already open, jump to it | |
|
118 | let cur_winnr = winnr() | |
|
119 | if winnr() != winnum | |
|
120 | exe winnum . 'wincmd w' | |
|
86 | 121 | exe 'bw' |
|
87 |
exe |
|
|
122 | exe cur_winnr . 'wincmd w' | |
|
88 | 123 | endif |
|
89 | 124 | endif |
|
90 | 125 | endfunction |
|
91 | 126 | "}}} |
|
92 | 127 | |
|
93 |
function! <SID>P |
|
|
94 |
" Usage: P |
|
|
128 | function! <SID>Pecho(...) "{{{ | |
|
129 | " Usage: Pecho(msg, [return_to_original_window_flag]) | |
|
95 | 130 | " default return_to_original_window_flag = 0 |
|
96 | 131 | " |
|
97 |
let |
|
|
98 |
let |
|
|
99 |
if |
|
|
100 |
if winnr() != |
|
|
101 |
exe |
|
|
132 | let cur_winnr = winnr() | |
|
133 | let winnum = bufwinnr(s:msgbufname) | |
|
134 | if winnum != -1 " If the window is already open, jump to it | |
|
135 | if winnr() != winnum | |
|
136 | exe winnum . 'wincmd w' | |
|
102 | 137 | endif |
|
103 | 138 | else |
|
104 |
let |
|
|
105 |
if |
|
|
106 |
let |
|
|
139 | let bufnum = bufnr(s:msgbufname) | |
|
140 | if bufnum == -1 | |
|
141 | let wcmd = s:msgbufname | |
|
107 | 142 | else |
|
108 |
let |
|
|
143 | let wcmd = '+buffer' . bufnum | |
|
109 | 144 | endif |
|
110 |
exe 'silent! botright 5split ' . |
|
|
145 | exe 'silent! botright 5split ' . wcmd | |
|
111 | 146 | endif |
|
112 | 147 | setlocal modifiable |
|
113 | 148 | setlocal buftype=nofile |
|
114 | 149 | setlocal bufhidden=delete |
|
115 | 150 | setlocal noswapfile |
|
116 | 151 | setlocal nowrap |
|
117 | 152 | setlocal nobuflisted |
|
118 | 153 | if a:0 != 0 |
|
119 | 154 | silent! $put =a:1 |
|
120 | 155 | endif |
|
121 | 156 | exe ':$' |
|
122 | 157 | setlocal nomodifiable |
|
123 | 158 | if a:0 > 1 && a:2 |
|
124 |
exe |
|
|
159 | exe cur_winnr . 'wincmd w' | |
|
125 | 160 | endif |
|
126 | 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) "{{{ | |
|
130 | 167 | " Verify that BinaryName is specified or available |
|
131 | 168 | if ! exists('g:patchreview_' . a:BinaryName) |
|
132 | 169 | if executable(a:BinaryName) |
|
133 | 170 | let g:patchreview_{a:BinaryName} = a:BinaryName |
|
134 | 171 | return 1 |
|
135 | 172 | else |
|
136 |
|
|
|
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 | 175 | return 0 |
|
138 | 176 | endif |
|
139 | 177 | elseif ! executable(g:patchreview_{a:BinaryName}) |
|
140 |
|
|
|
178 | Pecho 'Specified g:patchreview_' . a:BinaryName . ' [' . g:patchreview_{a:BinaryName} . '] is not executable.' | |
|
141 | 179 | return 0 |
|
142 | 180 | else |
|
143 | 181 | return 1 |
|
144 | 182 | endif |
|
145 | 183 | endfunction |
|
146 | 184 | "}}} |
|
147 | 185 | |
|
148 | function! <SID>PR_GetTempDirLocation(Quiet) "{{{ | |
|
186 | function! <SID>PR_GetTempDirLocation(Quiet) "{{{ | |
|
149 | 187 | if exists('g:patchreview_tmpdir') |
|
150 | 188 | if ! isdirectory(g:patchreview_tmpdir) || ! filewritable(g:patchreview_tmpdir) |
|
151 | 189 | if ! a:Quiet |
|
152 |
|
|
|
190 | Pecho 'Temporary directory specified by g:patchreview_tmpdir [' . g:patchreview_tmpdir . '] is not accessible.' | |
|
153 | 191 | return 0 |
|
154 | 192 | endif |
|
155 | 193 | endif |
|
156 | 194 | elseif exists("$TMP") && isdirectory($TMP) && filewritable($TMP) |
|
157 | 195 | let g:patchreview_tmpdir = $TMP |
|
158 | 196 | elseif exists("$TEMP") && isdirectory($TEMP) && filewritable($TEMP) |
|
159 | 197 | let g:patchreview_tmpdir = $TEMP |
|
160 | 198 | elseif exists("$TMPDIR") && isdirectory($TMPDIR) && filewritable($TMPDIR) |
|
161 | 199 | let g:patchreview_tmpdir = $TMPDIR |
|
162 | 200 | 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.') | |
|
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') | |
|
219 | if ! a:Quiet | |
|
220 | Pecho 'Could not figure out a temporary directory to use. Please specify g:patchreview_tmpdir in your .vimrc.' | |
|
221 | endif | |
|
165 | 222 | return 0 |
|
166 | 223 | endif |
|
167 | 224 | endif |
|
225 | let g:patchreview_tmpdir = expand(g:patchreview_tmpdir, ':p') | |
|
168 | 226 | let g:patchreview_tmpdir = g:patchreview_tmpdir . '/' |
|
169 | 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 | 229 | if has('win32') |
|
172 | 230 | let g:patchreview_tmpdir = substitute(g:patchreview_tmpdir, '/', '\\', 'g') |
|
173 | 231 | endif |
|
174 | 232 | return 1 |
|
175 | 233 | endfunction |
|
176 | 234 | "}}} |
|
177 | 235 | |
|
178 |
function! <SID> |
|
|
179 | " VIM 7+ required"{{{ | |
|
180 | if version < 700 | |
|
181 | call s:PR_echo('This plugin needs VIM 7 or higher') | |
|
236 | function! <SID>ExtractDiffsNative(...) "{{{ | |
|
237 | " Sets g:patches = {'reason':'', 'patch':[ | |
|
238 | " { | |
|
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 | 257 | return |
|
183 | 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 | |
|
187 | set shortmess+=aW | |
|
188 | call s:PR_wipeMsgBuf() | |
|
189 | ||
|
190 | " Check passed arguments "{{{ | |
|
293 | function! <SID>ExtractDiffsPureVim(...) "{{{ | |
|
294 | " Sets g:patches = {'reason':'', 'patch':[ | |
|
295 | " { | |
|
296 | " 'filename': filepath | |
|
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 | 304 | 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 | |
|
305 | let g:patches['reason'] = "ExtractDiffsPureVim expects at least a patchfile argument" | |
|
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 | 314 | return |
|
195 | 315 | 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 | |
|
316 | call s:PR_wipeMsgBuf() | |
|
317 | let collect = [] | |
|
318 | let linum = 0 | |
|
319 | let lines = readfile(patchfile) | |
|
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 | |
|
355 | return | |
|
356 | endif | |
|
357 | let p_type = '+' | |
|
358 | let filepath = p_second_file | |
|
359 | else | |
|
360 | if p_second_file == '/dev/null' | |
|
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 | |
|
468 | return | |
|
469 | endif | |
|
470 | let p_type = '+' | |
|
471 | let filepath = p_second_file | |
|
472 | else | |
|
473 | if p_second_file == '/dev/null' | |
|
474 | let p_type = '-' | |
|
475 | let filepath = p_first_file | |
|
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 | |
|
556 | endif | |
|
557 | else | |
|
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>" | |
|
201 | 559 | return |
|
202 | 560 | 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 | |
|
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' | |
|
217 | 581 | 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 | |
|
582 | return s:STATE | |
|
222 | 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 "{{{ | |
|
226 | if ! s:PR_checkBinary('filterdiff') || ! s:PR_checkBinary('patch') | |
|
227 | let &shortmess = s:save_shortmess | |
|
588 | function! <SID>PatchReview(...) "{{{ | |
|
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 | |
|
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 | 614 | return |
|
229 | 615 | endif |
|
230 | 616 | |
|
231 | let s:retval = s:PR_GetTempDirLocation(0) | |
|
232 | if ! s:retval | |
|
233 | let &shortmess = s:save_shortmess | |
|
617 | " +diff required | |
|
618 | if ! has('diff') | |
|
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.' | |
|
234 | 636 | return |
|
235 | 637 | endif |
|
236 | "}}} | |
|
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' | |
|
649 | return | |
|
650 | endif | |
|
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 "{{{ | |
|
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) | |
|
678 | " Verify that patch command and temporary directory are available or specified | |
|
679 | if ! s:PR_checkBinary('patch') | |
|
680 | return | |
|
681 | endif | |
|
682 | ||
|
683 | let retval = s:PR_GetTempDirLocation(0) | |
|
684 | if ! retval | |
|
685 | return | |
|
686 | endif | |
|
687 | ||
|
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 | 705 | continue |
|
250 | 706 | endif |
|
251 |
unlet! |
|
|
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 : ' | |
|
707 | unlet! relpath | |
|
708 | let relpath = patch.filename | |
|
709 | " XXX: svn diff and hg diff produce different kind of outputs, one requires | |
|
710 | " XXX: stripping but the other doesn't. We need to take care of that | |
|
711 | let stripmore = StripCount | |
|
712 | let StrippedRelativeFilePath = relpath | |
|
713 | while stripmore > 0 | |
|
714 | " strip one | |
|
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: ' | |
|
723 | endif | |
|
724 | elseif patch.type == '+' | |
|
725 | if s:reviewmode == 'patch' | |
|
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 | |
|
260 | 736 | endif |
|
261 |
let |
|
|
262 |
if buflisted( |
|
|
263 |
|
|
|
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 | 740 | continue |
|
265 | 741 | endif |
|
266 |
let |
|
|
267 |
let |
|
|
268 |
let |
|
|
742 | let tmpname = substitute(relpath, '/', '_', 'g') | |
|
743 | let tmpname = substitute(tmpname, '\\', '_', 'g') | |
|
744 | let tmpname = g:patchreview_tmpdir . 'PatchReview.' . tmpname . '.' . strftime('%Y%m%d%H%M%S') | |
|
269 | 745 | if has('win32') |
|
270 |
let |
|
|
746 | let tmpname = substitute(tmpname, '/', '\\', 'g') | |
|
271 | 747 | 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 | 748 | |
|
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 |
|
|
|
284 | endif | |
|
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 | |
|
285 | 757 | else |
|
286 |
let |
|
|
758 | let inputfile = expand(StrippedRelativeFilePath, ':p') | |
|
759 | let patchcmd = '!' . g:patchreview_patch . patch_R_option . ' -o "' . tmpname . '.file" "' . inputfile . '" < "' . tmpname . '"' | |
|
287 | 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 | 773 | let s:origtabpagenr = tabpagenr() |
|
290 |
silent! exe 'tabedit ' . |
|
|
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) | |
|
774 | silent! exe 'tabedit ' . StrippedRelativeFilePath | |
|
775 | if exists('patchcmd') | |
|
776 | silent! exe 'vert diffsplit ' . tmpname . '.file' | |
|
295 | 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 | 785 | endif |
|
298 | 786 | silent! exe 'tabn ' . s:origtabpagenr |
|
299 | 787 | endfor |
|
300 |
|
|
|
301 |
|
|
|
302 | let &shortmess = s:save_shortmess | |
|
303 | "}}} | |
|
788 | Pecho '-----' | |
|
789 | Pecho 'Done.' | |
|
790 | ||
|
304 | 791 | endfunction |
|
305 | 792 | "}}} |
|
306 | 793 | |
|
307 | function! <SID>PatchReviewCleanup() "{{{ | |
|
308 |
let |
|
|
309 |
if |
|
|
310 |
let |
|
|
311 |
let |
|
|
312 |
for |
|
|
313 |
call delete( |
|
|
794 | function! <SID>PatchReviewCleanup() "{{{ | |
|
795 | let retval = s:PR_GetTempDirLocation(1) | |
|
796 | if retval && exists('g:patchreview_tmpdir') && isdirectory(g:patchreview_tmpdir) && filewritable(g:patchreview_tmpdir) | |
|
797 | let zefilestr = globpath(g:patchreview_tmpdir, 'PatchReview.*') | |
|
798 | let fileslist = split(zefilestr, '\m[\r\n]\+') | |
|
799 | for thefile in fileslist | |
|
800 | call delete(thefile) | |
|
314 | 801 | endfor |
|
315 | 802 | endif |
|
316 | 803 | endfunction |
|
317 | 804 | "}}} |
|
318 | 805 | |
|
319 |
|
|
|
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 | 878 | " :PatchReview |
|
322 | 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 | 884 | " :PatchReviewCleanup |
|
326 | 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 | |
|
331 | " vim: filetype=vim encoding=latin1 fileformat=unix foldlevel=0 foldmethod=marker | |
|
889 | " Development "{{{ | |
|
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