ComPPare 1.0.0
Loading...
Searching...
No Matches
ansi.hpp
Go to the documentation of this file.
1/*
2
3Copyright 2025 | Leong Fan FUNG | funglf | stanleyfunglf@gmail.com
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the “Software”), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21SOFTWARE.
22
23*/
24
69#pragma once
70#include <ostream>
71#include <sstream>
72#include <string>
73#include <concepts>
74#include <utility>
75
77
86{
128 template <comppare::internal::concepts::Streamable T>
130 {
132 const char *on_;
134 const char *off_;
137
138 public:
139 ScopedAnsiWrapper(const char *on, const char *off, T v)
140 : on_(on), off_(off), val_(std::move(v)) {}
141
149 friend std::ostream &operator<<(std::ostream &os, ScopedAnsiWrapper const &w)
150 {
151 // Save the current state of the stream
152 std::ios saved(nullptr);
153 saved.copyfmt(os);
154
155 // convert the value into a string
156 std::ostringstream tmp;
157 tmp.copyfmt(os);
158 tmp << w.val_;
159 std::string body = std::move(tmp).str();
160
161 // apply the ANSI codes
162 os.width(0);
163 os << w.on_ << body << w.off_;
164
165 // Restore the original state of the stream -- formatting, precision, etc.
166 os.copyfmt(saved);
167 return os;
168 }
169 };
170
241#define ANSI_DEFINE(NAME, ON, OFF) \
242 /* Actual ANSI codes for the style/color (eg: BLACK_ON_CODE = "\033[30m") */ \
243 inline constexpr const char *NAME##_ON_CODE = "\033[" ON "m"; \
244 inline constexpr const char *NAME##_OFF_CODE = "\033[" OFF "m"; \
245 \
246 class NAME##_ON_t \
247 { \
248 public: \
249 /* Usage: std::cout << comppare::internal::ansi::BOLD << "Hello world"; */ \
250 friend std::ostream &operator<<(std::ostream &os, NAME##_ON_t) \
251 { \
252 /* Save the current state of the stream and apply the ANSI code */ \
253 std::ios saved(nullptr); \
254 saved.copyfmt(os); \
255 os.width(0); \
256 os << NAME##_ON_CODE; \
257 os.copyfmt(saved); \
258 return os; \
259 } \
260 \
261 /* Usage: std::cout << comppare::internal::ansi::BOLD("Hello world") */ \
262 template <comppare::internal::concepts::Streamable T> \
263 auto operator()(T &&v) const \
264 { \
265 return ScopedAnsiWrapper<std::decay_t<T>>(NAME##_ON_CODE, NAME##_OFF_CODE, std::forward<T>(v)); \
266 } \
267 }; \
268 /* Instance of the ON class */ \
269 inline constexpr NAME##_ON_t NAME{}; \
270 class NAME##_OFF_t \
271 { \
272 public: \
273 /* Usage: std::cout << ... << comppare::internal::ansi::BOLD_OFF; */ \
274 friend std::ostream &operator<<(std::ostream &os, NAME##_OFF_t) \
275 { \
276 /* Save the current state of the stream and apply the ANSI code */ \
277 std::ios saved(nullptr); \
278 saved.copyfmt(os); \
279 os.width(0); \
280 os << NAME##_OFF_CODE; \
281 os.copyfmt(saved); \
282 return os; \
283 } \
284 }; \
285 /* Instance of the OFF class */ \
286 inline constexpr NAME##_OFF_t NAME##_OFF{};
287
289 // Each style/color is defined with its ON and OFF codes
290 // https://man7.org/linux/man-pages/man4/console_codes.4.html
291
292 /* STYLES 0-9 */
293 ANSI_DEFINE(RESET, "0", "0");
294 ANSI_DEFINE(BOLD, "1", "22");
295 ANSI_DEFINE(DIM, "2", "22");
296 ANSI_DEFINE(ITALIC, "3", "23");
297 ANSI_DEFINE(UNDERLINE, "4", "24");
298 ANSI_DEFINE(BLINK, "5", "25");
299 ANSI_DEFINE(REVERSE, "7", "27");
300 ANSI_DEFINE(HIDDEN, "8", "28");
301 ANSI_DEFINE(STRIKE, "9", "29");
302
303 /* FOREGROUND (TEXT) COLOURS 30-37/90-97 */
304 ANSI_DEFINE(BLACK, "30", "39");
305 ANSI_DEFINE(RED, "31", "39");
306 ANSI_DEFINE(GREEN, "32", "39");
307 ANSI_DEFINE(YELLOW, "33", "39");
308 ANSI_DEFINE(BLUE, "34", "39");
309 ANSI_DEFINE(MAGENTA, "35", "39");
310 ANSI_DEFINE(CYAN, "36", "39");
311 ANSI_DEFINE(WHITE, "37", "39");
312
313 ANSI_DEFINE(BRIGHT_BLACK, "90", "39");
314 ANSI_DEFINE(BRIGHT_RED, "91", "39");
315 ANSI_DEFINE(BRIGHT_GREEN, "92", "39");
316 ANSI_DEFINE(BRIGHT_YELLOW, "93", "39");
317 ANSI_DEFINE(BRIGHT_BLUE, "94", "39");
318 ANSI_DEFINE(BRIGHT_MAGENTA, "95", "39");
319 ANSI_DEFINE(BRIGHT_CYAN, "96", "39");
320 ANSI_DEFINE(BRIGHT_WHITE, "97", "39");
321
322 /* BACKGROUND COLOURS (40-47 / 100-107) */
323 ANSI_DEFINE(BG_BLACK, "40", "49");
324 ANSI_DEFINE(BG_RED, "41", "49");
325 ANSI_DEFINE(BG_GREEN, "42", "49");
326 ANSI_DEFINE(BG_YELLOW, "43", "49");
327 ANSI_DEFINE(BG_BLUE, "44", "49");
328 ANSI_DEFINE(BG_MAGENTA, "45", "49");
329 ANSI_DEFINE(BG_CYAN, "46", "49");
330 ANSI_DEFINE(BG_WHITE, "47", "49");
331
332 ANSI_DEFINE(BG_BRIGHT_BLACK, "100", "49");
333 ANSI_DEFINE(BG_BRIGHT_RED, "101", "49");
334 ANSI_DEFINE(BG_BRIGHT_GREEN, "102", "49");
335 ANSI_DEFINE(BG_BRIGHT_YELLOW, "103", "49");
336 ANSI_DEFINE(BG_BRIGHT_BLUE, "104", "49");
337 ANSI_DEFINE(BG_BRIGHT_MAGENTA, "105", "49");
338 ANSI_DEFINE(BG_BRIGHT_CYAN, "106", "49");
339 ANSI_DEFINE(BG_BRIGHT_WHITE, "107", "49");
341
342 // undefine the macro as no longer needed
343#undef ANSI_DEFINE
344}
#define ANSI_DEFINE(NAME, ON, OFF)
Macro to define ANSI escape codes for text styling and colors.
Definition ansi.hpp:241
Applying ANSI styles/colors to a value in a scope.
Definition ansi.hpp:130
const char * on_
ANSI "on" code.
Definition ansi.hpp:132
ScopedAnsiWrapper(const char *on, const char *off, T v)
Definition ansi.hpp:139
T val_
The value to be wrapped.
Definition ansi.hpp:136
const char * off_
ANSI "off" code.
Definition ansi.hpp:134
friend std::ostream & operator<<(std::ostream &os, ScopedAnsiWrapper const &w)
Overloaded operator<< to stream the value with ANSI codes.
Definition ansi.hpp:149
This file contains commonly used concepts internally within the ComPPare library.
Utilities for applying ANSI styles and colors to console output.