diff options
author | Julian Andres Klode <jak@debian.org> | 2024-04-19 17:20:31 +0000 |
---|---|---|
committer | Julian Andres Klode <jak@debian.org> | 2024-04-19 17:20:31 +0000 |
commit | 70103339b017a42ea71a56c27c221a79ccc3116f (patch) | |
tree | a1797800fb7ebeb1bdd8833d3bcc2503438de4f4 | |
parent | 633f6d67a28b375cf1f225f14d3c926e618d46af (diff) | |
parent | 28ec28746d8633b9c4b67cd6d1b603a1da57f436 (diff) |
Merge branch 'color-framework' into 'main'
Introduce APT::Configuration::Color, --color option and documentation for color.
See merge request apt-team/apt!342
-rw-r--r-- | apt-pkg/aptconfiguration.cc | 35 | ||||
-rw-r--r-- | apt-pkg/aptconfiguration.h | 2 | ||||
-rw-r--r-- | apt-private/acqprogress.cc | 5 | ||||
-rw-r--r-- | apt-private/private-cmndline.cc | 7 | ||||
-rw-r--r-- | apt-private/private-install.cc | 2 | ||||
-rw-r--r-- | apt-private/private-moo.cc | 2 | ||||
-rw-r--r-- | apt-private/private-output.cc | 24 | ||||
-rw-r--r-- | apt-private/private-output.h | 8 | ||||
-rw-r--r-- | doc/apt.conf.5.xml | 39 | ||||
-rw-r--r-- | doc/apt.ent | 10 | ||||
-rw-r--r-- | test/libapt/configuration_test.cc | 30 |
11 files changed, 144 insertions, 20 deletions
diff --git a/apt-pkg/aptconfiguration.cc b/apt-pkg/aptconfiguration.cc index 982e68bb1..f462b6eda 100644 --- a/apt-pkg/aptconfiguration.cc +++ b/apt-pkg/aptconfiguration.cc @@ -563,4 +563,39 @@ bool Configuration::checkUsrMerged() return true; } /*}}}*/ +// isUsrMerged - whether usr is merged t /*{{{*/ +// --------------------------------------------------------------------- +/* */ +std::string Configuration::color(std::string const &colorName, std::string const &content) +{ + if (not _config->FindB("APT::Color")) + return content; + + auto colors = ::Configuration(_config->Tree("APT::Color")); + auto color = colors.Find(colorName); + + // Resolve the color recursively. A color string has the following format + // <color> := \x1B<word> ; fully resolved color + // | \\x1B<word> ; color escaped. + // | <word> ; a simple color name + // | <color> <color> ; a sequence of colors + if (color.find(" ") != color.npos) + { + std::string res; + for (auto &&colorPart : VectorizeString(color, ' ')) + res += Configuration::color(colorPart); + color = res; + } + else if (not color.empty() && color[0] != '\x1B') + { + if (APT::String::Startswith(color, "\\x1B")) + color = "\x1B" + color.substr(4); + else + color = Configuration::color(color); + } + if (content.empty()) + return color; + return color + content + Configuration::color("Neutral"); +} + /*}}}*/ } diff --git a/apt-pkg/aptconfiguration.h b/apt-pkg/aptconfiguration.h index 3e2636edc..58c925b7f 100644 --- a/apt-pkg/aptconfiguration.h +++ b/apt-pkg/aptconfiguration.h @@ -130,7 +130,9 @@ namespace Configuration { /*{{{*/ APT_PUBLIC bool isChroot(); /** \return Check usr is merged or produce error. */ APT_PUBLIC bool checkUsrMerged(); + APT_PUBLIC std::string color(std::string const &colorName, std::string const &content = ""); #endif + /*}}}*/ } /*}}}*/ diff --git a/apt-private/acqprogress.cc b/apt-private/acqprogress.cc index 1f5acdd97..b4b16e6a9 100644 --- a/apt-private/acqprogress.cc +++ b/apt-private/acqprogress.cc @@ -9,6 +9,7 @@ // Include files /*{{{*/ #include <config.h> +#include <apt-pkg/aptconfiguration.h> #include <apt-pkg/acquire-item.h> #include <apt-pkg/acquire-worker.h> #include <apt-pkg/acquire.h> @@ -281,14 +282,14 @@ bool AcqTextStatus::Pulse(pkgAcquire *Owner) // Draw the current status if (_config->FindB("Apt::Color", false) == true) - out << _config->Find("APT::Color::Yellow"); + out << APT::Configuration::color("Yellow"); if (LastLineLength > Line.length()) clearLastLine(); else out << '\r'; out << Line << std::flush; if (_config->FindB("Apt::Color", false) == true) - out << _config->Find("APT::Color::Neutral") << std::flush; + out << APT::Configuration::color("Neutral") << std::flush; LastLineLength = Line.length(); Update = false; diff --git a/apt-private/private-cmndline.cc b/apt-private/private-cmndline.cc index 9b84f2dd5..e0e00c917 100644 --- a/apt-private/private-cmndline.cc +++ b/apt-private/private-cmndline.cc @@ -246,10 +246,8 @@ static bool addArgumentsAPTGet(std::vector<CommandLine::Args> &Args, char const } else if (CmdMatches("clean", "autoclean", "auto-clean", "distclean", "dist-clean", "check", "download", "changelog") || CmdMatches("markauto", "unmarkauto")) // deprecated commands - ; - else if (CmdMatches("moo")) - addArg(0, "color", "APT::Moo::Color", 0); - + { + } if (CmdMatches("install", "reinstall", "remove", "purge", "upgrade", "dist-upgrade", "dselect-upgrade", "autoremove", "auto-remove", "autopurge", "check", "clean", "autoclean", "auto-clean", "distclean", "dist-clean", @@ -409,6 +407,7 @@ std::vector<CommandLine::Args> getCommandArgs(APT_CMD const Program, char const addArg('h', "help", "help", 0); addArg('v', "version", "version", 0); // general options + addArg(0, "color", "APT::Color", 0); addArg('q', "quiet", "quiet", CommandLine::IntLevel); addArg('q', "silent", "quiet", CommandLine::IntLevel); addArg('c', "config-file", 0, CommandLine::ConfigFile); diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc index ecbd703d8..774c03d0a 100644 --- a/apt-private/private-install.cc +++ b/apt-private/private-install.cc @@ -1104,7 +1104,7 @@ bool DoInstall(CommandLine &CmdL) if (_config->FindI("APT::Output-Version") < 30 && Cache->InstCount() != verset[MOD_INSTALL].size()) ShowList(c1out, _("The following additional packages will be installed:"), Universe, PkgIsExtraInstalled(&Cache, &verset[MOD_INSTALL]), - &PrettyFullName, CandidateVersion(&Cache), "APT::Color::Green"); + &PrettyFullName, CandidateVersion(&Cache), "action::install-dependencies"); /* Print out a list of suggested and recommended packages */ if (_config->FindI("APT::Output-Version") < 30) diff --git a/apt-private/private-moo.cc b/apt-private/private-moo.cc index 2a9ed9391..5eb6db56a 100644 --- a/apt-private/private-moo.cc +++ b/apt-private/private-moo.cc @@ -96,7 +96,7 @@ static bool DoMoo2(time_t const timenow) /*{{{*/ return printMooLine(timenow); std::string const moo = getMooLine(timenow); size_t const depth = moo.length()/4; - if (_config->FindB("APT::Moo::Color", false) == false) + if (_config->FindB("APT::Color", false) == false) c1out << OutputInDepth(depth, " ") << " (__) \n" << OutputInDepth(depth, " ") << " _______~(..)~ \n" << diff --git a/apt-private/private-output.cc b/apt-private/private-output.cc index 522fba4c6..c2e936d2c 100644 --- a/apt-private/private-output.cc +++ b/apt-private/private-output.cc @@ -1,6 +1,7 @@ // Include files /*{{{*/ #include <config.h> +#include <apt-pkg/aptconfiguration.h> #include <apt-pkg/cachefile.h> #include <apt-pkg/configuration.h> #include <apt-pkg/depcache.h> @@ -30,6 +31,7 @@ /*}}}*/ using namespace std; +using APT::Configuration::color; std::ostream c0out(0); std::ostream c1out(0); @@ -103,6 +105,12 @@ bool InitOutput(std::basic_streambuf<char> * const out) /*{{{*/ _config->CndSet("APT::Color::Magenta", "\x1B[35m"); _config->CndSet("APT::Color::Cyan", "\x1B[36m"); _config->CndSet("APT::Color::White", "\x1B[37m"); + + _config->CndSet("APT::Color::Action::Upgrade", "green"); + _config->CndSet("APT::Color::Action::Install", "green"); + _config->CndSet("APT::Color::Action::Install-Dependencies", "green"); + _config->CndSet("APT::Color::Action::Downgrade", "yellow"); + _config->CndSet("APT::Color::Action::Remove", "red"); } return true; @@ -302,8 +310,8 @@ void ListSingleVersion(pkgCacheFile &CacheFile, pkgRecords &records, /*{{{*/ else if (V.ParentPkg()->CurrentState == pkgCache::State::ConfigFiles) StatusStr = _("[residual-config]"); output = SubstVar(output, "${apt:Status}", StatusStr); - output = SubstVar(output, "${color:highlight}", _config->Find("APT::Color::Highlight", "")); - output = SubstVar(output, "${color:neutral}", _config->Find("APT::Color::Neutral", "")); + output = SubstVar(output, "${color:highlight}", color("Highlight")); + output = SubstVar(output, "${color:neutral}", color("Neutral")); output = SubstVar(output, "${Description}", GetShortDescription(CacheFile, records, P)); if (output.find("${LongDescription}") != string::npos) output = SubstVar(output, "${LongDescription}", GetLongDescription(CacheFile, records, P)); @@ -555,7 +563,7 @@ void ShowNew(ostream &out,CacheFile &Cache) [&Cache](pkgCache::PkgIterator const &Pkg) { return Cache[Pkg].NewInstall(); }, &PrettyFullName, CandidateVersion(&Cache), - "APT::Color::Green"); + "action::install"); return; } @@ -563,12 +571,12 @@ void ShowNew(ostream &out,CacheFile &Cache) [&Cache](pkgCache::PkgIterator const &Pkg) { return Cache[Pkg].NewInstall() && (Cache[Pkg].Flags & pkgCache::Flag::Auto) == 0; }, &PrettyFullName, CandidateVersion(&Cache), - "APT::Color::Green"); + "action::install"); ShowList(out,_("Installing dependencies:"), Universe, [&Cache](pkgCache::PkgIterator const &Pkg) { return Cache[Pkg].NewInstall() && Cache[Pkg].Flags & pkgCache::Flag::Auto;}, &PrettyFullName, CandidateVersion(&Cache), - "APT::Color::Green"); + "action::install-dependencies"); } /*}}}*/ // ShowDel - Show packages to delete /*{{{*/ @@ -586,7 +594,7 @@ void ShowDel(ostream &out,CacheFile &Cache) return str; }, CandidateVersion(&Cache), - "APT::Color::Red"); + "action::remove"); } /*}}}*/ // ShowPhasing - Show packages kept due to phasing /*{{{*/ @@ -625,7 +633,7 @@ void ShowUpgraded(ostream &out,CacheFile &Cache) }, &PrettyFullName, CurrentToCandidateVersion(&Cache), - "APT::Color::Green"); + "action::upgrade"); } /*}}}*/ // ShowDowngraded - Show downgraded packages /*{{{*/ @@ -642,7 +650,7 @@ bool ShowDowngraded(ostream &out,CacheFile &Cache) }, &PrettyFullName, CurrentToCandidateVersion(&Cache), - "APT::Color::Yellow"); + "action::downgrade"); } /*}}}*/ // ShowHold - Show held but changed packages /*{{{*/ diff --git a/apt-private/private-output.h b/apt-private/private-output.h index 4cc7c01b4..a3e961458 100644 --- a/apt-private/private-output.h +++ b/apt-private/private-output.h @@ -1,6 +1,7 @@ #ifndef APT_PRIVATE_OUTPUT_H #define APT_PRIVATE_OUTPUT_H +#include <apt-pkg/aptconfiguration.h> #include <apt-pkg/cacheset.h> #include <apt-pkg/configuration.h> #include <apt-pkg/macros.h> @@ -18,7 +19,6 @@ class CacheFile; class pkgDepCache; class pkgRecords; - APT_PUBLIC extern std::ostream c0out; APT_PUBLIC extern std::ostream c1out; APT_PUBLIC extern std::ostream c2out; @@ -43,7 +43,7 @@ template<class Container, class PredicateC, class DisplayP, class DisplayV> bool PredicateC Predicate, DisplayP PkgDisplay, DisplayV VerboseDisplay, - std::string colorName = "APT::Color::Neutral") + std::string colorName = "") { size_t const ScreenWidth = (::ScreenWidth > 3) ? ::ScreenWidth - 3 : 0; int ScreenUsed = 0; @@ -52,8 +52,8 @@ template<class Container, class PredicateC, class DisplayP, class DisplayV> bool bool printedTitle = false; std::vector<std::string> PackageList; - auto setColor = _config->FindI("APT::Output-Version") >= 30 ? _config->Find(colorName) : ""; - auto resetColor = _config->FindI("APT::Output-Version") >= 30 ? _config->Find("APT::Color::Neutral") : ""; + auto setColor = APT::Configuration::color(colorName); + auto resetColor = not setColor.empty() ? APT::Configuration::color("neutral") : ""; for (auto const &Pkg: cont) { diff --git a/doc/apt.conf.5.xml b/doc/apt.conf.5.xml index 2ae569e26..a648d7079 100644 --- a/doc/apt.conf.5.xml +++ b/doc/apt.conf.5.xml @@ -174,6 +174,45 @@ DPkg::Pre-Install-Pkgs {"/usr/sbin/dpkg-preconfigure --apt";}; </para></listitem> </varlistentry> + <varlistentry><term><option>Color</option></term> + <listitem><para> + This scope defines colors and styles. The basic colors supported are + <option>red</option>, + <option>green</option>, + <option>yellow</option>, + <option>blue</option>, + <option>magenta</option>, + <option>cyan</option>, and + <option>white</option>. + </para> + <para> + The subscope <option>action</option> defines the colors for package lists + in <option>install</option> and similar commands. The following options may be set: + <option>APT::Color::Action::Upgrade</option>, + <option>APT::Color::Action::Install</option>, + <option>APT::Color::Action::Install-Dependencies</option>, + <option>APT::Color::Action::Downgrade</option>, + <option>APT::Color::Action::Remove</option>; corresponding to their + lists in the &apt; output. + </para> + <para> + Each color may reference one or more other color options by name, relative + to <option>APT::Color</option>. Their escape sequences will be combined. + </para> + <informalexample><programlisting> +APT::Color::Bold "\x1B[1m"; +APT::Color::Action::Install "cyan"; +APT::Color::Action::Upgrade "bold action::install"; + </programlisting></informalexample> + <para> + Colors may be turned on or off completely by setting <option>APT::Color</option> + to <option>yes</option> or <option>no</option>, by utilizing <envar>NO_COLOR</envar> + or <envar>APT_NO_COLOR</envar> environment variables, or using the + <option>--color</option>, <option>--no-color</option> command-line options. + </para> + </listitem> + </varlistentry> + <varlistentry><term><option>Compressor</option></term> <listitem><para> This scope defines which compression formats are supported, how compression diff --git a/doc/apt.ent b/doc/apt.ent index a6abb0e0a..386abd493 100644 --- a/doc/apt.ent +++ b/doc/apt.ent @@ -70,6 +70,16 @@ </para> </listitem> </varlistentry> + + <varlistentry> + <term><option>--no-color</option></term> + <term><option>--color</option></term> +<listitem><para>Turn colors on or off. Colors are on by default on supported terminals for &apt; and +can also be disabled using the <envar>NO_COLOR</envar> or <envar>APT_NO_COLOR</envar> environment variables, +or further configured by the <option>APT::Color</option> configuration option and scope, see &apt-conf; for information on that. + </para> + </listitem> + </varlistentry> "> <!-- Should be used within the option section of the text to diff --git a/test/libapt/configuration_test.cc b/test/libapt/configuration_test.cc index 4d297a9f2..61c7348a2 100644 --- a/test/libapt/configuration_test.cc +++ b/test/libapt/configuration_test.cc @@ -230,3 +230,33 @@ List::Option2 { "Multi"; EXPECT_TRUE(Cnf.FindB("Trailing")); EXPECT_FALSE(Cnf.Exists("Commented::Out")); } + +TEST(ConfigurationTest, Color) +{ + _config->Clear(); + _config->Set("APT::Color::Neutral", "\x1B[N"); + _config->Set("APT::Color::Green", "\x1B[G"); + // This is escaped for extra fun + _config->Set("APT::Color::Bold", "\\x1B[B"); + _config->Set("APT::Color::BoldGreen", "bold green"); + _config->Set("APT::Color::BoldGreenRef", "boldgreen"); + _config->Set("APT::Color::BoldGreenNeutral", "boldgreen neutral"); + _config->Set("APT::Color::BoldGreenRefNeutral", "boldgreenref neutral"); + + EXPECT_EQ("", APT::Configuration::color("bold")); + EXPECT_EQ("", APT::Configuration::color("green")); + EXPECT_EQ("content", APT::Configuration::color("green", "content")); + EXPECT_EQ("", APT::Configuration::color("boldgreen")); + EXPECT_EQ("", APT::Configuration::color("boldgreenref")); + EXPECT_EQ("", APT::Configuration::color("boldgreenneutral")); + EXPECT_EQ("", APT::Configuration::color("boldgreenrefneutral")); + + _config->Set("APT::Color", "true"); + EXPECT_EQ("\x1B[B", APT::Configuration::color("bold")); + EXPECT_EQ("\x1B[G", APT::Configuration::color("green")); + EXPECT_EQ("\x1B[Gcontent\x1B[N", APT::Configuration::color("green", "content")); + EXPECT_EQ("\x1B[B\x1B[G", APT::Configuration::color("boldgreen")); + EXPECT_EQ("\x1B[B\x1B[G", APT::Configuration::color("boldgreenref")); + EXPECT_EQ("\x1B[B\x1B[G\x1B[N", APT::Configuration::color("boldgreenneutral")); + EXPECT_EQ("\x1B[B\x1B[G\x1B[N", APT::Configuration::color("boldgreenrefneutral")); +} |