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