From 197dbde7d93131ce7868c3c621736ef9d39c0b79 Mon Sep 17 00:00:00 2001 From: Ailin Nemui Date: Fri, 2 Jan 2026 17:35:39 +0100 Subject: [PATCH] Restore the colours to the previous one instead of the theme default Fixes #1592 --- src/core/special-vars.c | 11 +- src/fe-common/core/formats.c | 267 +++++++++++++++++++++++++++++----- src/fe-common/core/formats.h | 47 +++--- src/fe-text/textbuffer-view.c | 10 +- 4 files changed, 278 insertions(+), 57 deletions(-) diff --git a/src/core/special-vars.c b/src/core/special-vars.c index 8c890645..b0ed037b 100644 --- a/src/core/special-vars.c +++ b/src/core/special-vars.c @@ -27,6 +27,7 @@ #include #include #include +#include #define isvarchar(c) \ (i_isalnum(c) || (c) == '_') @@ -81,12 +82,20 @@ static char *get_argument(char **cmd, char **arglist) } str = g_string_new(NULL); + g_string_append_c(str, 4); + g_string_append_c(str, FORMAT_STYLE_PUSH); while (arg >= 0 && arg < argcount && (arg <= max || max == -1)) { g_string_append(str, arglist[arg]); g_string_append_c(str, ' '); arg++; } - if (str->len > 0) g_string_truncate(str, str->len-1); + if (str->len > 2) { + g_string_truncate(str, str->len - 1); + g_string_append_c(str, 4); + g_string_append_c(str, FORMAT_STYLE_POP); + } else { + g_string_truncate(str, 0); + } ret = g_string_free_and_steal(str); return ret; diff --git a/src/fe-common/core/formats.c b/src/fe-common/core/formats.c index d22af8e4..aa3b7923 100644 --- a/src/fe-common/core/formats.c +++ b/src/fe-common/core/formats.c @@ -36,6 +36,14 @@ #include #include +#define FORMAT_STYLE_STACK_MAX 10 +typedef struct { + int fgcolor_s[FORMAT_STYLE_STACK_MAX]; + int bgcolor_s[FORMAT_STYLE_STACK_MAX]; + int flags_s[FORMAT_STYLE_STACK_MAX]; + int cur, keep; +} STYLE_STACK_REC; + static const char *format_backs = "04261537"; static const char *format_fores = "kbgcrmyw"; static const char *format_boldfores = "KBGCRMYW"; @@ -262,11 +270,15 @@ int format_expand_styles(GString *out, const char **format, int *flags) g_string_append_c(out, FORMAT_STYLE_BLINK); break; case 'n': - case 'N': /* default color */ g_string_append_c(out, 4); g_string_append_c(out, FORMAT_STYLE_DEFAULTS); break; + case 'N': + /* default theme color */ + g_string_append_c(out, 4); + g_string_append_c(out, FORMAT_STYLE_THEME_DEFAULTS); + break; case '>': /* clear to end of line */ g_string_append_c(out, 4); @@ -284,6 +296,18 @@ int format_expand_styles(GString *out, const char **format, int *flags) (*format)--; break; + case '(': + g_string_append_c(out, 4); + g_string_append_c(out, FORMAT_STYLE_PUSH); + break; + case ')': + g_string_append_c(out, 4); + g_string_append_c(out, FORMAT_STYLE_POP); + break; + case '`': + g_string_append_c(out, 4); + g_string_append_c(out, FORMAT_STYLE_KEEP); + break; case 'x': case 'X': if ((*format)[1] < '0' || (*format)[1] > '7') @@ -682,6 +706,9 @@ char *format_string_unexpand(const char *text, int flags) format_flag_unexpand(out, 'I'); break; case FORMAT_STYLE_DEFAULTS: + format_flag_unexpand(out, 'n'); + break; + case FORMAT_STYLE_THEME_DEFAULTS: format_flag_unexpand(out, 'N'); break; case FORMAT_STYLE_CLRTOEOL: @@ -690,6 +717,15 @@ char *format_string_unexpand(const char *text, int flags) case FORMAT_STYLE_MONOSPACE: format_flag_unexpand(out, '#'); break; + case FORMAT_STYLE_PUSH: + format_flag_unexpand(out, '('); + break; + case FORMAT_STYLE_POP: + format_flag_unexpand(out, ')'); + break; + case FORMAT_STYLE_KEEP: + format_flag_unexpand(out, '`'); + break; default: if (*text != FORMAT_COLOR_NOCHANGE) { unsigned int value = (unsigned char) *text - '0'; @@ -1044,10 +1080,117 @@ void format_newline(TEXT_DEST_REC *dest) GINT_TO_POINTER(-1), GINT_TO_POINTER(GUI_PRINT_FLAG_NEWLINE), "", dest); } +#define SS_FGCOLOR_CUR(stack) (stack)->fgcolor_s[(stack)->cur] +#define SS_FGCOLOR_PREV(stack) (stack)->fgcolor_s[(stack)->cur - 1] +#define SS_FGCOLOR_KEEP(stack) (stack)->fgcolor_s[(stack)->keep] + +#define SS_BGCOLOR_CUR(stack) (stack)->bgcolor_s[(stack)->cur] +#define SS_BGCOLOR_PREV(stack) (stack)->bgcolor_s[(stack)->cur - 1] +#define SS_BGCOLOR_KEEP(stack) (stack)->bgcolor_s[(stack)->keep] + +#define SS_FLAGS_CUR(stack) (stack)->flags_s[(stack)->cur] +#define SS_FLAGS_PREV(stack) (stack)->flags_s[(stack)->cur - 1] +#define SS_FLAGS_KEEP(stack) (stack)->flags_s[(stack)->keep] + +inline static void ss_restore_fgcolor(THEME_REC *theme, STYLE_STACK_REC *stack, int *fgcolor, + int *flags) +{ + if (stack != NULL && stack->cur > 0) { + *fgcolor = SS_FGCOLOR_PREV(stack); + if (SS_FLAGS_PREV(stack) & GUI_PRINT_FLAG_COLOR_24_FG) { + *flags |= GUI_PRINT_FLAG_COLOR_24_FG; + } else { + *flags &= ~GUI_PRINT_FLAG_COLOR_24_FG; + } + } else { + if (theme != NULL) + *fgcolor = theme->default_color; + else + *fgcolor = -1; + *flags &= ~GUI_PRINT_FLAG_COLOR_24_FG; + } +} + +inline static void ss_restore_bgcolor(THEME_REC *theme, STYLE_STACK_REC *stack, int *bgcolor, + int *flags) +{ + (void) theme; + if (stack != NULL && stack->cur > 0) { + *bgcolor = SS_BGCOLOR_PREV(stack); + if (SS_FLAGS_PREV(stack) & GUI_PRINT_FLAG_COLOR_24_BG) { + *flags |= GUI_PRINT_FLAG_COLOR_24_BG; + } else { + *flags &= ~GUI_PRINT_FLAG_COLOR_24_BG; + } + } else { + *bgcolor = -1; + *flags &= ~GUI_PRINT_FLAG_COLOR_24_BG; + } +} + +inline static void ss_restore_flags(THEME_REC *theme, STYLE_STACK_REC *stack, int *flags, int reset) +{ + int oldflags = *flags; + (void) theme; + if (reset) + oldflags &= ~reset; + else + oldflags &= (GUI_PRINT_FLAG_COLOR_24_FG | GUI_PRINT_FLAG_COLOR_24_BG); + if (stack != NULL && stack->cur > 0) + *flags = (SS_FLAGS_PREV(stack) & + ~(GUI_PRINT_FLAG_COLOR_24_FG | GUI_PRINT_FLAG_COLOR_24_BG)) | + oldflags; + else + *flags = oldflags; +} + +inline static void ss_push(THEME_REC *theme, STYLE_STACK_REC *stack, int flags, int fgcolor, + int bgcolor) +{ + (void) theme; + SS_FLAGS_CUR(stack) = + flags & ~(GUI_PRINT_FLAG_INDENT | GUI_PRINT_FLAG_NEWLINE | GUI_PRINT_FLAG_CLRTOEOL); + SS_FGCOLOR_CUR(stack) = fgcolor; + SS_BGCOLOR_CUR(stack) = bgcolor; + if (stack->cur + 1 < FORMAT_STYLE_STACK_MAX) + stack->cur++; +} + +inline static void ss_pop(THEME_REC *theme, STYLE_STACK_REC *stack, int oldflags, int *flags, + int *fgcolor, int *bgcolor) +{ + stack->keep = stack->cur; + SS_FLAGS_KEEP(stack) = + oldflags & ~(GUI_PRINT_FLAG_INDENT | GUI_PRINT_FLAG_NEWLINE | GUI_PRINT_FLAG_CLRTOEOL); + SS_FGCOLOR_KEEP(stack) = *fgcolor; + SS_BGCOLOR_KEEP(stack) = *bgcolor; + if (stack->cur > 0) { + stack->cur--; + *flags = SS_FLAGS_CUR(stack); + *fgcolor = SS_FGCOLOR_CUR(stack); + *bgcolor = SS_BGCOLOR_CUR(stack); + } else { + *flags = 0; + *fgcolor = theme->default_color; + *bgcolor = -1; + } +} + +inline static void ss_keep(THEME_REC *theme, STYLE_STACK_REC *stack, int oldflags, int *flags, + int *fgcolor, int *bgcolor) +{ + *flags = oldflags; + if (stack->keep >= 0) { + *flags = SS_FLAGS_KEEP(stack); + *bgcolor = SS_BGCOLOR_KEEP(stack); + *fgcolor = SS_FGCOLOR_KEEP(stack); + stack->keep--; + } +} /* parse ANSI color string */ -static const char *get_ansi_color(THEME_REC *theme, const char *str, - int *fg_ret, int *bg_ret, int *flags_ret) +static const char *get_ansi_color(THEME_REC *theme, const char *str, int *fg_ret, int *bg_ret, + int *flags_ret, STYLE_STACK_REC *style_stack) { static char ansitab[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; const char *start; @@ -1055,13 +1198,24 @@ static const char *get_ansi_color(THEME_REC *theme, const char *str, int fg, bg, flags, i; guint num, num2; + flags = 0; + if (*str != '[') return str; start = str++; - fg = fg_ret == NULL || *fg_ret < 0 ? theme->default_color : *fg_ret; - bg = bg_ret == NULL || *bg_ret < 0 ? -1 : *bg_ret; - flags = flags_ret == NULL ? 0 : *flags_ret; + if (fg_ret == NULL || *fg_ret < 0) + ss_restore_fgcolor(theme, style_stack, &fg, &flags); + else + fg = *fg_ret; + if (bg_ret == NULL || *bg_ret < 0) + ss_restore_bgcolor(theme, style_stack, &bg, &flags); + else + bg = *bg_ret; + if (flags_ret == NULL) + ss_restore_flags(theme, style_stack, &flags, 0); + else + flags = *flags_ret; num = 0; for (;; str++) { @@ -1074,18 +1228,20 @@ static const char *get_ansi_color(THEME_REC *theme, const char *str, str = endptr; } - if (*str != ';' && *str != 'm') + if (!(*str == ';' || *str == 'm' || (*str == ':' && (num == 38 || num == 48)))) return start; switch (num) { case 0: /* reset colors and attributes back to default */ - fg = theme->default_color; - bg = -1; - flags &= ~(GUI_PRINT_FLAG_INDENT | - GUI_PRINT_FLAG_BOLD | GUI_PRINT_FLAG_ITALIC | GUI_PRINT_FLAG_UNDERLINE | - GUI_PRINT_FLAG_BLINK | GUI_PRINT_FLAG_REVERSE | - GUI_PRINT_FLAG_COLOR_24_FG | GUI_PRINT_FLAG_COLOR_24_BG); + ss_restore_fgcolor(theme, style_stack, &fg, &flags); + ss_restore_bgcolor(theme, style_stack, &bg, &flags); + ss_restore_flags(theme, style_stack, &flags, + GUI_PRINT_FLAG_INDENT | GUI_PRINT_FLAG_BOLD | + GUI_PRINT_FLAG_ITALIC | GUI_PRINT_FLAG_UNDERLINE | + GUI_PRINT_FLAG_BLINK | GUI_PRINT_FLAG_REVERSE | + GUI_PRINT_FLAG_COLOR_24_FG | + GUI_PRINT_FLAG_COLOR_24_BG); break; case 1: /* hilight */ @@ -1129,18 +1285,18 @@ static const char *get_ansi_color(THEME_REC *theme, const char *str, break; case 39: /* reset fg */ - flags &= ~GUI_PRINT_FLAG_COLOR_24_FG; - fg = theme->default_color; + ss_restore_fgcolor(theme, style_stack, &fg, &flags); break; case 49: /* reset bg */ - bg = -1; - flags &= ~(GUI_PRINT_FLAG_COLOR_24_BG | GUI_PRINT_FLAG_INDENT); + ss_restore_bgcolor(theme, style_stack, &bg, &flags); + flags &= ~GUI_PRINT_FLAG_INDENT; break; case 38: case 48: /* ANSI indexed color or RGB color */ - if (*str != ';') break; + if (*str != ';' && *str != ':') + break; str++; if (!parse_uint(str, &endptr, 10, &num2)) { @@ -1183,7 +1339,8 @@ static const char *get_ansi_color(THEME_REC *theme, const char *str, break; case 5: /* indexed */ - if (*str != ';') break; + if (*str != ';' && *str != ':') + break; str++; if (!parse_uint(str, &endptr, 10, &num2)) { @@ -1320,7 +1477,8 @@ int strip_real_length(const char *str, int len, if (last_color_len != NULL) *last_color_len = 3; str++; - } else if (str[1] == FORMAT_STYLE_DEFAULTS) { + } else if (str[1] == FORMAT_STYLE_DEFAULTS || + str[1] == FORMAT_STYLE_THEME_DEFAULTS) { if (last_color_pos != NULL) *last_color_pos = (int) (str-start); if (last_color_len != NULL) @@ -1369,14 +1527,17 @@ char *strip_codes(const char *input) else if (p[5] == '\0') p += 4; else p += 5; } else - p += 2; + p += 2; continue; } } if (*p == 27 && p[1] != '\0') { p++; - p = get_ansi_color(current_theme, p, NULL, NULL, NULL); + if (strncmp(p, "[#", 2) == 0 && (p[2] == '}' || p[2] == '{')) + p += 3; + else + p = get_ansi_color(current_theme, p, NULL, NULL, NULL, NULL); p--; } else if (!IS_COLOR_CODE(*p)) *out++ = *p; @@ -1398,13 +1559,18 @@ void format_send_as_gui_flags(TEXT_DEST_REC *dest, const char *text, SIGNAL_FUNC THEME_REC *theme; char *dup, *str, *ptr, type; int fgcolor, bgcolor; - int flags; + int flags, oldflags; + STYLE_STACK_REC style_stack; theme = window_get_theme(dest->window); dup = str = g_strdup(text); - flags = 0; fgcolor = theme->default_color; bgcolor = -1; + flags = 0; + fgcolor = theme->default_color; + bgcolor = -1; + style_stack.cur = 0; + style_stack.keep = -1; if (*str == '\0') { /* empty line, write line info only */ @@ -1437,14 +1603,16 @@ void format_send_as_gui_flags(TEXT_DEST_REC *dest, const char *text, SIGNAL_FUNC if (type == '\n') { handler(dest->window, GINT_TO_POINTER(-1), GINT_TO_POINTER(-1), GINT_TO_POINTER(GUI_PRINT_FLAG_NEWLINE), "", dest); - fgcolor = theme->default_color; - bgcolor = -1; - flags &= GUI_PRINT_FLAG_INDENT|GUI_PRINT_FLAG_MONOSPACE; + ss_restore_fgcolor(theme, &style_stack, &fgcolor, &flags); + ss_restore_bgcolor(theme, &style_stack, &bgcolor, &flags); + ss_restore_flags(theme, &style_stack, &flags, + ~(GUI_PRINT_FLAG_INDENT | GUI_PRINT_FLAG_MONOSPACE)); } if (*ptr == '\0') break; + oldflags = flags; switch (type) { case 2: @@ -1486,12 +1654,26 @@ void format_send_as_gui_flags(TEXT_DEST_REC *dest, const char *text, SIGNAL_FUNC flags |= GUI_PRINT_FLAG_INDENT; break; case FORMAT_STYLE_DEFAULTS: + ss_restore_fgcolor(theme, &style_stack, &fgcolor, &flags); + ss_restore_bgcolor(theme, &style_stack, &bgcolor, &flags); + ss_restore_flags(theme, &style_stack, &flags, 0); + break; + case FORMAT_STYLE_THEME_DEFAULTS: fgcolor = theme->default_color; bgcolor = -1; flags &= GUI_PRINT_FLAG_INDENT|GUI_PRINT_FLAG_MONOSPACE; break; case FORMAT_STYLE_CLRTOEOL: break; + case FORMAT_STYLE_PUSH: + ss_push(theme, &style_stack, oldflags, fgcolor, bgcolor); + break; + case FORMAT_STYLE_POP: + ss_pop(theme, &style_stack, oldflags, &flags, &fgcolor, &bgcolor); + break; + case FORMAT_STYLE_KEEP: + ss_keep(theme, &style_stack, oldflags, &flags, &fgcolor, &bgcolor); + break; case FORMAT_COLOR_EXT1: fgcolor = 0x10 + *++ptr - FORMAT_COLOR_NOCHANGE; flags &= ~GUI_PRINT_FLAG_COLOR_24_FG; @@ -1548,10 +1730,10 @@ void format_send_as_gui_flags(TEXT_DEST_REC *dest, const char *text, SIGNAL_FUNC /* remove all styling */ if (!hide_text_style) { if (!hide_colors) { - fgcolor = theme->default_color; - bgcolor = -1; + ss_restore_fgcolor(theme, &style_stack, &fgcolor, &flags); + ss_restore_bgcolor(theme, &style_stack, &bgcolor, &flags); } - flags &= GUI_PRINT_FLAG_INDENT | GUI_PRINT_FLAG_MONOSPACE; + ss_restore_flags(theme, &style_stack, &flags, 0); } break; case 17: @@ -1574,12 +1756,25 @@ void format_send_as_gui_flags(TEXT_DEST_REC *dest, const char *text, SIGNAL_FUNC flags ^= GUI_PRINT_FLAG_UNDERLINE; break; case 27: - /* ansi color code */ - ptr = (char *) - get_ansi_color(theme, ptr, - hide_colors ? NULL : &fgcolor, - hide_colors ? NULL : &bgcolor, - hide_colors ? NULL : &flags); + if (strncmp(ptr, "[#", 2) == 0) { + switch (ptr[2]) { + case '{': + ss_push(theme, &style_stack, oldflags, fgcolor, bgcolor); + ptr += 3; + break; + case '}': + ss_pop(theme, &style_stack, oldflags, &flags, &fgcolor, + &bgcolor); + ptr += 3; + break; + } + } else { + /* ansi color code */ + ptr = (char *) get_ansi_color( + theme, ptr, hide_colors ? NULL : &fgcolor, + hide_colors ? NULL : &bgcolor, hide_colors ? NULL : &flags, + &style_stack); + } break; } diff --git a/src/fe-common/core/formats.h b/src/fe-common/core/formats.h index f85ceecb..1aa99427 100644 --- a/src/fe-common/core/formats.h +++ b/src/fe-common/core/formats.h @@ -151,25 +151,36 @@ void format_send_to_gui(TEXT_DEST_REC *dest, const char *text); */ void format_send_as_gui_flags(TEXT_DEST_REC *dest, const char *text, SIGNAL_FUNC handler); -#define FORMAT_COLOR_NOCHANGE ('0'-1) /* don't change this, at least hilighting depends this value */ -#define FORMAT_COLOR_EXT1 ('0'-2) -#define FORMAT_COLOR_EXT2 ('0'-3) -#define FORMAT_COLOR_EXT3 ('0'-4) -#define FORMAT_COLOR_EXT1_BG ('0'-5) -#define FORMAT_COLOR_EXT2_BG ('0'-9) -#define FORMAT_COLOR_EXT3_BG ('0'-10) -#define FORMAT_COLOR_24 ('0'-13) +enum { + FORMAT_COLOR_24 = ('0' - 13), + FORMAT_COLOR_EXT3_BG = ('0' - 10), + FORMAT_COLOR_EXT2_BG, + FORMAT_COLOR_EXT1_BG = ('0' - 5), + FORMAT_COLOR_EXT3, + FORMAT_COLOR_EXT2, + FORMAT_COLOR_EXT1, + FORMAT_COLOR_NOCHANGE +}; +/* don't change this, at least hilighting depends this value */ +G_STATIC_ASSERT(FORMAT_COLOR_NOCHANGE == ('0' - 1)); + +enum { + FORMAT_STYLE_SPECIAL = 0x60, + FORMAT_STYLE_BLINK, + FORMAT_STYLE_UNDERLINE, + FORMAT_STYLE_BOLD, + FORMAT_STYLE_REVERSE, + FORMAT_STYLE_INDENT, + FORMAT_STYLE_ITALIC, + FORMAT_STYLE_DEFAULTS, + FORMAT_STYLE_CLRTOEOL, + FORMAT_STYLE_MONOSPACE, + FORMAT_STYLE_THEME_DEFAULTS, + FORMAT_STYLE_PUSH, + FORMAT_STYLE_POP, + FORMAT_STYLE_KEEP +}; -#define FORMAT_STYLE_SPECIAL 0x60 -#define FORMAT_STYLE_BLINK (0x01 + FORMAT_STYLE_SPECIAL) -#define FORMAT_STYLE_UNDERLINE (0x02 + FORMAT_STYLE_SPECIAL) -#define FORMAT_STYLE_BOLD (0x03 + FORMAT_STYLE_SPECIAL) -#define FORMAT_STYLE_REVERSE (0x04 + FORMAT_STYLE_SPECIAL) -#define FORMAT_STYLE_INDENT (0x05 + FORMAT_STYLE_SPECIAL) -#define FORMAT_STYLE_ITALIC (0x06 + FORMAT_STYLE_SPECIAL) -#define FORMAT_STYLE_DEFAULTS (0x07 + FORMAT_STYLE_SPECIAL) -#define FORMAT_STYLE_CLRTOEOL (0x08 + FORMAT_STYLE_SPECIAL) -#define FORMAT_STYLE_MONOSPACE (0x09 + FORMAT_STYLE_SPECIAL) int format_expand_styles(GString *out, const char **format, int *flags); void format_ext_color(GString *out, int bg, int color); void format_24bit_color(GString *out, int bg, unsigned int color); diff --git a/src/fe-text/textbuffer-view.c b/src/fe-text/textbuffer-view.c index d125e694..40a0ea59 100644 --- a/src/fe-text/textbuffer-view.c +++ b/src/fe-text/textbuffer-view.c @@ -172,10 +172,16 @@ static inline void unformat(const unsigned char **ptr, int *color, unsigned int case FORMAT_STYLE_MONOSPACE: /* *color ^= ATTR_MONOSPACE; */ break; + case FORMAT_STYLE_SPECIAL: + case FORMAT_STYLE_INDENT: /* this must be handled by view_line_draw */ case FORMAT_STYLE_DEFAULTS: - *color = ATTR_RESET; - break; case FORMAT_STYLE_CLRTOEOL: + case FORMAT_STYLE_THEME_DEFAULTS: + case FORMAT_STYLE_PUSH: + case FORMAT_STYLE_POP: + case FORMAT_STYLE_KEEP: + /* these are not supposed to leak into the textbuffer-view */ + g_assert_not_reached(); break; #define SET_COLOR_EXT_FG_BITS(base, pc) \ *color &= ~ATTR_FGCOLOR24; \