1
2
3
4
5
6 namespace System
7 {
8 public class delegate void ColorCharOutputMethod(Color.Constant textColor, Color.Constant backColor, int handle, uchar c);
9
10 [nodiscard]
11 public Result<bool> AnsiProcess(int handle, const string& text, const ColorCharOutputMethod& writeOutputChar)
12 {
13 if (handle == 1)
14 {
15 AnsiEngine.Out().Process(text, writeOutputChar);
16 }
17 else if (handle == 2)
18 {
19 AnsiEngine.Error().Process(text, writeOutputChar);
20 }
21 else
22 {
23 string errorMessage = "AnsiEngine: invalid handle value " + ToString(handle) + " (not 1 or 2)";
24 int errorId = AllocateError(errorMessage);
25 return Result<bool>(ErrorId(errorId));
26 }
27 return Result<bool>(true);
28 }
29
30 public class AnsiEngine : IOBase
31 {
32 static AnsiEngine() :
33 out(new AnsiEngine(1)),
34 error(new AnsiEngine(2))
35 {
36 }
37 public static AnsiEngine& Out()
38 {
39 return *out;
40 }
41 public static AnsiEngine& Error()
42 {
43 return *error;
44 }
45 public void Process(const string& text, const ColorCharOutputMethod& writeOutputChar)
46 {
47 for (char c : text)
48 {
49 Put(c, writeOutputChar);
50 }
51 }
52 public inline Color.Constant DefaultTextColor() const
53 {
54 return defaultTextColor;
55 }
56 public inline Color.Constant DefaultBackColor() const
57 {
58 return defaultBackColor;
59 }
60 public void SetDefaultTextColor(Color.Constant color)
61 {
62 defaultTextColor = color;
63 }
64 public void SetDefaultBackColor(Color.Constant color)
65 {
66 defaultBackColor = color;
67 }
68 private AnsiEngine(int handle_) : handle(handle_), state(0), unicodeEngine(),
69 defaultTextColor(Color.Constant.gray), defaultBackColor(Color.Constant.black),
70 currentTextColor(defaultTextColor), currentBackColor(defaultBackColor),
71 textColor(defaultTextColor), backColor(defaultBackColor)
72 {
73 }
74 private void Put(char c, const ColorCharOutputMethod& writeOutputChar)
75 {
76 switch (state)
77 {
78 case 0:
79 {
80 if (c == '\U0000001B')
81 {
82 state = 1;
83 }
84 else
85 {
86 Emit(c, writeOutputChar);
87 }
88 break;
89 }
90 case 1:
91 {
92 if (c == '[')
93 {
94 state = 2;
95 }
96 else if (c == '\U0000001B')
97 {
98 Emit('\U0000001B', writeOutputChar);
99 }
100 else
101 {
102 Emit('\U0000001B', writeOutputChar);
103 Emit(c, writeOutputChar);
104 state = 0;
105 }
106 break;
107 }
108 case 2:
109 {
110 switch (c)
111 {
112 case '3': state = 3; break;
113 case '9': state = 9; break;
114 case '4': state = 4; break;
115 case '1': state = 10; break;
116 case '0': state = 999; break;
117 default:
118 {
119 Emit('\U0000001B', writeOutputChar);
120 Emit('[', writeOutputChar);
121 Emit(c, writeOutputChar);
122 state = 0;
123 break;
124 }
125 }
126 break;
127 }
128 case 3:
129 {
130 switch (c)
131 {
132 case '0': currentTextColor = Color.Constant.black; state = 1000; break;
133 case '1': currentTextColor = Color.Constant.darkRed; state = 1001; break;
134 case '2': currentTextColor = Color.Constant.darkGreen; state = 1002; break;
135 case '3': currentTextColor = Color.Constant.darkYellow; state = 1003; break;
136 case '4': currentTextColor = Color.Constant.darkBlue; state = 1004; break;
137 case '5': currentTextColor = Color.Constant.darkGray; state = 1005; break;
138 case '6': currentTextColor = Color.Constant.darkCyan; state = 1006; break;
139 case '7': currentTextColor = Color.Constant.gray; state = 1007; break;
140 default:
141 {
142 Emit('\U0000001B', writeOutputChar);
143 Emit('[', writeOutputChar);
144 Emit('3', writeOutputChar);
145 Emit(c, writeOutputChar);
146 state = 0;
147 break;
148 }
149 }
150 break;
151 }
152 case 9:
153 {
154 switch (c)
155 {
156 case '1': currentTextColor = Color.Constant.red; state = 9001; break;
157 case '2': currentTextColor = Color.Constant.green; state = 9002; break;
158 case '3': currentTextColor = Color.Constant.yellow; state = 9003; break;
159 case '4': currentTextColor = Color.Constant.blue; state = 9004; break;
160 case '5': currentTextColor = Color.Constant.magenta; state = 9005; break;
161 case '6': currentTextColor = Color.Constant.cyan; state = 9006; break;
162 case '7': currentTextColor = Color.Constant.white; state = 9007; break;
163 default:
164 {
165 Emit('\U0000001B', writeOutputChar);
166 Emit('[', writeOutputChar);
167 Emit('9', writeOutputChar);
168 Emit(c, writeOutputChar);
169 state = 0;
170 break;
171 }
172 }
173 break;
174 }
175 case 4:
176 {
177 switch (c)
178 {
179 case '0': currentBackColor = Color.Constant.black; state = 4000; break;
180 case '1': currentBackColor = Color.Constant.darkRed; state = 4001; break;
181 case '2': currentBackColor = Color.Constant.darkGreen; state = 4002; break;
182 case '3': currentBackColor = Color.Constant.darkYellow; state = 4003; break;
183 case '4': currentBackColor = Color.Constant.darkBlue; state = 4004; break;
184 case '5': currentBackColor = Color.Constant.darkGray; state = 4005; break;
185 case '6': currentBackColor = Color.Constant.darkCyan; state = 4006; break;
186 case '7': currentBackColor = Color.Constant.gray; state = 4007; break;
187 default:
188 {
189 Emit('\U0000001B', writeOutputChar);
190 Emit('[', writeOutputChar);
191 Emit('4', writeOutputChar);
192 Emit(c, writeOutputChar);
193 state = 0;
194 break;
195 }
196 }
197 break;
198 }
199 case 10:
200 {
201 if (c == '0')
202 {
203 state = 100;
204 }
205 else
206 {
207 Emit('\U0000001B', writeOutputChar);
208 Emit('[', writeOutputChar);
209 Emit('1', writeOutputChar);
210 Emit(c, writeOutputChar);
211 state = 0;
212 }
213 break;
214 }
215 case 100:
216 {
217 switch (c)
218 {
219 case '1': currentBackColor = Color.Constant.red; state = 10001; break;
220 case '2': currentBackColor = Color.Constant.green; state = 10002; break;
221 case '3': currentBackColor = Color.Constant.yellow; state = 10003; break;
222 case '4': currentBackColor = Color.Constant.blue; state = 10004; break;
223 case '5': currentBackColor = Color.Constant.magenta; state = 10005; break;
224 case '6': currentBackColor = Color.Constant.cyan; state = 10006; break;
225 case '7': currentBackColor = Color.Constant.white; state = 10007; break;
226 default:
227 {
228 Emit('\U0000001B', writeOutputChar);
229 Emit('[', writeOutputChar);
230 Emit('1', writeOutputChar);
231 Emit('0', writeOutputChar);
232 Emit(c, writeOutputChar);
233 state = 0;
234 break;
235 }
236 }
237 break;
238 }
239 case 999:
240 {
241 if (c == 'm')
242 {
243 ResetAttributes();
244 }
245 else
246 {
247 Emit('\U0000001B', writeOutputChar);
248 Emit('[', writeOutputChar);
249 Emit('0', writeOutputChar);
250 Emit(c, writeOutputChar);
251 }
252 state = 0;
253 break;
254 }
255 case 1000:
256 {
257 if (c == 'm')
258 {
259 SetAttributes();
260 }
261 else
262 {
263 Emit('\U0000001B', writeOutputChar);
264 Emit('[', writeOutputChar);
265 Emit('3', writeOutputChar);
266 Emit('0', writeOutputChar);
267 Emit(c, writeOutputChar);
268 }
269 state = 0;
270 break;
271 }
272 case 1001:
273 {
274 if (c == 'm')
275 {
276 SetAttributes();
277 }
278 else
279 {
280 Emit('\U0000001B', writeOutputChar);
281 Emit('[', writeOutputChar);
282 Emit('3', writeOutputChar);
283 Emit('1', writeOutputChar);
284 Emit(c, writeOutputChar);
285 }
286 state = 0;
287 break;
288 }
289 case 1002:
290 {
291 if (c == 'm')
292 {
293 SetAttributes();
294 }
295 else
296 {
297 Emit('\U0000001B', writeOutputChar);
298 Emit('[', writeOutputChar);
299 Emit('3', writeOutputChar);
300 Emit('2', writeOutputChar);
301 Emit(c, writeOutputChar);
302 }
303 state = 0;
304 break;
305 }
306 case 1003:
307 {
308 if (c == 'm')
309 {
310 SetAttributes();
311 }
312 else
313 {
314 Emit('\U0000001B', writeOutputChar);
315 Emit('[', writeOutputChar);
316 Emit('3', writeOutputChar);
317 Emit('3', writeOutputChar);
318 Emit(c, writeOutputChar);
319 }
320 state = 0;
321 break;
322 }
323 case 1004:
324 {
325 if (c == 'm')
326 {
327 SetAttributes();
328 }
329 else
330 {
331 Emit('\U0000001B', writeOutputChar);
332 Emit('[', writeOutputChar);
333 Emit('3', writeOutputChar);
334 Emit('4', writeOutputChar);
335 Emit(c, writeOutputChar);
336 }
337 state = 0;
338 break;
339 }
340 case 1005:
341 {
342 if (c == 'm')
343 {
344 SetAttributes();
345 }
346 else
347 {
348 Emit('\U0000001B', writeOutputChar);
349 Emit('[', writeOutputChar);
350 Emit('3', writeOutputChar);
351 Emit('5', writeOutputChar);
352 Emit(c, writeOutputChar);
353 }
354 state = 0;
355 break;
356 }
357 case 1006:
358 {
359 if (c == 'm')
360 {
361 SetAttributes();
362 }
363 else
364 {
365 Emit('\U0000001B', writeOutputChar);
366 Emit('[', writeOutputChar);
367 Emit('3', writeOutputChar);
368 Emit('6', writeOutputChar);
369 Emit(c, writeOutputChar);
370 }
371 state = 0;
372 break;
373 }
374 case 1007:
375 {
376 if (c == 'm')
377 {
378 SetAttributes();
379 }
380 else
381 {
382 Emit('\U0000001B', writeOutputChar);
383 Emit('[', writeOutputChar);
384 Emit('3', writeOutputChar);
385 Emit('7', writeOutputChar);
386 Emit(c, writeOutputChar);
387 }
388 state = 0;
389 break;
390 }
391 case 9001:
392 {
393 if (c == 'm')
394 {
395 SetAttributes();
396 }
397 else
398 {
399 Emit('\U0000001B', writeOutputChar);
400 Emit('[', writeOutputChar);
401 Emit('9', writeOutputChar);
402 Emit('1', writeOutputChar);
403 Emit(c, writeOutputChar);
404 }
405 state = 0;
406 break;
407 }
408 case 9002:
409 {
410 if (c == 'm')
411 {
412 SetAttributes();
413 }
414 else
415 {
416 Emit('\U0000001B', writeOutputChar);
417 Emit('[', writeOutputChar);
418 Emit('9', writeOutputChar);
419 Emit('2', writeOutputChar);
420 Emit(c, writeOutputChar);
421 }
422 state = 0;
423 break;
424 }
425 case 9003:
426 {
427 if (c == 'm')
428 {
429 SetAttributes();
430 }
431 else
432 {
433 Emit('\U0000001B', writeOutputChar);
434 Emit('[', writeOutputChar);
435 Emit('9', writeOutputChar);
436 Emit('3', writeOutputChar);
437 Emit(c, writeOutputChar);
438 }
439 state = 0;
440 break;
441 }
442 case 9004:
443 {
444 if (c == 'm')
445 {
446 SetAttributes();
447 }
448 else
449 {
450 Emit('\U0000001B', writeOutputChar);
451 Emit('[', writeOutputChar);
452 Emit('9', writeOutputChar);
453 Emit('4', writeOutputChar);
454 Emit(c, writeOutputChar);
455 }
456 state = 0;
457 break;
458 }
459 case 9005:
460 {
461 if (c == 'm')
462 {
463 SetAttributes();
464 }
465 else
466 {
467 Emit('\U0000001B', writeOutputChar);
468 Emit('[', writeOutputChar);
469 Emit('9', writeOutputChar);
470 Emit('5', writeOutputChar);
471 Emit(c, writeOutputChar);
472 }
473 state = 0;
474 break;
475 }
476 case 9006:
477 {
478 if (c == 'm')
479 {
480 SetAttributes();
481 }
482 else
483 {
484 Emit('\U0000001B', writeOutputChar);
485 Emit('[', writeOutputChar);
486 Emit('9', writeOutputChar);
487 Emit('6', writeOutputChar);
488 Emit(c, writeOutputChar);
489 }
490 state = 0;
491 break;
492 }
493 case 9007:
494 {
495 if (c == 'm')
496 {
497 SetAttributes();
498 }
499 else
500 {
501 Emit('\U0000001B', writeOutputChar);
502 Emit('[', writeOutputChar);
503 Emit('9', writeOutputChar);
504 Emit('7', writeOutputChar);
505 Emit(c, writeOutputChar);
506 }
507 state = 0;
508 break;
509 }
510 case 4000:
511 {
512 if (c == 'm')
513 {
514 SetAttributes();
515 }
516 else
517 {
518 Emit('\U0000001B', writeOutputChar);
519 Emit('[', writeOutputChar);
520 Emit('4', writeOutputChar);
521 Emit('0', writeOutputChar);
522 Emit(c, writeOutputChar);
523 }
524 state = 0;
525 break;
526 }
527 case 4001:
528 {
529 if (c == 'm')
530 {
531 SetAttributes();
532 }
533 else
534 {
535 Emit('\U0000001B', writeOutputChar);
536 Emit('[', writeOutputChar);
537 Emit('4', writeOutputChar);
538 Emit('1', writeOutputChar);
539 Emit(c, writeOutputChar);
540 }
541 state = 0;
542 break;
543 }
544 case 4002:
545 {
546 if (c == 'm')
547 {
548 SetAttributes();
549 }
550 else
551 {
552 Emit('\U0000001B', writeOutputChar);
553 Emit('[', writeOutputChar);
554 Emit('4', writeOutputChar);
555 Emit('2', writeOutputChar);
556 Emit(c, writeOutputChar);
557 }
558 state = 0;
559 break;
560 }
561 case 4003:
562 {
563 if (c == 'm')
564 {
565 SetAttributes();
566 }
567 else
568 {
569 Emit('\U0000001B', writeOutputChar);
570 Emit('[', writeOutputChar);
571 Emit('4', writeOutputChar);
572 Emit('3', writeOutputChar);
573 Emit(c, writeOutputChar);
574 }
575 state = 0;
576 break;
577 }
578 case 4004:
579 {
580 if (c == 'm')
581 {
582 SetAttributes();
583 }
584 else
585 {
586 Emit('\U0000001B', writeOutputChar);
587 Emit('[', writeOutputChar);
588 Emit('4', writeOutputChar);
589 Emit('4', writeOutputChar);
590 Emit(c, writeOutputChar);
591 }
592 state = 0;
593 break;
594 }
595 case 4005:
596 {
597 if (c == 'm')
598 {
599 SetAttributes();
600 }
601 else
602 {
603 Emit('\U0000001B', writeOutputChar);
604 Emit('[', writeOutputChar);
605 Emit('4', writeOutputChar);
606 Emit('5', writeOutputChar);
607 Emit(c, writeOutputChar);
608 }
609 state = 0;
610 break;
611 }
612 case 4006:
613 {
614 if (c == 'm')
615 {
616 SetAttributes();
617 }
618 else
619 {
620 Emit('\U0000001B', writeOutputChar);
621 Emit('[', writeOutputChar);
622 Emit('4', writeOutputChar);
623 Emit('6', writeOutputChar);
624 Emit(c, writeOutputChar);
625 }
626 state = 0;
627 break;
628 }
629 case 4007:
630 {
631 if (c == 'm')
632 {
633 SetAttributes();
634 }
635 else
636 {
637 Emit('\U0000001B', writeOutputChar);
638 Emit('[', writeOutputChar);
639 Emit('4', writeOutputChar);
640 Emit('7', writeOutputChar);
641 Emit(c, writeOutputChar);
642 }
643 state = 0;
644 break;
645 }
646 case 10001:
647 {
648 if (c == 'm')
649 {
650 SetAttributes();
651 }
652 else
653 {
654 Emit('\U0000001B', writeOutputChar);
655 Emit('[', writeOutputChar);
656 Emit('1', writeOutputChar);
657 Emit('0', writeOutputChar);
658 Emit('1', writeOutputChar);
659 Emit(c, writeOutputChar);
660 }
661 state = 0;
662 break;
663 }
664 case 10002:
665 {
666 if (c == 'm')
667 {
668 SetAttributes();
669 }
670 else
671 {
672 Emit('\U0000001B', writeOutputChar);
673 Emit('[', writeOutputChar);
674 Emit('1', writeOutputChar);
675 Emit('0', writeOutputChar);
676 Emit('2', writeOutputChar);
677 Emit(c, writeOutputChar);
678 }
679 state = 0;
680 break;
681 }
682 case 10003:
683 {
684 if (c == 'm')
685 {
686 SetAttributes();
687 }
688 else
689 {
690 Emit('\U0000001B', writeOutputChar);
691 Emit('[', writeOutputChar);
692 Emit('1', writeOutputChar);
693 Emit('0', writeOutputChar);
694 Emit('3', writeOutputChar);
695 Emit(c, writeOutputChar);
696 }
697 state = 0;
698 break;
699 }
700 case 10004:
701 {
702 if (c == 'm')
703 {
704 SetAttributes();
705 }
706 else
707 {
708 Emit('\U0000001B', writeOutputChar);
709 Emit('[', writeOutputChar);
710 Emit('1', writeOutputChar);
711 Emit('0', writeOutputChar);
712 Emit('4', writeOutputChar);
713 Emit(c, writeOutputChar);
714 }
715 state = 0;
716 break;
717 }
718 case 10005:
719 {
720 if (c == 'm')
721 {
722 SetAttributes();
723 }
724 else
725 {
726 Emit('\U0000001B', writeOutputChar);
727 Emit('[', writeOutputChar);
728 Emit('1', writeOutputChar);
729 Emit('0', writeOutputChar);
730 Emit('5', writeOutputChar);
731 Emit(c, writeOutputChar);
732 }
733 state = 0;
734 break;
735 }
736 case 10006:
737 {
738 if (c == 'm')
739 {
740 SetAttributes();
741 }
742 else
743 {
744 Emit('\U0000001B', writeOutputChar);
745 Emit('[', writeOutputChar);
746 Emit('1', writeOutputChar);
747 Emit('0', writeOutputChar);
748 Emit('6', writeOutputChar);
749 Emit(c, writeOutputChar);
750 }
751 state = 0;
752 break;
753 }
754 case 10007:
755 {
756 if (c == 'm')
757 {
758 SetAttributes();
759 }
760 else
761 {
762 Emit('\U0000001B', writeOutputChar);
763 Emit('[', writeOutputChar);
764 Emit('1', writeOutputChar);
765 Emit('0', writeOutputChar);
766 Emit('7', writeOutputChar);
767 Emit(c, writeOutputChar);
768 }
769 state = 0;
770 break;
771 }
772 }
773 }
774 private void Emit(char c, const ColorCharOutputMethod& writeOutputChar)
775 {
776 auto result = unicodeEngine.Put(cast<byte>(c));
777 if (result.Error())
778 {
779 SetErrorId(result.GetErrorId());
780 return;
781 }
782 if (unicodeEngine.ResultReady())
783 {
784 writeOutputChar(textColor, backColor, handle, unicodeEngine.Get());
785 }
786 }
787 private void SetAttributes()
788 {
789 textColor = currentTextColor;
790 backColor = currentBackColor;
791 }
792 private void ResetAttributes()
793 {
794 textColor = defaultTextColor;
795 backColor = defaultBackColor;
796 }
797 private static UniquePtr<AnsiEngine> out;
798 private static UniquePtr<AnsiEngine> error;
799 private int handle;
800 private int state;
801 private System.Unicode.UnicodeEngine unicodeEngine;
802 private Color.Constant defaultTextColor;
803 private Color.Constant defaultBackColor;
804 private Color.Constant currentTextColor;
805 private Color.Constant currentBackColor;
806 private Color.Constant textColor;
807 private Color.Constant backColor;
808 }