2012-07-02 16:34:25 -04:00
|
|
|
module Gitlab
|
|
|
|
class InlineDiff
|
|
|
|
class << self
|
|
|
|
|
|
|
|
START = "#!idiff-start!#"
|
|
|
|
FINISH = "#!idiff-finish!#"
|
2013-03-20 17:46:30 -04:00
|
|
|
|
2014-09-25 18:07:40 -04:00
|
|
|
def processing(diff_arr)
|
2012-07-02 16:34:25 -04:00
|
|
|
indexes = _indexes_of_changed_lines diff_arr
|
|
|
|
|
|
|
|
indexes.each do |index|
|
|
|
|
first_line = diff_arr[index+1]
|
|
|
|
second_line = diff_arr[index+2]
|
|
|
|
|
2013-09-04 11:15:42 -04:00
|
|
|
# Skip inline diff if empty line was replaced with content
|
|
|
|
next if first_line == "-\n"
|
|
|
|
|
2015-11-12 18:44:16 -05:00
|
|
|
first_token = find_first_token(first_line, second_line)
|
2015-11-12 19:07:33 -05:00
|
|
|
apply_first_token(diff_arr, index, first_token)
|
2013-09-04 11:15:42 -04:00
|
|
|
|
2015-11-12 18:44:16 -05:00
|
|
|
last_token = find_last_token(first_line, second_line, first_token)
|
2015-11-12 19:07:33 -05:00
|
|
|
apply_last_token(diff_arr, index, last_token)
|
2012-07-02 16:34:25 -04:00
|
|
|
end
|
2015-11-12 18:44:16 -05:00
|
|
|
|
2012-07-02 16:34:25 -04:00
|
|
|
diff_arr
|
|
|
|
end
|
|
|
|
|
2015-11-12 19:07:33 -05:00
|
|
|
def apply_first_token(diff_arr, index, first_token)
|
|
|
|
start = first_token + START
|
|
|
|
|
|
|
|
if first_token.empty?
|
|
|
|
# In case if we remove string of spaces in commit
|
|
|
|
diff_arr[index+1].sub!("-", "-" => "-#{START}")
|
|
|
|
diff_arr[index+2].sub!("+", "+" => "+#{START}")
|
|
|
|
else
|
|
|
|
diff_arr[index+1].sub!(first_token, first_token => start)
|
|
|
|
diff_arr[index+2].sub!(first_token, first_token => start)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def apply_last_token(diff_arr, index, last_token)
|
|
|
|
# This is tricky: escape backslashes so that `sub` doesn't interpret them
|
|
|
|
# as backreferences. Regexp.escape does NOT do the right thing.
|
|
|
|
replace_token = FINISH + last_token.gsub(/\\/, '\&\&')
|
|
|
|
diff_arr[index+1].sub!(/#{Regexp.escape(last_token)}$/, replace_token)
|
|
|
|
diff_arr[index+2].sub!(/#{Regexp.escape(last_token)}$/, replace_token)
|
|
|
|
end
|
|
|
|
|
2015-11-12 18:44:16 -05:00
|
|
|
def find_first_token(first_line, second_line)
|
|
|
|
max_length = [first_line.size, second_line.size].max
|
|
|
|
first_the_same_symbols = 0
|
|
|
|
|
|
|
|
(0..max_length + 1).each do |i|
|
|
|
|
first_the_same_symbols = i - 1
|
|
|
|
|
|
|
|
if first_line[i] != second_line[i] && i > 0
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
first_line[0..first_the_same_symbols][1..-1]
|
|
|
|
end
|
|
|
|
|
|
|
|
def find_last_token(first_line, second_line, first_token)
|
|
|
|
max_length = [first_line.size, second_line.size].max
|
|
|
|
last_the_same_symbols = 0
|
|
|
|
|
|
|
|
(1..max_length + 1).each do |i|
|
|
|
|
last_the_same_symbols = -i
|
|
|
|
shortest_line = second_line.size > first_line.size ? first_line : second_line
|
|
|
|
|
|
|
|
if (first_line[-i] != second_line[-i]) || "#{first_token}#{START}".size == shortest_line[1..-i].size
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
last_the_same_symbols += 1
|
|
|
|
first_line[last_the_same_symbols..-1]
|
|
|
|
end
|
|
|
|
|
2014-09-25 18:07:40 -04:00
|
|
|
def _indexes_of_changed_lines(diff_arr)
|
2012-07-02 16:34:25 -04:00
|
|
|
chain_of_first_symbols = ""
|
|
|
|
diff_arr.each_with_index do |line, i|
|
|
|
|
chain_of_first_symbols += line[0]
|
|
|
|
end
|
|
|
|
chain_of_first_symbols.gsub!(/[^\-\+]/, "#")
|
|
|
|
|
|
|
|
offset = 0
|
|
|
|
indexes = []
|
|
|
|
while index = chain_of_first_symbols.index("#-+#", offset)
|
|
|
|
indexes << index
|
|
|
|
offset = index + 1
|
|
|
|
end
|
|
|
|
indexes
|
|
|
|
end
|
|
|
|
|
2014-09-25 18:07:40 -04:00
|
|
|
def replace_markers(line)
|
2012-07-02 16:34:25 -04:00
|
|
|
line.gsub!(START, "<span class='idiff'>")
|
|
|
|
line.gsub!(FINISH, "</span>")
|
|
|
|
line
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|