| |   |
| 37 | 37 | end |
| 38 | 38 | |
| 39 | 39 | # Takes a unified diff as input and renders it as html |
| 40 | | # this is the crappy one from collaboa |
| 41 | | # TODO: finish up the proper OO one |
| 42 | | def render_diff(udiff, src_sha, dst_sha) |
| 43 | | return if udiff.blank? |
| 44 | | out = "<table class=\"codediff\">\n" |
| 45 | | |
| 46 | | lines = udiff.split("\n") |
| 47 | | lines.reject!{ |line| line =~ /^(new|deleted) file mode [0-9]+/ } |
| 48 | | lines.reject!{ |line| line =~ /^index [a-z0-9]+\.\.[a-z0-9]+/ } |
| 49 | | |
| 50 | | lines_that_differs = /@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@/ |
| 51 | | |
| 52 | | out << "<thead>\n" |
| 53 | | out << %Q{\t<tr><td class="line-numbers">#{src_sha}</td>} |
| 54 | | out << %Q{<td class="line-numbers">#{dst_sha}</td><td> </td></tr>\n} |
| 55 | | out << "</thead>\n" |
| 56 | | |
| 57 | | prev_counter = 0 |
| 58 | | cur_counter = 0 |
| 59 | | change_num = 0 |
| 60 | | |
| 61 | | if lines.size < 3 |
| 62 | | return |
| 63 | | end |
| 64 | | |
| 65 | | lines[3..lines.length].each do |line| |
| 66 | | if line_nums = line.match(lines_that_differs) |
| 67 | | prev_line_numbers = line_nums[1].to_i...(line_nums[1].to_i + (line_nums[2]).to_i) |
| 68 | | cur_line_numbers = line_nums[3].to_i...(line_nums[3].to_i + (line_nums[4]).to_i) |
| 69 | | prev_counter = prev_line_numbers.first - 1 |
| 70 | | cur_counter = cur_line_numbers.first - 1 |
| 71 | | change_num += 1 |
| 72 | | end |
| 73 | | |
| 74 | | line = h(line) |
| 75 | | line.gsub!(/^\s/, '') # The column where + or - would be |
| 76 | | line.gsub!(/^(\+{1}(\s+|\t+)?(.*))/, '\2<ins>\3</ins>') |
| 77 | | line.gsub!(/^(-{1}(\s+|\t+)?(.*))/, '\2<del>\3</del>') |
| 78 | | #line.gsub!('\ No newline at end of file', '') |
| 79 | | |
| 80 | | out << "<tr class=\"changes\">\n" |
| 81 | | |
| 82 | | if line.match(/^(\s+|\t+)?<del>/) |
| 83 | | out << "\t<td class=\"line-numbers\">" + prev_counter.to_s + "</td>\n" |
| 84 | | out << "\t<td class=\"line-numbers\"> </td>\n" |
| 85 | | prev_counter += 1 |
| 86 | | action_class = 'del' |
| 87 | | elsif line.match(/^(\s+|\t+)?<ins>/) |
| 88 | | out << "\t<td class=\"line-numbers\"> </td>\n" |
| 89 | | out << "\t<td class=\"line-numbers\">" + cur_counter.to_s + "</td>\n" |
| 90 | | cur_counter += 1 |
| 91 | | action_class = 'ins' |
| 92 | | else |
| 93 | | if line.match(lines_that_differs) |
| 94 | | line = '' |
| 95 | | if change_num > 1 |
| 96 | | out << "\t<td class=\"line-numbers line-num-cut\">...</td>\n" |
| 97 | | out << "\t<td class=\"line-numbers line-num-cut\">...</td>\n" |
| 98 | | action_class = 'cut-line' |
| 99 | | else |
| 100 | | out << "\t<td class=\"line-numbers\"></td>\n" |
| 101 | | out << "\t<td class=\"line-numbers\"></td>\n" |
| 102 | | action_class = 'unchanged' |
| 103 | | end |
| 104 | | else |
| 105 | | out << "\t<td class=\"line-numbers\"></td>\n" |
| 106 | | out << "\t<td class=\"line-numbers\"></td>\n" |
| 107 | | action_class = 'unchanged' |
| 108 | | end |
| 109 | | prev_counter += 1 |
| 110 | | cur_counter += 1 |
| 111 | | end |
| 112 | | |
| 113 | | out << "\t<td class=\"code #{action_class}\">" + line + "</td></tr>\n" |
| 114 | | end |
| 115 | | out << "\n</table>\n" |
| 116 | | end |
| 40 | def render_diff(udiff, src_sha, dst_sha) |
| 41 | return if udiff.blank? |
| 42 | |
| 43 | callback = Gitorious::Diff::InlineTableCallback.new |
| 44 | |
| 45 | out = %Q{<table class="codediff">\n} |
| 46 | out << "<thead>\n" |
| 47 | out << "<tr>" |
| 48 | out << %Q{<td class="line-numbers">#{src_sha}</td>} |
| 49 | out << %Q{<td class="line-numbers">#{dst_sha}</td>} |
| 50 | out << "<td> </td></tr>\n" |
| 51 | out << "</thead>\n" |
| 52 | out << Diff::Display::Unified::Renderer.run(udiff, callback) |
| 53 | out << "</table>" |
| 54 | out |
| 55 | end |
| 117 | 56 | |
| 118 | 57 | end |
| toggle raw diff |
--- a/app/helpers/browse_helper.rb
+++ b/app/helpers/browse_helper.rb
@@ -37,82 +37,21 @@ module BrowseHelper
end
# Takes a unified diff as input and renders it as html
- # this is the crappy one from collaboa
- # TODO: finish up the proper OO one
- def render_diff(udiff, src_sha, dst_sha)
- return if udiff.blank?
- out = "<table class=\"codediff\">\n"
-
- lines = udiff.split("\n")
- lines.reject!{ |line| line =~ /^(new|deleted) file mode [0-9]+/ }
- lines.reject!{ |line| line =~ /^index [a-z0-9]+\.\.[a-z0-9]+/ }
-
- lines_that_differs = /@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@/
-
- out << "<thead>\n"
- out << %Q{\t<tr><td class="line-numbers">#{src_sha}</td>}
- out << %Q{<td class="line-numbers">#{dst_sha}</td><td> </td></tr>\n}
- out << "</thead>\n"
-
- prev_counter = 0
- cur_counter = 0
- change_num = 0
-
- if lines.size < 3
- return
- end
-
- lines[3..lines.length].each do |line|
- if line_nums = line.match(lines_that_differs)
- prev_line_numbers = line_nums[1].to_i...(line_nums[1].to_i + (line_nums[2]).to_i)
- cur_line_numbers = line_nums[3].to_i...(line_nums[3].to_i + (line_nums[4]).to_i)
- prev_counter = prev_line_numbers.first - 1
- cur_counter = cur_line_numbers.first - 1
- change_num += 1
- end
-
- line = h(line)
- line.gsub!(/^\s/, '') # The column where + or - would be
- line.gsub!(/^(\+{1}(\s+|\t+)?(.*))/, '\2<ins>\3</ins>')
- line.gsub!(/^(-{1}(\s+|\t+)?(.*))/, '\2<del>\3</del>')
- #line.gsub!('\ No newline at end of file', '')
-
- out << "<tr class=\"changes\">\n"
-
- if line.match(/^(\s+|\t+)?<del>/)
- out << "\t<td class=\"line-numbers\">" + prev_counter.to_s + "</td>\n"
- out << "\t<td class=\"line-numbers\"> </td>\n"
- prev_counter += 1
- action_class = 'del'
- elsif line.match(/^(\s+|\t+)?<ins>/)
- out << "\t<td class=\"line-numbers\"> </td>\n"
- out << "\t<td class=\"line-numbers\">" + cur_counter.to_s + "</td>\n"
- cur_counter += 1
- action_class = 'ins'
- else
- if line.match(lines_that_differs)
- line = ''
- if change_num > 1
- out << "\t<td class=\"line-numbers line-num-cut\">...</td>\n"
- out << "\t<td class=\"line-numbers line-num-cut\">...</td>\n"
- action_class = 'cut-line'
- else
- out << "\t<td class=\"line-numbers\"></td>\n"
- out << "\t<td class=\"line-numbers\"></td>\n"
- action_class = 'unchanged'
- end
- else
- out << "\t<td class=\"line-numbers\"></td>\n"
- out << "\t<td class=\"line-numbers\"></td>\n"
- action_class = 'unchanged'
- end
- prev_counter += 1
- cur_counter += 1
- end
-
- out << "\t<td class=\"code #{action_class}\">" + line + "</td></tr>\n"
- end
- out << "\n</table>\n"
- end
+ def render_diff(udiff, src_sha, dst_sha)
+ return if udiff.blank?
+
+ callback = Gitorious::Diff::InlineTableCallback.new
+
+ out = %Q{<table class="codediff">\n}
+ out << "<thead>\n"
+ out << "<tr>"
+ out << %Q{<td class="line-numbers">#{src_sha}</td>}
+ out << %Q{<td class="line-numbers">#{dst_sha}</td>}
+ out << "<td> </td></tr>\n"
+ out << "</thead>\n"
+ out << Diff::Display::Unified::Renderer.run(udiff, callback)
+ out << "</table>"
+ out
+ end
end |
| |   |
| 1 | module Diff #:nodoc:# |
| 2 | module Display #:nodoc:# |
| 3 | # = Diff::Display::Unified |
| 4 | # |
| 5 | # Diff::Display::Unified is meant to make dealing with the presentation of |
| 6 | # diffs easy, customizable and succinct. It breaks a diff up into sections, |
| 7 | # or blocks, which are defined by the types of lines they contain. If, for |
| 8 | # example, there is a section where five lines have been added then an |
| 9 | # AddBlock is created and those five lines are placed into that AddBlock. |
| 10 | # The design is quite simple: The generated object is made up of Block |
| 11 | # objects which are themselves made up of Line objects. |
| 12 | # |
| 13 | # === Blocks |
| 14 | # |
| 15 | # Blocks represent various sections that one finds in a diff. |
| 16 | # There are five different Block classes: |
| 17 | # |
| 18 | # [AddBlock] |
| 19 | # Contains only instances of AddLine |
| 20 | # |
| 21 | # [RemBlock] |
| 22 | # Contains only instances of RemLine |
| 23 | # |
| 24 | # [ModBlock] |
| 25 | # Contains a set of RemLine objects followed by a set of AddLine |
| 26 | # objects |
| 27 | # |
| 28 | # [UnModBlock] |
| 29 | # Contains instances of UnModLine which represent sets of context lines |
| 30 | # that are unchanged in both the old and modified data set that |
| 31 | # surround Mod, Add or Rem blocks |
| 32 | # |
| 33 | # [SepBlock] |
| 34 | # Contains a single SepLine. SepBlocks are placed between blocks when |
| 35 | # the distances between one modification set and the next exceeds the |
| 36 | # number of context buffer surrounding them. |
| 37 | # |
| 38 | # === Lines |
| 39 | # |
| 40 | # The Line classes are much line the Block classes, just on a smaller |
| 41 | # scale. |
| 42 | # |
| 43 | # There are 4 lines classes: |
| 44 | # |
| 45 | # === Example |
| 46 | # |
| 47 | # Consider the following before and after on a diff. |
| 48 | # |
| 49 | # Before: |
| 50 | # |
| 51 | # - class OldName < Array |
| 52 | # + class NewName < Array |
| 53 | # |
| 54 | # - def initialize(boundry) |
| 55 | # - @boundry = boundry |
| 56 | # - end |
| 57 | # - |
| 58 | # def stay(the, same) |
| 59 | # + end |
| 60 | # + |
| 61 | # + def all_new |
| 62 | # + @this, @method = *IS_ALL_NEW |
| 63 | # |
| 64 | # After: |
| 65 | # |
| 66 | # ---------------------------------------- ModBlock |
| 67 | # 1 [RemLine] class OldName < Array |
| 68 | # 1 [AddLine] class NewName < Array |
| 69 | # ---------------------------------------- |
| 70 | # |
| 71 | # ---------------------------------------- UnModBlock |
| 72 | # 2 [UnModLine] |
| 73 | # ---------------------------------------- |
| 74 | # |
| 75 | # ---------------------------------------- RemBlock |
| 76 | # 3 [RemLine] def initialize(boundry) |
| 77 | # 4 [RemLine] @boundry = boundry |
| 78 | # 5 [RemLine] end |
| 79 | # 6 [RemLine] |
| 80 | # ---------------------------------------- |
| 81 | # |
| 82 | # ---------------------------------------- UnModBlock |
| 83 | # 7 [UnModLine] def stay(the, same) |
| 84 | # ---------------------------------------- |
| 85 | # |
| 86 | # ---------------------------------------- AddBlock |
| 87 | # 8 [AddLine] end |
| 88 | # 9 [AddLine] |
| 89 | # 10 [AddLine] def all_new |
| 90 | # 11 [AddLine] @this, @method = -IS_ALL_NEW |
| 91 | # ---------------------------------------- |
| 92 | # |
| 93 | # Note: That is just a representation of the structure of the generated |
| 94 | # object. Also note that this example does not include any SepBlocks since |
| 95 | # the changes in the example diff are all contiguous. |
| 96 | # |
| 97 | # Internally the datastructure is quite simple: The Data object has an |
| 98 | # array of Block objects which themselves have an array of Line |
| 99 | # objects. Traversing the object on the block level or line level is |
| 100 | # equally simple so you can focus on what to do for each type of block and |
| 101 | # line. |
| 102 | module Unified |
| 103 | # Every line from the passed in diff gets transformed into an instance of |
| 104 | # one of line Line class's subclasses. One subclass exists for each line |
| 105 | # type in a diff. As such there is an AddLine class for added lines, a RemLine |
| 106 | # class for removed lines, an UnModLine class for lines which remain unchanged and |
| 107 | # a SepLine class which represents all the lines that aren't part of the diff. |
| 108 | class Line < String |
| 109 | def initialize(line, line_number) |
| 110 | super(line) |
| 111 | @line_number = line_number |
| 112 | self |
| 113 | end |
| 114 | |
| 115 | def contains_inline_change? |
| 116 | @inline |
| 117 | end |
| 118 | |
| 119 | # Returns the line number of the diff line |
| 120 | def number |
| 121 | @line_number |
| 122 | end |
| 123 | |
| 124 | def decorate(&block) |
| 125 | yield self |
| 126 | end |
| 127 | |
| 128 | protected |
| 129 | |
| 130 | def inline_add_open; '' end |
| 131 | def inline_add_close; '' end |
| 132 | def inline_rem_open; '' end |
| 133 | def inline_rem_close; '' end |
| 134 | |
| 135 | def escape |
| 136 | self |
| 137 | end |
| 138 | |
| 139 | def expand |
| 140 | escape.gsub("\t", ' ' * tabwidth).gsub(/ ( +)|^ /) do |match| |
| 141 | (space + ' ') * (match.size / 2) + |
| 142 | space * (match.size % 2) |
| 143 | end |
| 144 | end |
| 145 | |
| 146 | def tabwidth |
| 147 | 4 |
| 148 | end |
| 149 | |
| 150 | |
| 151 | def space |
| 152 | ' ' |
| 153 | end |
| 154 | |
| 155 | class << self |
| 156 | def add(line, line_number, inline = false) |
| 157 | AddLine.new(line, line_number, inline) |
| 158 | end |
| 159 | |
| 160 | def rem(line, line_number, inline = false) |
| 161 | RemLine.new(line, line_number, inline) |
| 162 | end |
| 163 | |
| 164 | def unmod(line, line_number) |
| 165 | UnModLine.new(line, line_number) |
| 166 | end |
| 167 | end |
| 168 | end |
| 169 | |
| 170 | class AddLine < Line #:nodoc:# |
| 171 | def initialize(line, line_number, inline = false) |
| 172 | line = inline ? line % [inline_add_open, inline_add_close] : line |
| 173 | super(line, line_number) |
| 174 | @inline = inline |
| 175 | self |
| 176 | end |
| 177 | end |
| 178 | |
| 179 | class RemLine < Line #:nodoc:# |
| 180 | def initialize(line, line_number, inline = false) |
| 181 | line = inline ? line % [inline_rem_open, inline_rem_close] : line |
| 182 | super(line, line_number) |
| 183 | @inline = inline |
| 184 | self |
| 185 | end |
| 186 | end |
| 187 | |
| 188 | class UnModLine < Line #:nodoc:# |
| 189 | def initialize(line, line_number) |
| 190 | super(line, line_number) |
| 191 | end |
| 192 | end |
| 193 | |
| 194 | class SepLine < Line #:nodoc:# |
| 195 | def initialize(line = '...') |
| 196 | super(line, nil) |
| 197 | end |
| 198 | end |
| 199 | |
| 200 | # This class is an array which contains Line objects. Just like Line |
| 201 | # classes, several Block classes inherit from Block. If all the lines |
| 202 | # in the block are added lines then it is an AddBlock. If all lines |
| 203 | # in the block are removed lines then it is a RemBlock. If the lines |
| 204 | # in the block are all unmodified then it is an UnMod block. If the |
| 205 | # lines in the block are a mixture of added and removed lines then |
| 206 | # it is a ModBlock. There are no blocks that contain a mixture of |
| 207 | # modified and unmodified lines. |
| 208 | class Block < Array |
| 209 | def initialize |
| 210 | super |
| 211 | end |
| 212 | |
| 213 | def <<(line_object) |
| 214 | super(line_object) |
| 215 | self |
| 216 | end |
| 217 | |
| 218 | def decorate(&block) |
| 219 | yield self |
| 220 | end |
| 221 | |
| 222 | class << self |
| 223 | def add; AddBlock.new end |
| 224 | def rem; RemBlock.new end |
| 225 | def mod; ModBlock.new end |
| 226 | def unmod; UnModBlock.new end |
| 227 | end |
| 228 | end |
| 229 | |
| 230 | #:stopdoc:# |
| 231 | class AddBlock < Block; end |
| 232 | class RemBlock < Block; end |
| 233 | class ModBlock < Block; end |
| 234 | class UnModBlock < Block; end |
| 235 | class SepBlock < Block; end |
| 236 | #:startdoc:# |
| 237 | |
| 238 | # A Data object contains the generated diff data structure. It is an |
| 239 | # array of Block objects which are themselves arrays of Line objects. The |
| 240 | # Generator class returns a Data instance object after it is done |
| 241 | # processing the diff. |
| 242 | class Data < Array |
| 243 | def initialize |
| 244 | super |
| 245 | end |
| 246 | |
| 247 | def debug |
| 248 | demodularize = Proc.new {|obj| obj.class.name[/\w+$/]} |
| 249 | each do |diff_block| |
| 250 | print "-" * 40, ' ', demodularize.call(diff_block) |
| 251 | puts |
| 252 | puts diff_block.map {|line| |
| 253 | "%5d" % line.number + |
| 254 | " [#{demodularize.call(line)}]" + |
| 255 | line |
| 256 | }.join("\n") |
| 257 | puts "-" * 40, ' ' |
| 258 | end |
| 259 | end |
| 260 | |
| 261 | end |
| 262 | |
| 263 | # Processes the diff and generates a Data object which contains the |
| 264 | # resulting data structure. |
| 265 | # |
| 266 | # The +run+ class method is fed a diff and returns a Data object. It will |
| 267 | # accept as its argument a String, an Array or a File object: |
| 268 | # |
| 269 | # Diff::Display::Unified::Generator.run(diff) |
| 270 | # |
| 271 | class Generator |
| 272 | |
| 273 | # Extracts the line number info for a given diff section |
| 274 | LINE_NUM_RE = /@@ [+-]([0-9]+),([0-9]+) [+-]([0-9]+),([0-9]+) @@/ |
| 275 | LINE_TYPES = {'+' => :add, '-' => :rem, ' ' => :unmod} |
| 276 | |
| 277 | class << self |
| 278 | |
| 279 | # Runs the generator on a diff and returns a Data object without |
| 280 | # instantiating a Generator object |
| 281 | def run(udiff) |
| 282 | raise ArgumentError, "Object must be enumerable" unless udiff.respond_to?(:each) |
| 283 | generator = new |
| 284 | udiff.each {|line| generator.process(line.chomp)} |
| 285 | generator.data |
| 286 | end |
| 287 | end |
| 288 | |
| 289 | def initialize |
| 290 | @buffer = [] |
| 291 | @prev_buffer = [] |
| 292 | @line_type = nil |
| 293 | @prev_line_type = nil |
| 294 | @offset_base = 0 |
| 295 | @offset_changed = 0 |
| 296 | @data = Diff::Display::Unified::Data.new |
| 297 | self |
| 298 | end |
| 299 | |
| 300 | # Operates on a single line from the diff and passes along the |
| 301 | # collected data to the appropriate method for further processing. The |
| 302 | # cycle of processing is in general: |
| 303 | # |
| 304 | # process --> identify_block --> process_block --> process_line |
| 305 | # |
| 306 | def process(line) |
| 307 | return if ['++', '--'].include?(line[0,2]) |
| 308 | |
| 309 | if match = LINE_NUM_RE.match(line) |
| 310 | identify_block |
| 311 | add_separator unless @offset_changed.zero? |
| 312 | @line_type = nil |
| 313 | @offset_base = match[1].to_i - 1 |
| 314 | @offset_changed = match[3].to_i - 1 |
| 315 | return |
| 316 | end |
| 317 | |
| 318 | new_line_type, line = LINE_TYPES[car(line)], cdr(line) |
| 319 | |
| 320 | # Add line to the buffer if it's the same diff line type |
| 321 | # as the previous line |
| 322 | # |
| 323 | # e.g. |
| 324 | # |
| 325 | # + This is a new line |
| 326 | # + As is this one |
| 327 | # + And yet another one... |
| 328 | # |
| 329 | if new_line_type.eql?(@line_type) |
| 330 | @buffer.push(line) |
| 331 | else |
| 332 | # Side by side inline diff |
| 333 | # |
| 334 | # e.g. |
| 335 | # |
| 336 | # - This line just had to go |
| 337 | # + This line is on the way in |
| 338 | # |
| 339 | if new_line_type.eql?(LINE_TYPES['+']) and @line_type.eql?(LINE_TYPES['-']) |
| 340 | @prev_buffer = @buffer |
| 341 | @prev_line_type = @line_type |
| 342 | else |
| 343 | identify_block |
| 344 | end |
| 345 | @buffer = [line] |
| 346 | @line_type = new_line_type |
| 347 | end |
| 348 | end |
| 349 | |
| 350 | # Finishes up with the generation and returns the Data object (could |
| 351 | # probably use a better name...maybe just #data?) |
| 352 | def data |
| 353 | close |
| 354 | @data |
| 355 | end |
| 356 | |
| 357 | protected |
| 358 | |
| 359 | def identify_block |
| 360 | if @prev_line_type.eql?(LINE_TYPES['-']) and @line_type.eql?(LINE_TYPES['+']) |
| 361 | process_block(:mod, true, true) |
| 362 | else |
| 363 | if LINE_TYPES.values.include?(@line_type) |
| 364 | process_block(@line_type, true) |
| 365 | end |
| 366 | end |
| 367 | |
| 368 | @prev_line_type = nil |
| 369 | end |
| 370 | |
| 371 | def process_block(diff_line_type, new = false, old = false) |
| 372 | push Block.send(diff_line_type) |
| 373 | |
| 374 | # Mod block |
| 375 | if diff_line_type.eql?(:mod) and @prev_buffer.size & @buffer.size == 1 |
| 376 | process_line(@prev_buffer.first, @buffer.first) |
| 377 | return |
| 378 | end |
| 379 | |
| 380 | unroll_prev_buffer if old |
| 381 | unroll_buffer if new |
| 382 | end |
| 383 | |
| 384 | # TODO Needs a better name...it does process a line (two in fact) but |
| 385 | # its primary function is to add a Rem and an Add pair which |
| 386 | # potentially have inline changes |
| 387 | def process_line(oldline, newline) |
| 388 | start, ending = get_change_extent(oldline, newline) |
| 389 | |
| 390 | # - |
| 391 | line = inline_diff(oldline, start, ending) |
| 392 | current_block << Line.rem(line, @offset_base += 1, true) |
| 393 | |
| 394 | # + |
| 395 | line = inline_diff(newline, start, ending) |
| 396 | current_block << Line.add(line, @offset_changed += 1, true) |
| 397 | end |
| 398 | |
| 399 | # Inserts string formating characters around the section of a string |
| 400 | # that differs internally from another line so that the Line class |
| 401 | # can insert the desired formating |
| 402 | def inline_diff(line, start, ending) |
| 403 | line[0, start] + |
| 404 | '%s' + extract_change(line, start, ending) + '%s' + |
| 405 | line[ending, ending.abs] |
| 406 | end |
| 407 | |
| 408 | def add_separator |
| 409 | push SepBlock.new |
| 410 | current_block << SepLine.new |
| 411 | end |
| 412 | |
| 413 | def extract_change(line, start, ending) |
| 414 | line.size > (start - ending) ? line[start...ending] : '' |
| 415 | end |
| 416 | |
| 417 | def car(line) |
| 418 | line[0,1] |
| 419 | end |
| 420 | |
| 421 | def cdr(line) |
| 422 | line[1..-1] |
| 423 | end |
| 424 | |
| 425 | # Returns the current Block object |
| 426 | def current_block |
| 427 | @data.last |
| 428 | end |
| 429 | |
| 430 | # Adds a Line object onto the current Block object |
| 431 | def push(line) |
| 432 | @data.push line |
| 433 | end |
| 434 | |
| 435 | def prev_buffer |
| 436 | @prev_buffer |
| 437 | end |
| 438 | |
| 439 | def unroll_prev_buffer |
| 440 | return if @prev_buffer.empty? |
| 441 | @prev_buffer.each do |line| |
| 442 | @offset_base += 1 |
| 443 | current_block << Line.send(@prev_line_type, line, @offset_base) |
| 444 | end |
| 445 | end |
| 446 | |
| 447 | def unroll_buffer |
| 448 | return if @buffer.empty? |
| 449 | @buffer.each do |line| |
| 450 | @offset_changed += 1 |
| 451 | current_block << Line.send(@line_type, line, @offset_changed) |
| 452 | end |
| 453 | end |
| 454 | |
| 455 | # This method is called once the generator is done with the unified |
| 456 | # diff. It is a finalizer of sorts. By the time it is called all data |
| 457 | # has been collected and processed. |
| |