Show More
@@ -1,30 +1,38 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 | 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 |
|
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 |
|
16 | 4.1 DiffReview Usage.............................: |:DiffReview| | |
17 |
4.2 PatchReview Usage............................: |:PatchReview |
|
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 |
|
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: | |
41 | path. |
|
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 | 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 |
|
|
74 | system path automatically. If the binary is not on system path, this | |
55 |
|
|
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 |
|
||||
59 | examples: |
|
|||
60 | (On Windows with Cygwin) |
|
|||
61 |
|
||||
62 | let g:patchreview_patch = 'c:\\cygwin\\bin\\patch.exe' |
|
|||
63 |
|
||||
64 | (On *nix systems) |
|
|||
65 |
|
||||
66 | let g:patchreview_patch = '/usr/bin/gpatch' |
|
|||
67 |
|
||||
68 |
|
||||
69 | g:patchreview_tmpdir : Optional path where the plugin can save temporary |
|
|||
70 | files. If this is not specified, the plugin tries to |
|
|||
71 | use TMP, TEMP and TMPDIR environment variables in |
|
|||
72 | succession. |
|
|||
73 |
|
77 | |||
74 | examples: |
|
78 | examples: | |
75 | (On Windows) let g:patchreview_tmpdir = 'c:\\tmp' |
|
79 | (On Windows with Cygwin) > | |
76 | (On *nix systems) let g:patchreview_tmpdir = '~/tmp' |
|
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 | 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 |
|
114 | After you are done using the :DiffReview or :PatchReview command, you can | |
94 |
temporary files in the temporary directory using |
|
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, (952 lines changed) Show them Hide them | |||||
@@ -1,113 +1,148 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 | " 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 |
|
|
25 | " Documentation: "{{{ | |
12 | " =========================================================================== |
|
26 | " =========================================================================== | |
13 |
" This plugin allows single or multipatch code reviews to |
|
27 | " This plugin allows single or multiple, patch or diff based code reviews to | |
14 |
" has :diffpatch command to do single file reviews |
|
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. | |||
|
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. |
|
48 | " Install patchutils ( http://cyberelk.net/tim/patchutils/ ) for your | |
25 | " 2) patch and patchutils ( http://cyberelk.net/tim/patchutils/ ) installed |
|
49 | " OS. For windows it is availble from Cygwin | |
26 | " for your OS. For windows it is availble from Cygwin ( |
|
50 | " | |
27 | " http://www.cygwin.com ) or GnuWin32 ( http://gnuwin32.sourceforge.net/ |
|
51 | " http://www.cygwin.com | |
28 | " ). |
|
52 | " | |
29 | ""}}} |
|
53 | " or GnuWin32 | |
30 | " Install: "{{{ |
|
54 | " | |
|
55 | " http://gnuwin32.sourceforge.net/ | |||
|
56 | " | |||
|
57 | " Install: | |||
31 | " |
|
58 | " | |
32 |
" 1) Extract th |
|
59 | " 1) Extract the zip in your $HOME/.vim or $VIM/vimfiles directory and | |
33 | " vim. |
|
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 |
|
63 | " 2) Restart vim. | |
36 | " installed. |
|
|||
37 | " |
|
64 | " | |
38 | " 3) Optinally, specify the locations to filterdiff and patch commands and |
|
65 | " Configuration: | |
39 | " location of a temporary directory to use in your .vimrc. |
|
|||
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 |
" |
|
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.') | |||
|
96 | finish | |||
|
97 | endif | |||
|
98 | ||||
|
99 | " load only once | |||
|
100 | if (! exists('g:patchreview_debug') && exists('g:loaded_patchreview')) || &compatible | |||
74 | finish |
|
101 | finish | |
75 | endif |
|
102 | endif | |
76 | let g:loaded_patchreview=1 |
|
103 | let g:loaded_patchreview="0.2.1" | |
77 | let s:msgbufname = 'Patch Review Messages' |
|
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 |
|
116 | let winnum = bufwinnr(s:msgbufname) | |
82 |
if |
|
117 | if winnum != -1 " If the window is already open, jump to it | |
83 |
let |
|
118 | let cur_winnr = winnr() | |
84 |
if winnr() != |
|
119 | if winnr() != winnum | |
85 |
exe |
|
120 | exe winnum . 'wincmd w' | |
86 | exe 'bw' |
|
121 | exe 'bw' | |
87 |
exe |
|
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>P |
|
128 | function! <SID>Pecho(...) "{{{ | |
94 |
" Usage: P |
|
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 |
|
132 | let cur_winnr = winnr() | |
98 |
let |
|
133 | let winnum = bufwinnr(s:msgbufname) | |
99 |
if |
|
134 | if winnum != -1 " If the window is already open, jump to it | |
100 |
if winnr() != |
|
135 | if winnr() != winnum | |
101 |
exe |
|
136 | exe winnum . 'wincmd w' | |
102 | endif |
|
137 | endif | |
103 | else |
|
138 | else | |
104 |
let |
|
139 | let bufnum = bufnr(s:msgbufname) | |
105 |
if |
|
140 | if bufnum == -1 | |
106 |
let |
|
141 | let wcmd = s:msgbufname | |
107 | else |
|
142 | else | |
108 |
let |
|
143 | let wcmd = '+buffer' . bufnum | |
109 | endif |
|
144 | endif | |
110 |
exe 'silent! botright 5split ' . |
|
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,23 +156,26 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 |
|
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) "{{{ | |
130 | " Verify that BinaryName is specified or available |
|
167 | " Verify that BinaryName is specified or available | |
131 | if ! exists('g:patchreview_' . a:BinaryName) |
|
168 | if ! exists('g:patchreview_' . a:BinaryName) | |
132 | if executable(a:BinaryName) |
|
169 | if executable(a: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 |
|
|
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 |
|
|
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 | |
@@ -145,11 +183,11 b' function! <SID>PR_checkBinary(BinaryName' | |||||
145 | endfunction |
|
183 | endfunction | |
146 | "}}} |
|
184 | "}}} | |
147 |
|
185 | |||
148 | function! <SID>PR_GetTempDirLocation(Quiet) "{{{ |
|
186 | function! <SID>PR_GetTempDirLocation(Quiet) "{{{ | |
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 |
|
|
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 | |
163 | if ! a:Quiet |
|
201 | if has("unix") | |
164 | call s:PR_echo('Could not figure out a temporary directory to use. Please specify g:patchreview_tmpdir in your .vimrc.') |
|
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 | 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> |
|
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 | |||
|
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 | return |
|
559 | return | |
202 | endif |
|
560 | endif | |
203 | if a:0 == 2 |
|
561 | endwhile | |
204 | let s:SrcDirectory = expand(a:2, ':p') |
|
562 | "Pecho State() | |
205 | if ! isdirectory(s:SrcDirectory) |
|
563 | if (State() == 'READ_CONTEXT_CHUNK' && c_count == goal_count) || (State() == 'READ_UNIFIED_CHUNK' && n_count == new_goal_count && o_count == old_goal_count) | |
206 | call s:PR_echo('[' . s:SrcDirectory . '] is not a directory') |
|
564 | let this_patch = {} | |
207 | let &shortmess = s:save_shortmess |
|
565 | let this_patch['filename'] = filepath | |
208 | return |
|
566 | let this_patch['type'] = p_type | |
209 | endif |
|
567 | let this_patch['content'] = collect | |
210 | try |
|
568 | let g:patches['patch'] += [this_patch] | |
211 | exe 'cd ' . s:SrcDirectory |
|
569 | Debug "Patch collected for " . filepath | |
212 | catch /^.*E344.*/ |
|
570 | endif | |
213 | call s:PR_echo('Could not change to directory [' . s:SrcDirectory . ']') |
|
571 | return | |
214 | let &shortmess = s:save_shortmess |
|
572 | endfunction | |
215 | return |
|
573 | "}}} | |
216 | endtry |
|
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 | endif |
|
581 | endif | |
218 | else |
|
582 | return s:STATE | |
219 | call s:PR_echo('PatchReview command needs at most two arguments: patchfile path and optional source directory path.') |
|
|||
220 | let &shortmess = s:save_shortmess |
|
|||
221 | return |
|
|||
222 | endif |
|
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 | |
227 | let &shortmess = s:save_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 | 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.' | |||
234 | return |
|
636 | return | |
235 | endif |
|
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 "{{{ |
|
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! |
|
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: ' | |||
|
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 | endif |
|
736 | endif | |
261 |
let |
|
737 | let bufnum = bufnr(relpath) | |
262 |
if buflisted( |
|
738 | if buflisted(bufnum) && getbufvar(bufnum, '&mod') | |
263 |
|
|
739 | Pecho 'Old buffer for file [' . relpath . '] exists in modified state. Skipping review.', 1 | |
264 | continue |
|
740 | continue | |
265 | endif |
|
741 | endif | |
266 |
let |
|
742 | let tmpname = substitute(relpath, '/', '_', 'g') | |
267 |
let |
|
743 | let tmpname = substitute(tmpname, '\\', '_', 'g') | |
268 |
let |
|
744 | let tmpname = g:patchreview_tmpdir . 'PatchReview.' . tmpname . '.' . strftime('%Y%m%d%H%M%S') | |
269 | if has('win32') |
|
745 | if has('win32') | |
270 |
let |
|
746 | let tmpname = substitute(tmpname, '/', '\\', 'g') | |
271 | endif |
|
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 |
|
749 | " write patch for patch.filename into tmpname | |
278 | silent! exe s:filterdiffcmd |
|
750 | call writefile(patch.content, tmpname) | |
279 | if s:filewithchangetype =~ '^+ ' |
|
751 | if patch.type == '+' && s:reviewmode == 'patch' | |
280 | if has('win32') |
|
752 | let inputfile = '' | |
281 | let s:inputfile = 'nul' |
|
753 | let patchcmd = '!' . g:patchreview_patch . patch_R_option . ' -o "' . tmpname . '.file" "' . inputfile . '" < "' . tmpname . '"' | |
282 | else |
|
754 | elseif patch.type == '+' && s:reviewmode == 'diff' | |
283 |
|
|
755 | let inputfile = '' | |
284 | endif |
|
756 | unlet! patchcmd | |
285 | else |
|
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 | 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 ' . |
|
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 |
|
|
788 | Pecho '-----' | |
301 |
|
|
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 |
|
795 | let retval = s:PR_GetTempDirLocation(1) | |
309 |
if |
|
796 | if retval && exists('g:patchreview_tmpdir') && isdirectory(g:patchreview_tmpdir) && filewritable(g:patchreview_tmpdir) | |
310 |
let |
|
797 | let zefilestr = globpath(g:patchreview_tmpdir, 'PatchReview.*') | |
311 |
let |
|
798 | let fileslist = split(zefilestr, '\m[\r\n]\+') | |
312 |
for |
|
799 | for thefile in fileslist | |
313 |
call delete( |
|
800 | call delete(thefile) | |
314 | endfor |
|
801 | endfor | |
315 | endif |
|
802 | endif | |
316 | endfunction |
|
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 | " :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