75inline bool env_set(
const char* name)
noexcept {
76 auto* value = std::getenv(name);
77 return value && *value !=
'\0';
80inline bool env_is(
const char* name,
const char* expected)
noexcept {
81 auto* value = std::getenv(name);
82 return value && std::strcmp(value, expected) == 0;
85inline Mode default_mode() noexcept {
87 if (env_set(
"CLICOLOR_FORCE") && !env_is(
"CLICOLOR_FORCE",
"0"))
return Mode::Always;
92inline std::atomic<Mode>& current_mode() noexcept {
93 static std::atomic<Mode>
mode(default_mode());
97inline std::streambuf* stdout_rdbuf() noexcept {
98 static std::streambuf* buf = std::cout.rdbuf();
102inline std::streambuf* stderr_rdbuf() noexcept {
103 static std::streambuf* buf = std::cerr.rdbuf();
107inline std::streambuf* clog_rdbuf() noexcept {
108 static std::streambuf* buf = std::clog.rdbuf();
112inline Stream stream(std::ostream& os)
noexcept {
113 auto*
const buf = os.rdbuf();
114 if (buf == stdout_rdbuf())
return Stream::Stdout;
115 if (buf == stderr_rdbuf() || buf == clog_rdbuf())
return Stream::Stderr;
116 return Stream::Unknown;
120inline bool enable_vt(HANDLE handle)
noexcept {
121 if (handle == INVALID_HANDLE_VALUE)
return false;
124 if (!GetConsoleMode(handle, &
mode))
return false;
125 if (
mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)
return true;
126 return SetConsoleMode(handle,
mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0;
129inline bool is_terminal(Stream s)
noexcept {
131 case Stream::Stdout: {
132 static bool stdout_is_terminal = enable_vt(GetStdHandle(STD_OUTPUT_HANDLE));
133 return stdout_is_terminal;
135 case Stream::Stderr: {
136 static bool stderr_is_terminal = enable_vt(GetStdHandle(STD_ERROR_HANDLE));
137 return stderr_is_terminal;
139 default:
return false;
143inline bool is_terminal(Stream s)
noexcept {
145 case Stream::Stdout: {
146 static bool stdout_is_terminal = ::isatty(STDOUT_FILENO) != 0;
147 return stdout_is_terminal;
149 case Stream::Stderr: {
150 static bool stderr_is_terminal = ::isatty(STDERR_FILENO) != 0;
151 return stderr_is_terminal;
153 default:
return false;
158inline bool use_color(std::ostream& os)
noexcept {
160 switch (current_mode().load(std::memory_order_relaxed)) {
163 case Mode::Auto:
return is_terminal(stream(os));
169constexpr std::string_view sgr(
FG color)
noexcept {
173 case FG::Red:
return "\033[31m";
189inline Mode mode() noexcept {
return detail::current_mode().load(std::memory_order_relaxed); }
192inline void set_mode(
Mode m)
noexcept { detail::current_mode().store(m, std::memory_order_relaxed); }
208 if (detail::use_color(os)) {
209 auto esc = detail::sgr(color);
210 os.write(esc.data(), esc.size());