From ad4a073bb5aba119749f1526994c436e59818163 Mon Sep 17 00:00:00 2001 From: Brayden Krus <151576863+braydenkrus@users.noreply.github.com> Date: Sat, 4 Apr 2026 08:47:05 -0400 Subject: [PATCH 01/13] Check `NO_COLOR` flag before `CLICOLOR_FORCE` In response to Issue #2295 (work in progress). --- src/line_printer.cc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/line_printer.cc b/src/line_printer.cc index 4a7b0bbf..85cace31 100644 --- a/src/line_printer.cc +++ b/src/line_printer.cc @@ -50,6 +50,10 @@ LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) { #ifdef _WIN32 // Try enabling ANSI escape sequence support on Windows 10 terminals. if (supports_color_) { + char* no_color = get_env("NO_COLOR"); + if (no_color != NULL && std::string(no_color) != "0") { + supports_color_ = false; + } DWORD mode; if (GetConsoleMode(console_, &mode)) { if (!SetConsoleMode(console_, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) { @@ -59,8 +63,13 @@ LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) { } #endif if (!supports_color_) { - const char* clicolor_force = getenv("CLICOLOR_FORCE"); - supports_color_ = clicolor_force && std::string(clicolor_force) != "0"; + char* no_color = get_env("NO_COLOR"); + if (no_color != NULL && std::string(no_color) != "0") { + supports_color_ = false; + } else { + const char* clicolor_force = getenv("CLICOLOR_FORCE"); + supports_color_ = clicolor_force && std::string(clicolor_force) != "0"; + } } } From 0d80e3c79211986b90c64d27578d8021b4a3b4c7 Mon Sep 17 00:00:00 2001 From: Brayden Krus <151576863+braydenkrus@users.noreply.github.com> Date: Sat, 4 Apr 2026 08:52:58 -0400 Subject: [PATCH 02/13] Fix `getenv` --- src/line_printer.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/line_printer.cc b/src/line_printer.cc index 85cace31..185649ea 100644 --- a/src/line_printer.cc +++ b/src/line_printer.cc @@ -50,7 +50,7 @@ LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) { #ifdef _WIN32 // Try enabling ANSI escape sequence support on Windows 10 terminals. if (supports_color_) { - char* no_color = get_env("NO_COLOR"); + char* no_color = getenv("NO_COLOR"); if (no_color != NULL && std::string(no_color) != "0") { supports_color_ = false; } @@ -63,7 +63,7 @@ LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) { } #endif if (!supports_color_) { - char* no_color = get_env("NO_COLOR"); + char* no_color = getenv("NO_COLOR"); if (no_color != NULL && std::string(no_color) != "0") { supports_color_ = false; } else { From 467483fc5c8954cd0e7d19410136c8c68f42ad30 Mon Sep 17 00:00:00 2001 From: Brayden Krus <151576863+braydenkrus@users.noreply.github.com> Date: Fri, 10 Apr 2026 14:46:52 -0400 Subject: [PATCH 03/13] Implement helper functions for NO_COLOR and CLICOLOR_FORCE --- src/line_printer.cc | 31 ++++++++++++++++++++++++++++--- src/line_printer.h | 6 ++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/line_printer.cc b/src/line_printer.cc index 185649ea..f6f878b0 100644 --- a/src/line_printer.cc +++ b/src/line_printer.cc @@ -50,9 +50,8 @@ LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) { #ifdef _WIN32 // Try enabling ANSI escape sequence support on Windows 10 terminals. if (supports_color_) { - char* no_color = getenv("NO_COLOR"); - if (no_color != NULL && std::string(no_color) != "0") { - supports_color_ = false; + if (EnvHasNoColor()) { + supports_color_ = false; } DWORD mode; if (GetConsoleMode(console_, &mode)) { @@ -63,6 +62,15 @@ LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) { } #endif if (!supports_color_) { + if (EnvHasNoColor()) { + supports_color_ = false; + } else if (EnvHasCliColorForce()) { + supports_color_ = true; + } + + + + /* char* no_color = getenv("NO_COLOR"); if (no_color != NULL && std::string(no_color) != "0") { supports_color_ = false; @@ -70,6 +78,7 @@ LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) { const char* clicolor_force = getenv("CLICOLOR_FORCE"); supports_color_ = clicolor_force && std::string(clicolor_force) != "0"; } + */ } } @@ -175,3 +184,19 @@ void LinePrinter::SetConsoleLocked(bool locked) { line_buffer_.clear(); } } + +bool LinePrinter::EnvHasNoColor() { + char* no_color = getenv("NO_COLOR"); + if (no_color != NULL) { + return true; + } + return false; +} + +bool LinePrinter::EnvHasCliColorForce() { + char* clicolor_force = getenv("CLICOLOR_FORCE"); + if (clicolor_force != NULL) { + return true; + } + return false; +} diff --git a/src/line_printer.h b/src/line_printer.h index a8ec9ff4..987b21ae 100644 --- a/src/line_printer.h +++ b/src/line_printer.h @@ -71,6 +71,12 @@ struct LinePrinter { /// Print the given data to the console, or buffer it if it is locked. void PrintOrBuffer(const char *data, size_t size); + + /// Check if environment variable NO_COLOR is set. + bool EnvHasNoColor(); + + /// Check if environment variable CLICOLOR_FORCE is set. + bool EnvHasCliColorForce(); }; #endif // NINJA_LINE_PRINTER_H_ From 54ce433b09aaa59051c3ad24d3310734f382cd1d Mon Sep 17 00:00:00 2001 From: Brayden Krus <151576863+braydenkrus@users.noreply.github.com> Date: Fri, 10 Apr 2026 15:04:21 -0400 Subject: [PATCH 04/13] Clean unneeded comment --- src/line_printer.cc | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/line_printer.cc b/src/line_printer.cc index f6f878b0..e2e5240a 100644 --- a/src/line_printer.cc +++ b/src/line_printer.cc @@ -67,18 +67,6 @@ LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) { } else if (EnvHasCliColorForce()) { supports_color_ = true; } - - - - /* - char* no_color = getenv("NO_COLOR"); - if (no_color != NULL && std::string(no_color) != "0") { - supports_color_ = false; - } else { - const char* clicolor_force = getenv("CLICOLOR_FORCE"); - supports_color_ = clicolor_force && std::string(clicolor_force) != "0"; - } - */ } } From e1707b46db6d77a3f95e32c52e4a67ca549b0c94 Mon Sep 17 00:00:00 2001 From: Brayden Krus <151576863+braydenkrus@users.noreply.github.com> Date: Sun, 12 Apr 2026 10:26:56 -0400 Subject: [PATCH 05/13] Add support for FORCE_COLOR. (For now) comment out NO_COLOR logic --- src/line_printer.cc | 20 ++++++++++++++++++++ src/line_printer.h | 5 ++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/line_printer.cc b/src/line_printer.cc index e2e5240a..00ca3f09 100644 --- a/src/line_printer.cc +++ b/src/line_printer.cc @@ -50,9 +50,11 @@ LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) { #ifdef _WIN32 // Try enabling ANSI escape sequence support on Windows 10 terminals. if (supports_color_) { + /* if (EnvHasNoColor()) { supports_color_ = false; } + */ DWORD mode; if (GetConsoleMode(console_, &mode)) { if (!SetConsoleMode(console_, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) { @@ -62,11 +64,21 @@ LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) { } #endif if (!supports_color_) { + /* + // NO_COLOR and CLICOLOR_FORCE: NO_COLOR "overrides" CLICOLOR_FORCE if (EnvHasNoColor()) { supports_color_ = false; } else if (EnvHasCliColorForce()) { supports_color_ = true; } + // NO_COLOR and FORCE_COLOR: FORCE_COLOR "overrides" NO_COLOR + if (EnvHasForceColor()) { + supports_color = true; + } + */ + if (EnvHasCliColorForce() || EnvHasForceColor()) { + supports_color_ = true; + } } } @@ -188,3 +200,11 @@ bool LinePrinter::EnvHasCliColorForce() { } return false; } + +bool LinePrinter::EnvHasForceColor() { + char* force_color = getenv("FORCE_COLOR"); + if (force_color != NULL) { + return true; + } + return false; +} diff --git a/src/line_printer.h b/src/line_printer.h index 987b21ae..c49a0f64 100644 --- a/src/line_printer.h +++ b/src/line_printer.h @@ -72,11 +72,14 @@ struct LinePrinter { /// Print the given data to the console, or buffer it if it is locked. void PrintOrBuffer(const char *data, size_t size); - /// Check if environment variable NO_COLOR is set. + /// CURRENTLY UNUSED (see line_printer.cc). Check if environment variable NO_COLOR is set. bool EnvHasNoColor(); /// Check if environment variable CLICOLOR_FORCE is set. bool EnvHasCliColorForce(); + + /// Check if environment variable FORCE_COLOR is set. + bool EnvHasForceColor(); }; #endif // NINJA_LINE_PRINTER_H_ From 27e4b60d831107140cdc15cbad82350d8a701647 Mon Sep 17 00:00:00 2001 From: Brayden Krus <151576863+braydenkrus@users.noreply.github.com> Date: Mon, 13 Apr 2026 08:54:39 -0400 Subject: [PATCH 06/13] Simplify helper functions --- src/line_printer.cc | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/line_printer.cc b/src/line_printer.cc index 00ca3f09..a35a7e62 100644 --- a/src/line_printer.cc +++ b/src/line_printer.cc @@ -187,24 +187,15 @@ void LinePrinter::SetConsoleLocked(bool locked) { bool LinePrinter::EnvHasNoColor() { char* no_color = getenv("NO_COLOR"); - if (no_color != NULL) { - return true; - } - return false; + return no_color != NULL; } bool LinePrinter::EnvHasCliColorForce() { char* clicolor_force = getenv("CLICOLOR_FORCE"); - if (clicolor_force != NULL) { - return true; - } - return false; + return clicolor_force != NULL; } bool LinePrinter::EnvHasForceColor() { char* force_color = getenv("FORCE_COLOR"); - if (force_color != NULL) { - return true; - } - return false; + return force_color != NULL; } From 201c9b944a8700ddfad2f5199d763206bb052532 Mon Sep 17 00:00:00 2001 From: Brayden Krus <151576863+braydenkrus@users.noreply.github.com> Date: Fri, 17 Apr 2026 15:05:56 -0400 Subject: [PATCH 07/13] Implement ansi_color --- CMakeLists.txt | 2 ++ configure.py | 4 ++- src/ansi_color.cc | 33 +++++++++++++++++ src/ansi_color.h | 27 ++++++++++++++ src/ansi_color_test.cc | 82 ++++++++++++++++++++++++++++++++++++++++++ src/line_printer.cc | 35 ++++-------------- src/line_printer.h | 9 ----- 7 files changed, 153 insertions(+), 39 deletions(-) create mode 100644 src/ansi_color.cc create mode 100644 src/ansi_color.h create mode 100644 src/ansi_color_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index c777afc2..3c1ea991 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,6 +125,7 @@ check_platform_supports_browse_mode(platform_supports_ninja_browse) # Core source files all build into ninja library. add_library(libninja OBJECT + src/ansi_color.cc src/build_log.cc src/build.cc src/clean.cc @@ -273,6 +274,7 @@ if(BUILD_TESTING) # Tests all build into ninja_test executable. add_executable(ninja_test + src/ansi_color_test.cc src/build_log_test.cc src/build_test.cc src/clean_test.cc diff --git a/configure.py b/configure.py index db5c4dc7..a3cf094b 100755 --- a/configure.py +++ b/configure.py @@ -537,7 +537,8 @@ n.newline() n.comment('Core source files all build into ninja library.') objs.extend(re2c_objs) -for name in ['build', +for name in ['ansi_color', + 'build', 'build_log', 'clean', 'clparser', @@ -643,6 +644,7 @@ if gtest_src_dir: test_variables += [('pdb', 'ninja_test.pdb')] test_names = [ + 'ansi_color_test', 'build_log_test', 'build_test', 'clean_test', diff --git a/src/ansi_color.cc b/src/ansi_color.cc new file mode 100644 index 00000000..1f374dc3 --- /dev/null +++ b/src/ansi_color.cc @@ -0,0 +1,33 @@ +// Copyright 2026 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "ansi_color.h" + +#include +#include + +bool EnvHasNoColor() { + char* no_color = std::getenv("NO_COLOR"); + return no_color && std::string(no_color) != "0"; +} + +bool EnvHasCliColorForce() { + char* clicolor_force = std::getenv("CLICOLOR_FORCE"); + return clicolor_force && std::string(clicolor_force) != "0"; +} + +bool EnvHasForceColor() { + char* force_color = std::getenv("FORCE_COLOR"); + return force_color && std::string(force_color) != "0"; +} diff --git a/src/ansi_color.h b/src/ansi_color.h new file mode 100644 index 00000000..d060f4bc --- /dev/null +++ b/src/ansi_color.h @@ -0,0 +1,27 @@ +// Copyright 2026 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef NINJA_ANSI_COLOR_H +#define NINJA_ANSI_COLOR_H + +/// Check if environment variable NO_COLOR is set. +bool EnvHasNoColor(); + +/// Check if environment variable CLICOLOR_FORCE is set. +bool EnvHasCliColorForce(); + +/// Check if environment variable FORCE_COLOR is set. +bool EnvHasForceColor(); + +#endif // NINJA_ANSI_COLOR_H diff --git a/src/ansi_color_test.cc b/src/ansi_color_test.cc new file mode 100644 index 00000000..92f197c2 --- /dev/null +++ b/src/ansi_color_test.cc @@ -0,0 +1,82 @@ +// Copyright 2026 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "ansi_color.h" +#include "test.h" + +#ifdef _WIN32 +#include +#endif + +#ifdef _WIN32 +TEST(AnsiColorTest, CliColorForce) { + const char* temp_value = std::getenv("CLICOLOR_FORCE"); + std::string original_value = temp_value ? temp_value : "0"; + SetEnvironmentVariable("CLICOLOR_FORCE", "1"); + ASSERT_EQ(true, EnvHasCliColorForce()); + SetEnvironmentVariable("CLICOLOR_FORCE", "0"); + ASSERT_EQ(false, EnvHasCliColorForce()); + SetEnvironmentVariable("CLICOLOR_FORCE", original_value); +} + +TEST(AnsiColorTest, ForceColor) { + const char* temp_value = std::getenv("FORCE_COLOR"); + std::string original_value = temp_value ? temp_value : "0"; + SetEnvironmentVariable("FORCE_COLOR", "1"); + ASSERT_EQ(true, EnvHasForceColor()); + SetEnvironmentVariable("FORCE_COLOR", "0"); + ASSERT_EQ(false, EnvHasForceColor()); + SetEnvironmentVariable("FORCE_COLOR", original_value); +} + +TEST(AnsiColorTest, NoColor) { + const char* temp_value = std::getenv("NO_COLOR"); + std::string original_value = temp_value ? temp_value : "0"; + SetEnvironmentVariable("NO_COLOR", "1"); + ASSERT_EQ(true, EnvHasNoColor()); + SetEnvironmentVariable("NO_COLOR", "0"); + ASSERT_EQ(false, EnvHasNoColor()); + SetEnvironmentVariable("NO_COLOR", original_value); +} +#else +TEST(AnsiColorTest, CliColorForce) { + const char* temp_value = std::getenv("CLICOLOR_FORCE"); + std::string original_value = temp_value ? temp_value : "0"; + setenv("CLICOLOR_FORCE", "1", 1); + ASSERT_EQ(true, EnvHasCliColorForce()); + setenv("CLICOLOR_FORCE", "0", 1); + ASSERT_EQ(false, EnvHasCliColorForce()); + setenv("CLICOLOR_FORCE", original_value.c_str(), 1); +} + +TEST(AnsiColorTest, ForceColor) { + const char* temp_value = std::getenv("FORCE_COLOR"); + std::string original_value = temp_value ? temp_value : "0"; + setenv("FORCE_COLOR", "1", 1); + ASSERT_EQ(true, EnvHasForceColor()); + setenv("FORCE_COLOR", "0", 1); + ASSERT_EQ(false, EnvHasForceColor()); + setenv("FORCE_COLOR", original_value.c_str(), 1); +} + +TEST(AnsiColorTest, NoColor) { + const char* temp_value = std::getenv("NO_COLOR"); + std::string original_value = temp_value ? temp_value : "0"; + setenv("NO_COLOR", "1", 1); + ASSERT_EQ(true, EnvHasNoColor()); + setenv("NO_COLOR", "0", 1); + ASSERT_EQ(false, EnvHasNoColor()); + setenv("NO_COLOR", original_value.c_str(), 1); +} +#endif diff --git a/src/line_printer.cc b/src/line_printer.cc index 00ca3f09..79b8642c 100644 --- a/src/line_printer.cc +++ b/src/line_printer.cc @@ -30,6 +30,7 @@ #include "elide_middle.h" #include "util.h" +#include "ansi_color.h" using namespace std; @@ -52,7 +53,7 @@ LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) { if (supports_color_) { /* if (EnvHasNoColor()) { - supports_color_ = false; + supports_color_ = false; } */ DWORD mode; @@ -67,17 +68,17 @@ LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) { /* // NO_COLOR and CLICOLOR_FORCE: NO_COLOR "overrides" CLICOLOR_FORCE if (EnvHasNoColor()) { - supports_color_ = false; + supports_color_ = false; } else if (EnvHasCliColorForce()) { - supports_color_ = true; + supports_color_ = true; } // NO_COLOR and FORCE_COLOR: FORCE_COLOR "overrides" NO_COLOR if (EnvHasForceColor()) { - supports_color = true; + supports_color = true; } */ if (EnvHasCliColorForce() || EnvHasForceColor()) { - supports_color_ = true; + supports_color_ = true; } } } @@ -184,27 +185,3 @@ void LinePrinter::SetConsoleLocked(bool locked) { line_buffer_.clear(); } } - -bool LinePrinter::EnvHasNoColor() { - char* no_color = getenv("NO_COLOR"); - if (no_color != NULL) { - return true; - } - return false; -} - -bool LinePrinter::EnvHasCliColorForce() { - char* clicolor_force = getenv("CLICOLOR_FORCE"); - if (clicolor_force != NULL) { - return true; - } - return false; -} - -bool LinePrinter::EnvHasForceColor() { - char* force_color = getenv("FORCE_COLOR"); - if (force_color != NULL) { - return true; - } - return false; -} diff --git a/src/line_printer.h b/src/line_printer.h index c49a0f64..a8ec9ff4 100644 --- a/src/line_printer.h +++ b/src/line_printer.h @@ -71,15 +71,6 @@ struct LinePrinter { /// Print the given data to the console, or buffer it if it is locked. void PrintOrBuffer(const char *data, size_t size); - - /// CURRENTLY UNUSED (see line_printer.cc). Check if environment variable NO_COLOR is set. - bool EnvHasNoColor(); - - /// Check if environment variable CLICOLOR_FORCE is set. - bool EnvHasCliColorForce(); - - /// Check if environment variable FORCE_COLOR is set. - bool EnvHasForceColor(); }; #endif // NINJA_LINE_PRINTER_H_ From 14fa2b7df0f826f03cd7bf9fba77b783ce75e73a Mon Sep 17 00:00:00 2001 From: Brayden Krus <151576863+braydenkrus@users.noreply.github.com> Date: Thu, 23 Apr 2026 10:45:25 -0400 Subject: [PATCH 08/13] Fix AnsiColorTest on Windows, remove Windows line endings --- src/ansi_color.cc | 88 ++++++++++++-------- src/ansi_color.h | 54 ++++++------- src/ansi_color_test.cc | 180 ++++++++++++++++++++++------------------- 3 files changed, 180 insertions(+), 142 deletions(-) diff --git a/src/ansi_color.cc b/src/ansi_color.cc index 1f374dc3..5011ff5a 100644 --- a/src/ansi_color.cc +++ b/src/ansi_color.cc @@ -1,33 +1,55 @@ -// Copyright 2026 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "ansi_color.h" - -#include -#include - -bool EnvHasNoColor() { - char* no_color = std::getenv("NO_COLOR"); - return no_color && std::string(no_color) != "0"; -} - -bool EnvHasCliColorForce() { - char* clicolor_force = std::getenv("CLICOLOR_FORCE"); - return clicolor_force && std::string(clicolor_force) != "0"; -} - -bool EnvHasForceColor() { - char* force_color = std::getenv("FORCE_COLOR"); - return force_color && std::string(force_color) != "0"; -} +// Copyright 2026 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "ansi_color.h" + +#include +#include + +#ifdef _WIN32 +#include +#endif + +bool EnvHasNoColor() { + #ifdef _WIN32 + char buf[1024]; + DWORD len = GetEnvironmentVariableA("NO_COLOR", buf, sizeof(buf)); + return len > 0 && std::string(buf) != "0"; + #else + char* no_color = std::getenv("NO_COLOR"); + return no_color && std::string(no_color) != "0"; + #endif +} + +bool EnvHasCliColorForce() { + #ifdef _WIN32 + char buf[1024]; + DWORD len = GetEnvironmentVariableA("CLICOLOR_FORCE", buf, sizeof(buf)); + return len > 0 && std::string(buf) != "0"; + #else + char* clicolor_force = std::getenv("CLICOLOR_FORCE"); + return clicolor_force && std::string(clicolor_force) != "0"; + #endif +} + +bool EnvHasForceColor() { + #ifdef _WIN32 + char buf[1024]; + DWORD len = GetEnvironmentVariableA("FORCE_COLOR", buf, sizeof(buf)); + return len > 0 && std::string(buf) != "0"; + #else + char* force_color = std::getenv("FORCE_COLOR"); + return force_color && std::string(force_color) != "0"; + #endif +} diff --git a/src/ansi_color.h b/src/ansi_color.h index d060f4bc..8f3c5a00 100644 --- a/src/ansi_color.h +++ b/src/ansi_color.h @@ -1,27 +1,27 @@ -// Copyright 2026 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef NINJA_ANSI_COLOR_H -#define NINJA_ANSI_COLOR_H - -/// Check if environment variable NO_COLOR is set. -bool EnvHasNoColor(); - -/// Check if environment variable CLICOLOR_FORCE is set. -bool EnvHasCliColorForce(); - -/// Check if environment variable FORCE_COLOR is set. -bool EnvHasForceColor(); - -#endif // NINJA_ANSI_COLOR_H +// Copyright 2026 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef NINJA_ANSI_COLOR_H +#define NINJA_ANSI_COLOR_H + +/// Check if environment variable NO_COLOR is set. +bool EnvHasNoColor(); + +/// Check if environment variable CLICOLOR_FORCE is set. +bool EnvHasCliColorForce(); + +/// Check if environment variable FORCE_COLOR is set. +bool EnvHasForceColor(); + +#endif // NINJA_ANSI_COLOR_H diff --git a/src/ansi_color_test.cc b/src/ansi_color_test.cc index 92f197c2..606d8044 100644 --- a/src/ansi_color_test.cc +++ b/src/ansi_color_test.cc @@ -1,82 +1,98 @@ -// Copyright 2026 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "ansi_color.h" -#include "test.h" - -#ifdef _WIN32 -#include -#endif - -#ifdef _WIN32 -TEST(AnsiColorTest, CliColorForce) { - const char* temp_value = std::getenv("CLICOLOR_FORCE"); - std::string original_value = temp_value ? temp_value : "0"; - SetEnvironmentVariable("CLICOLOR_FORCE", "1"); - ASSERT_EQ(true, EnvHasCliColorForce()); - SetEnvironmentVariable("CLICOLOR_FORCE", "0"); - ASSERT_EQ(false, EnvHasCliColorForce()); - SetEnvironmentVariable("CLICOLOR_FORCE", original_value); -} - -TEST(AnsiColorTest, ForceColor) { - const char* temp_value = std::getenv("FORCE_COLOR"); - std::string original_value = temp_value ? temp_value : "0"; - SetEnvironmentVariable("FORCE_COLOR", "1"); - ASSERT_EQ(true, EnvHasForceColor()); - SetEnvironmentVariable("FORCE_COLOR", "0"); - ASSERT_EQ(false, EnvHasForceColor()); - SetEnvironmentVariable("FORCE_COLOR", original_value); -} - -TEST(AnsiColorTest, NoColor) { - const char* temp_value = std::getenv("NO_COLOR"); - std::string original_value = temp_value ? temp_value : "0"; - SetEnvironmentVariable("NO_COLOR", "1"); - ASSERT_EQ(true, EnvHasNoColor()); - SetEnvironmentVariable("NO_COLOR", "0"); - ASSERT_EQ(false, EnvHasNoColor()); - SetEnvironmentVariable("NO_COLOR", original_value); -} -#else -TEST(AnsiColorTest, CliColorForce) { - const char* temp_value = std::getenv("CLICOLOR_FORCE"); - std::string original_value = temp_value ? temp_value : "0"; - setenv("CLICOLOR_FORCE", "1", 1); - ASSERT_EQ(true, EnvHasCliColorForce()); - setenv("CLICOLOR_FORCE", "0", 1); - ASSERT_EQ(false, EnvHasCliColorForce()); - setenv("CLICOLOR_FORCE", original_value.c_str(), 1); -} - -TEST(AnsiColorTest, ForceColor) { - const char* temp_value = std::getenv("FORCE_COLOR"); - std::string original_value = temp_value ? temp_value : "0"; - setenv("FORCE_COLOR", "1", 1); - ASSERT_EQ(true, EnvHasForceColor()); - setenv("FORCE_COLOR", "0", 1); - ASSERT_EQ(false, EnvHasForceColor()); - setenv("FORCE_COLOR", original_value.c_str(), 1); -} - -TEST(AnsiColorTest, NoColor) { - const char* temp_value = std::getenv("NO_COLOR"); - std::string original_value = temp_value ? temp_value : "0"; - setenv("NO_COLOR", "1", 1); - ASSERT_EQ(true, EnvHasNoColor()); - setenv("NO_COLOR", "0", 1); - ASSERT_EQ(false, EnvHasNoColor()); - setenv("NO_COLOR", original_value.c_str(), 1); -} -#endif +// Copyright 2026 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "ansi_color.h" +#include "test.h" + +#ifdef _WIN32 +#include +#endif + +TEST(AnsiColorTest, CliColorForce) { + #ifdef _WIN32 + char buf[32767]; + DWORD len = GetEnvironmentVariableA("CLICOLOR_FORCE", buf, sizeof(buf)); + std::string original_value; + if (len > 0) { + original_value = buf; + } else { + original_value = "0"; + } + SetEnvironmentVariableA("CLICOLOR_FORCE", "1"); + ASSERT_EQ(true, EnvHasCliColorForce()); + SetEnvironmentVariableA("CLICOLOR_FORCE", "0"); + ASSERT_EQ(false, EnvHasCliColorForce()); + SetEnvironmentVariableA("CLICOLOR_FORCE", original_value.c_str()); + #else + const char* temp_value = std::getenv("CLICOLOR_FORCE"); + std::string original_value = temp_value ? temp_value : "0"; + setenv("CLICOLOR_FORCE", "1", 1); + ASSERT_EQ(true, EnvHasCliColorForce()); + setenv("CLICOLOR_FORCE", "0", 1); + ASSERT_EQ(false, EnvHasCliColorForce()); + setenv("CLICOLOR_FORCE", original_value.c_str(), 1); + #endif +} + +TEST(AnsiColorTest, ForceColor) { + #ifdef _WIN32 + char buf[32767]; + DWORD len = GetEnvironmentVariableA("FORCE_COLOR", buf, sizeof(buf)); + std::string original_value; + if (len > 0) { + original_value = buf; + } else { + original_value = "0"; + } + SetEnvironmentVariableA("FORCE_COLOR", "1"); + ASSERT_EQ(true, EnvHasForceColor()); + SetEnvironmentVariableA("FORCE_COLOR", "0"); + ASSERT_EQ(false, EnvHasForceColor()); + SetEnvironmentVariableA("FORCE_COLOR", original_value.c_str()); + #else + const char* temp_value = std::getenv("FORCE_COLOR"); + std::string original_value = temp_value ? temp_value : "0"; + setenv("FORCE_COLOR", "1", 1); + ASSERT_EQ(true, EnvHasForceColor()); + setenv("FORCE_COLOR", "0", 1); + ASSERT_EQ(false, EnvHasForceColor()); + setenv("FORCE_COLOR", original_value.c_str(), 1); + #endif +} + +TEST(AnsiColorTest, NoColor) { + #ifdef _WIN32 + char buf[32767]; + DWORD len = GetEnvironmentVariableA("NO_COLOR", buf, sizeof(buf)); + std::string original_value; + if (len > 0) { + original_value = buf; + } else { + original_value = "0"; + } + SetEnvironmentVariableA("NO_COLOR", "1"); + ASSERT_EQ(true, EnvHasNoColor()); + SetEnvironmentVariableA("NO_COLOR", "0"); + ASSERT_EQ(false, EnvHasNoColor()); + SetEnvironmentVariableA("NO_COLOR", original_value.c_str()); + #else + const char* temp_value = std::getenv("NO_COLOR"); + std::string original_value = temp_value ? temp_value : "0"; + setenv("NO_COLOR", "1", 1); + ASSERT_EQ(true, EnvHasNoColor()); + setenv("NO_COLOR", "0", 1); + ASSERT_EQ(false, EnvHasNoColor()); + setenv("NO_COLOR", original_value.c_str(), 1); + #endif +} From 61b029a1f387ed054f9bcf2d0870414153d3990d Mon Sep 17 00:00:00 2001 From: Brayden Krus <151576863+braydenkrus@users.noreply.github.com> Date: Tue, 28 Apr 2026 10:20:59 -0400 Subject: [PATCH 09/13] Switch to getenv and _putenv_s for Windows ansi_color --- src/ansi_color.cc | 22 ------------------- src/ansi_color_test.cc | 48 +++++++++++++----------------------------- 2 files changed, 15 insertions(+), 55 deletions(-) diff --git a/src/ansi_color.cc b/src/ansi_color.cc index 5011ff5a..ba99c77d 100644 --- a/src/ansi_color.cc +++ b/src/ansi_color.cc @@ -17,39 +17,17 @@ #include #include -#ifdef _WIN32 -#include -#endif - bool EnvHasNoColor() { - #ifdef _WIN32 - char buf[1024]; - DWORD len = GetEnvironmentVariableA("NO_COLOR", buf, sizeof(buf)); - return len > 0 && std::string(buf) != "0"; - #else char* no_color = std::getenv("NO_COLOR"); return no_color && std::string(no_color) != "0"; - #endif } bool EnvHasCliColorForce() { - #ifdef _WIN32 - char buf[1024]; - DWORD len = GetEnvironmentVariableA("CLICOLOR_FORCE", buf, sizeof(buf)); - return len > 0 && std::string(buf) != "0"; - #else char* clicolor_force = std::getenv("CLICOLOR_FORCE"); return clicolor_force && std::string(clicolor_force) != "0"; - #endif } bool EnvHasForceColor() { - #ifdef _WIN32 - char buf[1024]; - DWORD len = GetEnvironmentVariableA("FORCE_COLOR", buf, sizeof(buf)); - return len > 0 && std::string(buf) != "0"; - #else char* force_color = std::getenv("FORCE_COLOR"); return force_color && std::string(force_color) != "0"; - #endif } diff --git a/src/ansi_color_test.cc b/src/ansi_color_test.cc index 606d8044..2ed776ed 100644 --- a/src/ansi_color_test.cc +++ b/src/ansi_color_test.cc @@ -21,19 +21,13 @@ TEST(AnsiColorTest, CliColorForce) { #ifdef _WIN32 - char buf[32767]; - DWORD len = GetEnvironmentVariableA("CLICOLOR_FORCE", buf, sizeof(buf)); - std::string original_value; - if (len > 0) { - original_value = buf; - } else { - original_value = "0"; - } - SetEnvironmentVariableA("CLICOLOR_FORCE", "1"); + const char* temp_value = std::getenv("CLICOLOR_FORCE"); + std::string original_value = temp_value ? temp_value : "0"; + _putenv_s("CLICOLOR_FORCE", "1"); ASSERT_EQ(true, EnvHasCliColorForce()); - SetEnvironmentVariableA("CLICOLOR_FORCE", "0"); + _putenv_s("CLICOLOR_FORCE", "0"); ASSERT_EQ(false, EnvHasCliColorForce()); - SetEnvironmentVariableA("CLICOLOR_FORCE", original_value.c_str()); + _putenv_s("CLICOLOR_FORCE", original_value.c_str()); #else const char* temp_value = std::getenv("CLICOLOR_FORCE"); std::string original_value = temp_value ? temp_value : "0"; @@ -47,19 +41,13 @@ TEST(AnsiColorTest, CliColorForce) { TEST(AnsiColorTest, ForceColor) { #ifdef _WIN32 - char buf[32767]; - DWORD len = GetEnvironmentVariableA("FORCE_COLOR", buf, sizeof(buf)); - std::string original_value; - if (len > 0) { - original_value = buf; - } else { - original_value = "0"; - } - SetEnvironmentVariableA("FORCE_COLOR", "1"); + const char* temp_value = std::getenv("FORCE_COLOR"); + std::string original_value = temp_value ? temp_value : "0"; + _putenv_s("FORCE_COLOR", "1"); ASSERT_EQ(true, EnvHasForceColor()); - SetEnvironmentVariableA("FORCE_COLOR", "0"); + _putenv_s("FORCE_COLOR", "0"); ASSERT_EQ(false, EnvHasForceColor()); - SetEnvironmentVariableA("FORCE_COLOR", original_value.c_str()); + _putenv_s("FORCE_COLOR", original_value.c_str()); #else const char* temp_value = std::getenv("FORCE_COLOR"); std::string original_value = temp_value ? temp_value : "0"; @@ -73,19 +61,13 @@ TEST(AnsiColorTest, ForceColor) { TEST(AnsiColorTest, NoColor) { #ifdef _WIN32 - char buf[32767]; - DWORD len = GetEnvironmentVariableA("NO_COLOR", buf, sizeof(buf)); - std::string original_value; - if (len > 0) { - original_value = buf; - } else { - original_value = "0"; - } - SetEnvironmentVariableA("NO_COLOR", "1"); + const char* temp_value = std::getenv("NO_COLOR"); + std::string original_value = temp_value ? temp_value : "0"; + _putenv_s("NO_COLOR", "1"); ASSERT_EQ(true, EnvHasNoColor()); - SetEnvironmentVariableA("NO_COLOR", "0"); + _putenv_s("NO_COLOR", "0"); ASSERT_EQ(false, EnvHasNoColor()); - SetEnvironmentVariableA("NO_COLOR", original_value.c_str()); + _putenv_s("NO_COLOR", original_value.c_str()); #else const char* temp_value = std::getenv("NO_COLOR"); std::string original_value = temp_value ? temp_value : "0"; From d4f11df90f7211a399625948254b2c8536da5a82 Mon Sep 17 00:00:00 2001 From: Brayden Krus <151576863+braydenkrus@users.noreply.github.com> Date: Thu, 30 Apr 2026 10:04:57 -0400 Subject: [PATCH 10/13] Remove ansi_color, move its implementation to line_printer --- CMakeLists.txt | 2 -- configure.py | 4 +-- src/ansi_color.cc | 33 ----------------- src/ansi_color.h | 27 -------------- src/ansi_color_test.cc | 80 ------------------------------------------ src/line_printer.cc | 16 ++++++++- src/line_printer.h | 9 +++++ 7 files changed, 25 insertions(+), 146 deletions(-) delete mode 100644 src/ansi_color.cc delete mode 100644 src/ansi_color.h delete mode 100644 src/ansi_color_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c1ea991..c777afc2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,7 +125,6 @@ check_platform_supports_browse_mode(platform_supports_ninja_browse) # Core source files all build into ninja library. add_library(libninja OBJECT - src/ansi_color.cc src/build_log.cc src/build.cc src/clean.cc @@ -274,7 +273,6 @@ if(BUILD_TESTING) # Tests all build into ninja_test executable. add_executable(ninja_test - src/ansi_color_test.cc src/build_log_test.cc src/build_test.cc src/clean_test.cc diff --git a/configure.py b/configure.py index a3cf094b..db5c4dc7 100755 --- a/configure.py +++ b/configure.py @@ -537,8 +537,7 @@ n.newline() n.comment('Core source files all build into ninja library.') objs.extend(re2c_objs) -for name in ['ansi_color', - 'build', +for name in ['build', 'build_log', 'clean', 'clparser', @@ -644,7 +643,6 @@ if gtest_src_dir: test_variables += [('pdb', 'ninja_test.pdb')] test_names = [ - 'ansi_color_test', 'build_log_test', 'build_test', 'clean_test', diff --git a/src/ansi_color.cc b/src/ansi_color.cc deleted file mode 100644 index ba99c77d..00000000 --- a/src/ansi_color.cc +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2026 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "ansi_color.h" - -#include -#include - -bool EnvHasNoColor() { - char* no_color = std::getenv("NO_COLOR"); - return no_color && std::string(no_color) != "0"; -} - -bool EnvHasCliColorForce() { - char* clicolor_force = std::getenv("CLICOLOR_FORCE"); - return clicolor_force && std::string(clicolor_force) != "0"; -} - -bool EnvHasForceColor() { - char* force_color = std::getenv("FORCE_COLOR"); - return force_color && std::string(force_color) != "0"; -} diff --git a/src/ansi_color.h b/src/ansi_color.h deleted file mode 100644 index 8f3c5a00..00000000 --- a/src/ansi_color.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2026 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef NINJA_ANSI_COLOR_H -#define NINJA_ANSI_COLOR_H - -/// Check if environment variable NO_COLOR is set. -bool EnvHasNoColor(); - -/// Check if environment variable CLICOLOR_FORCE is set. -bool EnvHasCliColorForce(); - -/// Check if environment variable FORCE_COLOR is set. -bool EnvHasForceColor(); - -#endif // NINJA_ANSI_COLOR_H diff --git a/src/ansi_color_test.cc b/src/ansi_color_test.cc deleted file mode 100644 index 2ed776ed..00000000 --- a/src/ansi_color_test.cc +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2026 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "ansi_color.h" -#include "test.h" - -#ifdef _WIN32 -#include -#endif - -TEST(AnsiColorTest, CliColorForce) { - #ifdef _WIN32 - const char* temp_value = std::getenv("CLICOLOR_FORCE"); - std::string original_value = temp_value ? temp_value : "0"; - _putenv_s("CLICOLOR_FORCE", "1"); - ASSERT_EQ(true, EnvHasCliColorForce()); - _putenv_s("CLICOLOR_FORCE", "0"); - ASSERT_EQ(false, EnvHasCliColorForce()); - _putenv_s("CLICOLOR_FORCE", original_value.c_str()); - #else - const char* temp_value = std::getenv("CLICOLOR_FORCE"); - std::string original_value = temp_value ? temp_value : "0"; - setenv("CLICOLOR_FORCE", "1", 1); - ASSERT_EQ(true, EnvHasCliColorForce()); - setenv("CLICOLOR_FORCE", "0", 1); - ASSERT_EQ(false, EnvHasCliColorForce()); - setenv("CLICOLOR_FORCE", original_value.c_str(), 1); - #endif -} - -TEST(AnsiColorTest, ForceColor) { - #ifdef _WIN32 - const char* temp_value = std::getenv("FORCE_COLOR"); - std::string original_value = temp_value ? temp_value : "0"; - _putenv_s("FORCE_COLOR", "1"); - ASSERT_EQ(true, EnvHasForceColor()); - _putenv_s("FORCE_COLOR", "0"); - ASSERT_EQ(false, EnvHasForceColor()); - _putenv_s("FORCE_COLOR", original_value.c_str()); - #else - const char* temp_value = std::getenv("FORCE_COLOR"); - std::string original_value = temp_value ? temp_value : "0"; - setenv("FORCE_COLOR", "1", 1); - ASSERT_EQ(true, EnvHasForceColor()); - setenv("FORCE_COLOR", "0", 1); - ASSERT_EQ(false, EnvHasForceColor()); - setenv("FORCE_COLOR", original_value.c_str(), 1); - #endif -} - -TEST(AnsiColorTest, NoColor) { - #ifdef _WIN32 - const char* temp_value = std::getenv("NO_COLOR"); - std::string original_value = temp_value ? temp_value : "0"; - _putenv_s("NO_COLOR", "1"); - ASSERT_EQ(true, EnvHasNoColor()); - _putenv_s("NO_COLOR", "0"); - ASSERT_EQ(false, EnvHasNoColor()); - _putenv_s("NO_COLOR", original_value.c_str()); - #else - const char* temp_value = std::getenv("NO_COLOR"); - std::string original_value = temp_value ? temp_value : "0"; - setenv("NO_COLOR", "1", 1); - ASSERT_EQ(true, EnvHasNoColor()); - setenv("NO_COLOR", "0", 1); - ASSERT_EQ(false, EnvHasNoColor()); - setenv("NO_COLOR", original_value.c_str(), 1); - #endif -} diff --git a/src/line_printer.cc b/src/line_printer.cc index 79b8642c..50309e74 100644 --- a/src/line_printer.cc +++ b/src/line_printer.cc @@ -30,7 +30,6 @@ #include "elide_middle.h" #include "util.h" -#include "ansi_color.h" using namespace std; @@ -185,3 +184,18 @@ void LinePrinter::SetConsoleLocked(bool locked) { line_buffer_.clear(); } } + +bool LinePrinter::EnvHasNoColor() { + char* no_color = std::getenv("NO_COLOR"); + return no_color && std::string(no_color) != "0"; +} + +bool LinePrinter::EnvHasCliColorForce() { + char* clicolor_force = std::getenv("CLICOLOR_FORCE"); + return clicolor_force && std::string(clicolor_force) != "0"; +} + +bool LinePrinter::EnvHasForceColor() { + char* force_color = std::getenv("FORCE_COLOR"); + return force_color && std::string(force_color) != "0"; +} diff --git a/src/line_printer.h b/src/line_printer.h index a8ec9ff4..ac1a7c67 100644 --- a/src/line_printer.h +++ b/src/line_printer.h @@ -43,6 +43,15 @@ struct LinePrinter { /// console is locked will not be printed until it is unlocked. void SetConsoleLocked(bool locked); + /// Check if environment variable NO_COLOR is set. + bool EnvHasNoColor(); + + /// Check if environment variable CLICOLOR_FORCE is set. + bool EnvHasCliColorForce(); + + /// Check if environment variable FORCE_COLOR is set. + bool EnvHasForceColor(); + private: /// Whether we can do fancy terminal control codes. bool smart_terminal_; From 6aa47db2a3509b990f34e5ed5ca538bfafd2f1b6 Mon Sep 17 00:00:00 2001 From: Brayden Krus <151576863+braydenkrus@users.noreply.github.com> Date: Mon, 4 May 2026 12:21:08 -0400 Subject: [PATCH 11/13] Use anonymous namespace for helper functions, uncomment NO_COLOR code --- src/line_printer.cc | 39 +++++++++++++++++---------------------- src/line_printer.h | 9 --------- 2 files changed, 17 insertions(+), 31 deletions(-) diff --git a/src/line_printer.cc b/src/line_printer.cc index 50309e74..dc79b46f 100644 --- a/src/line_printer.cc +++ b/src/line_printer.cc @@ -33,6 +33,23 @@ using namespace std; +namespace { +bool EnvHasNoColor() { + char* no_color = std::getenv("NO_COLOR"); + return no_color && std::string(no_color) != "0"; +} + +bool EnvHasCliColorForce() { + char* clicolor_force = std::getenv("CLICOLOR_FORCE"); + return clicolor_force && std::string(clicolor_force) != "0"; +} + +bool EnvHasForceColor() { + char* force_color = std::getenv("FORCE_COLOR"); + return force_color && std::string(force_color) != "0"; +} +} // anonymous namespace + LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) { const char* term = getenv("TERM"); #ifndef _WIN32 @@ -50,11 +67,9 @@ LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) { #ifdef _WIN32 // Try enabling ANSI escape sequence support on Windows 10 terminals. if (supports_color_) { - /* if (EnvHasNoColor()) { supports_color_ = false; } - */ DWORD mode; if (GetConsoleMode(console_, &mode)) { if (!SetConsoleMode(console_, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) { @@ -64,7 +79,6 @@ LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) { } #endif if (!supports_color_) { - /* // NO_COLOR and CLICOLOR_FORCE: NO_COLOR "overrides" CLICOLOR_FORCE if (EnvHasNoColor()) { supports_color_ = false; @@ -73,10 +87,6 @@ LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) { } // NO_COLOR and FORCE_COLOR: FORCE_COLOR "overrides" NO_COLOR if (EnvHasForceColor()) { - supports_color = true; - } - */ - if (EnvHasCliColorForce() || EnvHasForceColor()) { supports_color_ = true; } } @@ -184,18 +194,3 @@ void LinePrinter::SetConsoleLocked(bool locked) { line_buffer_.clear(); } } - -bool LinePrinter::EnvHasNoColor() { - char* no_color = std::getenv("NO_COLOR"); - return no_color && std::string(no_color) != "0"; -} - -bool LinePrinter::EnvHasCliColorForce() { - char* clicolor_force = std::getenv("CLICOLOR_FORCE"); - return clicolor_force && std::string(clicolor_force) != "0"; -} - -bool LinePrinter::EnvHasForceColor() { - char* force_color = std::getenv("FORCE_COLOR"); - return force_color && std::string(force_color) != "0"; -} diff --git a/src/line_printer.h b/src/line_printer.h index ac1a7c67..a8ec9ff4 100644 --- a/src/line_printer.h +++ b/src/line_printer.h @@ -43,15 +43,6 @@ struct LinePrinter { /// console is locked will not be printed until it is unlocked. void SetConsoleLocked(bool locked); - /// Check if environment variable NO_COLOR is set. - bool EnvHasNoColor(); - - /// Check if environment variable CLICOLOR_FORCE is set. - bool EnvHasCliColorForce(); - - /// Check if environment variable FORCE_COLOR is set. - bool EnvHasForceColor(); - private: /// Whether we can do fancy terminal control codes. bool smart_terminal_; From 044656d45d0e56e082d9361df229254a183d1fff Mon Sep 17 00:00:00 2001 From: Brayden Krus <151576863+braydenkrus@users.noreply.github.com> Date: Mon, 4 May 2026 15:26:59 -0400 Subject: [PATCH 12/13] Add a check for NO_COLOR for UNIX that was included for Windows --- src/line_printer.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/line_printer.cc b/src/line_printer.cc index dc79b46f..a9fc2851 100644 --- a/src/line_printer.cc +++ b/src/line_printer.cc @@ -64,6 +64,9 @@ LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) { } #endif supports_color_ = smart_terminal_; + if (EnvHasNoColor()) { + supports_color_ = false; + } #ifdef _WIN32 // Try enabling ANSI escape sequence support on Windows 10 terminals. if (supports_color_) { From 2c729faff30a8014e29bb1e2c03697209a75a6a5 Mon Sep 17 00:00:00 2001 From: Brayden Krus <151576863+braydenkrus@users.noreply.github.com> Date: Wed, 20 May 2026 12:44:39 -0400 Subject: [PATCH 13/13] Remove unnecessary NO_COLOR checks, condense checks for CLICOLOR_FORCE and FORCE_COLOR --- src/line_printer.cc | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/line_printer.cc b/src/line_printer.cc index a9fc2851..b52ba301 100644 --- a/src/line_printer.cc +++ b/src/line_printer.cc @@ -70,9 +70,6 @@ LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) { #ifdef _WIN32 // Try enabling ANSI escape sequence support on Windows 10 terminals. if (supports_color_) { - if (EnvHasNoColor()) { - supports_color_ = false; - } DWORD mode; if (GetConsoleMode(console_, &mode)) { if (!SetConsoleMode(console_, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) { @@ -83,13 +80,8 @@ LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) { #endif if (!supports_color_) { // NO_COLOR and CLICOLOR_FORCE: NO_COLOR "overrides" CLICOLOR_FORCE - if (EnvHasNoColor()) { - supports_color_ = false; - } else if (EnvHasCliColorForce()) { - supports_color_ = true; - } // NO_COLOR and FORCE_COLOR: FORCE_COLOR "overrides" NO_COLOR - if (EnvHasForceColor()) { + if ((!EnvHasNoColor() && EnvHasCliColorForce()) || EnvHasForceColor()) { supports_color_ = true; } }