From 4ef809c77d7f4155709a6d3f0188332c206ba0e0 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
Date: Mon, 8 Sep 2014 16:25:50 +0300
Subject: [PATCH] Gitlab::Diff classes added

Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
---
 lib/gitlab/diff/file.rb   | 42 +++++++++++++++++++
 lib/gitlab/diff/line.rb   | 12 ++++++
 lib/gitlab/diff/parser.rb | 86 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 140 insertions(+)
 create mode 100644 lib/gitlab/diff/file.rb
 create mode 100644 lib/gitlab/diff/line.rb
 create mode 100644 lib/gitlab/diff/parser.rb

diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
new file mode 100644
index 000000000..adc78616f
--- /dev/null
+++ b/lib/gitlab/diff/file.rb
@@ -0,0 +1,42 @@
+module Gitlab
+  module Diff
+    class File
+      attr_reader :diff, :blob
+
+      delegate :new_file, :deleted_file, :renamed_file,
+        :old_path, :new_path, to: :diff, prefix: false
+
+      def initialize(project, commit, diff)
+        @diff = diff
+        @blob = project.repository.blob_for_diff(commit, diff)
+      end
+
+      # Array of Gitlab::DIff::Line objects
+      def diff_lines
+        @lines ||= parser.parse(diff.diff.lines, old_path, new_path)
+      end
+
+      def blob_exists?
+        !@blob.nil?
+      end
+
+      def mode_changed?
+        diff.a_mode && diff.b_mode && diff.a_mode != diff.b_mode
+      end
+
+      def parser
+        Gitlab::Diff::Parser.new
+      end
+
+      def next_line(index)
+        diff_lines[index + 1]
+      end
+
+      def prev_line(index)
+        if index > 0
+          diff_lines[index - 1]
+        end
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/diff/line.rb b/lib/gitlab/diff/line.rb
new file mode 100644
index 000000000..e8b9c980a
--- /dev/null
+++ b/lib/gitlab/diff/line.rb
@@ -0,0 +1,12 @@
+module Gitlab
+  module Diff
+    class Line
+      attr_reader :type, :text, :index, :code, :old_pos, :new_pos
+
+      def initialize(text, type, index, old_pos, new_pos, code = nil)
+        @text, @type, @index, @code = text, type, index, code
+        @old_pos, @new_pos = old_pos, new_pos
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/diff/parser.rb b/lib/gitlab/diff/parser.rb
new file mode 100644
index 000000000..0fd11c69a
--- /dev/null
+++ b/lib/gitlab/diff/parser.rb
@@ -0,0 +1,86 @@
+module Gitlab
+  module Diff
+    class Parser
+      include Enumerable
+
+      def parse(lines, old_path, new_path)
+        @lines = lines,
+        lines_obj = []
+        line_obj_index = 0
+        line_old = 1
+        line_new = 1
+        type = nil
+
+        lines_arr = ::Gitlab::InlineDiff.processing lines
+
+        lines_arr.each do |line|
+          raw_line = line.dup
+
+          next if filename?(line)
+
+          full_line = html_escape(line.gsub(/\n/, ''))
+          full_line = ::Gitlab::InlineDiff.replace_markers full_line
+
+          if line.match(/^@@ -/)
+            type = "match"
+
+            line_old = line.match(/\-[0-9]*/)[0].to_i.abs rescue 0
+            line_new = line.match(/\+[0-9]*/)[0].to_i.abs rescue 0
+
+            next if line_old == 1 && line_new == 1 #top of file
+            lines_obj << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new)
+            line_obj_index += 1
+            next
+          else
+            type = identification_type(line)
+            line_code = generate_line_code(new_path, line_new, line_old)
+            lines_obj << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new, line_code)
+            line_obj_index += 1
+          end
+
+
+          if line[0] == "+"
+            line_new += 1
+          elsif line[0] == "-"
+            line_old += 1
+          else
+            line_new += 1
+            line_old += 1
+          end
+        end
+
+        lines_obj
+      end
+
+      def empty?
+        @lines.empty?
+      end
+
+      private
+
+      def filename?(line)
+        line.start_with?('--- /dev/null', '+++ /dev/null', '--- a', '+++ b',
+                         '--- /tmp/diffy', '+++ /tmp/diffy')
+      end
+
+      def identification_type(line)
+        if line[0] == "+"
+          "new"
+        elsif line[0] == "-"
+          "old"
+        else
+          nil
+        end
+      end
+
+      def generate_line_code(path, line_new, line_old)
+        "#{Digest::SHA1.hexdigest(path)}_#{line_old}_#{line_new}"
+      end
+
+      def html_escape str
+        replacements = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;', "'" => '&#39;' }
+          str.gsub(/[&"'><]/, replacements)
+      end
+    end
+  end
+end
-- 
2.30.9