summaryrefslogtreecommitdiff
path: root/lib/gitlab/diff/file.rb
blob: c6bf25b5874ca6fca9780891481d8d2a8288ed02 (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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
module Gitlab
  module Diff
    class File
      attr_reader :diff, :repository, :diff_refs

      delegate :new_file, :deleted_file, :renamed_file,
        :old_path, :new_path, :a_mode, :b_mode,
        :submodule?, :too_large?, :collapsed?, to: :diff, prefix: false

      def initialize(diff, repository:, diff_refs: nil)
        @diff = diff
        @repository = repository
        @diff_refs = diff_refs
      end

      def position(line)
        return unless diff_refs

        Position.new(
          old_path: old_path,
          new_path: new_path,
          old_line: line.old_line,
          new_line: line.new_line,
          diff_refs: diff_refs
        )
      end

      def line_code(line)
        return if line.meta?

        Gitlab::Diff::LineCode.generate(file_path, line.new_pos, line.old_pos)
      end

      def line_for_line_code(code)
        diff_lines.find { |line| line_code(line) == code }
      end

      def line_for_position(pos)
        diff_lines.find { |line| position(line) == pos }
      end

      def position_for_line_code(code)
        line = line_for_line_code(code)
        position(line) if line
      end

      def line_code_for_position(pos)
        line = line_for_position(pos)
        line_code(line) if line
      end

      def content_commit
        return unless diff_refs

        repository.commit(deleted_file ? old_ref : new_ref)
      end

      def old_content_commit
        return unless diff_refs

        repository.commit(old_ref)
      end

      def old_ref
        diff_refs.try(:base_sha)
      end

      def new_ref
        diff_refs.try(:head_sha)
      end

      attr_writer :highlighted_diff_lines

      # Array of Gitlab::Diff::Line objects
      def diff_lines
        @diff_lines ||= Gitlab::Diff::Parser.new.parse(raw_diff.each_line).to_a
      end

      def highlighted_diff_lines
        @highlighted_diff_lines ||= Gitlab::Diff::Highlight.new(self, repository: self.repository).highlight
      end

      # Array[<Hash>] with right/left keys that contains Gitlab::Diff::Line objects which text is hightlighted
      def parallel_diff_lines
        @parallel_diff_lines ||= Gitlab::Diff::ParallelDiff.new(self).parallelize
      end

      def mode_changed?
        a_mode && b_mode && a_mode != b_mode
      end

      def raw_diff
        diff.diff.to_s
      end

      def next_line(index)
        diff_lines[index + 1]
      end

      def prev_line(index)
        diff_lines[index - 1] if index > 0
      end

      def paths
        [old_path, new_path].compact
      end

      def file_path
        new_path.presence || old_path
      end

      def added_lines
        diff_lines.count(&:added?)
      end

      def removed_lines
        diff_lines.count(&:removed?)
      end

      def old_blob(commit = old_content_commit)
        return unless commit

        repository.blob_at(commit.id, old_path)
      end

      def blob(commit = content_commit)
        return unless commit

        repository.blob_at(commit.id, file_path)
      end

      def file_identifier
        "#{file_path}-#{new_file}-#{deleted_file}-#{renamed_file}"
      end
    end
  end
end