58 lines
1.8 KiB
Ruby
58 lines
1.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Gitlab
|
|
module Diff
|
|
class PairSelector
|
|
include Enumerable
|
|
|
|
# Regex to find a run of deleted lines followed by the same number of added lines
|
|
# rubocop: disable Lint/MixedRegexpCaptureTypes
|
|
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)
|
|
|
|
# This matches a number of `-`s followed by the same number of `+`s through recursion
|
|
(?<del_ins>
|
|
-
|
|
\g<del_ins>?
|
|
\+
|
|
)
|
|
|
|
# Runs end at the end of the string (the last line) or before a space (for an unchanged line)
|
|
(?=\s|\z)
|
|
}x.freeze
|
|
# rubocop: enable Lint/MixedRegexpCaptureTypes
|
|
|
|
def initialize(lines)
|
|
@lines = lines
|
|
end
|
|
|
|
# Finds pairs of old/new line pairs that represent the same line that changed
|
|
# rubocop: disable CodeReuse/ActiveRecord
|
|
def each
|
|
# Prefixes of all diff lines, indicating their types
|
|
# For example: `" - + -+ ---+++ --+ -++"`
|
|
line_prefixes = lines.each_with_object(+"") { |line, s| s << (line[0] || ' ') }.gsub(/[^ +-]/, ' ')
|
|
|
|
line_prefixes.scan(LINE_PAIRS_PATTERN) 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
|
|
yield [i, i + changed_line_count]
|
|
end
|
|
end
|
|
end
|
|
# rubocop: enable CodeReuse/ActiveRecord
|
|
|
|
private
|
|
|
|
attr_reader :lines
|
|
end
|
|
end
|
|
end
|