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
|
# frozen_string_literal: true
module Gitlab
module Diff
class Line
# When SERIALIZE_KEYS is updated, to reset the redis cache entries you'll
# need to bump the VERSION constant on Gitlab::Diff::HighlightCache
#
SERIALIZE_KEYS = %i(line_code rich_text text type index old_pos new_pos).freeze
attr_reader :marker_ranges
attr_writer :text, :rich_text, :discussable
attr_accessor :index, :type, :old_pos, :new_pos, :line_code
def initialize(text, type, index, old_pos, new_pos, parent_file: nil, line_code: nil, rich_text: nil)
@text = text
@type = type
@index = index
@old_pos = old_pos
@new_pos = new_pos
@parent_file = parent_file
@rich_text = rich_text
# When line code is not provided from cache store we build it
# using the parent_file(Diff::File or Conflict::File).
@line_code = line_code || calculate_line_code
@marker_ranges = []
@discussable = true
end
def self.init_from_hash(hash)
new(hash[:text],
hash[:type],
hash[:index],
hash[:old_pos],
hash[:new_pos],
parent_file: hash[:parent_file],
line_code: hash[:line_code],
rich_text: hash[:rich_text])
end
def self.safe_init_from_hash(hash)
line = hash.with_indifferent_access
rich_text = line[:rich_text]
line[:rich_text] = rich_text&.html_safe
init_from_hash(line)
end
def to_hash
hash = {}
SERIALIZE_KEYS.each { |key| hash[key] = send(key) } # rubocop:disable GitlabSecurity/PublicSend
hash
end
def set_marker_ranges(marker_ranges)
@marker_ranges = marker_ranges
end
def text(prefix: true)
return @text if prefix
@text&.slice(1..).to_s
end
def old_line
old_pos unless added? || meta?
end
def new_line
new_pos unless removed? || meta?
end
def line
new_line || old_line
end
def unchanged?
type.nil?
end
def added?
%w[new new-nonewline].include?(type)
end
def removed?
%w[old old-nonewline].include?(type)
end
def meta?
%w[match new-nonewline old-nonewline].include?(type)
end
def match?
type == :match
end
def discussable?
@discussable && !meta?
end
def suggestible?
!removed?
end
def rich_text
@parent_file.try(:highlight_lines!) if @parent_file && !@rich_text
@rich_text
end
def meta_positions
return unless meta?
{
old_pos: old_pos,
new_pos: new_pos
}
end
# We have to keep this here since it is still used for conflict resolution
# Conflict::File#as_json renders json diff lines in sections
def as_json(opts = nil)
DiffLineSerializer.new.represent(self)
end
private
def calculate_line_code
@parent_file&.line_code(self)
end
end
end
end
|