annotate lib/redmine/.svn/text-base/unified_diff.rb.svn-base @ 245:051f544170fe

* Update to SVN trunk revision 4993
author Chris Cannam
date Thu, 03 Mar 2011 11:42:28 +0000
parents 513646585e45
children cbce1fd3b1b7
rev   line source
Chris@0 1 # redMine - project management software
Chris@0 2 # Copyright (C) 2006-2008 Jean-Philippe Lang
Chris@0 3 #
Chris@0 4 # This program is free software; you can redistribute it and/or
Chris@0 5 # modify it under the terms of the GNU General Public License
Chris@0 6 # as published by the Free Software Foundation; either version 2
Chris@0 7 # of the License, or (at your option) any later version.
Chris@0 8 #
Chris@0 9 # This program is distributed in the hope that it will be useful,
Chris@0 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@0 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@0 12 # GNU General Public License for more details.
Chris@0 13 #
Chris@0 14 # You should have received a copy of the GNU General Public License
Chris@0 15 # along with this program; if not, write to the Free Software
Chris@0 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Chris@0 17
Chris@0 18 module Redmine
Chris@0 19 # Class used to parse unified diffs
Chris@0 20 class UnifiedDiff < Array
Chris@0 21 def initialize(diff, options={})
Chris@0 22 options.assert_valid_keys(:type, :max_lines)
Chris@0 23 diff = diff.split("\n") if diff.is_a?(String)
Chris@0 24 diff_type = options[:type] || 'inline'
Chris@0 25 lines = 0
Chris@0 26 @truncated = false
Chris@0 27 diff_table = DiffTable.new(diff_type)
Chris@0 28 diff.each do |line|
Chris@245 29 line_encoding = nil
Chris@245 30 if line.respond_to?(:force_encoding)
Chris@245 31 line_encoding = line.encoding
Chris@245 32 # TODO: UTF-16 and Japanese CP932 which is imcompatible with ASCII
Chris@245 33 # In Japan, diffrence between file path encoding
Chris@245 34 # and file contents encoding is popular.
Chris@245 35 line.force_encoding('ASCII-8BIT')
Chris@245 36 end
Chris@0 37 unless diff_table.add_line line
Chris@245 38 line.force_encoding(line_encoding) if line_encoding
Chris@245 39 self << diff_table if diff_table.length > 0
Chris@0 40 diff_table = DiffTable.new(diff_type)
Chris@0 41 end
Chris@0 42 lines += 1
Chris@0 43 if options[:max_lines] && lines > options[:max_lines]
Chris@0 44 @truncated = true
Chris@0 45 break
Chris@0 46 end
Chris@0 47 end
Chris@0 48 self << diff_table unless diff_table.empty?
Chris@0 49 self
Chris@0 50 end
Chris@245 51
Chris@0 52 def truncated?; @truncated; end
Chris@0 53 end
Chris@0 54
Chris@0 55 # Class that represents a file diff
Chris@0 56 class DiffTable < Hash
Chris@0 57 attr_reader :file_name, :line_num_l, :line_num_r
Chris@0 58
Chris@0 59 # Initialize with a Diff file and the type of Diff View
Chris@0 60 # The type view must be inline or sbs (side_by_side)
Chris@0 61 def initialize(type="inline")
Chris@0 62 @parsing = false
Chris@0 63 @nb_line = 1
Chris@0 64 @start = false
Chris@0 65 @before = 'same'
Chris@0 66 @second = true
Chris@0 67 @type = type
Chris@0 68 end
Chris@0 69
Chris@0 70 # Function for add a line of this Diff
Chris@0 71 # Returns false when the diff ends
Chris@0 72 def add_line(line)
Chris@0 73 unless @parsing
Chris@0 74 if line =~ /^(---|\+\+\+) (.*)$/
Chris@0 75 @file_name = $2
Chris@0 76 elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/
Chris@0 77 @line_num_l = $2.to_i
Chris@0 78 @line_num_r = $5.to_i
Chris@0 79 @parsing = true
Chris@0 80 end
Chris@0 81 else
Chris@0 82 if line =~ /^[^\+\-\s@\\]/
Chris@0 83 @parsing = false
Chris@0 84 return false
Chris@0 85 elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/
Chris@0 86 @line_num_l = $2.to_i
Chris@0 87 @line_num_r = $5.to_i
Chris@0 88 else
Chris@0 89 @nb_line += 1 if parse_line(line, @type)
Chris@0 90 end
Chris@0 91 end
Chris@0 92 return true
Chris@0 93 end
Chris@0 94
Chris@0 95 def inspect
Chris@0 96 puts '### DIFF TABLE ###'
Chris@0 97 puts "file : #{file_name}"
Chris@0 98 self.each do |d|
Chris@0 99 d.inspect
Chris@0 100 end
Chris@0 101 end
Chris@0 102
Chris@0 103 private
Chris@0 104 # Test if is a Side By Side type
Chris@0 105 def sbs?(type, func)
Chris@0 106 if @start and type == "sbs"
Chris@0 107 if @before == func and @second
Chris@0 108 tmp_nb_line = @nb_line
Chris@0 109 self[tmp_nb_line] = Diff.new
Chris@0 110 else
Chris@0 111 @second = false
Chris@0 112 tmp_nb_line = @start
Chris@0 113 @start += 1
Chris@0 114 @nb_line -= 1
Chris@0 115 end
Chris@0 116 else
Chris@0 117 tmp_nb_line = @nb_line
Chris@0 118 @start = @nb_line
Chris@0 119 self[tmp_nb_line] = Diff.new
Chris@0 120 @second = true
Chris@0 121 end
Chris@0 122 unless self[tmp_nb_line]
Chris@0 123 @nb_line += 1
Chris@0 124 self[tmp_nb_line] = Diff.new
Chris@0 125 else
Chris@0 126 self[tmp_nb_line]
Chris@0 127 end
Chris@0 128 end
Chris@0 129
Chris@0 130 # Escape the HTML for the diff
Chris@0 131 def escapeHTML(line)
Chris@0 132 CGI.escapeHTML(line)
Chris@0 133 end
Chris@0 134
Chris@0 135 def parse_line(line, type="inline")
Chris@0 136 if line[0, 1] == "+"
Chris@0 137 diff = sbs? type, 'add'
Chris@0 138 @before = 'add'
Chris@0 139 diff.line_right = escapeHTML line[1..-1]
Chris@0 140 diff.nb_line_right = @line_num_r
Chris@0 141 diff.type_diff_right = 'diff_in'
Chris@0 142 @line_num_r += 1
Chris@0 143 true
Chris@0 144 elsif line[0, 1] == "-"
Chris@0 145 diff = sbs? type, 'remove'
Chris@0 146 @before = 'remove'
Chris@0 147 diff.line_left = escapeHTML line[1..-1]
Chris@0 148 diff.nb_line_left = @line_num_l
Chris@0 149 diff.type_diff_left = 'diff_out'
Chris@0 150 @line_num_l += 1
Chris@0 151 true
Chris@0 152 elsif line[0, 1] =~ /\s/
Chris@0 153 @before = 'same'
Chris@0 154 @start = false
Chris@0 155 diff = Diff.new
Chris@0 156 diff.line_right = escapeHTML line[1..-1]
Chris@0 157 diff.nb_line_right = @line_num_r
Chris@0 158 diff.line_left = escapeHTML line[1..-1]
Chris@0 159 diff.nb_line_left = @line_num_l
Chris@0 160 self[@nb_line] = diff
Chris@0 161 @line_num_l += 1
Chris@0 162 @line_num_r += 1
Chris@0 163 true
Chris@0 164 elsif line[0, 1] = "\\"
Chris@0 165 true
Chris@0 166 else
Chris@0 167 false
Chris@0 168 end
Chris@0 169 end
Chris@0 170 end
Chris@0 171
Chris@0 172 # A line of diff
Chris@0 173 class Diff
Chris@0 174 attr_accessor :nb_line_left
Chris@0 175 attr_accessor :line_left
Chris@0 176 attr_accessor :nb_line_right
Chris@0 177 attr_accessor :line_right
Chris@0 178 attr_accessor :type_diff_right
Chris@0 179 attr_accessor :type_diff_left
Chris@0 180
Chris@0 181 def initialize()
Chris@0 182 self.nb_line_left = ''
Chris@0 183 self.nb_line_right = ''
Chris@0 184 self.line_left = ''
Chris@0 185 self.line_right = ''
Chris@0 186 self.type_diff_right = ''
Chris@0 187 self.type_diff_left = ''
Chris@0 188 end
Chris@0 189
Chris@0 190 def inspect
Chris@0 191 puts '### Start Line Diff ###'
Chris@0 192 puts self.nb_line_left
Chris@0 193 puts self.line_left
Chris@0 194 puts self.nb_line_right
Chris@0 195 puts self.line_right
Chris@0 196 end
Chris@0 197 end
Chris@0 198 end