]> git.feebdaed.xyz Git - 0xmirror/radare2.git/commitdiff
Better color limit checks with TERM ##cons
authorpancake <trufae@gmail.com>
Thu, 18 Dec 2025 13:34:41 +0000 (14:34 +0100)
committerGitHub <noreply@github.com>
Thu, 18 Dec 2025 13:34:41 +0000 (14:34 +0100)
libr/cons/cons.c
libr/core/cconfig.c
libr/include/r_cons.h

index 3934eb3482e83f84903bfd7d7f64d94dc9ca6efd..8f2cbf3a9c716c07adf86686ef2b4e8e4984bb4f 100644 (file)
@@ -120,7 +120,7 @@ static void mark_free(RConsMark *m) {
 }
 
 /*
- * Update the scrcolorlimit based on TERM environment variable.
+ * Update the color_limit based on TERM environment variable.
  *
  * This function provides a basic, hard-coded mapping from TERM values to
  * maximum color capabilities. It is intentionally simple and does not implement
@@ -137,27 +137,31 @@ static void mark_free(RConsMark *m) {
  * - No consideration of terminal multiplexers (screen/tmux) capability passthrough
  * - No handling of terminal emulation compatibility layers
  */
-static void rcons_update_scrcolorlimit_from_term(RCons *cons) {
+static void rcons_update_color_limit_from_term(RCons *cons) {
        char *term = r_sys_getenv ("TERM");
-       int limit = COLOR_MODE_16M; // Default to no limit for unknown terminals
+       int limit = COLOR_MODE_16M; // Default to no limit
+       // alacritty, kitty, ghostty, wezterm, foot, konsole-256color, iterm2, ..
        if (R_STR_ISNOTEMPTY (term)) {
                if (!strcmp (term, "dumb")) {
                        limit = COLOR_MODE_DISABLED;
                } else if (!strcmp (term, "vt100") || !strcmp (term, "vt102") ||
                           !strcmp (term, "vt220") || !strcmp (term, "vt200") ||
-                          !strncmp (term, "vt2", 3)) {
+                          r_str_startswith (term, "vt2")) {
                        limit = COLOR_MODE_DISABLED;
                } else if (!strcmp (term, "cons25")) {
                        limit = COLOR_MODE_DISABLED;
                } else if (strstr (term, "16color")) {
                        limit = COLOR_MODE_16;
                } else if (strstr (term, "256color")) {
-                       limit = COLOR_MODE_256;
+                       // requires extra check for COLORTERM=truecolor|24bit
+                       // but it's the standard, and 99% of them support truecolor
+                       // limit = COLOR_MODE_256;
+                       limit = COLOR_MODE_16M;
                } else if (!strcmp (term, "ansi") || !strcmp (term, "screen")) {
                        limit = COLOR_MODE_16;
                }
        }
-       cons->context->scrcolorlimit = limit;
+       cons->context->color_limit = limit;
        free (term);
 }
 
@@ -181,13 +185,13 @@ static void init_cons_context(RCons *cons, RConsContext * R_NULLABLE parent) {
 
        if (parent) {
                ctx->color_mode = parent->color_mode;
-               ctx->scrcolorlimit = parent->scrcolorlimit;
+               ctx->color_limit = parent->color_limit;
                r_cons_pal_copy (cons, parent);
        } else {
                ctx->color_mode = COLOR_MODE_DISABLED;
-               ctx->scrcolorlimit = COLOR_MODE_16M; // Default to no limit
+               ctx->color_limit = COLOR_MODE_16M; // Default to no limit
                r_cons_pal_init (cons);
-               rcons_update_scrcolorlimit_from_term (cons);
+               rcons_update_color_limit_from_term (cons);
        }
        cons_grep_reset (&ctx->grep);
 }
index 0c75c5318f33563f7bdcf66dc6c178e0fadf273a..9b23b5afe015497cea8aa0329dcc1863091231a1 100644 (file)
@@ -1732,7 +1732,17 @@ static bool cb_scr_color_ophex(void *user, void *data) {
 
 static bool cb_color(void *user, void *data) {
        RCore *core = (RCore *)user;
+       const int limit = core->cons->context->color_limit;
        RConfigNode *node = (RConfigNode *)data;
+       if (*node->value == '?') {
+               r_cons_printf (core->cons, "Possible values:\n"
+                               "  0 - disable colors\n"
+                               "  1 - ansi 16 colors\n"
+                               "  2 - 256 colors\n"
+                               "  3 - 16 million colors (truecolor)\n"
+                               "Maximum supported by your terminal: %d\n", limit);
+               return false;
+       }
        if (node->i_value) {
                core->print->flags |= R_PRINT_FLAGS_COLOR;
        } else {
@@ -1743,11 +1753,13 @@ static bool cb_color(void *user, void *data) {
        } else if (!strcmp (node->value, "false")) {
                node->i_value = 0;
        }
-       int requested_mode = (node->i_value > COLOR_MODE_16M)
-               ? COLOR_MODE_16M
-               : node->i_value;
-       // Enforce scrcolorlimit: never exceed the terminal's capability
-       core->cons->context->color_mode = R_MIN (requested_mode, core->cons->context->scrcolorlimit);
+       int requested_mode = R_MIN (node->i_value, COLOR_MODE_16M);
+       if (requested_mode > limit) {
+               R_LOG_WARN ("Color mode %d requested but terminal only supports %d", requested_mode, limit);
+               // core->cons->context->color_mode = R_MIN (requested_mode, limit);
+       }
+       core->cons->context->color_mode = requested_mode;
+
        r_cons_pal_reload (core->cons); // double flute
        r_print_set_flags (core->print, core->print->flags);
        r_log_set_colors (node->i_value);
@@ -2666,6 +2678,13 @@ static bool cb_scrhighlight(void *user, void *data) {
 }
 
 #if R2__WINDOWS__
+static inline DWORD modevalue(DWORD mode, bool set) {
+       if (set) {
+               return mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
+       }
+       return mode & ~ENABLE_VIRTUAL_TERMINAL_PROCESSING & ~ENABLE_WRAP_AT_EOL_OUTPUT;
+}
+
 static bool scr_vtmode(void *user, void *data) {
        RCore *core = (RCore *)user;
        RConfigNode *node = (RConfigNode *)data;
@@ -2687,18 +2706,10 @@ static bool scr_vtmode(void *user, void *data) {
        }
        HANDLE streams[] = { GetStdHandle (STD_OUTPUT_HANDLE), GetStdHandle (STD_ERROR_HANDLE) };
        int i;
-       if (node->i_value > 0) {
-               for (i = 0; i < R_ARRAY_SIZE (streams); i++) {
-                       GetConsoleMode (streams[i], &mode);
-                       SetConsoleMode (streams[i],
-                               mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
-               }
-       } else {
-               for (i = 0; i < R_ARRAY_SIZE (streams); i++) {
-                       GetConsoleMode (streams[i], &mode);
-                       SetConsoleMode (streams[i],
-                               mode & ~ENABLE_VIRTUAL_TERMINAL_PROCESSING & ~ENABLE_WRAP_AT_EOL_OUTPUT);
-               }
+       bool set = (node->i_value > 0);
+       for (i = 0; i < R_ARRAY_SIZE (streams); i++) {
+               GetConsoleMode (streams[i], &mode);
+               SetConsoleMode (streams[i], modevalue (mode, set));
        }
        return true;
 }
@@ -4660,7 +4671,8 @@ R_API int r_core_config_init(RCore *core) {
        SETB ("scr.tts", "false", "use tts if available by a command (see ic)");
        SETCB ("scr.prompt", "true", &cb_scrprompt, "show user prompt (used by r2 -q)");
        SETICB ("scr.limit", 0, &cb_scr_limit, "stop printing after N bytes");
-       SETICB ("scr.color", (core->print->flags & R_PRINT_FLAGS_COLOR)? COLOR_MODE_16: COLOR_MODE_DISABLED, &cb_color, "enable colors (0: none, 1: ansi, 2: 256 colors, 3: truecolor)");
+       const int default_color = (core->print->flags & R_PRINT_FLAGS_COLOR)? core->cons->context->color_limit: COLOR_MODE_DISABLED;
+       SETICB ("scr.color", default_color, &cb_color, "enable colors (0: none, 1: ansi, 2: 256 colors, 3: truecolor)");
        r_config_set_getter (cfg, "scr.color", (RConfigCallback)cb_color_getter);
        SETCB ("scr.color.grep", "false", &cb_scr_color_grep, "enable colors when using ~grep");
        SETB ("scr.color.pipe", "false", "enable colors when using pipes");
index a76dfadb6937c9838766c8a43877cbb5b906d2d0..b91549411e4c46abaf05a43787aece5d318301b4 100644 (file)
@@ -449,7 +449,7 @@ typedef struct r_cons_context_t {
        bool pageable;
 
        int color_mode;
-       int scrcolorlimit; // maximum color mode allowed based on TERM detection
+       int color_limit; // maximum mode based TERM envvar
        RConsPalette cpal;
        RConsPrintablePalette pal;