1 module sily.bashfmt;
2 
3 import std.conv : to;
4 import std.stdio : write, writef;
5 
6 static this() {
7     version(windows) {
8         import core.stdc.stdlib: exit;
9         exit(2);
10     }
11 }
12 
13 
14 alias FG = Foreground;
15 alias BG = Background;
16 alias FM = Formatting;
17 alias FR = FormattingReset;
18 
19 enum Foreground : string {
20     reset = "\033[39m",
21     black = "\033[30m",
22     red = "\033[31m",
23     green = "\033[32m",
24     yellow = "\033[33m",
25     blue = "\033[34m",
26     magenta = "\033[35m",
27     cyan = "\033[36m",
28     ltgray = "\033[37m",
29     dkgray = "\033[90m",
30     ltred = "\033[91m",
31     ltgreen = "\033[92m",
32     ltyellow = "\033[93m",
33     ltblue = "\033[94m",
34     ltmagenta = "\033[95m",
35     ltcyan = "\033[96m",
36     white = "\033[97m",
37 }
38 
39 enum Background : string {
40     reset = "\033[49m",
41     black = "\033[40m",
42     red = "\033[41m",
43     green = "\033[42m",
44     yellow = "\033[43m",
45     blue = "\033[44m",
46     magenta = "\033[45m",
47     cyan = "\033[46m",
48     ltgray = "\033[47m",
49     dkgray = "\033[100m",
50     ltred = "\033[101m",
51     ltgreen = "\033[102m",
52     ltyellow = "\033[103m",
53     ltblue = "\033[104m",
54     ltmagenta = "\033[105m",
55     ltcyan = "\033[106m",
56     white = "\033[107m"
57 }
58 
59 enum Formatting : string {
60     bold = "\033[1m",
61     dim = "\033[2m",
62     italics = "\033[3m",
63     uline = "\033[4m",
64     blink = "\033[5m",
65     inverse = "\033[7m",
66     hidden = "\033[8m",
67     striked = "\033[9m",
68     dline = "\033[21m",
69     cline = "\033[4:3m",
70     oline = "\033[53"
71 }
72 
73 enum FormattingReset : string {
74     reset = "\033[0m",
75     fullreset = "\033[m",
76 
77     bold = "\033[21m",
78     dim = "\033[22m",
79     italics = "\033[22m",
80     uline = "\033[24m",
81     blink = "\033[25m",
82     inverse = "\033[27m",
83     hidden = "\033[28m",
84     striked = "\033[29m",
85     dline = "\033[24m",
86     cline = "\033[4:0m",
87     oline = "\033[55m"
88 }
89 
90 /** 
91  * Casts args to string and writes to stdout
92  *
93  * Intended to be used to print formatting
94  * ---
95  * fwrite("White text", FG.red, "Red text", FG.reset, BG.red, "Red background", FR.fullreset);
96  * ---
97  * Params:
98  *   args = Text or one of formatting strings
99  */
100 void fwrite(A...)(A args) {
101     foreach (arg; args) {
102         write(cast(string) arg);
103     }
104 }
105 
106 /** 
107  * Casts args to string and writes to stdout with `\n` at the end
108  *
109  * Intended to be used to print formatting
110  * ---
111  * fwriteln("White text", FG.red, "Red text", FG.reset, BG.red, "Red background", FR.fullreset);
112  * ---
113  * Params:
114  *   args = Text or one of formatting strings
115  */
116 void fwriteln(A...)(A args) {
117     foreach (arg; args) {
118         write(cast(string) arg);
119     }
120     write("\n");
121 }
122 
123 /** 
124  * Erases `num` lines in terminal starting with current.
125  * Params:
126  *   num = Number of lines to erase
127  */
128 void eraseLines(int num) {
129     eraseCurrentLine();
130     --num;
131 
132     while (num) {
133         moveCursorUp(1);
134         eraseCurrentLine();
135         --num;
136     }
137 }
138 
139 /** 
140  * Moves cursor in terminal to `{x, y}`
141  * Params:
142  *   x = Column to move to
143  *   y = Row to move to
144  */
145 void moveCursorTo(int x, int y) {
146     writef("\033[%d;%df", x, y);
147 }
148 
149 /** 
150  * Moves cursor in terminal up by `lineAmount`
151  * Params: 
152  *   lineAmount = int
153  */
154 void moveCursorUp(int lineAmount = 1) {
155     writef("\033[%dA", lineAmount);
156 }
157 
158 /** 
159  * Moves cursor in terminal down by `lineAmount`
160  * Params: 
161  *   lineAmount = int
162  */
163 void moveCursorDown(int lineAmount = 1) {
164     writef("\033[%dB", lineAmount);
165 }
166 
167 /** 
168  * Moves cursor in terminal right by `columnAmount`
169  * Params: 
170  *   columnAmount = int
171  */
172 void moveCursorRight(int columnAmount = 1) {
173     writef("\033[%dC", columnAmount);
174 }
175 
176 /** 
177  * Moves cursor in terminal left by `columnAmount`
178  * Params: 
179  *   columnAmount = int
180  */
181 void moveCursorLeft(int columnAmount = 1) {
182     writef("\033[%dD", columnAmount);
183 }
184 
185 /** 
186  * Clears terminal screen and resets cursor position
187  */
188 void clearScreen() {
189     write("\033[2J");
190     moveCursorTo(0, 0);
191 }
192 
193 /** 
194  * Clears terminal screen
195  */
196 void clearScreenOnly() {
197     write("\033[2J");
198 }
199 
200 /** 
201  * Fully erases current line 
202  */
203 void eraseCurrentLine() {
204     write("\033[2K");
205 }
206 
207 /** 
208  * Erases text from start of current line to cursor 
209  */
210 void eraseLineLeft() {
211     write("\033[1K");
212 }
213 
214 /** 
215  * Erases text from cursor to end of current line
216  */
217 void eraseLineRight() {
218     write("\033[K");
219 }
220 
221 /** 
222  * Saves cursor position to be restored later
223  */
224 void saveCursorPosition() {
225     write("\033[s");
226 }
227 
228 /** 
229  * Restores saved cursor position (moves cursor to saved pos)
230  */
231 void restoreCursorPosition() {
232     write("\033[u");
233 }
234 
235 /** 
236  * Hides cursor. Does not reset position
237  */
238 void hideCursor() {
239     write("\033[?25l");
240 }
241 
242 /** 
243  * Shows cursor. Does not reset position
244  */
245 void showCursor() {
246     write("\033[?25h");
247 }
248 
249 /** 
250  * Intended to be used in SIGINT callback
251  *
252  * Resets all formatting and shows cursor
253  */
254 void cleanTerminalState() nothrow @nogc @system {
255     import core.stdc.stdio: printf;
256     printf("\033[?25h\033[m");
257 }