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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
|
# frozen_string_literal: true
# This Parser translates ANSI escape codes into human readable format.
# It considers color and format changes.
# Inspired by http://en.wikipedia.org/wiki/ANSI_escape_code
module Gitlab
module Ci
module Ansi2json
class Parser
# keys represent the trailing digit in color changing command (30-37, 40-47, 90-97. 100-107)
COLOR = {
0 => 'black', # Note: This is gray in the intense color table.
1 => 'red',
2 => 'green',
3 => 'yellow',
4 => 'blue',
5 => 'magenta',
6 => 'cyan',
7 => 'white' # Note: This is gray in the dark (aka default) color table.
}.freeze
STYLE_SWITCHES = {
bold: 0x01,
italic: 0x02,
underline: 0x04,
conceal: 0x08,
cross: 0x10
}.freeze
def self.bold?(mask)
mask & STYLE_SWITCHES[:bold] != 0
end
def self.matching_formats(mask)
formats = []
STYLE_SWITCHES.each do |text_format, flag|
formats << "term-#{text_format}" if mask & flag != 0
end
formats
end
def initialize(command, ansi_stack = nil)
@command = command
@ansi_stack = ansi_stack
end
def changes
if self.respond_to?("on_#{@command}")
send("on_#{@command}", @ansi_stack) # rubocop:disable GitlabSecurity/PublicSend
end
end
# rubocop:disable Style/SingleLineMethods
def on_0(_) { reset: true } end
def on_1(_) { enable: STYLE_SWITCHES[:bold] } end
def on_3(_) { enable: STYLE_SWITCHES[:italic] } end
def on_4(_) { enable: STYLE_SWITCHES[:underline] } end
def on_8(_) { enable: STYLE_SWITCHES[:conceal] } end
def on_9(_) { enable: STYLE_SWITCHES[:cross] } end
def on_21(_) { disable: STYLE_SWITCHES[:bold] } end
def on_22(_) { disable: STYLE_SWITCHES[:bold] } end
def on_23(_) { disable: STYLE_SWITCHES[:italic] } end
def on_24(_) { disable: STYLE_SWITCHES[:underline] } end
def on_28(_) { disable: STYLE_SWITCHES[:conceal] } end
def on_29(_) { disable: STYLE_SWITCHES[:cross] } end
def on_30(_) { fg: fg_color(0) } end
def on_31(_) { fg: fg_color(1) } end
def on_32(_) { fg: fg_color(2) } end
def on_33(_) { fg: fg_color(3) } end
def on_34(_) { fg: fg_color(4) } end
def on_35(_) { fg: fg_color(5) } end
def on_36(_) { fg: fg_color(6) } end
def on_37(_) { fg: fg_color(7) } end
def on_38(stack) { fg: fg_color_256(stack) } end
def on_39(_) { fg: nil } end
def on_40(_) { bg: bg_color(0) } end
def on_41(_) { bg: bg_color(1) } end
def on_42(_) { bg: bg_color(2) } end
def on_43(_) { bg: bg_color(3) } end
def on_44(_) { bg: bg_color(4) } end
def on_45(_) { bg: bg_color(5) } end
def on_46(_) { bg: bg_color(6) } end
def on_47(_) { bg: bg_color(7) } end
def on_48(stack) { bg: bg_color_256(stack) } end
def on_49(_) { bg: nil } end
def on_90(_) { fg: fg_color(0, 'l') } end
def on_91(_) { fg: fg_color(1, 'l') } end
def on_92(_) { fg: fg_color(2, 'l') } end
def on_93(_) { fg: fg_color(3, 'l') } end
def on_94(_) { fg: fg_color(4, 'l') } end
def on_95(_) { fg: fg_color(5, 'l') } end
def on_96(_) { fg: fg_color(6, 'l') } end
def on_97(_) { fg: fg_color(7, 'l') } end
def on_99(_) { fg: fg_color(9, 'l') } end
def on_100(_) { fg: bg_color(0, 'l') } end
def on_101(_) { fg: bg_color(1, 'l') } end
def on_102(_) { fg: bg_color(2, 'l') } end
def on_103(_) { fg: bg_color(3, 'l') } end
def on_104(_) { fg: bg_color(4, 'l') } end
def on_105(_) { fg: bg_color(5, 'l') } end
def on_106(_) { fg: bg_color(6, 'l') } end
def on_107(_) { fg: bg_color(7, 'l') } end
def on_109(_) { fg: bg_color(9, 'l') } end
# rubocop:enable Style/SingleLineMethods
def fg_color(color_index, prefix = nil)
term_color_class(color_index, ['fg', prefix])
end
def fg_color_256(command_stack)
xterm_color_class(command_stack, 'fg')
end
def bg_color(color_index, prefix = nil)
term_color_class(color_index, ['bg', prefix])
end
def bg_color_256(command_stack)
xterm_color_class(command_stack, 'bg')
end
def term_color_class(color_index, prefix)
color_name = COLOR[color_index]
return if color_name.nil?
color_class(['term', prefix, color_name])
end
def xterm_color_class(command_stack, prefix)
# the 38 and 48 commands have to be followed by "5" and the color index
return unless command_stack.length >= 2
return unless command_stack[0] == "5"
command_stack.shift # ignore the "5" command
color_index = command_stack.shift.to_i
return unless color_index >= 0
return unless color_index <= 255
color_class(["xterm", prefix, color_index])
end
def color_class(segments)
[segments].flatten.compact.join('-')
end
end
end
end
end
|