Mercurial > hg > soundsoftware-site
diff lib/redmine/.svn/text-base/unified_diff.rb.svn-base @ 441:cbce1fd3b1b7 redmine-1.2
Update to Redmine 1.2-stable branch (Redmine SVN rev 6000)
author | Chris Cannam |
---|---|
date | Mon, 06 Jun 2011 14:24:13 +0100 |
parents | 051f544170fe |
children |
line wrap: on
line diff
--- a/lib/redmine/.svn/text-base/unified_diff.rb.svn-base Thu Mar 03 11:42:28 2011 +0000 +++ b/lib/redmine/.svn/text-base/unified_diff.rb.svn-base Mon Jun 06 14:24:13 2011 +0100 @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -17,14 +17,16 @@ module Redmine # Class used to parse unified diffs - class UnifiedDiff < Array + class UnifiedDiff < Array + attr_reader :diff_type + def initialize(diff, options={}) options.assert_valid_keys(:type, :max_lines) diff = diff.split("\n") if diff.is_a?(String) - diff_type = options[:type] || 'inline' + @diff_type = options[:type] || 'inline' lines = 0 @truncated = false - diff_table = DiffTable.new(diff_type) + diff_table = DiffTable.new(@diff_type) diff.each do |line| line_encoding = nil if line.respond_to?(:force_encoding) @@ -53,17 +55,15 @@ end # Class that represents a file diff - class DiffTable < Hash - attr_reader :file_name, :line_num_l, :line_num_r + class DiffTable < Array + attr_reader :file_name # Initialize with a Diff file and the type of Diff View # The type view must be inline or sbs (side_by_side) def initialize(type="inline") @parsing = false - @nb_line = 1 - @start = false - @before = 'same' - @second = true + @added = 0 + @removed = 0 @type = type end @@ -86,11 +86,21 @@ @line_num_l = $2.to_i @line_num_r = $5.to_i else - @nb_line += 1 if parse_line(line, @type) + parse_line(line, @type) end end return true end + + def each_line + prev_line_left, prev_line_right = nil, nil + each do |line| + spacing = prev_line_left && prev_line_right && (line.nb_line_left != prev_line_left+1) && (line.nb_line_right != prev_line_right+1) + yield spacing, line + prev_line_left = line.nb_line_left.to_i if line.nb_line_left.to_i > 0 + prev_line_right = line.nb_line_right.to_i if line.nb_line_right.to_i > 0 + end + end def inspect puts '### DIFF TABLE ###' @@ -100,74 +110,91 @@ end end - private - # Test if is a Side By Side type - def sbs?(type, func) - if @start and type == "sbs" - if @before == func and @second - tmp_nb_line = @nb_line - self[tmp_nb_line] = Diff.new - else - @second = false - tmp_nb_line = @start - @start += 1 - @nb_line -= 1 - end - else - tmp_nb_line = @nb_line - @start = @nb_line - self[tmp_nb_line] = Diff.new - @second = true - end - unless self[tmp_nb_line] - @nb_line += 1 - self[tmp_nb_line] = Diff.new - else - self[tmp_nb_line] - end - end + private # Escape the HTML for the diff def escapeHTML(line) CGI.escapeHTML(line) end + + def diff_for_added_line + if @type == 'sbs' && @removed > 0 && @added < @removed + self[-(@removed - @added)] + else + diff = Diff.new + self << diff + diff + end + end def parse_line(line, type="inline") if line[0, 1] == "+" - diff = sbs? type, 'add' - @before = 'add' + diff = diff_for_added_line diff.line_right = escapeHTML line[1..-1] diff.nb_line_right = @line_num_r diff.type_diff_right = 'diff_in' @line_num_r += 1 + @added += 1 true elsif line[0, 1] == "-" - diff = sbs? type, 'remove' - @before = 'remove' + diff = Diff.new diff.line_left = escapeHTML line[1..-1] diff.nb_line_left = @line_num_l diff.type_diff_left = 'diff_out' + self << diff @line_num_l += 1 + @removed += 1 true - elsif line[0, 1] =~ /\s/ - @before = 'same' - @start = false - diff = Diff.new - diff.line_right = escapeHTML line[1..-1] - diff.nb_line_right = @line_num_r - diff.line_left = escapeHTML line[1..-1] - diff.nb_line_left = @line_num_l - self[@nb_line] = diff - @line_num_l += 1 - @line_num_r += 1 - true - elsif line[0, 1] = "\\" + else + write_offsets + if line[0, 1] =~ /\s/ + diff = Diff.new + diff.line_right = escapeHTML line[1..-1] + diff.nb_line_right = @line_num_r + diff.line_left = escapeHTML line[1..-1] + diff.nb_line_left = @line_num_l + self << diff + @line_num_l += 1 + @line_num_r += 1 + true + elsif line[0, 1] = "\\" true else false end end end + + def write_offsets + if @added > 0 && @added == @removed + @added.times do |i| + line = self[-(1 + i)] + removed = (@type == 'sbs') ? line : self[-(1 + @added + i)] + offsets = offsets(removed.line_left, line.line_right) + removed.offsets = line.offsets = offsets + end + end + @added = 0 + @removed = 0 + end + + def offsets(line_left, line_right) + if line_left.present? && line_right.present? && line_left != line_right + max = [line_left.size, line_right.size].min + starting = 0 + while starting < max && line_left[starting] == line_right[starting] + starting += 1 + end + ending = -1 + while ending >= -(max - starting) && line_left[ending] == line_right[ending] + ending -= 1 + end + unless starting == 0 && ending == -1 + [starting, ending] + end + end + end + end # A line of diff class Diff @@ -177,6 +204,7 @@ attr_accessor :line_right attr_accessor :type_diff_right attr_accessor :type_diff_left + attr_accessor :offsets def initialize() self.nb_line_left = '' @@ -186,6 +214,38 @@ self.type_diff_right = '' self.type_diff_left = '' end + + def type_diff + type_diff_right == 'diff_in' ? type_diff_right : type_diff_left + end + + def line + type_diff_right == 'diff_in' ? line_right : line_left + end + + def html_line_left + if offsets + line_left.dup.insert(offsets.first, '<span>').insert(offsets.last, '</span>') + else + line_left + end + end + + def html_line_right + if offsets + line_right.dup.insert(offsets.first, '<span>').insert(offsets.last, '</span>') + else + line_right + end + end + + def html_line + if offsets + line.dup.insert(offsets.first, '<span>').insert(offsets.last, '</span>') + else + line + end + end def inspect puts '### Start Line Diff ###'