Skip to content

Commit 2335f81

Browse files
committed
refactor: clean up style token code
1 parent add13a1 commit 2335f81

File tree

2 files changed

+207
-114
lines changed

2 files changed

+207
-114
lines changed

lib/src/parser.dart

Lines changed: 176 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -63,49 +63,129 @@ class ColorParser implements IReader<StringTokenValue> {
6363

6464
ColorToken _consumeStyleToken(ColorToken token) {
6565
// print('Consuming style token for $token');
66-
final color = _consumeUntil('m');
66+
final args = _consumeUntil('m');
6767
reader.read();
68+
token = _parseStyleToken(token, args.split(';'));
69+
return token;
70+
}
6871

69-
if (!color.contains(';')) {
70-
//single number color [30-37] / [40-47]
71-
// or [90-97] / [100-107], fg / bg
72-
// e.g. ^[40m
73-
// or just style ? e.g. ^[1m
74-
75-
// TODO: this seems to crash on ^[40m, don't understand exactly why
76-
// doesn't seem to be the 40m, that one gets interpreted well (black bg)
77-
78-
int colorValue = -1;
79-
try {
80-
colorValue = int.parse(color);
81-
} on FormatException {
82-
// ignore, then??
83-
// print("failing color= " + color);
84-
// TODO: it keeps logging thousands of empty "failing colors" ?
85-
}
86-
if (colorValue > -1) { // init safely, ignore if nothing ?
87-
if ((30 <= colorValue) && (colorValue <= 37) ||
88-
(90 <= colorValue) && (colorValue <= 97)) {
89-
token.fgColor = colorValue;
90-
} else if ((40 <= colorValue) && (colorValue <= 47) ||
91-
(100 <= colorValue) && (colorValue <= 107)) {
92-
token.bgColor = colorValue;
93-
} else if (colorValue < 30) { // style ?
94-
token.setStyle(colorValue);
72+
ColorToken _parseStyleToken(ColorToken token, List<String> colors) {
73+
final colorNums = colors.map((n) => int.parse(n)).toList();
74+
// Special cases
75+
if (_checkPair(colorNums, 38, 2) || _checkPair(colors, 48, 2)) {
76+
// RGB format is 38;2;R;G;B or 48;2;R;G;B
77+
token = _consumeRgbToken(token, colors);
78+
colors.removeRange(0, 5);
79+
} else if (_checkPair(colorNums, 38, 5) || _checkPair(colorNums, 48, 5)) {
80+
// Xterm256 format is 38;5;N or 48;5;N
81+
token = _consumeXterm256Token(token, colors);
82+
colors.removeRange(0, 3);
83+
} else {
84+
// Other style codes
85+
for (var color in colorNums) {
86+
if (color < 30) {
87+
token.setStyle(color);
88+
} else if (_checkBetween(color, 30, 37) ||
89+
_checkBetween(color, 90, 97)) {
90+
token.fgColor = color;
91+
if (_checkBetween(color, 90, 97)) {
92+
token.brightFg = true;
93+
}
94+
} else if (_checkBetween(color, 40, 47) ||
95+
_checkBetween(color, 100, 107)) {
96+
token.bgColor = color;
97+
if (_checkBetween(color, 100, 107)) {
98+
token.brightBg = true;
99+
}
95100
}
101+
colors.removeAt(0);
96102
}
97103
}
98-
// things like ^[1;38;2;114;150;50;48;2;125;70;22m TEXT ^[0m
99-
else { // multi number madness, trying recursive parser ?
100-
final colors = color.split(';');
101-
processTokenStyle(colors, token); //really hope this works by reference
104+
105+
if (colors.isNotEmpty) {
106+
token = _parseStyleToken(token, colors);
102107
}
103-
if (reader.peek() == Consts.esc) {
104-
return _consumeEscSequence(token);
108+
109+
return token;
110+
}
111+
112+
ColorToken _consumeRgbToken(ColorToken token, List<String> colors) {
113+
final rgb = '${colors[2]};${colors[3]};${colors[4]}';
114+
if (colors[0] == '38') {
115+
token.rgbFg = true;
116+
token.rgbFgColor = rgb;
117+
} else if (colors[0] == '48') {
118+
token.rgbBg = true;
119+
token.rgbBgColor = rgb;
120+
}
121+
return token;
122+
}
123+
124+
ColorToken _consumeXterm256Token(ColorToken token, List<String> colors) {
125+
final color = int.parse(colors[2]);
126+
if (colors[0] == '38') {
127+
token.xterm256 = true;
128+
token.fgColor = color;
129+
} else if (colors[0] == '48') {
130+
token.xterm256 = true;
131+
token.bgColor = color;
105132
}
106133
return token;
107134
}
108135

136+
bool _checkPair<T>(List<T> arr, T v1, T v2) {
137+
return arr.length > 1 && arr[0] == v1 && arr[1] == v2;
138+
}
139+
140+
bool _checkBetween<T extends num>(T value, T min, T max) {
141+
return min <= value && value <= max;
142+
}
143+
144+
// ColorToken _consumeStyleToken(ColorToken token) {
145+
// // print('Consuming style token for $token');
146+
// final color = _consumeUntil('m');
147+
// reader.read();
148+
//
149+
// if (!color.contains(';')) {
150+
// //single number color [30-37] / [40-47]
151+
// // or [90-97] / [100-107], fg / bg
152+
// // e.g. ^[40m
153+
// // or just style ? e.g. ^[1m
154+
//
155+
// // TODO: this seems to crash on ^[40m, don't understand exactly why
156+
// // doesn't seem to be the 40m, that one gets interpreted well (black bg)
157+
//
158+
// int colorValue = -1;
159+
// try {
160+
// colorValue = int.parse(color);
161+
// } on FormatException {
162+
// // ignore, then??
163+
// // print("failing color= " + color);
164+
// // TODO: it keeps logging thousands of empty "failing colors" ?
165+
// }
166+
// if (colorValue > -1) { // init safely, ignore if nothing ?
167+
// if ((30 <= colorValue) && (colorValue <= 37) ||
168+
// (90 <= colorValue) && (colorValue <= 97)) {
169+
// token.fgColor = colorValue;
170+
// } else if ((40 <= colorValue) && (colorValue <= 47) ||
171+
// (100 <= colorValue) && (colorValue <= 107)) {
172+
// token.bgColor = colorValue;
173+
// } else if (colorValue < 30) { // style ?
174+
// token.setStyle(colorValue);
175+
// }
176+
// }
177+
// }
178+
// // things like ^[1;38;2;114;150;50;48;2;125;70;22m TEXT ^[0m
179+
// else { // multi number madness, trying recursive parser ?
180+
// final colors = color.split(';');
181+
// processTokenStyle(colors, token); //really hope this works by reference
182+
// }
183+
// if (reader.peek() == Consts.esc) {
184+
// return _consumeEscSequence(token);
185+
// }
186+
// return token;
187+
// }
188+
109189
ColorToken _consumeText(ColorToken token) {
110190
// print('Consuming text for $token');
111191
token.text += _consumeUntil(Consts.esc);
@@ -155,62 +235,69 @@ class ColorParser implements IReader<StringTokenValue> {
155235
return result;
156236
}
157237

158-
processTokenStyle(List<String> colors, ColorToken token){
159-
if (colors.isNotEmpty) { //if it's already empty, do nothing more
160-
int first = int.parse(colors[0]);
161-
if (first < 30) { // bold, underline, etc?
162-
token.setStyle(first);
163-
colors.removeAt(0);
164-
} else if((30 <= first) && (first <= 37) || (90 <= first) && (first <= 97) ||
165-
(40 <= first) && (first <= 47) || (100 <= first) && (first <= 107)){
166-
if((30 <= first) && (first <= 37) || (90 <= first) && (first <= 97)) {
167-
token.fgColor = first ;
168-
colors.removeAt(0);
169-
}else if((40 <= first) && (first <= 47) || (100 <= first) && (first <= 107)) {
170-
token.bgColor = first;
171-
colors.removeAt(0);
172-
}
173-
}else {
174-
int second = int.parse(colors[1]);
175-
if (first == 38 && second == 5) {
176-
token.xterm256 = true;
177-
int third = int.parse(colors[2]);
178-
token.fgColor = third;
179-
colors.removeRange(0, 3);
180-
// bg = 0;
181-
} else if (first == 48 && second == 5) {
182-
token.xterm256 = true;
183-
int third = int.parse(colors[2]);
184-
token.bgColor = third;
185-
colors.removeRange(0, 3);
186-
// bg = 0;
187-
} else {
188-
if (first == 38 && second == 2) { //rgb
189-
String red = colors[2];
190-
String green = colors[3];
191-
String blue = colors[4];
192-
token.rgbFg = true;
193-
token.rgbFgColor = "$red;$green;$blue";
194-
colors.removeRange(0, 5);
195-
} else if (first == 48 && second == 2) { //rgb
196-
String red = colors[2];
197-
String green = colors[3];
198-
String blue = colors[4];
199-
token.rgbBg = true;
200-
token.rgbBgColor = "$red;$green;$blue";
201-
colors.removeRange(0, 5);
202-
}
203-
else {
204-
return;
205-
}
206-
}
207-
}
208-
//pass the rest of the color codes, hope for the best
209-
if(colors.isNotEmpty) {
210-
processTokenStyle(colors, token); // really really hoping these go by reference
211-
}
212-
}
213-
}
238+
// processTokenStyle(List<String> colors, ColorToken token) {
239+
// if (colors.isNotEmpty) {
240+
// //if it's already empty, do nothing more
241+
// int first = int.parse(colors[0]);
242+
// if (first < 30) {
243+
// // bold, underline, etc?
244+
// token.setStyle(first);
245+
// colors.removeAt(0);
246+
// } else if ((30 <= first) && (first <= 37) ||
247+
// (90 <= first) && (first <= 97) ||
248+
// (40 <= first) && (first <= 47) ||
249+
// (100 <= first) && (first <= 107)) {
250+
// if ((30 <= first) && (first <= 37) || (90 <= first) && (first <= 97)) {
251+
// token.fgColor = first;
252+
// colors.removeAt(0);
253+
// } else if ((40 <= first) && (first <= 47) ||
254+
// (100 <= first) && (first <= 107)) {
255+
// token.bgColor = first;
256+
// colors.removeAt(0);
257+
// }
258+
// } else {
259+
// int second = int.parse(colors[1]);
260+
// if (first == 38 && second == 5) {
261+
// token.xterm256 = true;
262+
// int third = int.parse(colors[2]);
263+
// token.fgColor = third;
264+
// colors.removeRange(0, 3);
265+
// // bg = 0;
266+
// } else if (first == 48 && second == 5) {
267+
// token.xterm256 = true;
268+
// int third = int.parse(colors[2]);
269+
// token.bgColor = third;
270+
// colors.removeRange(0, 3);
271+
// // bg = 0;
272+
// } else {
273+
// if (first == 38 && second == 2) {
274+
// //rgb
275+
// String red = colors[2];
276+
// String green = colors[3];
277+
// String blue = colors[4];
278+
// token.rgbFg = true;
279+
// token.rgbFgColor = "$red;$green;$blue";
280+
// colors.removeRange(0, 5);
281+
// } else if (first == 48 && second == 2) {
282+
// //rgb
283+
// String red = colors[2];
284+
// String green = colors[3];
285+
// String blue = colors[4];
286+
// token.rgbBg = true;
287+
// token.rgbBgColor = "$red;$green;$blue";
288+
// colors.removeRange(0, 5);
289+
// } else {
290+
// return;
291+
// }
292+
// }
293+
// }
294+
// //pass the rest of the color codes, hope for the best
295+
// if (colors.isNotEmpty) {
296+
// processTokenStyle(
297+
// colors, token); // really really hoping these go by reference
298+
// }
299+
// }
300+
// }
214301

215302
// ignore: unused_element
216303
_debugString(String string) => string.replaceAll('\x1B', '\\x1B');

0 commit comments

Comments
 (0)