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