From 5f0ef50077002f0308fc45f7d0a01a508c970516 Mon Sep 17 00:00:00 2001 From: Jade Lovelace Date: Wed, 31 Jul 2024 22:06:18 -0700 Subject: [PATCH] cli: eat terminal codes from stdout also This *should* be sound, plus or minus the amount that the terminal code eating code is messed up already. This is useful for testing CLI output because it will strip the escapes enough to just shove the expected output in a file. Change-Id: I8a9b58fafb918466ac76e9ab585fc32fb9294819 --- doc/manual/rl-next/clicolor-clarity.md | 26 ++++++++++++++++++++++++++ src/libutil/logging.cc | 2 +- src/libutil/terminal.cc | 5 +++-- src/libutil/terminal.hh | 3 ++- tests/functional/search.sh | 2 ++ 5 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 doc/manual/rl-next/clicolor-clarity.md 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 ))