2016-01-15 10:02:48 -05:00
|
|
|
module Gitlab
|
|
|
|
module Diff
|
|
|
|
class InlineDiff
|
2016-01-29 13:37:17 -05:00
|
|
|
attr_accessor :old_line, :new_line, :offset
|
2016-01-15 10:02:48 -05:00
|
|
|
|
2016-01-29 13:37:17 -05:00
|
|
|
def self.for_lines(lines)
|
|
|
|
local_edit_indexes = self.find_local_edits(lines)
|
2016-01-15 10:02:48 -05:00
|
|
|
|
|
|
|
inline_diffs = []
|
|
|
|
|
|
|
|
local_edit_indexes.each do |index|
|
|
|
|
old_index = index
|
|
|
|
new_index = index + 1
|
2016-01-29 13:37:17 -05:00
|
|
|
old_line = lines[old_index]
|
|
|
|
new_line = lines[new_index]
|
2016-01-15 10:02:48 -05:00
|
|
|
|
2016-01-29 13:37:17 -05:00
|
|
|
old_diffs, new_diffs = new(old_line, new_line, offset: 1).inline_diffs
|
2016-01-15 10:02:48 -05:00
|
|
|
|
2016-01-29 13:37:17 -05:00
|
|
|
inline_diffs[old_index] = old_diffs
|
|
|
|
inline_diffs[new_index] = new_diffs
|
2016-01-15 10:02:48 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
inline_diffs
|
|
|
|
end
|
|
|
|
|
2016-01-29 13:37:17 -05:00
|
|
|
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
|
|
|
|
|
2016-01-15 10:02:48 -05:00
|
|
|
private
|
|
|
|
|
2016-01-29 13:37:17 -05:00
|
|
|
def self.find_local_edits(lines)
|
|
|
|
line_prefixes = lines.map { |line| line.match(/\A([+-])/) ? $1 : ' ' }
|
2016-01-15 10:02:48 -05:00
|
|
|
joined_line_prefixes = " #{line_prefixes.join} "
|
|
|
|
|
|
|
|
offset = 0
|
|
|
|
local_edit_indexes = []
|
|
|
|
while index = joined_line_prefixes.index(" -+ ", offset)
|
|
|
|
local_edit_indexes << index
|
|
|
|
offset = index + 1
|
|
|
|
end
|
|
|
|
|
|
|
|
local_edit_indexes
|
|
|
|
end
|
|
|
|
|
|
|
|
def longest_common_prefix(a, b)
|
|
|
|
max_length = [a.length, b.length].max
|
|
|
|
|
|
|
|
length = 0
|
|
|
|
(0..max_length - 1).each do |pos|
|
|
|
|
old_char = a[pos]
|
|
|
|
new_char = b[pos]
|
|
|
|
|
|
|
|
break if old_char != new_char
|
|
|
|
length += 1
|
|
|
|
end
|
|
|
|
|
|
|
|
length
|
|
|
|
end
|
|
|
|
|
|
|
|
def longest_common_suffix(a, b)
|
|
|
|
longest_common_prefix(a.reverse, b.reverse)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|