From f5cc3f63a8a6a44e755aa81ac6cba8e544b848e6 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Mon, 11 Jul 2016 00:08:01 -0500 Subject: Render inline diffs for multiple changed lines following eachother --- lib/gitlab/diff/inline_diff.rb | 52 ++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 14 deletions(-) (limited to 'lib/gitlab/diff') diff --git a/lib/gitlab/diff/inline_diff.rb b/lib/gitlab/diff/inline_diff.rb index 789c14518b0..72d9abeefcc 100644 --- a/lib/gitlab/diff/inline_diff.rb +++ b/lib/gitlab/diff/inline_diff.rb @@ -1,16 +1,30 @@ module Gitlab module Diff class InlineDiff + # Regex to find a run of deleted lines followed by the same number of added lines + REGEX = %r{ + # Runs start at the beginning of the string (the first line) or after a space (for an unchanged line) + (?:\A| ) + + # This matches a number of `-`s followed by the same number of `+`s through recursion + (? + - + \g? + \+ + ) + + # Runs end at the end of the string (the last line) or before a space (for an unchanged line) + (?= |\z) + }x.freeze + attr_accessor :old_line, :new_line, :offset def self.for_lines(lines) - local_edit_indexes = self.find_local_edits(lines) + changed_line_pairs = self.find_changed_line_pairs(lines) inline_diffs = [] - local_edit_indexes.each do |index| - old_index = index - new_index = index + 1 + changed_line_pairs.each do |old_index, new_index| old_line = lines[old_index] new_line = lines[new_index] @@ -51,18 +65,28 @@ module Gitlab private - def self.find_local_edits(lines) - line_prefixes = lines.map { |line| line.match(/\A([+-])/) ? $1 : ' ' } - 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 + # Finds pairs of old/new line pairs that represent the same line that changed + def self.find_changed_line_pairs(lines) + # Prefixes of all diff lines, indicating their types + # For example: `" - + -+ ---+++ --+ -++"` + line_prefixes = lines.each_with_object("") { |line, s| s << line[0] }.gsub(/[^ +-]/, ' ') + + changed_line_pairs = [] + line_prefixes.scan(REGEX) do + # For `"---+++"`, `begin_index == 0`, `end_index == 6` + begin_index, end_index = Regexp.last_match.offset(:del_ins) + + # For `"---+++"`, `changed_line_count == 3` + changed_line_count = (end_index - begin_index) / 2 + + halfway_index = begin_index + changed_line_count + (begin_index...halfway_index).each do |i| + # For `"---+++"`, index 1 maps to 1 + 3 = 4 + changed_line_pairs << [i, i + changed_line_count] + end end - local_edit_indexes + changed_line_pairs end def longest_common_prefix(a, b) -- cgit v1.2.3 From e981d6cd0d6b8ae7d2911a57a65751deaa9ec555 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 12 Jul 2016 11:25:39 -0500 Subject: Extended regexes ignore whitespace, so use \s --- lib/gitlab/diff/inline_diff.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/gitlab/diff') diff --git a/lib/gitlab/diff/inline_diff.rb b/lib/gitlab/diff/inline_diff.rb index 72d9abeefcc..4a3eb92b9fc 100644 --- a/lib/gitlab/diff/inline_diff.rb +++ b/lib/gitlab/diff/inline_diff.rb @@ -4,7 +4,7 @@ module Gitlab # Regex to find a run of deleted lines followed by the same number of added lines REGEX = %r{ # Runs start at the beginning of the string (the first line) or after a space (for an unchanged line) - (?:\A| ) + (?:\A|\s) # This matches a number of `-`s followed by the same number of `+`s through recursion (? @@ -14,7 +14,7 @@ module Gitlab ) # Runs end at the end of the string (the last line) or before a space (for an unchanged line) - (?= |\z) + (?=\s|\z) }x.freeze attr_accessor :old_line, :new_line, :offset -- cgit v1.2.3 From 489e1937043d6f58af28d11831ba6da94e90a705 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 13 Jul 2016 00:02:10 -0500 Subject: Rename constant to be more descriptive --- lib/gitlab/diff/inline_diff.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/gitlab/diff') diff --git a/lib/gitlab/diff/inline_diff.rb b/lib/gitlab/diff/inline_diff.rb index 4a3eb92b9fc..28ad637fda4 100644 --- a/lib/gitlab/diff/inline_diff.rb +++ b/lib/gitlab/diff/inline_diff.rb @@ -2,7 +2,7 @@ module Gitlab module Diff class InlineDiff # Regex to find a run of deleted lines followed by the same number of added lines - REGEX = %r{ + LINE_PAIRS_PATTERN = %r{ # Runs start at the beginning of the string (the first line) or after a space (for an unchanged line) (?:\A|\s) @@ -72,7 +72,7 @@ module Gitlab line_prefixes = lines.each_with_object("") { |line, s| s << line[0] }.gsub(/[^ +-]/, ' ') changed_line_pairs = [] - line_prefixes.scan(REGEX) do + line_prefixes.scan(LINE_PAIRS_PATTERN) do # For `"---+++"`, `begin_index == 0`, `end_index == 6` begin_index, end_index = Regexp.last_match.offset(:del_ins) -- cgit v1.2.3