From f7600f07eecbdac0a4400ca2bc39e3e9f5a53b1b Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 8 Dec 2022 10:49:57 +0200 Subject: Add --[no]diag-color options (infrastructure only) --- build2/b.cxx | 1 + libbuild2/b-cmdline.cxx | 6 ++++++ libbuild2/b-cmdline.hxx | 1 + libbuild2/b-options.cxx | 33 ++++++++++++++++++++++++++++++++- libbuild2/b-options.hxx | 8 ++++++++ libbuild2/b-options.ixx | 12 ++++++++++++ libbuild2/b.cli | 18 +++++++++++++++++- libbuild2/context.cxx | 18 +++++++++++++++--- libbuild2/diagnostics.cxx | 40 ++++++++++++++++++++++++++++++++++++---- libbuild2/diagnostics.hxx | 16 +++++++++++++--- libbuild2/utility.hxx | 13 ++++++++++++- 11 files changed, 153 insertions(+), 13 deletions(-) diff --git a/build2/b.cxx b/build2/b.cxx index 68c77c8..0e52d25 100644 --- a/build2/b.cxx +++ b/build2/b.cxx @@ -329,6 +329,7 @@ main (int argc, char* argv[]) init_diag (cmdl.verbosity, ops.silent (), cmdl.progress, + cmdl.diag_color, ops.no_line (), ops.no_column (), fdterm (stderr_fd ())); diff --git a/libbuild2/b-cmdline.cxx b/libbuild2/b-cmdline.cxx index 2e2deb8..8d78036 100644 --- a/libbuild2/b-cmdline.cxx +++ b/libbuild2/b-cmdline.cxx @@ -396,6 +396,9 @@ namespace build2 if (ops.progress () && ops.no_progress ()) fail << "both --progress and --no-progress specified"; + if (ops.diag_color () && ops.no_diag_color ()) + fail << "both --diag-color and --no-diag-color specified"; + if (ops.mtime_check () && ops.no_mtime_check ()) fail << "both --mtime-check and --no-mtime-check specified"; } @@ -416,6 +419,9 @@ namespace build2 r.progress = (ops.progress () ? optional (true) : ops.no_progress () ? optional (false) : nullopt); + r.diag_color = (ops.diag_color () ? optional (true) : + ops.no_diag_color () ? optional (false) : nullopt); + r.mtime_check = (ops.mtime_check () ? optional (true) : ops.no_mtime_check () ? optional (false) : nullopt); diff --git a/libbuild2/b-cmdline.hxx b/libbuild2/b-cmdline.hxx index c5c82fc..8ccbb20 100644 --- a/libbuild2/b-cmdline.hxx +++ b/libbuild2/b-cmdline.hxx @@ -24,6 +24,7 @@ namespace build2 // uint16_t verbosity = 1; optional progress; + optional diag_color; optional mtime_check; optional config_sub; optional config_guess; diff --git a/libbuild2/b-options.cxx b/libbuild2/b-options.cxx index c1e5f23..1fa801a 100644 --- a/libbuild2/b-options.cxx +++ b/libbuild2/b-options.cxx @@ -278,6 +278,8 @@ namespace build2 stat_ (), progress_ (), no_progress_ (), + diag_color_ (), + no_diag_color_ (), jobs_ (), jobs_specified_ (false), max_jobs_ (), @@ -449,6 +451,18 @@ namespace build2 this->no_progress_, a.no_progress_); } + if (a.diag_color_) + { + ::build2::build::cli::parser< bool>::merge ( + this->diag_color_, a.diag_color_); + } + + if (a.no_diag_color_) + { + ::build2::build::cli::parser< bool>::merge ( + this->no_diag_color_, a.no_diag_color_); + } + if (a.jobs_specified_) { ::build2::build::cli::parser< size_t>::merge ( @@ -690,6 +704,19 @@ namespace build2 << "\033[1m--no-progress\033[0m Don't display build progress." << ::std::endl; os << std::endl + << "\033[1m--diag-color\033[0m Use color in diagnostics. If printing to a terminal the" << ::std::endl + << " color is used by default provided the terminal is not" << ::std::endl + << " dumb. Use \033[1m--no-diag-color\033[0m to suppress." << ::std::endl + << ::std::endl + << " This option affects the diagnostics printed by the" << ::std::endl + << " build system itself. Some rules may also choose to" << ::std::endl + << " propagate its value to tools (such as compilers) that" << ::std::endl + << " they invoke." << ::std::endl; + + os << std::endl + << "\033[1m--no-diag-color\033[0m Don't use color in diagnostics." << ::std::endl; + + os << std::endl << "\033[1m--jobs\033[0m|\033[1m-j\033[0m \033[4mnum\033[0m Number of active jobs to perform in parallel. This" << ::std::endl << " includes both the number of active threads inside the" << ::std::endl << " build system as well as the number of external commands" << ::std::endl @@ -763,7 +790,7 @@ namespace build2 << " in order to prevent interleaving. However, this can" << ::std::endl << " have side-effects since the child process' \033[1mstderr\033[0m is no" << ::std::endl << " longer a terminal. Most notably, the use of color in" << ::std::endl - << " diagnostics will be disabled by most programs. On the" << ::std::endl + << " diagnostics may be disabled by some programs. On the" << ::std::endl << " other hand, depending on the platform and programs" << ::std::endl << " invoked, the interleaving diagnostics may not break" << ::std::endl << " lines and thus could be tolerable." << ::std::endl; @@ -998,6 +1025,10 @@ namespace build2 &::build2::build::cli::thunk< b_options, &b_options::progress_ >; _cli_b_options_map_["--no-progress"] = &::build2::build::cli::thunk< b_options, &b_options::no_progress_ >; + _cli_b_options_map_["--diag-color"] = + &::build2::build::cli::thunk< b_options, &b_options::diag_color_ >; + _cli_b_options_map_["--no-diag-color"] = + &::build2::build::cli::thunk< b_options, &b_options::no_diag_color_ >; _cli_b_options_map_["--jobs"] = &::build2::build::cli::thunk< b_options, size_t, &b_options::jobs_, &b_options::jobs_specified_ >; diff --git a/libbuild2/b-options.hxx b/libbuild2/b-options.hxx index 4e85192..d965ff6 100644 --- a/libbuild2/b-options.hxx +++ b/libbuild2/b-options.hxx @@ -104,6 +104,12 @@ namespace build2 const bool& no_progress () const; + const bool& + diag_color () const; + + const bool& + no_diag_color () const; + const size_t& jobs () const; @@ -266,6 +272,8 @@ namespace build2 bool stat_; bool progress_; bool no_progress_; + bool diag_color_; + bool no_diag_color_; size_t jobs_; bool jobs_specified_; size_t max_jobs_; diff --git a/libbuild2/b-options.ixx b/libbuild2/b-options.ixx index 895831f..cdbbc3a 100644 --- a/libbuild2/b-options.ixx +++ b/libbuild2/b-options.ixx @@ -80,6 +80,18 @@ namespace build2 return this->no_progress_; } + inline const bool& b_options:: + diag_color () const + { + return this->diag_color_; + } + + inline const bool& b_options:: + no_diag_color () const + { + return this->no_diag_color_; + } + inline const size_t& b_options:: jobs () const { diff --git a/libbuild2/b.cli b/libbuild2/b.cli index 4b5e459..773e29e 100644 --- a/libbuild2/b.cli +++ b/libbuild2/b.cli @@ -549,6 +549,22 @@ namespace build2 "Don't display build progress." } + bool --diag-color + { + "Use color in diagnostics. If printing to a terminal the color is used + by default provided the terminal is not dumb. Use \cb{--no-diag-color} + to suppress. + + This option affects the diagnostics printed by the build system itself. + Some rules may also choose to propagate its value to tools (such as + compilers) that they invoke." + } + + bool --no-diag-color + { + "Don't use color in diagnostics." + } + size_t --jobs|-j { "", @@ -632,7 +648,7 @@ namespace build2 once after each child exits in order to prevent interleaving. However, this can have side-effects since the child process' \cb{stderr} is no longer a terminal. Most notably, the use of - color in diagnostics will be disabled by most programs. On the + color in diagnostics may be disabled by some programs. On the other hand, depending on the platform and programs invoked, the interleaving diagnostics may not break lines and thus could be tolerable." diff --git a/libbuild2/context.cxx b/libbuild2/context.cxx index 967577f..c9f4340 100644 --- a/libbuild2/context.cxx +++ b/libbuild2/context.cxx @@ -204,10 +204,10 @@ namespace build2 // set ("build.verbosity", uint64_t (verb)); - // Build system progress diagnostics. + // Build system diagnostics progress and color. // - // Note that it can be true, false, or NULL if progress was neither - // requested nor suppressed. + // Note that these can be true, false, or NULL if neither requested nor + // suppressed explicitly. // { value& v (gs.assign (vp.insert ("build.progress", v_g))); @@ -215,6 +215,18 @@ namespace build2 v = *diag_progress_option; } + { + value& v (gs.assign (vp.insert ("build.diag_color", v_g))); + if (diag_color_option) + v = *diag_color_option; + } + + // These are the "effective" values that incorporate a suitable default + // if neither requested nor suppressed explicitly. + // + set ("build.show_progress", show_progress (verb_never)); + set ("build.show_diag_color", show_diag_color ()); + // Build system version (similar to what we do in the version module // except here we don't include package epoch/revision). // diff --git a/libbuild2/diagnostics.cxx b/libbuild2/diagnostics.cxx index d91150b..b31ff82 100644 --- a/libbuild2/diagnostics.cxx +++ b/libbuild2/diagnostics.cxx @@ -3,7 +3,8 @@ #include -#include // strchr(), memcpy() +#include // strcmp(), strchr(), memcpy() +#include // getenv() #include @@ -24,23 +25,54 @@ namespace build2 bool silent = true; optional diag_progress_option; + optional diag_color_option; bool diag_no_line = false; bool diag_no_column = false; - bool stderr_term = false; + optional stderr_term = nullopt; + bool stderr_term_color = false; void - init_diag (uint16_t v, bool s, optional p, bool nl, bool nc, bool st) + init_diag (uint16_t v, + bool s, + optional p, + optional c, + bool nl, + bool nc, + bool st) { assert (!s || v == 0); verb = v; silent = s; diag_progress_option = p; + diag_color_option = c; diag_no_line = nl; diag_no_column = nc; - stderr_term = st; + + if (st) + { + stderr_term = std::getenv ("TERM"); + + stderr_term_color = +#ifdef _WIN32 + // For now we disable color on Windows since it's unclear if/where/how + // it is supported. Maybe one day someone will figure this out. + // + false +#else + // This test was lifted from GCC (Emacs shell sets TERM=dumb). + // + *stderr_term != nullptr && strcmp (*stderr_term, "dumb") != 0 +#endif + ; + } + else + { + stderr_term = nullopt; + stderr_term_color = false; + } } // Stream verbosity. diff --git a/libbuild2/diagnostics.hxx b/libbuild2/diagnostics.hxx index c048d5b..129e00d 100644 --- a/libbuild2/diagnostics.hxx +++ b/libbuild2/diagnostics.hxx @@ -401,15 +401,25 @@ namespace build2 using butl::diag_progress_lock; // Return true if progress is to be shown. The max_verb argument is the - // maximum verbosity level that this type of progress should be shown by - // default. + // maximum verbosity level that this type of progress should be shown at by + // default. If it is verb_never, then both min and max verbosity checks are + // omitted, assuming the caller takes care of that themselves. // inline bool show_progress (uint16_t max_verb) { return diag_progress_option ? *diag_progress_option - : stderr_term && verb >= 1 && verb <= max_verb; + : stderr_term && (max_verb == verb_never || + (verb >= 1 && verb <= max_verb)); + } + + // Diagnostics color. + // + inline bool + show_diag_color () + { + return diag_color_option ? *diag_color_option : stderr_term_color; } // Diagnostic facility. diff --git a/libbuild2/utility.hxx b/libbuild2/utility.hxx index c12fae7..e27eec2 100644 --- a/libbuild2/utility.hxx +++ b/libbuild2/utility.hxx @@ -129,6 +129,7 @@ namespace build2 init_diag (uint16_t verbosity, bool silent = false, optional progress = nullopt, + optional diag_color = nullopt, bool no_lines = false, bool no_columns = false, bool stderr_term = false); @@ -138,13 +139,23 @@ namespace build2 LIBBUILD2_SYMEXPORT extern bool silent; // --[no-]progress + // --[no-]diag-color // LIBBUILD2_SYMEXPORT extern optional diag_progress_option; + LIBBUILD2_SYMEXPORT extern optional diag_color_option; LIBBUILD2_SYMEXPORT extern bool diag_no_line; // --no-line LIBBUILD2_SYMEXPORT extern bool diag_no_column; // --no-column - LIBBUILD2_SYMEXPORT extern bool stderr_term; // True if stderr is a terminal. + // If stderr is not a terminal, then the value is absent (so can be used as + // bool). Otherwise, it is the value of the TERM environment variable (which + // can be NULL). + // + LIBBUILD2_SYMEXPORT extern optional stderr_term; + + // True if the color can be used on the stderr terminal. + // + LIBBUILD2_SYMEXPORT extern bool stderr_term_color; // Global state (verbosity, home/work directories, etc). -- cgit v1.1