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
|
/* 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 <array>
#include <functional>
#include <iosfwd>
#include <string>
#include <type_traits>
#include <cm/string_view>
#include <cmext/string_view>
#ifdef _WIN32
# include <windows.h>
#endif
#include <cm/optional>
#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<WORD, kTermAttrCount> 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<std::underlying_type<TermAttr>::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<cm::string_view, kTermAttrCount> 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<std::underlying_type<TermAttr>::type>(attr);
os << kVT100Codes[index];
}
}
auto const TermEnv = []() -> cm::optional<TermKind> {
/* Disable color according to https://bixense.com/clicolors/ convention. */
if (cm::optional<std::string> 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<std::string> 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<std::string> 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<std::string> makeTermOut =
cmSystemTools::GetEnvVar("MAKE_TERMOUT")) {
if (!makeTermOut->empty()) {
return TermKind::VT100;
}
}
return cm::nullopt;
}();
void Print(OStream& os, TermAttrSet const& attrs,
std::function<void(std::ostream&)> 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; });
}
}
}
|