1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.fusesource.jansi;
20
21 import java.util.ArrayList;
22
23
24
25
26
27
28
29
30
31 @SuppressWarnings("unused")
32 public class Ansi implements Appendable {
33
34 private static final char FIRST_ESC_CHAR = 27;
35 private static final char SECOND_ESC_CHAR = '[';
36
37
38
39
40 public enum Color {
41 BLACK(0, "BLACK"),
42 RED(1, "RED"),
43 GREEN(2, "GREEN"),
44 YELLOW(3, "YELLOW"),
45 BLUE(4, "BLUE"),
46 MAGENTA(5, "MAGENTA"),
47 CYAN(6, "CYAN"),
48 WHITE(7, "WHITE"),
49 DEFAULT(9, "DEFAULT");
50
51 private final int value;
52 private final String name;
53
54 Color(int index, String name) {
55 this.value = index;
56 this.name = name;
57 }
58
59 @Override
60 public String toString() {
61 return name;
62 }
63
64 public int value() {
65 return value;
66 }
67
68 public int fg() {
69 return value + 30;
70 }
71
72 public int bg() {
73 return value + 40;
74 }
75
76 public int fgBright() {
77 return value + 90;
78 }
79
80 public int bgBright() {
81 return value + 100;
82 }
83 }
84
85
86
87
88
89
90 public enum Attribute {
91 RESET(0, "RESET"),
92 INTENSITY_BOLD(1, "INTENSITY_BOLD"),
93 INTENSITY_FAINT(2, "INTENSITY_FAINT"),
94 ITALIC(3, "ITALIC_ON"),
95 UNDERLINE(4, "UNDERLINE_ON"),
96 BLINK_SLOW(5, "BLINK_SLOW"),
97 BLINK_FAST(6, "BLINK_FAST"),
98 NEGATIVE_ON(7, "NEGATIVE_ON"),
99 CONCEAL_ON(8, "CONCEAL_ON"),
100 STRIKETHROUGH_ON(9, "STRIKETHROUGH_ON"),
101 UNDERLINE_DOUBLE(21, "UNDERLINE_DOUBLE"),
102 INTENSITY_BOLD_OFF(22, "INTENSITY_BOLD_OFF"),
103 ITALIC_OFF(23, "ITALIC_OFF"),
104 UNDERLINE_OFF(24, "UNDERLINE_OFF"),
105 BLINK_OFF(25, "BLINK_OFF"),
106 NEGATIVE_OFF(27, "NEGATIVE_OFF"),
107 CONCEAL_OFF(28, "CONCEAL_OFF"),
108 STRIKETHROUGH_OFF(29, "STRIKETHROUGH_OFF");
109
110 private final int value;
111 private final String name;
112
113 Attribute(int index, String name) {
114 this.value = index;
115 this.name = name;
116 }
117
118 @Override
119 public String toString() {
120 return name;
121 }
122
123 public int value() {
124 return value;
125 }
126 }
127
128
129
130
131
132
133
134 public enum Erase {
135 FORWARD(0, "FORWARD"),
136 BACKWARD(1, "BACKWARD"),
137 ALL(2, "ALL");
138
139 private final int value;
140 private final String name;
141
142 Erase(int index, String name) {
143 this.value = index;
144 this.name = name;
145 }
146
147 @Override
148 public String toString() {
149 return name;
150 }
151
152 public int value() {
153 return value;
154 }
155 }
156
157 @FunctionalInterface
158 public interface Consumer {
159 void apply(Ansi ansi);
160 }
161
162 public static boolean isEnabled() {
163 return org.apache.maven.jline.MessageUtils.isColorEnabled() && org.jline.jansi.Ansi.isEnabled();
164 }
165
166 public static void setEnabled(final boolean flag) {
167 org.jline.jansi.Ansi.setEnabled(flag);
168 }
169
170 public static Ansi ansi() {
171 if (isEnabled()) {
172 return new Ansi();
173 } else {
174 return new NoAnsi();
175 }
176 }
177
178 public static Ansi ansi(StringBuilder builder) {
179 if (isEnabled()) {
180 return new Ansi(builder);
181 } else {
182 return new NoAnsi(builder);
183 }
184 }
185
186 public static Ansi ansi(int size) {
187 if (isEnabled()) {
188 return new Ansi(size);
189 } else {
190 return new NoAnsi(size);
191 }
192 }
193
194 private static class NoAnsi extends Ansi {
195 NoAnsi() {
196 super();
197 }
198
199 NoAnsi(int size) {
200 super(size);
201 }
202
203 NoAnsi(StringBuilder builder) {
204 super(builder);
205 }
206
207 @Override
208 public Ansi fg(Color color) {
209 return this;
210 }
211
212 @Override
213 public Ansi bg(Color color) {
214 return this;
215 }
216
217 @Override
218 public Ansi fgBright(Color color) {
219 return this;
220 }
221
222 @Override
223 public Ansi bgBright(Color color) {
224 return this;
225 }
226
227 @Override
228 public Ansi fg(int color) {
229 return this;
230 }
231
232 @Override
233 public Ansi fgRgb(int r, int g, int b) {
234 return this;
235 }
236
237 @Override
238 public Ansi bg(int color) {
239 return this;
240 }
241
242 @Override
243 public Ansi bgRgb(int r, int g, int b) {
244 return this;
245 }
246
247 @Override
248 public Ansi a(Attribute attribute) {
249 return this;
250 }
251
252 @Override
253 public Ansi cursor(int row, int column) {
254 return this;
255 }
256
257 @Override
258 public Ansi cursorToColumn(int x) {
259 return this;
260 }
261
262 @Override
263 public Ansi cursorUp(int y) {
264 return this;
265 }
266
267 @Override
268 public Ansi cursorRight(int x) {
269 return this;
270 }
271
272 @Override
273 public Ansi cursorDown(int y) {
274 return this;
275 }
276
277 @Override
278 public Ansi cursorLeft(int x) {
279 return this;
280 }
281
282 @Override
283 public Ansi cursorDownLine() {
284 return this;
285 }
286
287 @Override
288 public Ansi cursorDownLine(final int n) {
289 return this;
290 }
291
292 @Override
293 public Ansi cursorUpLine() {
294 return this;
295 }
296
297 @Override
298 public Ansi cursorUpLine(final int n) {
299 return this;
300 }
301
302 @Override
303 public Ansi eraseScreen() {
304 return this;
305 }
306
307 @Override
308 public Ansi eraseScreen(Erase kind) {
309 return this;
310 }
311
312 @Override
313 public Ansi eraseLine() {
314 return this;
315 }
316
317 @Override
318 public Ansi eraseLine(Erase kind) {
319 return this;
320 }
321
322 @Override
323 public Ansi scrollUp(int rows) {
324 return this;
325 }
326
327 @Override
328 public Ansi scrollDown(int rows) {
329 return this;
330 }
331
332 @Override
333 public Ansi saveCursorPosition() {
334 return this;
335 }
336
337 @Override
338 @Deprecated
339 public Ansi restorCursorPosition() {
340 return this;
341 }
342
343 @Override
344 public Ansi restoreCursorPosition() {
345 return this;
346 }
347
348 @Override
349 public Ansi reset() {
350 return this;
351 }
352 }
353
354 private final StringBuilder builder;
355 private final ArrayList<Integer> attributeOptions = new ArrayList<>(5);
356
357 public Ansi() {
358 this(new StringBuilder(80));
359 }
360
361 public Ansi(Ansi parent) {
362 this(new StringBuilder(parent.builder));
363 attributeOptions.addAll(parent.attributeOptions);
364 }
365
366 public Ansi(int size) {
367 this(new StringBuilder(size));
368 }
369
370 public Ansi(StringBuilder builder) {
371 this.builder = builder;
372 }
373
374 public Ansi fg(Color color) {
375 attributeOptions.add(color.fg());
376 return this;
377 }
378
379 public Ansi fg(int color) {
380 attributeOptions.add(38);
381 attributeOptions.add(5);
382 attributeOptions.add(color & 0xff);
383 return this;
384 }
385
386 public Ansi fgRgb(int color) {
387 return fgRgb(color >> 16, color >> 8, color);
388 }
389
390 public Ansi fgRgb(int r, int g, int b) {
391 attributeOptions.add(38);
392 attributeOptions.add(2);
393 attributeOptions.add(r & 0xff);
394 attributeOptions.add(g & 0xff);
395 attributeOptions.add(b & 0xff);
396 return this;
397 }
398
399 public Ansi fgBlack() {
400 return this.fg(Color.BLACK);
401 }
402
403 public Ansi fgBlue() {
404 return this.fg(Color.BLUE);
405 }
406
407 public Ansi fgCyan() {
408 return this.fg(Color.CYAN);
409 }
410
411 public Ansi fgDefault() {
412 return this.fg(Color.DEFAULT);
413 }
414
415 public Ansi fgGreen() {
416 return this.fg(Color.GREEN);
417 }
418
419 public Ansi fgMagenta() {
420 return this.fg(Color.MAGENTA);
421 }
422
423 public Ansi fgRed() {
424 return this.fg(Color.RED);
425 }
426
427 public Ansi fgYellow() {
428 return this.fg(Color.YELLOW);
429 }
430
431 public Ansi bg(Color color) {
432 attributeOptions.add(color.bg());
433 return this;
434 }
435
436 public Ansi bg(int color) {
437 attributeOptions.add(48);
438 attributeOptions.add(5);
439 attributeOptions.add(color & 0xff);
440 return this;
441 }
442
443 public Ansi bgRgb(int color) {
444 return bgRgb(color >> 16, color >> 8, color);
445 }
446
447 public Ansi bgRgb(int r, int g, int b) {
448 attributeOptions.add(48);
449 attributeOptions.add(2);
450 attributeOptions.add(r & 0xff);
451 attributeOptions.add(g & 0xff);
452 attributeOptions.add(b & 0xff);
453 return this;
454 }
455
456 public Ansi bgCyan() {
457 return this.bg(Color.CYAN);
458 }
459
460 public Ansi bgDefault() {
461 return this.bg(Color.DEFAULT);
462 }
463
464 public Ansi bgGreen() {
465 return this.bg(Color.GREEN);
466 }
467
468 public Ansi bgMagenta() {
469 return this.bg(Color.MAGENTA);
470 }
471
472 public Ansi bgRed() {
473 return this.bg(Color.RED);
474 }
475
476 public Ansi bgYellow() {
477 return this.bg(Color.YELLOW);
478 }
479
480 public Ansi fgBright(Color color) {
481 attributeOptions.add(color.fgBright());
482 return this;
483 }
484
485 public Ansi fgBrightBlack() {
486 return this.fgBright(Color.BLACK);
487 }
488
489 public Ansi fgBrightBlue() {
490 return this.fgBright(Color.BLUE);
491 }
492
493 public Ansi fgBrightCyan() {
494 return this.fgBright(Color.CYAN);
495 }
496
497 public Ansi fgBrightDefault() {
498 return this.fgBright(Color.DEFAULT);
499 }
500
501 public Ansi fgBrightGreen() {
502 return this.fgBright(Color.GREEN);
503 }
504
505 public Ansi fgBrightMagenta() {
506 return this.fgBright(Color.MAGENTA);
507 }
508
509 public Ansi fgBrightRed() {
510 return this.fgBright(Color.RED);
511 }
512
513 public Ansi fgBrightYellow() {
514 return this.fgBright(Color.YELLOW);
515 }
516
517 public Ansi bgBright(Color color) {
518 attributeOptions.add(color.bgBright());
519 return this;
520 }
521
522 public Ansi bgBrightCyan() {
523 return this.bgBright(Color.CYAN);
524 }
525
526 public Ansi bgBrightDefault() {
527 return this.bgBright(Color.DEFAULT);
528 }
529
530 public Ansi bgBrightGreen() {
531 return this.bgBright(Color.GREEN);
532 }
533
534 public Ansi bgBrightMagenta() {
535 return this.bgBright(Color.MAGENTA);
536 }
537
538 public Ansi bgBrightRed() {
539 return this.bgBright(Color.RED);
540 }
541
542 public Ansi bgBrightYellow() {
543 return this.bgBright(Color.YELLOW);
544 }
545
546 public Ansi a(Attribute attribute) {
547 attributeOptions.add(attribute.value());
548 return this;
549 }
550
551
552
553
554
555
556
557
558
559 public Ansi cursor(final int row, final int column) {
560 return appendEscapeSequence('H', Math.max(1, row), Math.max(1, column));
561 }
562
563
564
565
566
567
568
569
570 public Ansi cursorToColumn(final int x) {
571 return appendEscapeSequence('G', Math.max(1, x));
572 }
573
574
575
576
577
578
579
580 public Ansi cursorUp(final int y) {
581 return y > 0 ? appendEscapeSequence('A', y) : y < 0 ? cursorDown(-y) : this;
582 }
583
584
585
586
587
588
589
590 public Ansi cursorDown(final int y) {
591 return y > 0 ? appendEscapeSequence('B', y) : y < 0 ? cursorUp(-y) : this;
592 }
593
594
595
596
597
598
599
600 public Ansi cursorRight(final int x) {
601 return x > 0 ? appendEscapeSequence('C', x) : x < 0 ? cursorLeft(-x) : this;
602 }
603
604
605
606
607
608
609
610 public Ansi cursorLeft(final int x) {
611 return x > 0 ? appendEscapeSequence('D', x) : x < 0 ? cursorRight(-x) : this;
612 }
613
614
615
616
617
618
619
620
621
622
623 public Ansi cursorMove(final int x, final int y) {
624 return cursorRight(x).cursorDown(y);
625 }
626
627
628
629
630
631
632 public Ansi cursorDownLine() {
633 return appendEscapeSequence('E');
634 }
635
636
637
638
639
640
641
642
643 public Ansi cursorDownLine(final int n) {
644 return n < 0 ? cursorUpLine(-n) : appendEscapeSequence('E', n);
645 }
646
647
648
649
650
651
652 public Ansi cursorUpLine() {
653 return appendEscapeSequence('F');
654 }
655
656
657
658
659
660
661
662
663 public Ansi cursorUpLine(final int n) {
664 return n < 0 ? cursorDownLine(-n) : appendEscapeSequence('F', n);
665 }
666
667 public Ansi eraseScreen() {
668 return appendEscapeSequence('J', Erase.ALL.value());
669 }
670
671 public Ansi eraseScreen(final Erase kind) {
672 return appendEscapeSequence('J', kind.value());
673 }
674
675 public Ansi eraseLine() {
676 return appendEscapeSequence('K');
677 }
678
679 public Ansi eraseLine(final Erase kind) {
680 return appendEscapeSequence('K', kind.value());
681 }
682
683 public Ansi scrollUp(final int rows) {
684 if (rows == Integer.MIN_VALUE) {
685 return scrollDown(Integer.MAX_VALUE);
686 }
687 return rows > 0 ? appendEscapeSequence('S', rows) : rows < 0 ? scrollDown(-rows) : this;
688 }
689
690 public Ansi scrollDown(final int rows) {
691 if (rows == Integer.MIN_VALUE) {
692 return scrollUp(Integer.MAX_VALUE);
693 }
694 return rows > 0 ? appendEscapeSequence('T', rows) : rows < 0 ? scrollUp(-rows) : this;
695 }
696
697 @Deprecated
698 public Ansi restorCursorPosition() {
699 return restoreCursorPosition();
700 }
701
702 public Ansi saveCursorPosition() {
703 saveCursorPositionSCO();
704 return saveCursorPositionDEC();
705 }
706
707
708 public Ansi saveCursorPositionSCO() {
709 return appendEscapeSequence('s');
710 }
711
712
713 public Ansi saveCursorPositionDEC() {
714 builder.append(FIRST_ESC_CHAR);
715 builder.append('7');
716 return this;
717 }
718
719 public Ansi restoreCursorPosition() {
720 restoreCursorPositionSCO();
721 return restoreCursorPositionDEC();
722 }
723
724
725 public Ansi restoreCursorPositionSCO() {
726 return appendEscapeSequence('u');
727 }
728
729
730 public Ansi restoreCursorPositionDEC() {
731 builder.append(FIRST_ESC_CHAR);
732 builder.append('8');
733 return this;
734 }
735
736 public Ansi reset() {
737 return a(Attribute.RESET);
738 }
739
740 public Ansi bold() {
741 return a(Attribute.INTENSITY_BOLD);
742 }
743
744 public Ansi boldOff() {
745 return a(Attribute.INTENSITY_BOLD_OFF);
746 }
747
748 public Ansi a(String value) {
749 flushAttributes();
750 builder.append(value);
751 return this;
752 }
753
754 public Ansi a(boolean value) {
755 flushAttributes();
756 builder.append(value);
757 return this;
758 }
759
760 public Ansi a(char value) {
761 flushAttributes();
762 builder.append(value);
763 return this;
764 }
765
766 public Ansi a(char[] value, int offset, int len) {
767 flushAttributes();
768 builder.append(value, offset, len);
769 return this;
770 }
771
772 public Ansi a(char[] value) {
773 flushAttributes();
774 builder.append(value);
775 return this;
776 }
777
778 public Ansi a(CharSequence value, int start, int end) {
779 flushAttributes();
780 builder.append(value, start, end);
781 return this;
782 }
783
784 public Ansi a(CharSequence value) {
785 flushAttributes();
786 builder.append(value);
787 return this;
788 }
789
790 public Ansi a(double value) {
791 flushAttributes();
792 builder.append(value);
793 return this;
794 }
795
796 public Ansi a(float value) {
797 flushAttributes();
798 builder.append(value);
799 return this;
800 }
801
802 public Ansi a(int value) {
803 flushAttributes();
804 builder.append(value);
805 return this;
806 }
807
808 public Ansi a(long value) {
809 flushAttributes();
810 builder.append(value);
811 return this;
812 }
813
814 public Ansi a(Object value) {
815 flushAttributes();
816 builder.append(value);
817 return this;
818 }
819
820 public Ansi a(StringBuffer value) {
821 flushAttributes();
822 builder.append(value);
823 return this;
824 }
825
826 public Ansi newline() {
827 flushAttributes();
828 builder.append(System.lineSeparator());
829 return this;
830 }
831
832 public Ansi format(String pattern, Object... args) {
833 flushAttributes();
834 builder.append(String.format(pattern, args));
835 return this;
836 }
837
838
839
840
841
842
843
844
845 public Ansi apply(Consumer fun) {
846 fun.apply(this);
847 return this;
848 }
849
850
851
852
853
854
855
856
857
858 public Ansi render(final String text) {
859 a(new org.jline.jansi.Ansi().render(text).toString());
860 return this;
861 }
862
863
864
865
866
867
868
869
870
871
872 public Ansi render(final String text, Object... args) {
873 a(String.format(new org.jline.jansi.Ansi().render(text).toString(), args));
874 return this;
875 }
876
877 @Override
878 public String toString() {
879 flushAttributes();
880 return builder.toString();
881 }
882
883
884
885
886
887 private Ansi appendEscapeSequence(char command) {
888 flushAttributes();
889 builder.append(FIRST_ESC_CHAR);
890 builder.append(SECOND_ESC_CHAR);
891 builder.append(command);
892 return this;
893 }
894
895 private Ansi appendEscapeSequence(char command, int option) {
896 flushAttributes();
897 builder.append(FIRST_ESC_CHAR);
898 builder.append(SECOND_ESC_CHAR);
899 builder.append(option);
900 builder.append(command);
901 return this;
902 }
903
904 private Ansi appendEscapeSequence(char command, Object... options) {
905 flushAttributes();
906 return doAppendEscapeSequence(command, options);
907 }
908
909 private void flushAttributes() {
910 if (attributeOptions.isEmpty()) {
911 return;
912 }
913 if (attributeOptions.size() == 1 && attributeOptions.get(0) == 0) {
914 builder.append(FIRST_ESC_CHAR);
915 builder.append(SECOND_ESC_CHAR);
916 builder.append('m');
917 } else {
918 doAppendEscapeSequence('m', attributeOptions.toArray());
919 }
920 attributeOptions.clear();
921 }
922
923 private Ansi doAppendEscapeSequence(char command, Object... options) {
924 builder.append(FIRST_ESC_CHAR);
925 builder.append(SECOND_ESC_CHAR);
926 int size = options.length;
927 for (int i = 0; i < size; i++) {
928 if (i != 0) {
929 builder.append(';');
930 }
931 if (options[i] != null) {
932 builder.append(options[i]);
933 }
934 }
935 builder.append(command);
936 return this;
937 }
938
939 @Override
940 public Ansi append(CharSequence csq) {
941 builder.append(csq);
942 return this;
943 }
944
945 @Override
946 public Ansi append(CharSequence csq, int start, int end) {
947 builder.append(csq, start, end);
948 return this;
949 }
950
951 @Override
952 public Ansi append(char c) {
953 builder.append(c);
954 return this;
955 }
956 }