/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file LICENSE.rst or https://cmake.org/licensing for details. */ #include "cmStdIoTerminal.h" #include #include #include #include #include #include #include #ifdef _WIN32 # include #endif #include #include "cmStdIoStream.h" #include "cmSystemTools.h" namespace cm { namespace StdIo { namespace { #ifdef _WIN32 WORD const kConsoleAttrMask = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY; std::array const kConsoleAttrs{ { 0, // Normal FOREGROUND_INTENSITY, // ForegroundBold 0, // ForegroundBlack FOREGROUND_BLUE, // ForegroundBlue FOREGROUND_GREEN | FOREGROUND_BLUE, // ForegroundCyan FOREGROUND_GREEN, // ForegroundGreen FOREGROUND_RED | FOREGROUND_BLUE, // ForegroundMagenta FOREGROUND_RED, // ForegroundRed FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // ForegroundWhite FOREGROUND_RED | FOREGROUND_GREEN, // ForegroundYellow BACKGROUND_INTENSITY, // BackgroundBold 0, // BackgroundBlack BACKGROUND_BLUE, // BackgroundBlue BACKGROUND_GREEN | BACKGROUND_BLUE, // BackgroundCyan BACKGROUND_GREEN, // BackgroundGreen BACKGROUND_RED | BACKGROUND_BLUE, // BackgroundMagenta BACKGROUND_RED, // BackgroundRed BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE, // BackgroundWhite BACKGROUND_RED | BACKGROUND_GREEN, // BackgroundYellow } }; WORD ConsoleAttrs(WORD consoleAttrs, TermAttrSet const& attrs) { consoleAttrs = attrs.contains(TermAttr::Normal) ? consoleAttrs & kConsoleAttrMask : 0; for (TermAttr attr : attrs) { auto index = static_cast::type>(attr); consoleAttrs |= kConsoleAttrs[index]; } return consoleAttrs; } #endif // VT100 escape sequence strings. #if defined(__MVS__) // z/OS: assume EBCDIC # define ESC "\47" #else # define ESC "\33" #endif std::array const kVT100Codes{ { ESC "[0m"_s, // Normal ESC "[1m"_s, // ForegroundBold ESC "[30m"_s, // ForegroundBlack ESC "[34m"_s, // ForegroundBlue ESC "[36m"_s, // ForegroundCyan ESC "[32m"_s, // ForegroundGreen ESC "[35m"_s, // ForegroundMagenta ESC "[31m"_s, // ForegroundRed ESC "[37m"_s, // ForegroundWhite ESC "[33m"_s, // ForegroundYellow ""_s, // BackgroundBold ESC "[40m"_s, // BackgroundBlack ESC "[44m"_s, // BackgroundBlue ESC "[46m"_s, // BackgroundCyan ESC "[42m"_s, // BackgroundGreen ESC "[45m"_s, // BackgroundMagenta ESC "[41m"_s, // BackgroundRed ESC "[47m"_s, // BackgroundWhite ESC "[43m"_s, // BackgroundYellow } }; void SetVT100Attrs(std::ostream& os, TermAttrSet const& attrs) { for (TermAttr attr : attrs) { auto index = static_cast::type>(attr); os << kVT100Codes[index]; } } auto const TermEnv = []() -> cm::optional { /* Disable color according to https://bixense.com/clicolors/ convention. */ if (cm::optional noColor = cmSystemTools::GetEnvVar("NO_COLOR")) { if (!noColor->empty() && *noColor != "0"_s) { return TermKind::None; } } /* Force color according to https://bixense.com/clicolors/ convention. */ if (cm::optional cliColorForce = cmSystemTools::GetEnvVar("CLICOLOR_FORCE")) { if (!cliColorForce->empty() && *cliColorForce != "0"_s) { return TermKind::VT100; } } /* Disable color according to https://bixense.com/clicolors/ convention. */ if (cm::optional cliColor = cmSystemTools::GetEnvVar("CLICOLOR")) { if (*cliColor == "0"_s) { return TermKind::None; } } /* GNU make 4.1+ may tell us that its output is destined for a TTY. */ if (cm::optional makeTermOut = cmSystemTools::GetEnvVar("MAKE_TERMOUT")) { if (!makeTermOut->empty()) { return TermKind::VT100; } } return cm::nullopt; }(); void Print(OStream& os, TermAttrSet const& attrs, std::function const& f) { TermKind kind = TermEnv ? *TermEnv : os.Kind(); switch (kind) { case TermKind::None: f(os.IOS()); break; case TermKind::VT100: if (!attrs.empty()) { SetVT100Attrs(os.IOS(), attrs); f(os.IOS()); SetVT100Attrs(os.IOS(), TermAttr::Normal); } else { f(os.IOS()); } break; #ifdef _WIN32 case TermKind::Console: { HANDLE console = os.Console(); CONSOLE_SCREEN_BUFFER_INFO sbi; if (!attrs.empty() && GetConsoleScreenBufferInfo(console, &sbi)) { Out().IOS().flush(); Err().IOS().flush(); SetConsoleTextAttribute(console, ConsoleAttrs(sbi.wAttributes, attrs)); f(os.IOS()); Out().IOS().flush(); Err().IOS().flush(); SetConsoleTextAttribute( console, ConsoleAttrs(sbi.wAttributes, TermAttr::Normal)); } else { f(os.IOS()); } } break; #endif }; } } // anonymous namespace void Print(OStream& os, TermAttrSet const& attrs, cm::string_view s) { Print(os, attrs, [s](std::ostream& o) { o << s; }); } } }