| 
									
										
										
										
											2008-06-08 16:28:42 +00:00
										 |  |  | # redMine - project management software | 
					
						
							|  |  |  | # Copyright (C) 2006-2008  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 | 
					
						
							|  |  |  | # as published by the Free Software Foundation; either version 2 | 
					
						
							|  |  |  | # of the License, or (at your option) any later version. | 
					
						
							|  |  |  | #  | 
					
						
							|  |  |  | # This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  | # GNU General Public License for more details. | 
					
						
							|  |  |  | #  | 
					
						
							|  |  |  | # You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | # along with this program; if not, write to the Free Software | 
					
						
							|  |  |  | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module Redmine | 
					
						
							|  |  |  |   # Class used to parse unified diffs | 
					
						
							|  |  |  |   class UnifiedDiff < Array   | 
					
						
							|  |  |  |     def initialize(diff, type="inline") | 
					
						
							|  |  |  |       diff_table = DiffTable.new type | 
					
						
							|  |  |  |       diff.each do |line| | 
					
						
							|  |  |  |         if line =~ /^(---|\+\+\+) (.*)$/ | 
					
						
							|  |  |  |           self << diff_table if diff_table.length > 1
 | 
					
						
							|  |  |  |           diff_table = DiffTable.new type | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |         a = diff_table.add_line line | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |       self << diff_table unless diff_table.empty? | 
					
						
							|  |  |  |       self | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # Class that represents a file diff | 
					
						
							|  |  |  |   class DiffTable < Hash   | 
					
						
							|  |  |  |     attr_reader :file_name, :line_num_l, :line_num_r     | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # 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 | 
					
						
							|  |  |  |       @type = type | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Function for add a line of this Diff | 
					
						
							|  |  |  |     def add_line(line) | 
					
						
							|  |  |  |       unless @parsing | 
					
						
							|  |  |  |         if line =~ /^(---|\+\+\+) (.*)$/ | 
					
						
							|  |  |  |           @file_name = $2 | 
					
						
							|  |  |  |           return false | 
					
						
							|  |  |  |         elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/ | 
					
						
							| 
									
										
										
										
											2008-09-21 18:45:30 +00:00
										 |  |  |           @line_num_l = $2.to_i | 
					
						
							|  |  |  |           @line_num_r = $5.to_i | 
					
						
							| 
									
										
										
										
											2008-06-08 16:28:42 +00:00
										 |  |  |           @parsing = true | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         if line =~ /^[^\+\-\s@\\]/ | 
					
						
							|  |  |  |           @parsing = false | 
					
						
							|  |  |  |           return false | 
					
						
							|  |  |  |         elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/ | 
					
						
							| 
									
										
										
										
											2008-09-21 18:45:30 +00:00
										 |  |  |           @line_num_l = $2.to_i | 
					
						
							|  |  |  |           @line_num_r = $5.to_i | 
					
						
							| 
									
										
										
										
											2008-06-08 16:28:42 +00:00
										 |  |  |         else | 
					
						
							|  |  |  |           @nb_line += 1 if parse_line(line, @type)           | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |       return true | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def inspect | 
					
						
							|  |  |  |       puts '### DIFF TABLE ###' | 
					
						
							|  |  |  |       puts "file : #{file_name}" | 
					
						
							|  |  |  |       self.each do |d| | 
					
						
							|  |  |  |         d.inspect | 
					
						
							|  |  |  |       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 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Escape the HTML for the diff | 
					
						
							|  |  |  |     def escapeHTML(line) | 
					
						
							|  |  |  |         CGI.escapeHTML(line) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def parse_line(line, type="inline") | 
					
						
							|  |  |  |       if line[0, 1] == "+" | 
					
						
							|  |  |  |         diff = sbs? type, 'add' | 
					
						
							|  |  |  |         @before = 'add' | 
					
						
							| 
									
										
										
										
											2008-09-21 18:45:30 +00:00
										 |  |  |         diff.line_right = escapeHTML line[1..-1] | 
					
						
							|  |  |  |         diff.nb_line_right = @line_num_r | 
					
						
							|  |  |  |         diff.type_diff_right = 'diff_in' | 
					
						
							|  |  |  |         @line_num_r += 1
 | 
					
						
							| 
									
										
										
										
											2008-06-08 16:28:42 +00:00
										 |  |  |         true | 
					
						
							|  |  |  |       elsif line[0, 1] == "-" | 
					
						
							|  |  |  |         diff = sbs? type, 'remove' | 
					
						
							|  |  |  |         @before = 'remove' | 
					
						
							| 
									
										
										
										
											2008-09-21 18:45:30 +00:00
										 |  |  |         diff.line_left = escapeHTML line[1..-1] | 
					
						
							|  |  |  |         diff.nb_line_left = @line_num_l | 
					
						
							|  |  |  |         diff.type_diff_left = 'diff_out' | 
					
						
							|  |  |  |         @line_num_l += 1
 | 
					
						
							| 
									
										
										
										
											2008-06-08 16:28:42 +00:00
										 |  |  |         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] = "\\" | 
					
						
							|  |  |  |           true | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           false | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # A line of diff | 
					
						
							|  |  |  |   class Diff   | 
					
						
							|  |  |  |     attr_accessor :nb_line_left | 
					
						
							|  |  |  |     attr_accessor :line_left | 
					
						
							|  |  |  |     attr_accessor :nb_line_right | 
					
						
							|  |  |  |     attr_accessor :line_right | 
					
						
							|  |  |  |     attr_accessor :type_diff_right | 
					
						
							|  |  |  |     attr_accessor :type_diff_left | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def initialize() | 
					
						
							|  |  |  |       self.nb_line_left = '' | 
					
						
							|  |  |  |       self.nb_line_right = '' | 
					
						
							|  |  |  |       self.line_left = '' | 
					
						
							|  |  |  |       self.line_right = '' | 
					
						
							|  |  |  |       self.type_diff_right = '' | 
					
						
							|  |  |  |       self.type_diff_left = '' | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def inspect | 
					
						
							|  |  |  |       puts '### Start Line Diff ###' | 
					
						
							|  |  |  |       puts self.nb_line_left | 
					
						
							|  |  |  |       puts self.line_left | 
					
						
							|  |  |  |       puts self.nb_line_right | 
					
						
							|  |  |  |       puts self.line_right | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end |