Welcome to mirror list, hosted at ThFree Co, Russian Federation.

pair_selector.rb « diff « gitlab « lib - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 2e5ee3a736329b817be6b2b58bd01e2e6759a802 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# 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