View Javadoc
1   package com.guinetik.hexafun.examples.tui;
2   
3   /**
4    * ANSI escape code utilities for terminal styling.
5    * No external dependencies - pure Java terminal control.
6    *
7    * <p>Usage:
8    * <pre class="language-java">{@code
9    * import static com.guinetik.hexafun.examples.tui.Ansi.*;
10   *
11   * System.out.println(color("Hello", GREEN, BOLD));
12   * System.out.println(color(center("Title", 40), BG_BLUE, WHITE));
13   * }</pre>
14   */
15  public final class Ansi {
16  
17      private Ansi() {}
18  
19      // ═══════════════════════════════════════════════════════════════════
20      //  TEXT STYLES
21      // ═══════════════════════════════════════════════════════════════════
22  
23      public static final String RESET = "\u001B[0m";
24      public static final String BOLD = "\u001B[1m";
25      public static final String DIM = "\u001B[2m";
26      public static final String ITALIC = "\u001B[3m";
27      public static final String UNDERLINE = "\u001B[4m";
28  
29      // ═══════════════════════════════════════════════════════════════════
30      //  FOREGROUND COLORS
31      // ═══════════════════════════════════════════════════════════════════
32  
33      public static final String BLACK = "\u001B[30m";
34      public static final String RED = "\u001B[31m";
35      public static final String GREEN = "\u001B[32m";
36      public static final String YELLOW = "\u001B[33m";
37      public static final String BLUE = "\u001B[34m";
38      public static final String MAGENTA = "\u001B[35m";
39      public static final String CYAN = "\u001B[36m";
40      public static final String WHITE = "\u001B[37m";
41  
42      // Bright variants
43      public static final String BRIGHT_BLACK = "\u001B[90m";
44      public static final String BRIGHT_RED = "\u001B[91m";
45      public static final String BRIGHT_GREEN = "\u001B[92m";
46      public static final String BRIGHT_YELLOW = "\u001B[93m";
47      public static final String BRIGHT_BLUE = "\u001B[94m";
48      public static final String BRIGHT_MAGENTA = "\u001B[95m";
49      public static final String BRIGHT_CYAN = "\u001B[96m";
50      public static final String BRIGHT_WHITE = "\u001B[97m";
51  
52      // ═══════════════════════════════════════════════════════════════════
53      //  BACKGROUND COLORS
54      // ═══════════════════════════════════════════════════════════════════
55  
56      public static final String BG_BLACK = "\u001B[40m";
57      public static final String BG_RED = "\u001B[41m";
58      public static final String BG_GREEN = "\u001B[42m";
59      public static final String BG_YELLOW = "\u001B[43m";
60      public static final String BG_BLUE = "\u001B[44m";
61      public static final String BG_MAGENTA = "\u001B[45m";
62      public static final String BG_CYAN = "\u001B[46m";
63      public static final String BG_WHITE = "\u001B[47m";
64  
65      // ═══════════════════════════════════════════════════════════════════
66      //  CURSOR & SCREEN CONTROL
67      // ═══════════════════════════════════════════════════════════════════
68  
69      public static final String CLEAR_SCREEN = "\u001B[2J";
70      public static final String CLEAR = CLEAR_SCREEN;
71      public static final String CURSOR_HOME = "\u001B[H";
72      public static final String HIDE_CURSOR = "\u001B[?25l";
73      public static final String SHOW_CURSOR = "\u001B[?25h";
74  
75      // Alternate screen buffer (doesn't pollute scrollback)
76      public static final String ALT_SCREEN_ON = "\u001B[?1049h";
77      public static final String ALT_SCREEN_OFF = "\u001B[?1049l";
78  
79      // ═══════════════════════════════════════════════════════════════════
80      //  BOX DRAWING - UNICODE
81      // ═══════════════════════════════════════════════════════════════════
82  
83      // Single line
84      public static final String BOX_TOP_LEFT = "\u250C"; // ┌
85      public static final String BOX_TOP_RIGHT = "\u2510"; // ┐
86      public static final String BOX_BOTTOM_LEFT = "\u2514"; // └
87      public static final String BOX_BOTTOM_RIGHT = "\u2518"; // ┘
88      public static final String BOX_HORIZONTAL = "\u2500"; // ─
89      public static final String BOX_VERTICAL = "\u2502"; // │
90      public static final String BOX_T_DOWN = "\u252C"; // ┬
91      public static final String BOX_T_UP = "\u2534"; // ┴
92      public static final String BOX_T_RIGHT = "\u251C"; // ├
93      public static final String BOX_T_LEFT = "\u2524"; // ┤
94      public static final String BOX_CROSS = "\u253C"; // ┼
95  
96      // Double line
97      public static final String DBOX_TOP_LEFT = "\u2554"; // ╔
98      public static final String DBOX_TOP_RIGHT = "\u2557"; // ╗
99      public static final String DBOX_BOTTOM_LEFT = "\u255A"; // ╚
100     public static final String DBOX_BOTTOM_RIGHT = "\u255D"; // ╝
101     public static final String DBOX_HORIZONTAL = "\u2550"; // ═
102     public static final String DBOX_VERTICAL = "\u2551"; // ║
103 
104     // ═══════════════════════════════════════════════════════════════════
105     //  NERDFONT SYMBOLS
106     // ═══════════════════════════════════════════════════════════════════
107 
108     // Common symbols
109     public static final String CHECK = "\uEAB2"; // nf-cod-check
110     public static final String CROSS = "\uEA76"; // nf-cod-close
111     public static final String BULLET = "\uEABC"; // nf-cod-circle
112     public static final String ARROW_RIGHT = "\uEA9C"; // nf-cod-arrow_right
113     public static final String ARROW_LEFT = "\uEA9B"; // nf-cod-arrow_left
114     public static final String STAR = "\uF005"; // nf-fa-star
115     public static final String EMPTY_STAR = "\uEA6A"; // nf-cod-star_empty
116 
117     // Icons
118     public static final String ICON_TASK = "\uEB67"; // nf-cod-tasklist
119     public static final String ICON_DASHBOARD = "\uEACD"; // nf-cod-dashboard
120     public static final String ICON_ADD = "\uEA60"; // nf-cod-add
121     public static final String ICON_TRASH = "\uEA81"; // nf-cod-trash
122     public static final String ICON_CHECK_ALL = "\uEBB1"; // nf-cod-check_all
123     public static final String ICON_INBOX = "\uEB09"; // nf-cod-inbox
124     public static final String ICON_FOLDER = "\uEA83"; // nf-cod-folder
125     public static final String ICON_FLAME = "\uEAF2"; // nf-cod-flame
126     public static final String ICON_GEAR = "\uEAF8"; // nf-cod-gear
127     public static final String ICON_EYE = "\uEAE5"; // nf-cod-eye
128     public static final String ICON_INFO = "\uEAFC"; // nf-cod-info
129     public static final String ICON_EDIT = "\uEA73"; // nf-cod-edit
130     public static final String ICON_SEARCH = "\uEA6D"; // nf-cod-search
131     public static final String ICON_HOME = "\uEAF0"; // nf-cod-home
132     public static final String ICON_TERMINAL = "\uEA85"; // nf-cod-terminal
133 
134     // Progress bar blocks
135     public static final String BLOCK_FULL = "\u2588"; // █
136     public static final String BLOCK_LIGHT = "\u2591"; // ░
137     public static final String BLOCK_MED = "\u2592"; // ▒
138     public static final String BLOCK_DARK = "\u2593"; // ▓
139 
140     // Powerline separators
141     public static final String PL_LEFT = "\uE0B0"; // nf-pl-left_hard_divider
142     public static final String PL_RIGHT = "\uE0B2"; // nf-pl-right_hard_divider
143     public static final String PL_LEFT_SOFT = "\uE0B1"; // nf-pl-left_soft_divider
144     public static final String PL_RIGHT_SOFT = "\uE0B3"; // nf-pl-right_soft_divider
145 
146     // ═══════════════════════════════════════════════════════════════════
147     //  HELPER METHODS
148     // ═══════════════════════════════════════════════════════════════════
149 
150     /** Apply ANSI codes to text with auto-reset */
151     public static String color(String text, String... codes) {
152         if (codes.length == 0) return text;
153         StringBuilder sb = new StringBuilder();
154         for (String code : codes) {
155             sb.append(code);
156         }
157         return sb.append(text).append(RESET).toString();
158     }
159 
160     /** Bold text shorthand */
161     public static String bold(String text) {
162         return BOLD + text + RESET;
163     }
164 
165     /** Dim text shorthand */
166     public static String dim(String text) {
167         return DIM + text + RESET;
168     }
169 
170     /** Clear screen (side effect) */
171     public static void clear() {
172         System.out.print(CLEAR_SCREEN + CURSOR_HOME);
173         System.out.flush();
174     }
175 
176     /** Hide cursor (side effect) */
177     public static void hideCursor() {
178         System.out.print(HIDE_CURSOR);
179         System.out.flush();
180     }
181 
182     /** Show cursor (side effect) */
183     public static void showCursor() {
184         System.out.print(SHOW_CURSOR);
185         System.out.flush();
186     }
187 
188     // ═══════════════════════════════════════════════════════════════════
189     //  STRING UTILITIES
190     // ═══════════════════════════════════════════════════════════════════
191 
192     /** Repeat a character n times */
193     public static String repeat(char c, int count) {
194         return String.valueOf(c).repeat(Math.max(0, count));
195     }
196 
197     /** Repeat a string n times */
198     public static String repeat(String s, int count) {
199         return s.repeat(Math.max(0, count));
200     }
201 
202     /** Right-pad string to width */
203     public static String pad(String text, int width) {
204         if (text.length() >= width) {
205             return text.substring(0, width);
206         }
207         return text + " ".repeat(width - text.length());
208     }
209 
210     /** Left-pad string to width */
211     public static String padLeft(String text, int width) {
212         if (text.length() >= width) {
213             return text.substring(0, width);
214         }
215         return " ".repeat(width - text.length()) + text;
216     }
217 
218     /** Center string within width */
219     public static String center(String text, int width) {
220         if (text.length() >= width) {
221             return text.substring(0, width);
222         }
223         int padding = (width - text.length()) / 2;
224         return (
225             " ".repeat(padding) +
226             text +
227             " ".repeat(width - text.length() - padding)
228         );
229     }
230 
231     /** Truncate string with ellipsis if too long */
232     public static String truncate(String text, int maxWidth) {
233         if (text.length() <= maxWidth) return text;
234         return text.substring(0, Math.max(0, maxWidth - 3)) + "...";
235     }
236 
237     /** Join strings with newlines */
238     public static String lines(String... lines) {
239         return String.join("\n", lines) + "\n";
240     }
241 }