138#if defined(OS_LINUX) || defined(OS_MAC)
140 static const bool result = [] {
141 const char* Terms[] = {
"ansi",
"color",
"console",
"cygwin",
"gnome",
"konsole",
"kterm",
142 "linux",
"msys",
"putty",
"rxvt",
"screen",
"vt100",
"xterm"};
144 const char* env_p = std::getenv(
"TERM");
145 if (env_p ==
nullptr) {
148 return std::any_of(std::begin(Terms), std::end(Terms),
149 [&](
const char* term) {
return std::strstr(env_p, term) !=
nullptr; });
154 static constexpr bool result =
true;
161 inline bool isMsysPty(
int fd)
noexcept {
163 const auto ptrGetFileInformationByHandleEx =
164 reinterpret_cast<decltype(&GetFileInformationByHandleEx)
>(
165 GetProcAddress(GetModuleHandle(TEXT(
"kernel32.dll")),
"GetFileInformationByHandleEx"));
166 if (!ptrGetFileInformationByHandleEx) {
170 HANDLE h =
reinterpret_cast<HANDLE
>(_get_osfhandle(fd));
171 if (h == INVALID_HANDLE_VALUE) {
176 if (GetFileType(h) != FILE_TYPE_PIPE) {
182 struct MY_FILE_NAME_INFO {
183 DWORD FileNameLength;
184 WCHAR FileName[MAX_PATH];
187 auto pNameInfo = std::unique_ptr<MY_FILE_NAME_INFO>(
new (std::nothrow) MY_FILE_NAME_INFO());
194 if (!ptrGetFileInformationByHandleEx(h, FileNameInfo, pNameInfo.get(),
195 sizeof(MY_FILE_NAME_INFO))) {
198 std::wstring name(pNameInfo->FileName, pNameInfo->FileNameLength /
sizeof(WCHAR));
199 if ((name.find(L
"msys-") == std::wstring::npos &&
200 name.find(L
"cygwin-") == std::wstring::npos) ||
201 name.find(L
"-pty") == std::wstring::npos) {
210 inline bool isTerminal(
const std::streambuf* osbuf)
noexcept {
214#if defined(OS_LINUX) || defined(OS_MAC)
215 if (osbuf == cout.rdbuf()) {
216 static const bool cout_term = isatty(fileno(stdout)) != 0;
218 }
else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) {
219 static const bool cerr_term = isatty(fileno(stderr)) != 0;
223 if (osbuf == cout.rdbuf()) {
224 static const bool cout_term = (_isatty(_fileno(stdout)) || isMsysPty(_fileno(stdout)));
226 }
else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) {
227 static const bool cerr_term = (_isatty(_fileno(stderr)) || isMsysPty(_fileno(stderr)));
234 template <
typename T>
236 std::is_same<T, rang::style>::value || std::is_same<T, rang::fg>::value ||
237 std::is_same<T, rang::bg>::value || std::is_same<T, rang::fgB>::value ||
238 std::is_same<T, rang::bgB>::value,
239 std::ostream&>::type;
252 enum class AttrColor : BYTE {
263 inline HANDLE getConsoleHandle(
const std::streambuf* osbuf)
noexcept {
264 if (osbuf == std::cout.rdbuf()) {
265 static const HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
267 }
else if (osbuf == std::cerr.rdbuf() || osbuf == std::clog.rdbuf()) {
268 static const HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE);
271 return INVALID_HANDLE_VALUE;
274 inline bool setWinTermAnsiColors(
const std::streambuf* osbuf)
noexcept {
275 HANDLE h = getConsoleHandle(osbuf);
276 if (h == INVALID_HANDLE_VALUE) {
280 if (!GetConsoleMode(h, &dwMode)) {
283 dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
284 if (!SetConsoleMode(h, dwMode)) {
290 inline bool supportsAnsi(
const std::streambuf* osbuf)
noexcept {
294 if (osbuf == cout.rdbuf()) {
295 static const bool cout_ansi = (isMsysPty(_fileno(stdout)) || setWinTermAnsiColors(osbuf));
297 }
else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) {
298 static const bool cerr_ansi = (isMsysPty(_fileno(stderr)) || setWinTermAnsiColors(osbuf));
304 inline const SGR& defaultState() noexcept {
305 static const SGR defaultSgr = []() -> SGR {
306 CONSOLE_SCREEN_BUFFER_INFO
info;
307 WORD attrib = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
308 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info) ||
309 GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &info)) {
310 attrib =
info.wAttributes;
313 sgr.fgColor = attrib & 0x0F;
314 sgr.bgColor = (attrib & 0xF0) >> 4;
320 inline BYTE ansi2attr(BYTE rgb)
noexcept {
321 static const AttrColor rev[8] = {AttrColor::black, AttrColor::red, AttrColor::green,
322 AttrColor::yellow, AttrColor::blue, AttrColor::magenta,
323 AttrColor::cyan, AttrColor::gray};
324 return static_cast<BYTE
>(rev[rgb]);
327 inline void setWinSGR(
rang::bg col, SGR& state)
noexcept {
329 state.bgColor = ansi2attr(
static_cast<BYTE
>(col) - 40);
331 state.bgColor = defaultState().bgColor;
335 inline void setWinSGR(
rang::fg col, SGR& state)
noexcept {
337 state.fgColor = ansi2attr(
static_cast<BYTE
>(col) - 30);
339 state.fgColor = defaultState().fgColor;
343 inline void setWinSGR(
rang::bgB col, SGR& state)
noexcept {
344 state.bgColor = (BACKGROUND_INTENSITY >> 4) | ansi2attr(
static_cast<BYTE
>(col) - 100);
347 inline void setWinSGR(
rang::fgB col, SGR& state)
noexcept {
348 state.fgColor = FOREGROUND_INTENSITY | ansi2attr(
static_cast<BYTE
>(col) - 90);
354 state = defaultState();
357 state.bold = FOREGROUND_INTENSITY;
361 state.underline = BACKGROUND_INTENSITY;
364 state.inverse =
TRUE;
367 state.conceal =
TRUE;
374 inline SGR& current_state() noexcept {
375 static SGR state = defaultState();
379 inline WORD SGR2Attr(
const SGR& state)
noexcept {
383 attrib = (state.fgColor << 4) | state.fgColor;
384 if (state.bold) attrib |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY;
386 attrib = (state.bgColor << 4) | state.bgColor;
387 if (state.underline) attrib |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY;
389 }
else if (state.inverse) {
390 attrib = (state.fgColor << 4) | state.bgColor;
391 if (state.bold) attrib |= BACKGROUND_INTENSITY;
392 if (state.underline) attrib |= FOREGROUND_INTENSITY;
394 attrib = state.fgColor | (state.bgColor << 4) | state.bold | state.underline;
399 template <
typename T>
400 inline void setWinColorAnsi(std::ostream& os, T
const value) {
401 os <<
"\033[" <<
static_cast<int>(value) <<
"m";
404 template <
typename T>
405 inline void setWinColorNative(std::ostream& os, T
const value) {
406 const HANDLE h = getConsoleHandle(os.rdbuf());
407 if (h != INVALID_HANDLE_VALUE) {
408 setWinSGR(value, current_state());
411 SetConsoleTextAttribute(h, SGR2Attr(current_state()));
415 template <
typename T>
418 if (supportsAnsi(os.rdbuf())) {
419 setWinColorAnsi(os, value);
421 setWinColorNative(os, value);
424 setWinColorAnsi(os, value);
426 setWinColorNative(os, value);
431 template <
typename T>
433 return os <<
"\033[" <<
static_cast<int>(value) <<
"m";