-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathconsole.h
More file actions
339 lines (270 loc) · 13 KB
/
Copy pathconsole.h
File metadata and controls
339 lines (270 loc) · 13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
// SPDX-License-Identifier: MIT
#ifndef STDCORELIB_CONSOLE_H
#define STDCORELIB_CONSOLE_H
#include <cstdarg>
#include <cstdio>
#include <stdcorelib/str.h>
namespace stdc {
/// \addtogroup text
/// @{
namespace console {
/// Text attributes, combined with \c |.
enum style {
nostyle = 0x0, ///< no attribute at all
bold = 0x1,
italic = 0x2,
underline = 0x4,
strikethrough = 0x8,
};
/// The eight base colors, each with a brighter variant.
///
/// Unlike \ref style these do not combine. Pass one, not a bitwise or of several.
/// \c intensified is the exception, being the bit the \c light names already carry.
enum color {
nocolor = 0, ///< leave the terminal's own color alone
intensified = 0x10, ///< the brightness bit, on its own
red = 0x1,
green = 0x2,
blue = 0x4,
yellow = red | green,
purple = red | blue,
cyan = green | blue,
white = red | green | blue,
black = 0x8,
lightred = intensified | red,
lightgreen = intensified | green,
lightblue = intensified | blue,
lightyellow = intensified | yellow,
lightpurple = intensified | purple,
lightcyan = intensified | cyan,
lightwhite = intensified | white,
lightblack = intensified | black,
};
/// \name Color mode
/// @{
/// How styling reaches the target.
enum color_mode {
automatic, ///< decide per target, styling it only when it is a terminal
never, ///< never emit styling, whatever the target
vt, ///< always emit ANSI escape sequences
windows_legacy, ///< always drive the Windows console API, meaning \c never elsewhere
};
/// Returns the mode the process is set to.
/// \sa set_color_mode()
STDC_EXPORT color_mode get_color_mode();
/// Overrides the mode process wide.
///
/// This is where a \c --color=always or \c NO_COLOR flag belongs.
///
/// \param mode the mode to force, or \c automatic to go back to deciding per target
/// \note Also drops what has been detected about the targets seen so far. Call this again
/// with the current mode after a \c freopen() to force them to be probed anew.
STDC_EXPORT void set_color_mode(color_mode mode);
/// Returns the mode that will actually be used for \a file.
///
/// \param file the target to resolve against, which is probed on the first call and
/// remembered afterwards
/// \return one of \c never, \c vt or \c windows_legacy, never \c automatic
STDC_EXPORT color_mode resolve_color_mode(FILE *file);
/// @}
/// \name Geometry
/// @{
/// How many columns wide the terminal behind \a file is.
///
/// \param file the target to ask about
/// \param fallback what to answer when there is no terminal there to ask, which is what
/// a pipe and a file get
/// \note Asked afresh every call rather than remembered, since a terminal is resized
/// while the program using it runs.
/// \note \c COLUMNS wins where it is set, which is how a shell says so and the only say
/// a caller has when the output is not going to a terminal at all.
STDC_EXPORT int width(FILE *file = stdout, int fallback = 80);
/// How many columns \a utf8 takes up when written to a terminal.
///
/// Neither its length in bytes nor its length in characters: one CJK ideograph occupies
/// two columns, and a combining mark occupies none.
STDC_EXPORT int display_width(const std::string_view &utf8);
/// \overload
///
/// For one code point, so that text can be measured while it is being walked rather than
/// a character at a time through the string form.
STDC_EXPORT int display_width(char32_t c);
/// @}
/// \name General output
/// @{
/// Writes \a buf to \a file with the given attributes, then puts them back.
///
/// The string is taken as UTF-8 and transcoded for a Windows console.
///
/// \param style a bitwise or of \ref style values, or \c nostyle
/// \param fg one \ref color value, or \c nocolor
/// \param bg likewise, for the background
/// \param buf the text, which is written whether or not the attributes are
/// \param file the target
/// \return the number of bytes of \a buf written, escape sequences not counted
/// \note Whether the attributes are emitted at all rests on resolve_color_mode() for
/// \a file, so a redirected stream receives the text alone.
STDC_EXPORT int fputs(int style, int fg, int bg, const char *buf, FILE *file);
/// \overload
STDC_EXPORT int fputs(int style, int fg, int bg, const std::string_view &buf, FILE *file);
/// Like fputs(), to \c stdout and followed by a newline.
STDC_EXPORT int puts(int style, int fg, int bg, const char *buf);
/// \overload
STDC_EXPORT int puts(int style, int fg, int bg, const std::string_view &buf);
/// Like fputs(), with printf-style formatting.
STDC_EXPORT int fprintf(int style, int fg, int bg, FILE *file, const char *fmt, ...)
STDC_PRINTF_FORMAT(5, 6);
STDC_EXPORT int vfprintf(int style, int fg, int bg, FILE *file, const char *fmt,
va_list args);
STDC_EXPORT int printf(int style, int fg, int bg, const char *fmt, ...)
STDC_PRINTF_FORMAT(4, 5);
STDC_EXPORT int vprintf(int style, int fg, int bg, const char *fmt, va_list args);
/// Like fputs(), with formatN() placeholders (\c %1, \c %2, ...) rather than printf
/// conversions.
/// \sa formatN()
template <class... Args>
inline int print(int style, int fg, int bg, const std::string_view &format,
Args &&...args) {
return console::fputs(style, fg, bg, formatN(format, args...), stdout);
}
template <class... Args>
inline int println(int style, int fg, int bg, const std::string_view &format,
Args &&...args) {
return console::puts(style, fg, bg, formatN(format, std::forward<Args>(args)...));
}
/// \overload
inline int println() {
return std::putchar('\n');
}
/// @}
/// \name Plain output
/// @{
/// The same writers with no attributes at all.
///
/// \note Still worth preferring over \c std::fputs on Windows, where the console needs
/// UTF-8 text transcoded before it will render.
inline int u8fputs(const char *buf, FILE *file) {
return console::fputs(nostyle, nocolor, nocolor, buf, file);
}
/// \overload
inline int u8fputs(const std::string_view &buf, FILE *file) {
return console::fputs(nostyle, nocolor, nocolor, buf, file);
}
inline int u8puts(const char *buf) {
return console::puts(nostyle, nocolor, nocolor, buf);
}
/// \overload
inline int u8puts(const std::string_view &buf) {
return console::puts(nostyle, nocolor, nocolor, buf);
}
STDC_EXPORT int u8fprintf(FILE *file, const char *fmt, ...) STDC_PRINTF_FORMAT(2, 3);
STDC_EXPORT int u8vfprintf(FILE *file, const char *fmt, va_list args);
STDC_EXPORT int u8printf(const char *fmt, ...) STDC_PRINTF_FORMAT(1, 2);
STDC_EXPORT int u8vprintf(const char *fmt, va_list args);
template <class... Args>
inline int u8print(const std::string_view &format, Args &&...args) {
return u8fputs(formatN(format, std::forward<Args>(args)...), stdout);
}
template <class... Args>
inline int u8println(const std::string_view &format, Args &&...args) {
return u8puts(formatN(format, std::forward<Args>(args)...));
}
/// \overload
inline int u8println() {
return std::putchar('\n');
}
/// @}
/// \name Messages
/// @{
/// One line each in a conventional color, for programs that want the four usual
/// severities without picking colors themselves.
///
/// All four go to \c stdout. For severities that route by destination, and for category
/// filtering, use the logging facility instead.
///
/// \sa formatN(), stdc::Logger
template <class... Args>
inline int debug(const std::string_view &format, Args &&...args) {
return println(nostyle, lightblue, nocolor, format, std::forward<Args>(args)...);
}
template <class... Args>
inline int success(const std::string_view &format, Args &&...args) {
return println(nostyle, lightgreen, nocolor, format, std::forward<Args>(args)...);
}
template <class... Args>
inline int warning(const std::string_view &format, Args &&...args) {
return println(nostyle, yellow, nocolor, format, std::forward<Args>(args)...);
}
template <class... Args>
inline int critical(const std::string_view &format, Args &&...args) {
return println(nostyle, red, nocolor, format, std::forward<Args>(args)...);
}
/// @}
}
using console::u8printf;
using console::u8vprintf;
using console::u8print;
using console::u8println;
namespace console {
/// \name Inline color markup
/// @{
/// Writes \a buf, reading \c ${...} as attribute changes rather than as text.
///
/// The alternative to threading \a style, \a fg and \a bg arguments through every call.
/// A group holds one or more names separated by spaces, and \c $$ writes a literal \c $.
/// Nested \c ${...} names are not supported and are ignored.
/// The names are:
/// \li a color: \c red, \c green, \c blue, \c yellow, \c purple, \c cyan, \c white,
/// \c black or \c nocolor, each also available with a \c light prefix
/// \li the same again behind \c @, which sets the background instead of the foreground
/// \li a style: \c bold, \c italic, \c underline, \c strikethrough or \c nostyle
/// \li \c intensified, or \c \@intensified, to brighten whichever color is in effect
/// \li \c reset, or \c clear, to drop back to plain text
///
/// \param buf the text and the markup within it
/// \param file the target
/// \return the number of bytes written, the markup and any escape sequences not counted
/// \note A name that is none of the above is dropped and changes nothing, so a typo
/// costs the styling rather than the text.
/// \note Attributes start out plain on every call and are restored when it returns, so
/// they never leak into what is written next.
///
/// \code
/// cprintln("${lightgreen}ok ${@blue bold}on blue ${reset}plain, 50$$ off");
/// \endcode
///
/// \sa fputs(), which takes the same attributes as arguments
STDC_EXPORT int cfputs(const char *buf, FILE *file);
/// \overload
STDC_EXPORT int cfputs(const std::string_view &buf, FILE *file);
/// Like cfputs(), to \c stdout and followed by a newline.
STDC_EXPORT int cputs(const char *buf);
/// \overload
STDC_EXPORT int cputs(const std::string_view &buf);
/// Like cfputs(), with printf-style formatting.
///
/// \warning The markup is read after the formatting, so a \c %s expanding to text that
/// holds \c ${ or \c $$ has it eaten rather than printed. Write text you do not
/// control with u8fprintf() instead.
STDC_EXPORT int cfprintf(FILE *file, const char *fmt, ...) STDC_PRINTF_FORMAT(2, 3);
STDC_EXPORT int cvfprintf(FILE *file, const char *fmt, va_list args);
STDC_EXPORT int cprintf(const char *fmt, ...) STDC_PRINTF_FORMAT(1, 2);
STDC_EXPORT int cvprintf(const char *fmt, va_list args);
/// Like cfputs(), with formatN() placeholders (\c %1, \c %2, ...).
template <class... Args>
inline int cprint(const std::string_view &format, Args &&...args) {
return cfputs(formatN(format, std::forward<Args>(args)...), stdout);
}
template <class... Args>
inline int cprintln(const std::string_view &format, Args &&...args) {
return cputs(formatN(format, std::forward<Args>(args)...));
}
/// @}
}
using console::cprintf;
using console::cvprintf;
using console::cprint;
using console::cprintln;
/// @}
}
#endif // STDCORELIB_CONSOLE_H