Class: Gitlab::Diff::PairSelector

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/gitlab/diff/pair_selector.rb

Constant Summary collapse

LINE_PAIRS_PATTERN =

Regex to find a run of deleted lines followed by the same number of added lines rubocop: disable Lint/MixedRegexpCaptureTypes

%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

Instance Method Summary collapse

Constructor Details

#initialize(lines) ⇒ PairSelector

rubocop: enable Lint/MixedRegexpCaptureTypes


26
27
28
# File 'lib/gitlab/diff/pair_selector.rb', line 26

def initialize(lines)
  @lines = lines
end

Instance Method Details

#eachObject

Finds pairs of old/new line pairs that represent the same line that changed rubocop: disable CodeReuse/ActiveRecord


32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/gitlab/diff/pair_selector.rb', line 32

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