summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Andres Klode <jak@debian.org>2024-04-19 17:20:31 +0000
committerJulian Andres Klode <jak@debian.org>2024-04-19 17:20:31 +0000
commit70103339b017a42ea71a56c27c221a79ccc3116f (patch)
treea1797800fb7ebeb1bdd8833d3bcc2503438de4f4
parent633f6d67a28b375cf1f225f14d3c926e618d46af (diff)
parent28ec28746d8633b9c4b67cd6d1b603a1da57f436 (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.cc35
-rw-r--r--apt-pkg/aptconfiguration.h2
-rw-r--r--apt-private/acqprogress.cc5
-rw-r--r--apt-private/private-cmndline.cc7
-rw-r--r--apt-private/private-install.cc2
-rw-r--r--apt-private/private-moo.cc2
-rw-r--r--apt-private/private-output.cc24
-rw-r--r--apt-private/private-output.h8
-rw-r--r--doc/apt.conf.5.xml39
-rw-r--r--doc/apt.ent10
-rw-r--r--test/libapt/configuration_test.cc30
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"));
+}