From: Mike Yuan Date: Sun, 1 Mar 2026 13:20:53 +0000 (+0100) Subject: ansi-color: in 256 mode, always set the fallback color first X-Git-Tag: v260-rc2~9 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=36d30330f7f643361d24f57088ee9cafb2c72a14;p=thirdparty%2Fsystemd.git ansi-color: in 256 mode, always set the fallback color first Linux console is very weird when it comes to ANSI color sequences. Not only that it isn't aware of ':' separator (c.f. https://github.com/systemd/systemd/pull/40878#issuecomment-3979826739), it even skips the whole CSI-m sequence if it contains parts it cannot parse. Hence when color mode is set to 256 (i.e. default when no extra info is available) let's always emit two distinct CSI-m sequences, and set the fallback 16 color first in case the terminal doesn't have complete support for the 256 one. Replaces #40905 --- diff --git a/src/basic/ansi-color.h b/src/basic/ansi-color.h index e686e1167b1..1ddb9c6681c 100644 --- a/src/basic/ansi-color.h +++ b/src/basic/ansi-color.h @@ -111,41 +111,20 @@ bool looks_like_ansi_color_code(const char *str); return colors_enabled() ? ANSI_##NAME : ""; \ } -#define DEFINE_ANSI_FUNC_256(name, NAME, FALLBACK) \ - static inline const char* ansi_##name(void) { \ - switch (get_color_mode()) { \ - case COLOR_OFF: return ""; \ - case COLOR_16: return ANSI_##FALLBACK; \ - default : return ANSI_##NAME; \ - } \ - } - -static inline const char* ansi_underline(void) { - return underline_enabled() ? ANSI_UNDERLINE : ""; -} - -static inline const char* ansi_add_underline(void) { - return underline_enabled() ? ANSI_ADD_UNDERLINE : ""; -} - -static inline const char* ansi_add_underline_grey(void) { - return underline_enabled() ? - (colors_enabled() ? ANSI_ADD_UNDERLINE_GREY : ANSI_ADD_UNDERLINE) : ""; -} - -#define DEFINE_ANSI_FUNC_UNDERLINE(name, NAME) \ - static inline const char* ansi_##name(void) { \ - return underline_enabled() ? ANSI_##NAME##_UNDERLINE : \ - colors_enabled() ? ANSI_##NAME : ""; \ - } - -#define DEFINE_ANSI_FUNC_UNDERLINE_256(name, NAME, FALLBACK) \ - static inline const char* ansi_##name(void) { \ - switch (get_color_mode()) { \ - case COLOR_OFF: return ""; \ - case COLOR_16: return underline_enabled() ? ANSI_##FALLBACK##_UNDERLINE : ANSI_##FALLBACK; \ - default : return underline_enabled() ? ANSI_##NAME##_UNDERLINE: ANSI_##NAME; \ - } \ +/* NB: in 256 mode we always emit the fallback color first, in order to deal with terminals with + * incomplete 256 color support (most notably Linux console, which a) lacks support for ":" + * subcommand separator and b) skips over the whole CSI-m sequence if it sees an "invalid" command). + * In 24-bit mode we don't bother with this however, under the assumption that $COLORTERM and friends + * reflect the correct status. */ + +#define DEFINE_ANSI_FUNC_256(name, NAME, FALLBACK) \ + static inline const char* ansi_##name(void) { \ + switch (get_color_mode()) { \ + case COLOR_OFF: return ""; \ + case COLOR_16: return ANSI_##FALLBACK; \ + case COLOR_256: return ANSI_##FALLBACK ANSI_##NAME; \ + default: return ANSI_##NAME; \ + } \ } DEFINE_ANSI_FUNC(normal, NORMAL); @@ -184,15 +163,47 @@ static inline const char* _ansi_highlight_yellow(void) { return colors_enabled() ? _ANSI_HIGHLIGHT_YELLOW : ""; } -DEFINE_ANSI_FUNC_UNDERLINE(highlight_underline, HIGHLIGHT); -DEFINE_ANSI_FUNC_UNDERLINE_256(grey_underline, GREY, BRIGHT_BLACK); -DEFINE_ANSI_FUNC_UNDERLINE(highlight_red_underline, HIGHLIGHT_RED); -DEFINE_ANSI_FUNC_UNDERLINE(highlight_green_underline, HIGHLIGHT_GREEN); -DEFINE_ANSI_FUNC_UNDERLINE_256(highlight_yellow_underline, HIGHLIGHT_YELLOW, HIGHLIGHT_YELLOW_FALLBACK); -DEFINE_ANSI_FUNC_UNDERLINE(highlight_blue_underline, HIGHLIGHT_BLUE); -DEFINE_ANSI_FUNC_UNDERLINE(highlight_magenta_underline, HIGHLIGHT_MAGENTA); -DEFINE_ANSI_FUNC_UNDERLINE_256(highlight_grey_underline, HIGHLIGHT_GREY, HIGHLIGHT_GREY_FALLBACK); - static inline const char* ansi_highlight_green_red(bool b) { return b ? ansi_highlight_green() : ansi_highlight_red(); } + +static inline const char* ansi_underline(void) { + return underline_enabled() ? ANSI_UNDERLINE : ""; +} + +static inline const char* ansi_add_underline(void) { + return underline_enabled() ? ANSI_ADD_UNDERLINE : ""; +} + +static inline const char* ansi_add_underline_grey(void) { + return underline_enabled() ? + (colors_enabled() ? ANSI_ADD_UNDERLINE_GREY : ANSI_ADD_UNDERLINE) : ""; +} + +#define DEFINE_ANSI_FUNC_UNDERLINE(name, NAME) \ + static inline const char* ansi_##name##_underline(void) { \ + return underline_enabled() ? ANSI_##NAME##_UNDERLINE : \ + ansi_##name(); \ + } + +#define DEFINE_ANSI_FUNC_UNDERLINE_256(name, NAME, FALLBACK) \ + static inline const char* ansi_##name##_underline(void) { \ + if (!underline_enabled()) \ + return ansi_##name(); \ + \ + switch (get_color_mode()) { \ + case COLOR_OFF: return ""; \ + case COLOR_16: return ANSI_##FALLBACK##_UNDERLINE; \ + case COLOR_256: return ANSI_##FALLBACK##_UNDERLINE ANSI_##NAME##_UNDERLINE; \ + default: return ANSI_##NAME##_UNDERLINE; \ + } \ + } + +DEFINE_ANSI_FUNC_UNDERLINE(highlight, HIGHLIGHT); +DEFINE_ANSI_FUNC_UNDERLINE(highlight_red, HIGHLIGHT_RED); +DEFINE_ANSI_FUNC_UNDERLINE(highlight_green, HIGHLIGHT_GREEN); +DEFINE_ANSI_FUNC_UNDERLINE_256(highlight_yellow, HIGHLIGHT_YELLOW, HIGHLIGHT_YELLOW_FALLBACK); +DEFINE_ANSI_FUNC_UNDERLINE(highlight_blue, HIGHLIGHT_BLUE); +DEFINE_ANSI_FUNC_UNDERLINE(highlight_magenta, HIGHLIGHT_MAGENTA); +DEFINE_ANSI_FUNC_UNDERLINE_256(grey, GREY, BRIGHT_BLACK); +DEFINE_ANSI_FUNC_UNDERLINE_256(highlight_grey, HIGHLIGHT_GREY, HIGHLIGHT_GREY_FALLBACK);