summaryrefslogtreecommitdiff
path: root/lib/gitlab/diff/inline_diff_marker.rb
diff options
context:
space:
mode:
authorDouwe Maan <douwe@gitlab.com>2016-01-15 16:02:48 +0100
committerDouwe Maan <douwe@gitlab.com>2016-01-15 16:02:48 +0100
commit5de8971ddfa10cbc6a082316eee7377038670f75 (patch)
treef69cb6eed018d7e2bdcae59aebb84a471655a7be /lib/gitlab/diff/inline_diff_marker.rb
parent13f10efcf120f2d5244bf6abe934dc7c026834ef (diff)
downloadgitlab-ce-5de8971ddfa10cbc6a082316eee7377038670f75.tar.gz
Whoops, forgot to add files
Diffstat (limited to 'lib/gitlab/diff/inline_diff_marker.rb')
-rw-r--r--lib/gitlab/diff/inline_diff_marker.rb85
1 files changed, 85 insertions, 0 deletions
diff --git a/lib/gitlab/diff/inline_diff_marker.rb b/lib/gitlab/diff/inline_diff_marker.rb
new file mode 100644
index 00000000000..4bb755e3d3d
--- /dev/null
+++ b/lib/gitlab/diff/inline_diff_marker.rb
@@ -0,0 +1,85 @@
+module Gitlab
+ module Diff
+ class InlineDiffMarker
+ attr_accessor :raw_line, :rich_line
+
+ def initialize(raw_line, rich_line = raw_line)
+ @raw_line = raw_line
+ @rich_line = rich_line
+ end
+
+ def mark(line_inline_diffs)
+ offset = 0
+ line_inline_diffs.each do |inline_diff_range|
+ inline_diff_positions = position_mapping[inline_diff_range]
+ marker_ranges = collapse_ranges(inline_diff_positions)
+
+ marker_ranges.each do |range|
+ offset = insert_around_range(rich_line, range, "<span class='idiff'>", "</span>", offset)
+ end
+ end
+
+ rich_line
+ end
+
+ def position_mapping
+ @position_mapping ||= begin
+ mapping = []
+ raw_pos = 0
+ rich_pos = 0
+ (0..raw_line.length).each do |raw_pos|
+ raw_char = raw_line[raw_pos]
+ rich_char = rich_line[rich_pos]
+
+ while rich_char == '<'
+ until rich_char == '>'
+ rich_pos += 1
+ rich_char = rich_line[rich_pos]
+ end
+
+ rich_pos += 1
+ rich_char = rich_line[rich_pos]
+ end
+
+ mapping[raw_pos] = rich_pos
+
+ rich_pos += 1
+ end
+
+ mapping
+ end
+ end
+
+ def collapse_ranges(positions)
+ return [] if positions.empty?
+ ranges = []
+
+ start = prev = positions[0]
+ range = start..prev
+ positions[1..-1].each do |pos|
+ if pos == prev + 1
+ range = start..pos
+ prev = pos
+ else
+ ranges << range
+ start = prev = pos
+ range = start..prev
+ end
+ end
+ ranges << range
+
+ ranges
+ end
+
+ def insert_around_range(text, range, before, after, offset = 0)
+ text.insert(offset + range.begin, before)
+ offset += before.length
+
+ text.insert(offset + range.end + 1, after)
+ offset += after.length
+
+ offset
+ end
+ end
+ end
+end