summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRobert Speicher <robert@gitlab.com>2016-01-31 03:04:33 +0000
committerRobert Speicher <robert@gitlab.com>2016-01-31 03:04:33 +0000
commit5d4f8012f6a97b1e7cb4a45e03d1a80ad4b8a09e (patch)
tree6618997f0ac51f73938e7f0c2cd4247125f92970 /lib
parentd240876abaf800c1878102201b7ee18569ac1708 (diff)
parent47afe7ae8ff33c756c9ff6e2339a82f07bf11c07 (diff)
downloadgitlab-ce-5d4f8012f6a97b1e7cb4a45e03d1a80ad4b8a09e.tar.gz
Merge branch 'rename-inline-diff' into 'master'
Mark inline difference between old and new paths when a file is renamed See merge request !2652
Diffstat (limited to 'lib')
-rw-r--r--lib/gitlab/diff/highlight.rb17
-rw-r--r--lib/gitlab/diff/inline_diff.rb57
-rw-r--r--lib/gitlab/diff/inline_diff_marker.rb14
3 files changed, 52 insertions, 36 deletions
diff --git a/lib/gitlab/diff/highlight.rb b/lib/gitlab/diff/highlight.rb
index a7f925ce134..9429b3ff88d 100644
--- a/lib/gitlab/diff/highlight.rb
+++ b/lib/gitlab/diff/highlight.rb
@@ -21,13 +21,13 @@ module Gitlab
# ignore highlighting for "match" lines
next diff_line if diff_line.type == 'match' || diff_line.type == 'nonewline'
- rich_line = highlight_line(diff_line, i)
+ rich_line = highlight_line(diff_line) || diff_line.text
if line_inline_diffs = inline_diffs[i]
rich_line = InlineDiffMarker.new(diff_line.text, rich_line).mark(line_inline_diffs)
end
- diff_line.text = rich_line.html_safe
+ diff_line.text = rich_line
diff_line
end
@@ -35,8 +35,8 @@ module Gitlab
private
- def highlight_line(diff_line, index)
- return html_escape(diff_line.text) unless diff_file && diff_file.diff_refs
+ def highlight_line(diff_line)
+ return unless diff_file && diff_file.diff_refs
line_prefix = diff_line.text.match(/\A(.)/) ? $1 : ' '
@@ -49,11 +49,11 @@ module Gitlab
# Only update text if line is found. This will prevent
# issues with submodules given the line only exists in diff content.
- rich_line ? line_prefix + rich_line : html_escape(diff_line.text)
+ "#{line_prefix}#{rich_line}".html_safe if rich_line
end
def inline_diffs
- @inline_diffs ||= InlineDiff.new(@raw_lines).inline_diffs
+ @inline_diffs ||= InlineDiff.for_lines(@raw_lines)
end
def old_lines
@@ -72,11 +72,6 @@ module Gitlab
[ref.project.repository, ref.id, path]
end
-
- def html_escape(str)
- replacements = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;', "'" => '&#39;' }
- str.gsub(/[&"'><]/, replacements)
- end
end
end
end
diff --git a/lib/gitlab/diff/inline_diff.rb b/lib/gitlab/diff/inline_diff.rb
index b8a61ad6115..789c14518b0 100644
--- a/lib/gitlab/diff/inline_diff.rb
+++ b/lib/gitlab/diff/inline_diff.rb
@@ -1,43 +1,58 @@
module Gitlab
module Diff
class InlineDiff
- attr_accessor :lines
+ attr_accessor :old_line, :new_line, :offset
- def initialize(lines)
- @lines = lines
- end
+ def self.for_lines(lines)
+ local_edit_indexes = self.find_local_edits(lines)
- def inline_diffs
inline_diffs = []
local_edit_indexes.each do |index|
old_index = index
new_index = index + 1
- old_line = @lines[old_index]
- new_line = @lines[new_index]
-
- # Skip inline diff if empty line was replaced with content
- next if old_line[1..-1] == ""
-
- # Add one, because this is based on the prefixless version
- lcp = longest_common_prefix(old_line[1..-1], new_line[1..-1]) + 1
- lcs = longest_common_suffix(old_line[lcp..-1], new_line[lcp..-1])
+ old_line = lines[old_index]
+ new_line = lines[new_index]
- old_diff_range = lcp..(old_line.length - lcs - 1)
- new_diff_range = lcp..(new_line.length - lcs - 1)
+ old_diffs, new_diffs = new(old_line, new_line, offset: 1).inline_diffs
- inline_diffs[old_index] = [old_diff_range] if old_diff_range.begin <= old_diff_range.end
- inline_diffs[new_index] = [new_diff_range] if new_diff_range.begin <= new_diff_range.end
+ inline_diffs[old_index] = old_diffs
+ inline_diffs[new_index] = new_diffs
end
inline_diffs
end
+ def initialize(old_line, new_line, offset: 0)
+ @old_line = old_line[offset..-1]
+ @new_line = new_line[offset..-1]
+ @offset = offset
+ end
+
+ def inline_diffs
+ # Skip inline diff if empty line was replaced with content
+ return if old_line == ""
+
+ lcp = longest_common_prefix(old_line, new_line)
+ lcs = longest_common_suffix(old_line[lcp..-1], new_line[lcp..-1])
+
+ lcp += offset
+ old_length = old_line.length + offset
+ new_length = new_line.length + offset
+
+ old_diff_range = lcp..(old_length - lcs - 1)
+ new_diff_range = lcp..(new_length - lcs - 1)
+
+ old_diffs = [old_diff_range] if old_diff_range.begin <= old_diff_range.end
+ new_diffs = [new_diff_range] if new_diff_range.begin <= new_diff_range.end
+
+ [old_diffs, new_diffs]
+ end
+
private
- # Find runs of single line edits
- def local_edit_indexes
- line_prefixes = @lines.map { |line| line.match(/\A([+-])/) ? $1 : ' ' }
+ def self.find_local_edits(lines)
+ line_prefixes = lines.map { |line| line.match(/\A([+-])/) ? $1 : ' ' }
joined_line_prefixes = " #{line_prefixes.join} "
offset = 0
diff --git a/lib/gitlab/diff/inline_diff_marker.rb b/lib/gitlab/diff/inline_diff_marker.rb
index 1d7fa1bce06..dccb717e95d 100644
--- a/lib/gitlab/diff/inline_diff_marker.rb
+++ b/lib/gitlab/diff/inline_diff_marker.rb
@@ -5,10 +5,12 @@ module Gitlab
def initialize(raw_line, rich_line = raw_line)
@raw_line = raw_line
- @rich_line = rich_line
+ @rich_line = ERB::Util.html_escape(rich_line)
end
def mark(line_inline_diffs)
+ return rich_line unless line_inline_diffs
+
marker_ranges = []
line_inline_diffs.each do |inline_diff_range|
# Map the inline-diff range based on the raw line to character positions in the rich line
@@ -19,11 +21,15 @@ module Gitlab
offset = 0
# Mark each range
- marker_ranges.each do |range|
- offset = insert_around_range(rich_line, range, "<span class='idiff'>", "</span>", offset)
+ marker_ranges.each_with_index do |range, i|
+ class_names = ["idiff"]
+ class_names << "left" if i == 0
+ class_names << "right" if i == marker_ranges.length - 1
+
+ offset = insert_around_range(rich_line, range, "<span class='#{class_names.join(" ")}'>", "</span>", offset)
end
- rich_line
+ rich_line.html_safe
end
private