diff-display 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/History.txt +4 -0
- data/License.txt +21 -0
- data/Manifest.txt +26 -0
- data/README.txt +58 -0
- data/Rakefile +48 -0
- data/doc/.gitignore +0 -0
- data/lib/diff-display.rb +14 -0
- data/lib/diff/display/data_structure.rb +193 -0
- data/lib/diff/display/unified.rb +15 -0
- data/lib/diff/display/unified/generator.rb +210 -0
- data/lib/diff/display/version.rb +11 -0
- data/lib/diff/renderer/base.rb +90 -0
- data/lib/diff/renderer/diff.rb +29 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +74 -0
- data/setup.rb +1585 -0
- data/test/fixtures/big.diff +590 -0
- data/test/fixtures/multiple_adds_after_rem.diff +11 -0
- data/test/fixtures/multiple_rems_then_add.diff +14 -0
- data/test/fixtures/only_add.diff +4 -0
- data/test/fixtures/only_rem.diff +4 -0
- data/test/fixtures/pseudo_recursive.diff +21 -0
- data/test/fixtures/simple.diff +12 -0
- data/test/fixtures/simple_oneliner.diff +7 -0
- data/test/fixtures/simple_rewrite.diff +8 -0
- data/test/test_api.rb +12 -0
- data/test/test_base_renderer.rb +101 -0
- data/test/test_datastructure.rb +100 -0
- data/test/test_diff_renderer.rb +14 -0
- data/test/test_generator.rb +148 -0
- data/test/test_helper.rb +25 -0
- data/test/test_unified.rb +22 -0
- metadata +123 -0
@@ -0,0 +1,590 @@
|
|
1
|
+
--- unified.rb (revision 620)
|
2
|
+
+++ unified.rb (revision 644)
|
3
|
+
@@ -1,298 +1,390 @@
|
4
|
+
module Diff
|
5
|
+
module Display
|
6
|
+
module Unified
|
7
|
+
-
|
8
|
+
- LINE_RE = /@@ [+-]([0-9]+),([0-9]+) [+-]([0-9]+),([0-9]+) @@/
|
9
|
+
- TABWIDTH = 4
|
10
|
+
- SPACE = ' ' #' '
|
11
|
+
- # By defaul don't wrap inline diffs in anything
|
12
|
+
- INLINE_REM_OPEN = "\e[4;33m"
|
13
|
+
- INLINE_REM_CLOSE = "\e[m"
|
14
|
+
- INLINE_ADD_OPEN = "\e[4;35m"
|
15
|
+
- INLINE_ADD_CLOSE = "\e[m"
|
16
|
+
- ESCAPE_HTML = false
|
17
|
+
-
|
18
|
+
class Line < String
|
19
|
+
- attr_reader :add_lineno, :rem_lineno
|
20
|
+
- def initialize(line, type, add_lineno, rem_lineno = add_lineno)
|
21
|
+
+ def initialize(line, line_number)
|
22
|
+
super(line)
|
23
|
+
- @type = type
|
24
|
+
- @add_lineno = add_lineno
|
25
|
+
- @rem_lineno = rem_lineno
|
26
|
+
+ @line_number = line_number
|
27
|
+
+ self
|
28
|
+
end
|
29
|
+
|
30
|
+
+ def contains_inline_change?
|
31
|
+
+ @inline
|
32
|
+
+ end
|
33
|
+
+
|
34
|
+
def number
|
35
|
+
- add_lineno ? add_lineno : rem_lineno
|
36
|
+
+ @line_number
|
37
|
+
end
|
38
|
+
|
39
|
+
- def type
|
40
|
+
- @type
|
41
|
+
+ def decorate(&block)
|
42
|
+
+ yield self
|
43
|
+
end
|
44
|
+
|
45
|
+
- class << self
|
46
|
+
- def add(line, add_lineno)
|
47
|
+
- AddLine.new(line, add_lineno)
|
48
|
+
+ def inline_add_open; '' end
|
49
|
+
+ def inline_add_close; '' end
|
50
|
+
+ def inline_rem_open; '' end
|
51
|
+
+ def inline_rem_close; '' end
|
52
|
+
+
|
53
|
+
+ protected
|
54
|
+
+
|
55
|
+
+ def escape
|
56
|
+
+ self
|
57
|
+
end
|
58
|
+
|
59
|
+
- def rem(line, rem_lineno)
|
60
|
+
- RemLine.new(line, rem_lineno)
|
61
|
+
+ def expand
|
62
|
+
+ escape.gsub("\t", ' ' * tabwidth).gsub(/ ( +)|^ /) do |match|
|
63
|
+
+ (space + ' ') * (match.size / 2) +
|
64
|
+
+ space * (match.size % 2)
|
65
|
+
+ end
|
66
|
+
end
|
67
|
+
|
68
|
+
- def unmod(line, lineno)
|
69
|
+
- UnModLine.new(line, lineno)
|
70
|
+
+ def tabwidth
|
71
|
+
+ 4
|
72
|
+
end
|
73
|
+
|
74
|
+
- def mod(line, lineno)
|
75
|
+
- ModLine.new(line, lineno)
|
76
|
+
+
|
77
|
+
+ def space
|
78
|
+
+ ' '
|
79
|
+
end
|
80
|
+
+
|
81
|
+
+ class << self
|
82
|
+
+ def add(line, line_number, inline = false)
|
83
|
+
+ AddLine.new(line, line_number, inline)
|
84
|
+
+ end
|
85
|
+
+
|
86
|
+
+ def rem(line, line_number, inline = false)
|
87
|
+
+ RemLine.new(line, line_number, inline)
|
88
|
+
+ end
|
89
|
+
+
|
90
|
+
+ def unmod(line, line_number)
|
91
|
+
+ UnModLine.new(line, line_number)
|
92
|
+
+ end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class AddLine < Line
|
97
|
+
- def initialize(line, add_lineno)
|
98
|
+
- super(line, 'add', add_lineno, nil)
|
99
|
+
+ def initialize(line, line_number, inline = false)
|
100
|
+
+ line = inline ? line % [inline_add_open, inline_add_close] : line
|
101
|
+
+ super(line, line_number)
|
102
|
+
+ @inline = inline
|
103
|
+
+ self
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class RemLine < Line
|
108
|
+
- def initialize(line, rem_lineno)
|
109
|
+
- super(line, 'rem', nil, rem_lineno)
|
110
|
+
+ def initialize(line, line_number, inline = false)
|
111
|
+
+ line = inline ? line % [inline_rem_open, inline_rem_close] : line
|
112
|
+
+ super(line, line_number)
|
113
|
+
+ @inline = inline
|
114
|
+
+ self
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
class UnModLine < Line
|
119
|
+
- def initialize(line, lineno)
|
120
|
+
- super(line, 'unmod', lineno)
|
121
|
+
+ def initialize(line, line_number)
|
122
|
+
+ super(line, line_number)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
- class ModLine < Line
|
127
|
+
- def initialize(line, lineno)
|
128
|
+
- super(line, 'mod', lineno)
|
129
|
+
+ class SepLine < Line
|
130
|
+
+ def initialize(line = '...')
|
131
|
+
+ super(line, nil)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
+ # This class is an array which contains Line objects. Just like Line
|
136
|
+
+ # classes, several Block classes inherit from Block. If all the lines
|
137
|
+
+ # in the block are added lines then it is an AddBlock. If all lines
|
138
|
+
+ # in the block are removed lines then it is a RemBlock. If the lines
|
139
|
+
+ # in the block are all unmodified then it is an UnMod block. If the
|
140
|
+
+ # lines in the block are a mixture of added and removed lines then
|
141
|
+
+ # it is a ModBlock. There are no blocks that contain a mixture of
|
142
|
+
+ # modified and unmodified lines.
|
143
|
+
class Block < Array
|
144
|
+
- def initialize(type)
|
145
|
+
- super(0)
|
146
|
+
- @type = type
|
147
|
+
+ def initialize
|
148
|
+
+ super
|
149
|
+
+ @line_types = []
|
150
|
+
end
|
151
|
+
|
152
|
+
def <<(line_object)
|
153
|
+
super(line_object)
|
154
|
+
- (@line_types ||= []).push(line_object.type)
|
155
|
+
- @line_types.uniq!
|
156
|
+
+ line_class = line_object.class.name[/\w+$/]
|
157
|
+
+ @line_types.push(line_class) unless @line_types.include?(line_class)
|
158
|
+
self
|
159
|
+
end
|
160
|
+
|
161
|
+
+ def decorate(&block)
|
162
|
+
+ yield self
|
163
|
+
+ end
|
164
|
+
+
|
165
|
+
def line_types
|
166
|
+
@line_types
|
167
|
+
end
|
168
|
+
|
169
|
+
- def type
|
170
|
+
- @type
|
171
|
+
+ class << self
|
172
|
+
+ def add; AddBlock.new end
|
173
|
+
+ def rem; RemBlock.new end
|
174
|
+
+ def mod; ModBlock.new end
|
175
|
+
+ def unmod; UnModBlock.new end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
- class Generator < Array
|
180
|
+
+ class AddBlock < Block; end
|
181
|
+
+ class RemBlock < Block; end
|
182
|
+
+ class ModBlock < Block; end
|
183
|
+
+ class UnModBlock < Block; end
|
184
|
+
+ class SepBlock < Block; end
|
185
|
+
|
186
|
+
+ # This data object contains the generated diff data structure. It is an
|
187
|
+
+ # array of Block objects which are themselves arrays of Line objects. The
|
188
|
+
+ # Generator class returns a Data instance object after it is done
|
189
|
+
+ # processing the diff.
|
190
|
+
+ class Data < Array
|
191
|
+
+ def initialize
|
192
|
+
+ super
|
193
|
+
+ end
|
194
|
+
+
|
195
|
+
+ def debug
|
196
|
+
+ demodularize = Proc.new {|obj| obj.class.name[/\w+$/]}
|
197
|
+
+ each do |diff_block|
|
198
|
+
+ print "*" * 40, ' ', demodularize.call(diff_block)
|
199
|
+
+ puts
|
200
|
+
+ puts diff_block.map {|line|
|
201
|
+
+ "%5d" % line.number +
|
202
|
+
+ " [#{demodularize.call(line)}]" +
|
203
|
+
+ line
|
204
|
+
+ }.join("\n")
|
205
|
+
+ puts "*" * 40, ' '
|
206
|
+
+ end
|
207
|
+
+ end
|
208
|
+
+
|
209
|
+
+ end
|
210
|
+
+
|
211
|
+
+ # Processes the diff and generates a Data object which contains the
|
212
|
+
+ # resulting data structure.
|
213
|
+
+ class Generator
|
214
|
+
+
|
215
|
+
+ # Extracts the line number info for a given diff section
|
216
|
+
+ LINE_NUM_RE = /@@ [+-]([0-9]+),([0-9]+) [+-]([0-9]+),([0-9]+) @@/
|
217
|
+
+ LINE_TYPES = {'+' => :add, '-' => :rem, ' ' => :unmod}
|
218
|
+
+
|
219
|
+
class << self
|
220
|
+
- def run(udiff, options = {})
|
221
|
+
- generator = new(options)
|
222
|
+
- udiff.split("\n").each {|line| generator.build(line) }
|
223
|
+
- generator.close
|
224
|
+
- generator
|
225
|
+
+
|
226
|
+
+ # Runs the generator on a diff and returns a Data object without
|
227
|
+
+ # instantiating a Generator object
|
228
|
+
+ def run(udiff)
|
229
|
+
+ raise ArgumentError, "Object must be enumerable" unless udiff.respond_to?(:each)
|
230
|
+
+ generator = new
|
231
|
+
+ udiff.each {|line| generator.process(line.chomp)}
|
232
|
+
+ generator.render
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
- def initialize(options = {})
|
237
|
+
- super(0)
|
238
|
+
- default_options = {:inline_add_open => INLINE_ADD_OPEN,
|
239
|
+
- :inline_add_close => INLINE_ADD_CLOSE,
|
240
|
+
- :inline_rem_open => INLINE_REM_OPEN,
|
241
|
+
- :inline_rem_close => INLINE_REM_CLOSE,
|
242
|
+
- :escape_html => ESCAPE_HTML,
|
243
|
+
- :tabwidth => TABWIDTH,
|
244
|
+
- :space => SPACE}
|
245
|
+
-
|
246
|
+
- @options = default_options.merge(options)
|
247
|
+
- @block = []
|
248
|
+
- @ttype = nil
|
249
|
+
- @p_block = []
|
250
|
+
- @p_type = nil
|
251
|
+
- @changeno = -1
|
252
|
+
- @blockno = 0
|
253
|
+
+ def initialize
|
254
|
+
+ @buffer = []
|
255
|
+
+ @prev_buffer = []
|
256
|
+
+ @line_type = nil
|
257
|
+
+ @prev_line_type = nil
|
258
|
+
@offset_base = 0
|
259
|
+
@offset_changed = 0
|
260
|
+
+ @data = Diff::Display::Unified::Data.new
|
261
|
+
+ self
|
262
|
+
end
|
263
|
+
|
264
|
+
- def current_block
|
265
|
+
- last
|
266
|
+
+ # Operates on a single line from the diff and passes along the
|
267
|
+
+ # collected data to the appropriate method for further processing. The
|
268
|
+
+ # cycle of processing is in general:
|
269
|
+
+ #
|
270
|
+
+ # process --> identify_block --> process_block --> process_line
|
271
|
+
+ #
|
272
|
+
+ def process(line)
|
273
|
+
+ return if ['++', '--'].include?(line[0,2])
|
274
|
+
+
|
275
|
+
+ if match = LINE_NUM_RE.match(line)
|
276
|
+
+ identify_block
|
277
|
+
+ push SepBlock.new and current_block << SepLine.new unless @offset_changed.zero?
|
278
|
+
+ @line_type = nil
|
279
|
+
+ @offset_base = match[1].to_i - 1
|
280
|
+
+ @offset_changed = match[3].to_i - 1
|
281
|
+
+ return
|
282
|
+
+ end
|
283
|
+
+
|
284
|
+
+ new_line_type, line = LINE_TYPES[car(line)], cdr(line)
|
285
|
+
+
|
286
|
+
+ # Add line to the buffer if it's the same diff line type
|
287
|
+
+ # as the previous line
|
288
|
+
+ #
|
289
|
+
+ # e.g.
|
290
|
+
+ #
|
291
|
+
+ # + This is a new line
|
292
|
+
+ # + As is this one
|
293
|
+
+ # + And yet another one...
|
294
|
+
+ #
|
295
|
+
+ if new_line_type.eql?(@line_type)
|
296
|
+
+ @buffer.push(line)
|
297
|
+
+ else
|
298
|
+
+ # Side by side inline diff
|
299
|
+
+ #
|
300
|
+
+ # e.g.
|
301
|
+
+ #
|
302
|
+
+ # - This line just had to go
|
303
|
+
+ # + This line is on the way in
|
304
|
+
+ #
|
305
|
+
+ if new_line_type.eql?(LINE_TYPES['+']) and @line_type.eql?(LINE_TYPES['-'])
|
306
|
+
+ @prev_buffer = @buffer
|
307
|
+
+ @prev_line_type = @line_type
|
308
|
+
+ else
|
309
|
+
+ identify_block
|
310
|
+
+ end
|
311
|
+
+ @buffer = [line]
|
312
|
+
+ @line_type = new_line_type
|
313
|
+
+ end
|
314
|
+
end
|
315
|
+
|
316
|
+
+ # Finishes up with the generation and returns the Data object (could
|
317
|
+
+ # probably use a better name...maybe just #data?)
|
318
|
+
def render
|
319
|
+
close
|
320
|
+
- self
|
321
|
+
+ @data
|
322
|
+
end
|
323
|
+
-
|
324
|
+
- def escape(text)
|
325
|
+
- return '' unless text
|
326
|
+
- return text unless @options[:escape_html]
|
327
|
+
- text.gsub('&', '&').
|
328
|
+
- gsub('<', '<' ).
|
329
|
+
- gsub('>', '>' ).
|
330
|
+
- gsub('"', '"')
|
331
|
+
- end
|
332
|
+
|
333
|
+
- def expand(text)
|
334
|
+
- escape(text).gsub(/ ( +)|^ /) do |match|
|
335
|
+
- (@options[:space] + ' ') * (match.size / 2) +
|
336
|
+
- @options[:space] * (match.size % 2)
|
337
|
+
- end
|
338
|
+
- end
|
339
|
+
+ protected
|
340
|
+
|
341
|
+
- def inline_diff(line, start, ending, change)
|
342
|
+
- expand(line[0, start]) +
|
343
|
+
- change +
|
344
|
+
- expand(line[ending, ending.abs])
|
345
|
+
- end
|
346
|
+
+ def identify_block
|
347
|
+
+ if @prev_line_type.eql?(LINE_TYPES['-']) and @line_type.eql?(LINE_TYPES['+'])
|
348
|
+
+ process_block(:mod, {:old => @prev_buffer, :new => @buffer})
|
349
|
+
+ else
|
350
|
+
+ if LINE_TYPES.values.include?(@line_type)
|
351
|
+
+ process_block(@line_type, {:new => @buffer})
|
352
|
+
+ end
|
353
|
+
+ end
|
354
|
+
|
355
|
+
- def write_line(oldline, newline)
|
356
|
+
- start, ending = get_change_extent(oldline, newline)
|
357
|
+
- change = ''
|
358
|
+
- if oldline.size > start - ending
|
359
|
+
- change = @options[:inline_rem_open] +
|
360
|
+
- expand(oldline[start...ending]) +
|
361
|
+
- @options[:inline_rem_close]
|
362
|
+
+ @prev_line_type = nil
|
363
|
+
end
|
364
|
+
|
365
|
+
- line = inline_diff(oldline, start, ending, change)
|
366
|
+
- current_block << Line.rem(line, @offset_base)
|
367
|
+
+ def process_block(diff_line_type, blocks = {:old => nil, :new => nil})
|
368
|
+
+ push Block.send(diff_line_type)
|
369
|
+
+ old, new = blocks[:old], blocks[:new]
|
370
|
+
|
371
|
+
- change = ''
|
372
|
+
- if newline.size > start - ending
|
373
|
+
- change = @options[:inline_add_open] +
|
374
|
+
- expand(newline[start...ending]) +
|
375
|
+
- @options[:inline_add_close]
|
376
|
+
+ # Mod block
|
377
|
+
+ if diff_line_type.eql?(:mod) and old.size & new.size == 1
|
378
|
+
+ process_line(old.first, new.first)
|
379
|
+
+ return
|
380
|
+
+ end
|
381
|
+
+
|
382
|
+
+ if old and not old.empty?
|
383
|
+
+ old.each do |line|
|
384
|
+
+ @offset_base += 1
|
385
|
+
+ current_block << Line.send(@prev_line_type, line, @offset_base)
|
386
|
+
+ end
|
387
|
+
+ end
|
388
|
+
+
|
389
|
+
+ if new and not new.empty?
|
390
|
+
+ new.each do |line|
|
391
|
+
+ @offset_changed += 1
|
392
|
+
+ current_block << Line.send(@line_type, line, @offset_changed)
|
393
|
+
+ end
|
394
|
+
+ end
|
395
|
+
end
|
396
|
+
|
397
|
+
- line = inline_diff(newline, start, ending, change)
|
398
|
+
- current_block << Line.add(line, @offset_changed)
|
399
|
+
- end
|
400
|
+
+ # TODO Needs a better name...it does process a line (two in fact) but
|
401
|
+
+ # its primary function is to add a Rem and an Add pair which
|
402
|
+
+ # potentially have inline changes
|
403
|
+
+ def process_line(oldline, newline)
|
404
|
+
+ start, ending = get_change_extent(oldline, newline)
|
405
|
+
|
406
|
+
- def write_block(dtype, old = nil, new = nil)
|
407
|
+
- push Block.new(dtype)
|
408
|
+
+ # -
|
409
|
+
+ line = inline_diff(oldline, start, ending)
|
410
|
+
+ current_block << Line.rem(line, @offset_base += 1, true)
|
411
|
+
|
412
|
+
- if dtype == 'mod' and old.size == 1 and new.size == 1
|
413
|
+
- write_line(old.first, new.first)
|
414
|
+
- return
|
415
|
+
+ # +
|
416
|
+
+ line = inline_diff(newline, start, ending)
|
417
|
+
+ current_block << Line.add(line, @offset_changed += 1, true)
|
418
|
+
end
|
419
|
+
|
420
|
+
- if old and not old.empty?
|
421
|
+
- old.each do |e|
|
422
|
+
- current_block << Line.send(dtype, expand(e), @offset_base)
|
423
|
+
- @offset_base += 1
|
424
|
+
- end
|
425
|
+
+ # Inserts string formating characters around the section of a string
|
426
|
+
+ # that differs internally from another line so that the Line class
|
427
|
+
+ # can insert the desired formating
|
428
|
+
+ def inline_diff(line, start, ending)
|
429
|
+
+ line[0, start] +
|
430
|
+
+ '%s' + extract_change(line, start, ending) + '%s' +
|
431
|
+
+ line[ending, ending.abs]
|
432
|
+
end
|
433
|
+
|
434
|
+
- if new and not new.empty?
|
435
|
+
- new.each do |e|
|
436
|
+
- current_block << Line.send(dtype, expand(e), @offset_changed)
|
437
|
+
- @offset_changed += 1
|
438
|
+
- end
|
439
|
+
+ def extract_change(line, start, ending)
|
440
|
+
+ line.size > (start - ending) ? line[start...ending] : ''
|
441
|
+
end
|
442
|
+
- end
|
443
|
+
|
444
|
+
- def print_block
|
445
|
+
- if @p_type.eql?('-') and @ttype.eql?('+')
|
446
|
+
- write_block('mod', @p_block, @block)
|
447
|
+
- else
|
448
|
+
- case @ttype
|
449
|
+
- when '+'
|
450
|
+
- write_block('add', @block)
|
451
|
+
- when '-'
|
452
|
+
- write_block('rem', @block)
|
453
|
+
- when ' '
|
454
|
+
- write_block('unmod', @block)
|
455
|
+
- end
|
456
|
+
+ def car(line)
|
457
|
+
+ line[0,1]
|
458
|
+
end
|
459
|
+
|
460
|
+
- @block = @p_block = []
|
461
|
+
- @p_type = ' '
|
462
|
+
- @blockno += 1
|
463
|
+
- end
|
464
|
+
+ def cdr(line)
|
465
|
+
+ line[1..-1]
|
466
|
+
+ end
|
467
|
+
|
468
|
+
- def build(text)
|
469
|
+
- # TODO Names of the files and their versions go here perhaps
|
470
|
+
+ # Returns the current Block object
|
471
|
+
+ def current_block
|
472
|
+
+ @data.last
|
473
|
+
+ end
|
474
|
+
|
475
|
+
- return if ['++', '--'].include?(text[0,2])
|
476
|
+
+ # Adds a Line object onto the current Block object
|
477
|
+
+ def push(line)
|
478
|
+
+ @data.push line
|
479
|
+
+ end
|
480
|
+
|
481
|
+
- if match = LINE_RE.match(text)
|
482
|
+
- print_block
|
483
|
+
- @changeno += 1
|
484
|
+
- @blockno = 0
|
485
|
+
- @offset_base = match[1].to_i - 1
|
486
|
+
- @offset_changed = match[3].to_i - 1
|
487
|
+
- return
|
488
|
+
+ # This method is called once the generator is done with the unified
|
489
|
+
+ # diff. It is a finalizer of sorts. By the time it is called all data
|
490
|
+
+ # has been collected and processed.
|
491
|
+
+ def close
|
492
|
+
+ # certain things could be set now that processing is done
|
493
|
+
+ identify_block
|
494
|
+
end
|
495
|
+
|
496
|
+
- # Set ttype to first character of line
|
497
|
+
- ttype = text[0, 1]
|
498
|
+
- text = text[1..-1]
|
499
|
+
- text = text.gsub("\t", ' ' * @options[:tabwidth]) if text
|
500
|
+
- # If it's the same type of mod as the last line push this line onto the
|
501
|
+
- # block stack
|
502
|
+
- if ttype.eql?(@ttype)
|
503
|
+
- @block.push(text)
|
504
|
+
- else
|
505
|
+
- # If we have a side by side subtraction/addition
|
506
|
+
- if ttype == '+' and @ttype == '-'
|
507
|
+
- @p_block = @block
|
508
|
+
- @p_type = @ttype
|
509
|
+
- else
|
510
|
+
- print_block
|
511
|
+
+ # Determines the extent of differences between two string. Returns
|
512
|
+
+ # an array containing the offset at which changes start, and then
|
513
|
+
+ # negative offset at which the chnages end. If the two strings have
|
514
|
+
+ # neither a common prefix nor a common suffic, [0, 0] is returned.
|
515
|
+
+ def get_change_extent(str1, str2)
|
516
|
+
+ start = 0
|
517
|
+
+ limit = [str1.size, str2.size].sort.first
|
518
|
+
+ while start < limit and str1[start, 1] == str2[start, 1]
|
519
|
+
+ start += 1
|
520
|
+
end
|
521
|
+
- @block = [text]
|
522
|
+
- @ttype = ttype
|
523
|
+
+ ending = -1
|
524
|
+
+ limit -= start
|
525
|
+
+ while -ending <= limit and str1[ending, 1] == str2[ending, 1]
|
526
|
+
+ ending -= 1
|
527
|
+
+ end
|
528
|
+
+
|
529
|
+
+ return [start, ending + 1]
|
530
|
+
end
|
531
|
+
- end
|
532
|
+
+ end
|
533
|
+
|
534
|
+
- def debug
|
535
|
+
- each do |diff_block|
|
536
|
+
- print "*" * (40 - diff_block.type.size / 2), ' ', diff_block.type
|
537
|
+
- puts
|
538
|
+
- puts diff_block.map {|line| "#{line.number}" << line << " [#{line.type}]"}.join("\n")
|
539
|
+
- print "Line types:"
|
540
|
+
- puts diff_block.line_types.join(", ")
|
541
|
+
- puts
|
542
|
+
- end
|
543
|
+
+ # Mostly a convinience class at this point that just overwrites various
|
544
|
+
+ # customization methods
|
545
|
+
+ class HTMLGenerator < Generator
|
546
|
+
+
|
547
|
+
+ # This and the space method now don't work/make sense now that those
|
548
|
+
+ # methods are part of the Line class and there certainly won't be an
|
549
|
+
+ # HTMLLine class
|
550
|
+
+ def escape(text)
|
551
|
+
+ text.gsub('&', '&').
|
552
|
+
+ gsub('<', '<' ).
|
553
|
+
+ gsub('>', '>' ).
|
554
|
+
+ gsub('"', '"')
|
555
|
+
end
|
556
|
+
|
557
|
+
- def close
|
558
|
+
- # certain things could be set now that processing is done
|
559
|
+
- print_block
|
560
|
+
+ def space
|
561
|
+
+ ' '
|
562
|
+
end
|
563
|
+
|
564
|
+
- # Determines the extent of differences between two string. Returns
|
565
|
+
- # an array containing the offset at which changes start, and then
|
566
|
+
- # negative offset at which the chnages end. If the two strings have
|
567
|
+
- # neither a common prefix nor a common suffic, [0, 0] is returned.
|
568
|
+
- def get_change_extent(str1, str2)
|
569
|
+
- start = 0
|
570
|
+
- limit = [str1.size, str2.size].sort.first
|
571
|
+
- while start < limit and str1[start, 1] == str2[start, 1]
|
572
|
+
- start += 1
|
573
|
+
- end
|
574
|
+
- ending = -1
|
575
|
+
- limit -= start
|
576
|
+
- while -ending <= limit and str1[ending, 1] == str2[ending, 1]
|
577
|
+
- ending -= 1
|
578
|
+
- end
|
579
|
+
+ end
|
580
|
+
|
581
|
+
- return [start, ending + 1]
|
582
|
+
- end
|
583
|
+
+ # See doc string for HTMLGenerator
|
584
|
+
+ class ASCIIGenerator < Generator
|
585
|
+
end
|
586
|
+
+
|
587
|
+
end
|
588
|
+
end
|
589
|
+
end
|
590
|
+
-
|