diff --git a/doc/manual/rl-next/clicolor-clarity.md b/doc/manual/rl-next/clicolor-clarity.md new file mode 100644 index 000000000..8a289e362 --- /dev/null +++ b/doc/manual/rl-next/clicolor-clarity.md @@ -0,0 +1,26 @@ +--- +synopsis: "Better usage of colour control environment variables" +cls: [1699, 1702] +credits: [jade] +category: Improvements +--- + +Lix now heeds `NO_COLOR`/`NOCOLOR` for more output types, such as that used in `nix search`, `nix flake metadata` and similar. + +It also now supports `CLICOLOR_FORCE`/`FORCE_COLOR` to force colours regardless of whether there is a terminal on the other side. + +It now follows rules compatible with those described on with `CLICOLOR` defaulted to enabled. + +That is to say, the following procedure is followed in order: +- NO_COLOR or NOCOLOR set + + Always disable colour +- CLICOLOR_FORCE or FORCE_COLOR set + + Enable colour +- The output is a tty; TERM != "dumb" + + Enable colour +- Otherwise + + Disable colour diff --git a/src/libutil/logging.cc b/src/libutil/logging.cc index 53460f729..cbeb7aa36 100644 --- a/src/libutil/logging.cc +++ b/src/libutil/logging.cc @@ -37,7 +37,7 @@ void Logger::warn(const std::string & msg) void Logger::writeToStdout(std::string_view s) { - writeFull(STDOUT_FILENO, s); + writeFull(STDOUT_FILENO, filterANSIEscapes(s, !shouldANSI(), std::numeric_limits::max(), false)); writeFull(STDOUT_FILENO, "\n"); } diff --git a/src/libutil/terminal.cc b/src/libutil/terminal.cc index 68d358dc5..2ba1cb81b 100644 --- a/src/libutil/terminal.cc +++ b/src/libutil/terminal.cc @@ -26,7 +26,8 @@ bool shouldANSI() return cached; } -std::string filterANSIEscapes(std::string_view s, bool filterAll, unsigned int width) +// FIXME(jade): replace with TerminalCodeEater. wowie this is evil code. +std::string filterANSIEscapes(std::string_view s, bool filterAll, unsigned int width, bool eatTabs) { std::string t, e; size_t w = 0; @@ -55,7 +56,7 @@ std::string filterANSIEscapes(std::string_view s, bool filterAll, unsigned int w t += e; } - else if (*i == '\t') { + else if (*i == '\t' && eatTabs) { i++; t += ' '; w++; while (w < (size_t) width && w % 8) { t += ' '; w++; diff --git a/src/libutil/terminal.hh b/src/libutil/terminal.hh index 6b8d59182..2c422ecff 100644 --- a/src/libutil/terminal.hh +++ b/src/libutil/terminal.hh @@ -30,7 +30,8 @@ bool shouldANSI(); */ std::string filterANSIEscapes(std::string_view s, bool filterAll = false, - unsigned int width = std::numeric_limits::max()); + unsigned int width = std::numeric_limits::max(), + bool eatTabs = true); /** * Recalculate the window size, updating a global variable. Used in the diff --git a/tests/functional/search.sh b/tests/functional/search.sh index d9c7a75da..1a2a20089 100644 --- a/tests/functional/search.sh +++ b/tests/functional/search.sh @@ -29,6 +29,8 @@ nix search -f search.nix '' ^ | grepQuiet hello ## Tests for multiple regex/match highlighting +# FIXME: possibly not test this with colour in the future +export CLICOLOR_FORCE=1 e=$'\x1b' # grep doesn't support \e, \033 or even \x1b # Multiple overlapping regexes (( $(nix search -f search.nix '' 'oo' 'foo' 'oo' | grep -c "$e\[32;1mfoo$e\\[0;1m") == 1 ))