69inline bool env_set(
const char* name)
noexcept {
70 auto* value = std::getenv(name);
71 return value && *value !=
'\0';
74inline bool env_is(
const char* name,
const char* expected)
noexcept {
75 auto* value = std::getenv(name);
76 return value && std::strcmp(value, expected) == 0;
79inline Mode default_mode() noexcept {
81 if (env_set(
"CLICOLOR_FORCE") && !env_is(
"CLICOLOR_FORCE",
"0"))
return Mode::Always;
86inline std::atomic<Mode>& current_mode() noexcept {
87 static std::atomic<Mode>
mode(default_mode());
91inline std::streambuf* stdout_rdbuf() noexcept {
92 static std::streambuf* buf = std::cout.rdbuf();
96inline std::streambuf* stderr_rdbuf() noexcept {
97 static std::streambuf* buf = std::cerr.rdbuf();
101inline std::streambuf* clog_rdbuf() noexcept {
102 static std::streambuf* buf = std::clog.rdbuf();
106inline Stream stream(std::ostream& os)
noexcept {
107 auto*
const buf = os.rdbuf();
108 if (buf == stdout_rdbuf())
return Stream::Stdout;
109 if (buf == stderr_rdbuf() || buf == clog_rdbuf())
return Stream::Stderr;
110 return Stream::Unknown;
114inline bool enable_vt(HANDLE handle)
noexcept {
115 if (handle == INVALID_HANDLE_VALUE)
return false;
118 if (!GetConsoleMode(handle, &
mode))
return false;
119 if (
mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)
return true;
120 return SetConsoleMode(handle,
mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0;
123inline bool is_terminal(Stream s)
noexcept {
125 case Stream::Stdout: {
126 static bool stdout_is_terminal = enable_vt(GetStdHandle(STD_OUTPUT_HANDLE));
127 return stdout_is_terminal;
129 case Stream::Stderr: {
130 static bool stderr_is_terminal = enable_vt(GetStdHandle(STD_ERROR_HANDLE));
131 return stderr_is_terminal;
133 default:
return false;
137inline bool is_terminal(Stream s)
noexcept {
139 case Stream::Stdout: {
140 static bool stdout_is_terminal = ::isatty(STDOUT_FILENO) != 0;
141 return stdout_is_terminal;
143 case Stream::Stderr: {
144 static bool stderr_is_terminal = ::isatty(STDERR_FILENO) != 0;
145 return stderr_is_terminal;
147 default:
return false;
152inline bool use_color(std::ostream& os)
noexcept {
154 switch (current_mode().load(std::memory_order_relaxed)) {
157 case Mode::Auto:
return is_terminal(stream(os));
163constexpr std::string_view sgr(
FG color)
noexcept {
167 case FG::Red:
return "\033[31m";
183inline Mode mode() noexcept {
return detail::current_mode().load(std::memory_order_relaxed); }
186inline void set_mode(
Mode m)
noexcept { detail::current_mode().store(m, std::memory_order_relaxed); }
190 if (detail::use_color(os)) {
191 auto esc = detail::sgr(color);
192 os.write(esc.data(), esc.size());