Mercurial > hg > soundsoftware-site
comparison .svn/pristine/e2/e2bb0cea92833ba8c44d8a93db57426fa0eda055.svn-base @ 1296:038ba2d95de8 redmine-2.2
Fix redmine-2.2 branch update (add missing svn files)
author | Chris Cannam |
---|---|
date | Fri, 14 Jun 2013 09:05:06 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
1294:3e4c3460b6ca | 1296:038ba2d95de8 |
---|---|
1 # Redmine - project management software | |
2 # Copyright (C) 2006-2012 Jean-Philippe Lang | |
3 # | |
4 # This program is free software; you can redistribute it and/or | |
5 # modify it under the terms of the GNU General Public License | |
6 # as published by the Free Software Foundation; either version 2 | |
7 # of the License, or (at your option) any later version. | |
8 # | |
9 # This program is distributed in the hope that it will be useful, | |
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 # GNU General Public License for more details. | |
13 # | |
14 # You should have received a copy of the GNU General Public License | |
15 # along with this program; if not, write to the Free Software | |
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 | |
18 module Redmine | |
19 # Class used to parse unified diffs | |
20 class UnifiedDiff < Array | |
21 attr_reader :diff_type, :diff_style | |
22 | |
23 def initialize(diff, options={}) | |
24 options.assert_valid_keys(:type, :style, :max_lines) | |
25 diff = diff.split("\n") if diff.is_a?(String) | |
26 @diff_type = options[:type] || 'inline' | |
27 @diff_style = options[:style] | |
28 lines = 0 | |
29 @truncated = false | |
30 diff_table = DiffTable.new(diff_type, diff_style) | |
31 diff.each do |line| | |
32 line_encoding = nil | |
33 if line.respond_to?(:force_encoding) | |
34 line_encoding = line.encoding | |
35 # TODO: UTF-16 and Japanese CP932 which is imcompatible with ASCII | |
36 # In Japan, diffrence between file path encoding | |
37 # and file contents encoding is popular. | |
38 line.force_encoding('ASCII-8BIT') | |
39 end | |
40 unless diff_table.add_line line | |
41 line.force_encoding(line_encoding) if line_encoding | |
42 self << diff_table if diff_table.length > 0 | |
43 diff_table = DiffTable.new(diff_type, diff_style) | |
44 end | |
45 lines += 1 | |
46 if options[:max_lines] && lines > options[:max_lines] | |
47 @truncated = true | |
48 break | |
49 end | |
50 end | |
51 self << diff_table unless diff_table.empty? | |
52 self | |
53 end | |
54 | |
55 def truncated?; @truncated; end | |
56 end | |
57 | |
58 # Class that represents a file diff | |
59 class DiffTable < Array | |
60 attr_reader :file_name | |
61 | |
62 # Initialize with a Diff file and the type of Diff View | |
63 # The type view must be inline or sbs (side_by_side) | |
64 def initialize(type="inline", style=nil) | |
65 @parsing = false | |
66 @added = 0 | |
67 @removed = 0 | |
68 @type = type | |
69 @style = style | |
70 @file_name = nil | |
71 @git_diff = false | |
72 end | |
73 | |
74 # Function for add a line of this Diff | |
75 # Returns false when the diff ends | |
76 def add_line(line) | |
77 unless @parsing | |
78 if line =~ /^(---|\+\+\+) (.*)$/ | |
79 self.file_name = $2 | |
80 elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/ | |
81 @line_num_l = $2.to_i | |
82 @line_num_r = $5.to_i | |
83 @parsing = true | |
84 end | |
85 else | |
86 if line =~ /^[^\+\-\s@\\]/ | |
87 @parsing = false | |
88 return false | |
89 elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/ | |
90 @line_num_l = $2.to_i | |
91 @line_num_r = $5.to_i | |
92 else | |
93 parse_line(line, @type) | |
94 end | |
95 end | |
96 return true | |
97 end | |
98 | |
99 def each_line | |
100 prev_line_left, prev_line_right = nil, nil | |
101 each do |line| | |
102 spacing = prev_line_left && prev_line_right && (line.nb_line_left != prev_line_left+1) && (line.nb_line_right != prev_line_right+1) | |
103 yield spacing, line | |
104 prev_line_left = line.nb_line_left.to_i if line.nb_line_left.to_i > 0 | |
105 prev_line_right = line.nb_line_right.to_i if line.nb_line_right.to_i > 0 | |
106 end | |
107 end | |
108 | |
109 def inspect | |
110 puts '### DIFF TABLE ###' | |
111 puts "file : #{file_name}" | |
112 self.each do |d| | |
113 d.inspect | |
114 end | |
115 end | |
116 | |
117 private | |
118 | |
119 def file_name=(arg) | |
120 both_git_diff = false | |
121 if file_name.nil? | |
122 @git_diff = true if arg =~ %r{^(a/|/dev/null)} | |
123 else | |
124 both_git_diff = (@git_diff && arg =~ %r{^(b/|/dev/null)}) | |
125 end | |
126 if both_git_diff | |
127 if file_name && arg == "/dev/null" | |
128 # keep the original file name | |
129 @file_name = file_name.sub(%r{^a/}, '') | |
130 else | |
131 # remove leading b/ | |
132 @file_name = arg.sub(%r{^b/}, '') | |
133 end | |
134 elsif @style == "Subversion" | |
135 # removing trailing "(revision nn)" | |
136 @file_name = arg.sub(%r{\t+\(.*\)$}, '') | |
137 else | |
138 @file_name = arg | |
139 end | |
140 end | |
141 | |
142 def diff_for_added_line | |
143 if @type == 'sbs' && @removed > 0 && @added < @removed | |
144 self[-(@removed - @added)] | |
145 else | |
146 diff = Diff.new | |
147 self << diff | |
148 diff | |
149 end | |
150 end | |
151 | |
152 def parse_line(line, type="inline") | |
153 if line[0, 1] == "+" | |
154 diff = diff_for_added_line | |
155 diff.line_right = line[1..-1] | |
156 diff.nb_line_right = @line_num_r | |
157 diff.type_diff_right = 'diff_in' | |
158 @line_num_r += 1 | |
159 @added += 1 | |
160 true | |
161 elsif line[0, 1] == "-" | |
162 diff = Diff.new | |
163 diff.line_left = line[1..-1] | |
164 diff.nb_line_left = @line_num_l | |
165 diff.type_diff_left = 'diff_out' | |
166 self << diff | |
167 @line_num_l += 1 | |
168 @removed += 1 | |
169 true | |
170 else | |
171 write_offsets | |
172 if line[0, 1] =~ /\s/ | |
173 diff = Diff.new | |
174 diff.line_right = line[1..-1] | |
175 diff.nb_line_right = @line_num_r | |
176 diff.line_left = line[1..-1] | |
177 diff.nb_line_left = @line_num_l | |
178 self << diff | |
179 @line_num_l += 1 | |
180 @line_num_r += 1 | |
181 true | |
182 elsif line[0, 1] = "\\" | |
183 true | |
184 else | |
185 false | |
186 end | |
187 end | |
188 end | |
189 | |
190 def write_offsets | |
191 if @added > 0 && @added == @removed | |
192 @added.times do |i| | |
193 line = self[-(1 + i)] | |
194 removed = (@type == 'sbs') ? line : self[-(1 + @added + i)] | |
195 offsets = offsets(removed.line_left, line.line_right) | |
196 removed.offsets = line.offsets = offsets | |
197 end | |
198 end | |
199 @added = 0 | |
200 @removed = 0 | |
201 end | |
202 | |
203 def offsets(line_left, line_right) | |
204 if line_left.present? && line_right.present? && line_left != line_right | |
205 max = [line_left.size, line_right.size].min | |
206 starting = 0 | |
207 while starting < max && line_left[starting] == line_right[starting] | |
208 starting += 1 | |
209 end | |
210 ending = -1 | |
211 while ending >= -(max - starting) && line_left[ending] == line_right[ending] | |
212 ending -= 1 | |
213 end | |
214 unless starting == 0 && ending == -1 | |
215 [starting, ending] | |
216 end | |
217 end | |
218 end | |
219 end | |
220 | |
221 # A line of diff | |
222 class Diff | |
223 attr_accessor :nb_line_left | |
224 attr_accessor :line_left | |
225 attr_accessor :nb_line_right | |
226 attr_accessor :line_right | |
227 attr_accessor :type_diff_right | |
228 attr_accessor :type_diff_left | |
229 attr_accessor :offsets | |
230 | |
231 def initialize() | |
232 self.nb_line_left = '' | |
233 self.nb_line_right = '' | |
234 self.line_left = '' | |
235 self.line_right = '' | |
236 self.type_diff_right = '' | |
237 self.type_diff_left = '' | |
238 end | |
239 | |
240 def type_diff | |
241 type_diff_right == 'diff_in' ? type_diff_right : type_diff_left | |
242 end | |
243 | |
244 def line | |
245 type_diff_right == 'diff_in' ? line_right : line_left | |
246 end | |
247 | |
248 def html_line_left | |
249 line_to_html(line_left, offsets) | |
250 end | |
251 | |
252 def html_line_right | |
253 line_to_html(line_right, offsets) | |
254 end | |
255 | |
256 def html_line | |
257 line_to_html(line, offsets) | |
258 end | |
259 | |
260 def inspect | |
261 puts '### Start Line Diff ###' | |
262 puts self.nb_line_left | |
263 puts self.line_left | |
264 puts self.nb_line_right | |
265 puts self.line_right | |
266 end | |
267 | |
268 private | |
269 | |
270 def line_to_html(line, offsets) | |
271 if offsets | |
272 s = '' | |
273 unless offsets.first == 0 | |
274 s << CGI.escapeHTML(line[0..offsets.first-1]) | |
275 end | |
276 s << '<span>' + CGI.escapeHTML(line[offsets.first..offsets.last]) + '</span>' | |
277 unless offsets.last == -1 | |
278 s << CGI.escapeHTML(line[offsets.last+1..-1]) | |
279 end | |
280 s | |
281 else | |
282 CGI.escapeHTML(line) | |
283 end | |
284 end | |
285 end | |
286 end |