mirror of
https://github.com/systemd/systemd.git
synced 2025-03-11 20:58:27 +03:00
Merge pull request #33456 from yuwata/terminal-util
terminal-util: use colon as separator for specifying color
This commit is contained in:
commit
28cb2803a2
@ -40,6 +40,7 @@
|
||||
#include "socket-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "terminal-util.h"
|
||||
@ -51,7 +52,7 @@ static volatile unsigned cached_lines = 0;
|
||||
|
||||
static volatile int cached_on_tty = -1;
|
||||
static volatile int cached_on_dev_null = -1;
|
||||
static volatile int cached_color_mode = _COLOR_INVALID;
|
||||
static volatile int cached_color_mode = _COLOR_MODE_INVALID;
|
||||
static volatile int cached_underline_enabled = -1;
|
||||
|
||||
bool isatty_safe(int fd) {
|
||||
@ -959,7 +960,7 @@ void reset_terminal_feature_caches(void) {
|
||||
cached_columns = 0;
|
||||
cached_lines = 0;
|
||||
|
||||
cached_color_mode = _COLOR_INVALID;
|
||||
cached_color_mode = _COLOR_MODE_INVALID;
|
||||
cached_underline_enabled = -1;
|
||||
cached_on_tty = -1;
|
||||
cached_on_dev_null = -1;
|
||||
@ -1315,69 +1316,68 @@ bool terminal_is_dumb(void) {
|
||||
return getenv_terminal_is_dumb();
|
||||
}
|
||||
|
||||
static const char* const color_mode_table[_COLOR_MODE_MAX] = {
|
||||
[COLOR_OFF] = "off",
|
||||
[COLOR_16] = "16",
|
||||
[COLOR_256] = "256",
|
||||
[COLOR_24BIT] = "24bit",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(color_mode, ColorMode, COLOR_24BIT);
|
||||
|
||||
static ColorMode parse_systemd_colors(void) {
|
||||
const char *e;
|
||||
int r;
|
||||
|
||||
e = getenv("SYSTEMD_COLORS");
|
||||
if (!e)
|
||||
return _COLOR_INVALID;
|
||||
if (streq(e, "16"))
|
||||
return COLOR_16;
|
||||
if (streq(e, "256"))
|
||||
return COLOR_256;
|
||||
r = parse_boolean(e);
|
||||
if (r >= 0)
|
||||
return r > 0 ? COLOR_ON : COLOR_OFF;
|
||||
return _COLOR_INVALID;
|
||||
return _COLOR_MODE_INVALID;
|
||||
|
||||
ColorMode m = color_mode_from_string(e);
|
||||
if (m < 0)
|
||||
return log_debug_errno(m, "Failed to parse $SYSTEMD_COLORS value '%s', ignoring: %m", e);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
static ColorMode get_color_mode_impl(void) {
|
||||
/* Returns the mode used to choose output colors. The possible modes are COLOR_OFF for no colors,
|
||||
* COLOR_16 for only the base 16 ANSI colors, COLOR_256 for more colors, and COLOR_24BIT for
|
||||
* unrestricted color output. */
|
||||
|
||||
/* First, we check $SYSTEMD_COLORS, which is the explicit way to change the mode. */
|
||||
ColorMode m = parse_systemd_colors();
|
||||
if (m >= 0)
|
||||
return m;
|
||||
|
||||
/* Next, check for the presence of $NO_COLOR; value is ignored. */
|
||||
if (getenv("NO_COLOR"))
|
||||
return COLOR_OFF;
|
||||
|
||||
/* If the above didn't work, we turn colors off unless we are on a TTY. And if we are on a TTY we
|
||||
* turn it off if $TERM is set to "dumb". There's one special tweak though: if we are PID 1 then we
|
||||
* do not check whether we are connected to a TTY, because we don't keep /dev/console open
|
||||
* continuously due to fear of SAK, and hence things are a bit weird. */
|
||||
if (getpid_cached() == 1 ? getenv_terminal_is_dumb() : terminal_is_dumb())
|
||||
return COLOR_OFF;
|
||||
|
||||
/* We failed to figure out any reason to *disable* colors. Let's see how many colors we shall use. */
|
||||
if (STRPTR_IN_SET(getenv("COLORTERM"),
|
||||
"truecolor",
|
||||
"24bit"))
|
||||
return COLOR_24BIT;
|
||||
|
||||
/* Note that the Linux console can only display 16 colors. We still enable 256 color mode
|
||||
* even for PID1 output though (which typically goes to the Linux console), since the Linux
|
||||
* console is able to parse the 256 color sequences and automatically map them to the closest
|
||||
* color in the 16 color palette (since kernel 3.16). Doing 256 colors is nice for people who
|
||||
* invoke systemd in a container or via a serial link or such, and use a true 256 color
|
||||
* terminal to do so. */
|
||||
return COLOR_256;
|
||||
}
|
||||
|
||||
ColorMode get_color_mode(void) {
|
||||
|
||||
/* Returns the mode used to choose output colors. The possible modes are COLOR_OFF for no colors,
|
||||
* COLOR_16 for only the base 16 ANSI colors, COLOR_256 for more colors and COLOR_ON for unrestricted
|
||||
* color output. For that we check $SYSTEMD_COLORS first (which is the explicit way to
|
||||
* change the mode). If that didn't work we turn colors off unless we are on a TTY. And if we are on a TTY
|
||||
* we turn it off if $TERM is set to "dumb". There's one special tweak though: if we are PID 1 then we do not
|
||||
* check whether we are connected to a TTY, because we don't keep /dev/console open continuously due to fear
|
||||
* of SAK, and hence things are a bit weird. */
|
||||
ColorMode m;
|
||||
|
||||
if (cached_color_mode < 0) {
|
||||
m = parse_systemd_colors();
|
||||
if (m >= 0)
|
||||
cached_color_mode = m;
|
||||
else if (getenv("NO_COLOR"))
|
||||
/* We only check for the presence of the variable; value is ignored. */
|
||||
cached_color_mode = COLOR_OFF;
|
||||
|
||||
else if (getpid_cached() == 1) {
|
||||
/* PID1 outputs to the console without holding it open all the time.
|
||||
*
|
||||
* Note that the Linux console can only display 16 colors. We still enable 256 color
|
||||
* mode even for PID1 output though (which typically goes to the Linux console),
|
||||
* since the Linux console is able to parse the 256 color sequences and automatically
|
||||
* map them to the closest color in the 16 color palette (since kernel 3.16). Doing
|
||||
* 256 colors is nice for people who invoke systemd in a container or via a serial
|
||||
* link or such, and use a true 256 color terminal to do so. */
|
||||
if (getenv_terminal_is_dumb())
|
||||
cached_color_mode = COLOR_OFF;
|
||||
} else {
|
||||
if (terminal_is_dumb())
|
||||
cached_color_mode = COLOR_OFF;
|
||||
}
|
||||
|
||||
if (cached_color_mode < 0) {
|
||||
/* We failed to figure out any reason to *disable* colors.
|
||||
* Let's see how many colors we shall use. */
|
||||
if (STRPTR_IN_SET(getenv("COLORTERM"),
|
||||
"truecolor",
|
||||
"24bit"))
|
||||
cached_color_mode = COLOR_24BIT;
|
||||
else
|
||||
cached_color_mode = COLOR_256;
|
||||
}
|
||||
}
|
||||
if (cached_color_mode < 0)
|
||||
cached_color_mode = get_color_mode_impl();
|
||||
|
||||
return cached_color_mode;
|
||||
}
|
||||
|
@ -42,26 +42,26 @@
|
||||
#define ANSI_HIGHLIGHT_MAGENTA "\x1B[0;1;35m"
|
||||
#define ANSI_HIGHLIGHT_CYAN "\x1B[0;1;36m"
|
||||
#define ANSI_HIGHLIGHT_WHITE "\x1B[0;1;37m"
|
||||
#define ANSI_HIGHLIGHT_YELLOW4 "\x1B[0;1;38;5;100m"
|
||||
#define ANSI_HIGHLIGHT_KHAKI3 "\x1B[0;1;38;5;185m"
|
||||
#define ANSI_HIGHLIGHT_GREY "\x1B[0;1;38;5;245m"
|
||||
#define ANSI_HIGHLIGHT_YELLOW4 "\x1B[0;1;38:5:100m"
|
||||
#define ANSI_HIGHLIGHT_KHAKI3 "\x1B[0;1;38:5:185m"
|
||||
#define ANSI_HIGHLIGHT_GREY "\x1B[0;1;38:5:245m"
|
||||
|
||||
#define ANSI_HIGHLIGHT_YELLOW ANSI_HIGHLIGHT_KHAKI3 /* Replacement yellow that is more legible */
|
||||
|
||||
/* Underlined */
|
||||
#define ANSI_GREY_UNDERLINE "\x1B[0;4;38;5;245m"
|
||||
#define ANSI_GREY_UNDERLINE "\x1B[0;4;38:5:245m"
|
||||
#define ANSI_BRIGHT_BLACK_UNDERLINE "\x1B[0;4;90m"
|
||||
#define ANSI_HIGHLIGHT_RED_UNDERLINE "\x1B[0;1;4;31m"
|
||||
#define ANSI_HIGHLIGHT_GREEN_UNDERLINE "\x1B[0;1;4;32m"
|
||||
#define ANSI_HIGHLIGHT_YELLOW_UNDERLINE "\x1B[0;1;4;38;5;185m"
|
||||
#define ANSI_HIGHLIGHT_YELLOW_UNDERLINE "\x1B[0;1;4;38:5:185m"
|
||||
#define ANSI_HIGHLIGHT_BLUE_UNDERLINE "\x1B[0;1;4;34m"
|
||||
#define ANSI_HIGHLIGHT_MAGENTA_UNDERLINE "\x1B[0;1;4;35m"
|
||||
#define ANSI_HIGHLIGHT_GREY_UNDERLINE "\x1B[0;1;4;38;5;245m"
|
||||
#define ANSI_HIGHLIGHT_GREY_UNDERLINE "\x1B[0;1;4;38:5:245m"
|
||||
|
||||
/* Other ANSI codes */
|
||||
#define ANSI_UNDERLINE "\x1B[0;4m"
|
||||
#define ANSI_ADD_UNDERLINE "\x1B[4m"
|
||||
#define ANSI_ADD_UNDERLINE_GREY ANSI_ADD_UNDERLINE "\x1B[58;5;245m"
|
||||
#define ANSI_ADD_UNDERLINE_GREY ANSI_ADD_UNDERLINE "\x1B[58:5:245m"
|
||||
#define ANSI_HIGHLIGHT "\x1B[0;1;39m"
|
||||
#define ANSI_HIGHLIGHT_UNDERLINE "\x1B[0;1;4m"
|
||||
|
||||
@ -119,24 +119,17 @@ typedef enum AcquireTerminalFlags {
|
||||
|
||||
/* Limits the use of ANSI colors to a subset. */
|
||||
typedef enum ColorMode {
|
||||
/* No colors, monochrome output. */
|
||||
COLOR_OFF,
|
||||
|
||||
/* All colors, no restrictions. */
|
||||
COLOR_ON,
|
||||
|
||||
/* Only the base 16 colors. */
|
||||
COLOR_16,
|
||||
|
||||
/* Only 256 colors. */
|
||||
COLOR_256,
|
||||
|
||||
/* For truecolor or 24bit color support. */
|
||||
COLOR_24BIT,
|
||||
|
||||
_COLOR_INVALID = -EINVAL,
|
||||
COLOR_OFF, /* No colors, monochrome output. */
|
||||
COLOR_16, /* Only the base 16 colors. */
|
||||
COLOR_256, /* Only 256 colors. */
|
||||
COLOR_24BIT, /* For truecolor or 24bit color support, no restriction. */
|
||||
_COLOR_MODE_MAX,
|
||||
_COLOR_MODE_INVALID = -EINVAL,
|
||||
} ColorMode;
|
||||
|
||||
const char* color_mode_to_string(ColorMode m) _const_;
|
||||
ColorMode color_mode_from_string(const char *s) _pure_;
|
||||
|
||||
int acquire_terminal(const char *name, AcquireTerminalFlags flags, usec_t timeout);
|
||||
int release_terminal(void);
|
||||
|
||||
|
@ -176,4 +176,37 @@ TEST(get_default_background_color) {
|
||||
log_notice("R=%g G=%g B=%g", red, green, blue);
|
||||
}
|
||||
|
||||
static void test_get_color_mode_with_env(const char *key, const char *val, ColorMode expected) {
|
||||
ASSERT_OK(setenv(key, val, true));
|
||||
reset_terminal_feature_caches();
|
||||
log_info("get_color_mode($%s=%s): %s", key, val, color_mode_to_string(get_color_mode()));
|
||||
ASSERT_EQ(get_color_mode(), expected);
|
||||
}
|
||||
|
||||
TEST(get_color_mode) {
|
||||
log_info("get_color_mode(default): %s", color_mode_to_string(get_color_mode()));
|
||||
ASSERT_OK(get_color_mode());
|
||||
|
||||
test_get_color_mode_with_env("SYSTEMD_COLORS", "0", COLOR_OFF);
|
||||
test_get_color_mode_with_env("SYSTEMD_COLORS", "no", COLOR_OFF);
|
||||
test_get_color_mode_with_env("SYSTEMD_COLORS", "16", COLOR_16);
|
||||
test_get_color_mode_with_env("SYSTEMD_COLORS", "256", COLOR_256);
|
||||
test_get_color_mode_with_env("SYSTEMD_COLORS", "1", COLOR_24BIT);
|
||||
test_get_color_mode_with_env("SYSTEMD_COLORS", "yes", COLOR_24BIT);
|
||||
test_get_color_mode_with_env("SYSTEMD_COLORS", "24bit", COLOR_24BIT);
|
||||
|
||||
ASSERT_OK(setenv("NO_COLOR", "1", true));
|
||||
test_get_color_mode_with_env("SYSTEMD_COLORS", "42", COLOR_OFF);
|
||||
test_get_color_mode_with_env("SYSTEMD_COLORS", "invalid", COLOR_OFF);
|
||||
ASSERT_OK(unsetenv("NO_COLOR"));
|
||||
ASSERT_OK(unsetenv("SYSTEMD_COLORS"));
|
||||
|
||||
test_get_color_mode_with_env("COLORTERM", "truecolor", terminal_is_dumb() ? COLOR_OFF : COLOR_24BIT);
|
||||
test_get_color_mode_with_env("COLORTERM", "24bit", terminal_is_dumb() ? COLOR_OFF : COLOR_24BIT);
|
||||
test_get_color_mode_with_env("COLORTERM", "invalid", terminal_is_dumb() ? COLOR_OFF : COLOR_256);
|
||||
test_get_color_mode_with_env("COLORTERM", "42", terminal_is_dumb() ? COLOR_OFF : COLOR_256);
|
||||
unsetenv("COLORTERM");
|
||||
reset_terminal_feature_caches();
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_INFO);
|
||||
|
Loading…
x
Reference in New Issue
Block a user