From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id ceF0BB66BGO7/SsAWB0awg (envelope-from ) for ; Tue, 23 Aug 2022 07:29:34 -0400 Received: by simark.ca (Postfix, from userid 112) id 055941E4A7; Tue, 23 Aug 2022 07:29:34 -0400 (EDT) Authentication-Results: simark.ca; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.a=rsa-sha256 header.s=default header.b=nYzCTYu8; dkim-atps=neutral X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-3.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 90B9F1E21F for ; Tue, 23 Aug 2022 07:29:31 -0400 (EDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id BCF3A3858295 for ; Tue, 23 Aug 2022 11:29:30 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BCF3A3858295 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1661254170; bh=oZe77k+pAaeplzpg3+u2xgLOAM3gl0KxglcBzrO3bww=; h=To:Subject:In-Reply-To:References:Date:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=nYzCTYu8rmlrVzcFGaPmRV7j/yfekBMzDylEWW1NixxiXX1+t+lqcN0JYbxKSZ3PQ US4yEFc6WUqTu4LjyWqlGMdj3Ib2/9gImukG0HI3aO9AblQqGiJvIhHI726x9nJP/c DG2g8LlJvasTFh3FrgsfDmUXQ0slU7fC8qwRdD84= Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 5F320385840C for ; Tue, 23 Aug 2022 11:29:07 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 5F320385840C Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-154-PJUoDkz1N5euHb6Owf08EA-1; Tue, 23 Aug 2022 07:29:06 -0400 X-MC-Unique: PJUoDkz1N5euHb6Owf08EA-1 Received: by mail-wm1-f70.google.com with SMTP id h133-20020a1c218b000000b003a5fa79008bso3552170wmh.5 for ; Tue, 23 Aug 2022 04:29:05 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:message-id:date:references:in-reply-to:subject:cc:to :from:x-gm-message-state:from:to:cc; bh=oZe77k+pAaeplzpg3+u2xgLOAM3gl0KxglcBzrO3bww=; b=xWF7DiAZg99qA1gnGm/vmBWHJWJT3CPWqmO88EomL1wMrX4ndgnmsfTosm6aW7BxDz i5IV8DijgWQuE5fB+nMbrJCtjRLNxdhzALsaYbLccLbK84mbR0kCWic8RoD6QmZzMzsC +85sEwbei+hEIYAfzCbP1dUp9d2d27UcR689VlqyJjcst83byxnZHtNGNPDFhNAm3MTP l59RnZfAqew+Ui2gHCAzPPEj0tPV1JWO67ZGUhPBr+eabIQXbQrsOg9L+SilvH2khAMX H9PLn2nsLntUvO3BH8vvrmWtJK2kpfTbei7pk++/6Hj2/h/gEb3JjbIQW/161Vvy4NIl S3kQ== X-Gm-Message-State: ACgBeo0VvdytVghbKc046YTDbZY1ljfF3DE0zAKooxFuwlr6FwqS41Xu RTwpET0/ku3tjMnQJ0qFn/fD0mU1itLi+yiN4rOIy4wa2arMLAZ1cE31nO5SAeHJohwmN9YJvQu p4iUYuiHARle3K1QKmI3HCA== X-Received: by 2002:a05:600c:3b0c:b0:3a6:aa0:5966 with SMTP id m12-20020a05600c3b0c00b003a60aa05966mr1865730wms.183.1661254143650; Tue, 23 Aug 2022 04:29:03 -0700 (PDT) X-Google-Smtp-Source: AA6agR6Uirqkx3oHGqNwdbLuWC3jrvoaV0ntJzlt7TGyXlXcw5AZQALcMrAPBID8gUAR5/7ehJ18Yg== X-Received: by 2002:a05:600c:3b0c:b0:3a6:aa0:5966 with SMTP id m12-20020a05600c3b0c00b003a60aa05966mr1865689wms.183.1661254142760; Tue, 23 Aug 2022 04:29:02 -0700 (PDT) Received: from localhost ([31.111.84.229]) by smtp.gmail.com with ESMTPSA id f14-20020a05600c154e00b003a32251c3f9sm24239941wmg.5.2022.08.23.04.29.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Aug 2022 04:29:02 -0700 (PDT) To: Andrei Pikas , gdb-patches@sourceware.org Subject: Re: [PATCH v3 (documentation fixed)] Add an option with a color type. In-Reply-To: <20220821210703.22790-1-gdb@mail.api.win> References: <835yindr0c.fsf@gnu.org> <20220821210703.22790-1-gdb@mail.api.win> Date: Tue, 23 Aug 2022 12:29:01 +0100 Message-ID: <87o7wbdwqq.fsf@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Andrew Burgess via Gdb-patches Reply-To: Andrew Burgess Cc: Andrei Pikas Errors-To: gdb-patches-bounces+public-inbox=simark.ca@sourceware.org Sender: "Gdb-patches" Andrei Pikas writes: > Colors can be specified as "none" for terminal's default color, as a name of > one of the eight standard colors of ISO/IEC 6429 "black", "red", "green", etc., > as an RGB hexadecimal tripplet #RRGGBB for 24-bit TrueColor, or as an > integer from 0 to 255. Integers 0 to 7 are the synonyms for the standard > colors. Integers 8-15 are used for the so-called bright colors from the > aixterm extended 16-color palette. Integers 16-255 are the indexes into xterm > extended 256-color palette (usually 6x6x6 cube plus gray ramp). In > general, 256-color palette is terminal dependent and sometimes can be > changed with OSC 4 sequences, e.g. "\033]4;1;rgb:00/FF/00\033\\". > > It is user's responsibility to provide colors which supported by his terminal. > --- > gdb/NEWS | 13 ++ > gdb/cli/cli-cmds.c | 7 + > gdb/cli/cli-decode.c | 173 ++++++++++++++++++++++ > gdb/cli/cli-decode.h | 21 +++ > gdb/cli/cli-option.c | 42 ++++++ > gdb/cli/cli-option.h | 21 +++ > gdb/cli/cli-setshow.c | 20 +++ > gdb/cli/cli-style.c | 49 ++---- > gdb/cli/cli-style.h | 4 +- > gdb/command.h | 26 +++- > gdb/doc/gdb.texinfo | 44 +++++- > gdb/doc/guile.texi | 8 + > gdb/doc/python.texi | 10 ++ > gdb/guile/scm-param.c | 68 ++++++++- > gdb/python/py-param.c | 63 +++++++- > gdb/python/python.c | 10 ++ > gdb/testsuite/gdb.base/style.exp | 15 ++ > gdb/testsuite/gdb.guile/scm-parameter.exp | 26 ++++ > gdb/testsuite/gdb.python/py-parameter.exp | 46 ++++++ > gdb/ui-style.c | 44 ++++++ > gdb/ui-style.h | 23 ++- > 21 files changed, 676 insertions(+), 57 deletions(-) > > diff --git a/gdb/NEWS b/gdb/NEWS > index d2efe2a0a58..c9d25890ed9 100644 > --- a/gdb/NEWS > +++ b/gdb/NEWS > @@ -55,6 +55,9 @@ > Python Pygments is still used. For supported targets, libopcodes > styling is used by default. > > + "set style" commands now supports numeric format for basic colors > + from 0 to 255 and #RRGGBB format for TrueColor. > + > * New commands > > maintenance set ignore-prologue-end-flag on|off > @@ -170,6 +173,16 @@ GNU/Linux/LoongArch (gdbserver) loongarch*-*-linux* > can be used to request a shorter representation of a value, the > way that 'set print frame-arguments scalars' does. > > + ** New constant gdb.PARAM_COLOR represents color type of a > + gdb.Parameter.value. Parameter's value is either an integer > + from 0 to 255 or string with color name or #RRGGBB hex triplet. > + > +* Guile API > + > + ** New constant PARAM_COLOR represents color type of a value > + of a object. Parameter's value is either an integer > + from 0 to 255 or string with color name or #RRGGBB hex triplet. > + > * New features in the GDB remote stub, GDBserver > > ** GDBserver is now supported on LoongArch GNU/Linux. > diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c > index 18fb6e6d869..1a515b99761 100644 > --- a/gdb/cli/cli-cmds.c > +++ b/gdb/cli/cli-cmds.c > @@ -2275,6 +2275,12 @@ value_from_setting (const setting &var, struct gdbarch *gdbarch) > return value_cstring ("", 1, > builtin_type (gdbarch)->builtin_char); > } > + case var_color: > + { > + std::string s = var.get ().to_string (); > + return value_cstring (s.c_str (), s.size (), > + builtin_type (gdbarch)->builtin_char); > + } > default: > gdb_assert_not_reached ("bad var_type"); > } > @@ -2324,6 +2330,7 @@ str_value_from_setting (const setting &var, struct gdbarch *gdbarch) > case var_auto_boolean: > case var_uinteger: > case var_zuinteger: > + case var_color: > { > std::string cmd_val = get_setshow_command_value_string (var); > > diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c > index fde554c7e6c..b0a4ceeedf6 100644 > --- a/gdb/cli/cli-decode.c > +++ b/gdb/cli/cli-decode.c > @@ -24,6 +24,7 @@ > #include "cli/cli-cmds.h" > #include "cli/cli-decode.h" > #include "cli/cli-style.h" > +#include "cli/cli-utils.h" > #include "gdbsupport/gdb_optional.h" > > /* Prototypes for local functions. */ > @@ -670,6 +671,87 @@ add_setshow_enum_cmd (const char *name, command_class theclass, > return cmds; > } > > +/* See cli-decode.h. */ > + > +void > +complete_on_color (completion_tracker &tracker, > + const char *text, const char *word) > +{ > + complete_on_enum (tracker, ui_file_style::basic_color_enums.data (), > + text, word); > + if (*text == '\0') > + { > + /* Convenience to let the user know what the option > + can accept. Note there's no common prefix between > + the strings on purpose, so that complete_on_enum doesn't do > + a partial match. */ > + tracker.add_completion (make_unique_xstrdup ("NUMBER")); > + tracker.add_completion (make_unique_xstrdup ("#RRGGBB")); > + } > +} > + > +/* Completer used in color commands. */ > + > +static void > +color_completer (struct cmd_list_element *ignore, > + completion_tracker &tracker, > + const char *text, const char *word) > +{ > + complete_on_color (tracker, text, word); > +} > + > + > +/* Add element named NAME to command list LIST (the list for set or > + some sublist thereof). CLASS is as in add_cmd. VAR is address > + of the variable which will contain the color. */ > + > +set_show_commands > +add_setshow_color_cmd (const char *name, > + enum command_class theclass, > + ui_file_style::color *var, > + const char *set_doc, > + const char *show_doc, > + const char *help_doc, > + cmd_func_ftype *set_func, > + show_value_ftype *show_func, > + struct cmd_list_element **set_list, > + struct cmd_list_element **show_list) > +{ > + set_show_commands commands = add_setshow_cmd_full > + (name, theclass, var_color, var, > + set_doc, show_doc, help_doc, > + nullptr, nullptr, set_func, show_func, > + set_list, show_list); > + > + set_cmd_completer (commands.set, color_completer); > + > + return commands; > +} > + > +/* Same as above but using a getter and a setter function instead of a pointer > + to a global storage buffer. */ > + > +set_show_commands > +add_setshow_color_cmd (const char *name, command_class theclass, > + const char *set_doc, const char *show_doc, > + const char *help_doc, > + setting_func_types::set set_func, > + setting_func_types::get get_func, > + show_value_ftype *show_func, > + cmd_list_element **set_list, > + cmd_list_element **show_list) > +{ > + auto cmds = add_setshow_cmd_full > + (name, theclass, var_color, nullptr, > + set_doc, show_doc, help_doc, > + set_func, get_func, nullptr, show_func, > + set_list, show_list); > + > + set_cmd_completer (cmds.set, color_completer); > + > + return cmds; > +} > + > /* See cli-decode.h. */ > const char * const auto_boolean_enums[] = { "on", "off", "auto", NULL }; > > @@ -2524,3 +2606,94 @@ cli_user_command_p (struct cmd_list_element *cmd) > { > return cmd->theclass == class_user && cmd->func == do_simple_func; > } > + > +/* See cli-decode.h. */ > + > +ui_file_style::color > +parse_cli_var_color (const char **args) > +{ > + /* Do a "set" command. ARG is NULL if no argument, or the > + text of the argument. */ > + > + if (args == nullptr || *args == nullptr || **args == '\0') > + { > + std::string msg; > + > + for (size_t i = 0; ui_file_style::basic_color_enums[i]; ++i) > + { > + msg.append ("\""); > + msg.append (ui_file_style::basic_color_enums[i]); > + msg.append ("\", "); > + } > + > + error (_("Requires an argument. Valid arguments are %s integer from -1 " > + "to 255 or an RGB hex triplet in a format #RRGGBB"), > + msg.c_str ()); > + } > + > + const char *p = skip_to_space (*args); > + size_t len = p - *args; > + > + int nmatches = 0; > + ui_file_style::basic_color match = ui_file_style::NONE; > + for (int i = 0; ui_file_style::basic_color_enums[i]; ++i) > + if (strncmp (*args, ui_file_style::basic_color_enums[i], len) == 0) > + { > + match = static_cast (i - 1); > + if (ui_file_style::basic_color_enums[i][len] == '\0') > + { > + nmatches = 1; > + break; /* Exact match. */ > + } > + else > + nmatches++; > + } > + > + if (nmatches == 1) > + { > + *args += len; > + return ui_file_style::color (match); > + } > + > + if (nmatches > 1) > + error (_("Ambiguous item \"%.*s\"."), (int) len, *args); > + > + if (**args != '#') > + { > + ULONGEST num = get_ulongest (args); > + if (num > 255) > + error (_("integer %s out of range"), pulongest (num)); > + return ui_file_style::color (static_cast (num)); > + } > + > + /* Try to parse #RRGGBB string. */ > + if (len != 7) > + error_no_arg (_("invalid RGB hex triplet format")); > + > + uint8_t r, g, b; > + int scanned_chars = 0; > + int parsed_args = sscanf (*args, "#%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%n", > + &r, &g, &b, &scanned_chars); > + > + if (parsed_args != 3 || scanned_chars != 7) > + error_no_arg (_("invalid RGB hex triplet format")); > + > + *args += len; > + return ui_file_style::color (r, g, b); > +} > + > +/* See cli-decode.h. */ > + > +ui_file_style::color > +parse_var_color (const char *arg) > +{ > + const char *end_arg = arg; > + ui_file_style::color color = parse_cli_var_color (&end_arg); > + > + int len = end_arg - arg; > + const char *after = skip_spaces (end_arg); > + if (*after != '\0') > + error (_("Junk after item \"%.*s\": %s"), len, arg, after); > + > + return color; > +} > diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h > index 18db8822af3..7f1233c87ad 100644 > --- a/gdb/cli/cli-decode.h > +++ b/gdb/cli/cli-decode.h > @@ -306,6 +306,27 @@ extern const char * const boolean_enums[]; > /* The enums of auto-boolean commands. */ > extern const char * const auto_boolean_enums[]; > > +/* Add the different possible completions of TEXT with color. > + > + WORD points in the same buffer as TEXT, and completions should be > + returned relative to this position. For example, suppose TEXT is "foo" > + and we want to complete to "foobar". If WORD is "oo", return > + "oobar"; if WORD is "baz/foo", return "baz/foobar". */ > + > +extern void complete_on_color (completion_tracker &tracker, > + const char *text, const char *word); > + > +/* Parse ARGS, an option to a var_color variable. > + * > + Either returns the parsed value on success or throws an error. ARGS may be > + one of strings {none, black, red, green, yellow, blue, magenta, > + cyan, white}, or color number from 0 to 255, or RGB hex triplet #RRGGBB. > + */ > +extern ui_file_style::color parse_cli_var_color (const char **args); > + > +/* Same as above but additionally check that there is no junk in the end. */ > +extern ui_file_style::color parse_var_color (const char *arg); > + > /* Verify whether a given cmd_list_element is a user-defined command. > Return 1 if it is user-defined. Return 0 otherwise. */ > > diff --git a/gdb/cli/cli-option.c b/gdb/cli/cli-option.c > index b1794ad4b17..ac62c6700fa 100644 > --- a/gdb/cli/cli-option.c > +++ b/gdb/cli/cli-option.c > @@ -46,6 +46,9 @@ union option_value > > /* For var_string options. This is malloc-allocated. */ > std::string *string; > + > + /* For var_color options. */ > + ui_file_style::color color = ui_file_style::NONE; > }; > > /* Holds an options definition and its value. */ > @@ -424,6 +427,33 @@ parse_option (gdb::array_view options_group, > val.enumeration = parse_cli_var_enum (args, match->enums); > return option_def_and_value {*match, match_ctx, val}; > } > + case var_color: > + { > + if (completion != nullptr) > + { > + const char *after_arg = skip_to_space (*args); > + if (*after_arg == '\0') > + { > + complete_on_color (completion->tracker, *args, *args); > + > + if (completion->tracker.have_completions ()) > + return {}; > + } > + } > + > + if (check_for_argument (args, "--")) > + { > + /* Treat e.g., "backtrace -entry-values --" as if there > + was no argument after "-entry-values". This makes > + parse_cli_var_color throw an error with a suggestion of > + what are the valid options. */ > + args = nullptr; > + } > + > + option_value val; > + val.color = parse_cli_var_color (args); > + return option_def_and_value {*match, match_ctx, val}; > + } > case var_string: > { > if (check_for_argument (args, "--")) > @@ -601,6 +631,10 @@ save_option_value_in_ctx (gdb::optional &ov) > *ov->option.var_address.enumeration (ov->option, ov->ctx) > = ov->value->enumeration; > break; > + case var_color: > + *ov->option.var_address.color (ov->option, ov->ctx) > + = ov->value->color; > + break; > case var_string: > *ov->option.var_address.string (ov->option, ov->ctx) > = std::move (*ov->value->string); > @@ -677,6 +711,14 @@ get_val_type_str (const option_def &opt, std::string &buffer) > } > return buffer.c_str (); > } > + case var_color: > + { > + buffer = ""; > + for (size_t i = 0; ui_file_style::basic_color_enums[i]; ++i) > + buffer.append (ui_file_style::basic_color_enums[i]).append ("|"); > + buffer += "NUMBER|#RRGGBB"; > + return buffer.c_str (); > + } > case var_string: > return "STRING"; > default: > diff --git a/gdb/cli/cli-option.h b/gdb/cli/cli-option.h > index 26a8da3a5a4..d30c7024324 100644 > --- a/gdb/cli/cli-option.h > +++ b/gdb/cli/cli-option.h > @@ -87,6 +87,7 @@ struct option_def > int *(*integer) (const option_def &, void *ctx); > const char **(*enumeration) (const option_def &, void *ctx); > std::string *(*string) (const option_def &, void *ctx); > + ui_file_style::color *(*color) (const option_def &, void *ctx); > } > var_address; > > @@ -282,6 +283,26 @@ struct string_option_def : option_def > } > }; > > +/* A var_color command line option. */ > + > +template > +struct color_option_def : option_def > +{ > + color_option_def (const char *long_option_, > + ui_file_style::color *(*get_var_address_cb_) (Context *), > + show_value_ftype *show_cmd_cb_, > + const char *set_doc_, > + const char *show_doc_ = nullptr, > + const char *help_doc_ = nullptr) > + : option_def (long_option_, var_color, > + (erased_get_var_address_ftype *) get_var_address_cb_, > + show_cmd_cb_, > + set_doc_, show_doc_, help_doc_) > + { > + var_address.color = detail::get_var_address; > + } > +}; > + > /* A group of options that all share the same context pointer to pass > to the options' get-current-value callbacks. */ > struct option_def_group > diff --git a/gdb/cli/cli-setshow.c b/gdb/cli/cli-setshow.c > index 139ebaf8323..4e8e5c7f0f8 100644 > --- a/gdb/cli/cli-setshow.c > +++ b/gdb/cli/cli-setshow.c > @@ -454,6 +454,12 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c) > option_changed = c->var->set (match); > } > break; > + case var_color: > + { > + ui_file_style::color color = parse_var_color (arg); > + option_changed = c->var->set (color); > + } > + break; > case var_zuinteger_unlimited: > option_changed = c->var->set > (parse_cli_var_zuinteger_unlimited (&arg, true)); > @@ -535,6 +541,14 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c) > gdb::observers::command_param_changed.notify > (name, c->var->get ()); > break; > + case var_color: > + { > + const ui_file_style::color &color > + = c->var->get (); > + gdb::observers::command_param_changed.notify > + (name, color.to_string ().c_str ()); > + } > + break; > case var_boolean: > { > const char *opt = c->var->get () ? "on" : "off"; > @@ -602,6 +616,12 @@ get_setshow_command_value_string (const setting &var) > stb.puts (value); > } > break; > + case var_color: > + { > + const ui_file_style::color &value = var.get (); > + stb.puts (value.to_string ().c_str ()); > + } > + break; > case var_boolean: > stb.puts (var.get () ? "on" : "off"); > break; > diff --git a/gdb/cli/cli-style.c b/gdb/cli/cli-style.c > index abf685561fa..3123a391763 100644 > --- a/gdb/cli/cli-style.c > +++ b/gdb/cli/cli-style.c > @@ -43,20 +43,6 @@ bool source_styling = true; > > bool disassembler_styling = true; > > -/* Name of colors; must correspond to ui_file_style::basic_color. */ > -static const char * const cli_colors[] = { > - "none", > - "black", > - "red", > - "green", > - "yellow", > - "blue", > - "magenta", > - "cyan", > - "white", > - nullptr > -}; > - > /* Names of intensities; must correspond to > ui_file_style::intensity. */ > static const char * const cli_intensities[] = { > @@ -132,8 +118,8 @@ cli_style_option::cli_style_option (const char *name, > ui_file_style::intensity intensity) > : changed (name), > m_name (name), > - m_foreground (cli_colors[fg - ui_file_style::NONE]), > - m_background (cli_colors[0]), > + m_foreground (fg), > + m_background (ui_file_style::NONE), > m_intensity (cli_intensities[intensity]) > { > } > @@ -144,32 +130,17 @@ cli_style_option::cli_style_option (const char *name, > ui_file_style::intensity i) > : changed (name), > m_name (name), > - m_foreground (cli_colors[0]), > - m_background (cli_colors[0]), > + m_foreground (ui_file_style::NONE), > + m_background (ui_file_style::NONE), > m_intensity (cli_intensities[i]) > { > } > > -/* Return the color number corresponding to COLOR. */ > - > -static int > -color_number (const char *color) > -{ > - for (int i = 0; i < ARRAY_SIZE (cli_colors); ++i) > - { > - if (color == cli_colors[i]) > - return i - 1; > - } > - gdb_assert_not_reached ("color not found"); > -} > - > /* See cli-style.h. */ > > ui_file_style > cli_style_option::style () const > { > - int fg = color_number (m_foreground); > - int bg = color_number (m_background); > ui_file_style::intensity intensity = ui_file_style::NORMAL; > > for (int i = 0; i < ARRAY_SIZE (cli_intensities); ++i) > @@ -181,7 +152,7 @@ cli_style_option::style () const > } > } > > - return ui_file_style (fg, bg, intensity); > + return ui_file_style (m_foreground, m_background, intensity); > } > > /* See cli-style.h. */ > @@ -254,9 +225,8 @@ cli_style_option::add_setshow_commands (enum command_class theclass, > > set_show_commands commands; > > - commands = add_setshow_enum_cmd > - ("foreground", theclass, cli_colors, > - &m_foreground, > + commands = add_setshow_color_cmd > + ("foreground", theclass, &m_foreground, > _("Set the foreground color for this property."), > _("Show the foreground color for this property."), > nullptr, > @@ -266,9 +236,8 @@ cli_style_option::add_setshow_commands (enum command_class theclass, > commands.set->set_context (this); > commands.show->set_context (this); > > - commands = add_setshow_enum_cmd > - ("background", theclass, cli_colors, > - &m_background, > + commands = add_setshow_color_cmd > + ("background", theclass, &m_background, > _("Set the background color for this property."), > _("Show the background color for this property."), > nullptr, > diff --git a/gdb/cli/cli-style.h b/gdb/cli/cli-style.h > index 4090cf01333..4db86b00359 100644 > --- a/gdb/cli/cli-style.h > +++ b/gdb/cli/cli-style.h > @@ -67,9 +67,9 @@ class cli_style_option > const char *m_name; > > /* The foreground. */ > - const char *m_foreground; > + ui_file_style::color m_foreground; > /* The background. */ > - const char *m_background; > + ui_file_style::color m_background; > /* The intensity. */ > const char *m_intensity; > > diff --git a/gdb/command.h b/gdb/command.h > index d901da3c8cb..eb3b2cc20d6 100644 > --- a/gdb/command.h > +++ b/gdb/command.h > @@ -119,7 +119,9 @@ enum var_types > /* Enumerated type. Can only have one of the specified values. > *VAR is a char pointer to the name of the element that we > find. */ > - var_enum > + var_enum, > + /* Color type. *VAR is a ui_file_style::color structure. */ > + var_color > }; > > /* Return true if a setting of type VAR_TYPE is backed with type T. > @@ -179,6 +181,14 @@ inline bool var_type_uses (var_types t) > return t == var_enum; > } > > +/* Return true if a setting of type T is backed by an ui_file_style::color > + variable. */ > +template<> > +inline bool var_type_uses (var_types t) > +{ > + return t == var_color; > +} > + > template struct setting_func_types_1; > > template > @@ -665,6 +675,20 @@ extern set_show_commands add_setshow_enum_cmd > setting_func_types::get get_func, show_value_ftype *show_func, > cmd_list_element **set_list, cmd_list_element **show_list); > > +extern set_show_commands add_setshow_color_cmd > + (const char *name, command_class theclass, ui_file_style::color *var, > + const char *set_doc, const char *show_doc, const char *help_doc, > + cmd_func_ftype *set_func, show_value_ftype *show_func, > + cmd_list_element **set_list, cmd_list_element **show_list); > + > +extern set_show_commands add_setshow_color_cmd > + (const char *name, command_class theclass, > + const char *set_doc, const char *show_doc, const char *help_doc, > + setting_func_types::set set_func, > + setting_func_types::get get_func, > + show_value_ftype *show_func, cmd_list_element **set_list, > + cmd_list_element **show_list); > + > extern set_show_commands add_setshow_auto_boolean_cmd > (const char *name, command_class theclass, auto_boolean *var, > const char *set_doc, const char *show_doc, const char *help_doc, > diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo > index 382df00ee7d..df007c63752 100644 > --- a/gdb/doc/gdb.texinfo > +++ b/gdb/doc/gdb.texinfo > @@ -26605,16 +26605,44 @@ For example, the style of file names can be controlled using the > > @table @code > @item set style filename background @var{color} > -Set the background to @var{color}. Valid colors are @samp{none} > -(meaning the terminal's default color), @samp{black}, @samp{red}, > -@samp{green}, @samp{yellow}, @samp{blue}, @samp{magenta}, @samp{cyan}, > -and@samp{white}. > +Set the background to @var{color}. @var{color} can be @samp{none} > +(meaning the terminal's default color), a name of one of the eight standard > +colors of ISO/IEC 6429, index from 0 to 255 into terminal's color > +palette or a hexadecimal RGB triplet in @samp{#RRGGBB} format for > +24-bit TrueColor. > + > +Valid color names are @samp{black}, @samp{red}, @samp{green}, > +@samp{yellow}, @samp{blue}, @samp{magenta}, @samp{cyan}, and > +@samp{white}. > + > +Integers 0 to 7 are the synonyms for the standard colors. Integers 8-15 are > +used for the so-called bright colors from the aixterm extended 16-color > +palette. Integers 16-255 are the indexes into xterm extended 256-color palette > +(usually 6x6x6 cube plus gray ramp). In general, 256-color palette is terminal > +dependent and sometimes can be changed with OSC 4 sequences, e.g. > +"\033]4;1;rgb:00/FF/00\033\\". > + > +It is user's responsibility to provide colors supported by its terminal. > > @item set style filename foreground @var{color} > -Set the foreground to @var{color}. Valid colors are @samp{none} > -(meaning the terminal's default color), @samp{black}, @samp{red}, > -@samp{green}, @samp{yellow}, @samp{blue}, @samp{magenta}, @samp{cyan}, > -and@samp{white}. > +Set the foreground to @var{color}. @var{color} can be @samp{none} > +(meaning the terminal's default color), a name of one of the eight standard > +colors of ISO/IEC 6429, index from 0 to 255 into terminal's color > +palette or a hexadecimal RGB triplet in @samp{#RRGGBB} format for > +24-bit TrueColor. > + > +Valid color names are @samp{black}, @samp{red}, @samp{green}, > +@samp{yellow}, @samp{blue}, @samp{magenta}, @samp{cyan}, and > +@samp{white}. > + > +Integers 0 to 7 are the synonyms for the standard colors. Integers 8-15 are > +used for the so-called bright colors from the aixterm extended 16-color > +palette. Integers 16-255 are the indexes into xterm extended 256-color palette > +(usually 6x6x6 cube plus gray ramp). In general, 256-color palette is terminal > +dependent and sometimes can be changed with OSC 4 sequences, e.g. > +"\033]4;1;rgb:00/FF/00\033\\". > + > +It is user's responsibility to provide colors supported by its terminal. > > @item set style filename intensity @var{value} > Set the intensity to @var{value}. Valid intensities are @samp{normal} > diff --git a/gdb/doc/guile.texi b/gdb/doc/guile.texi > index 63916eed181..395cad8891a 100644 > --- a/gdb/doc/guile.texi > +++ b/gdb/doc/guile.texi > @@ -2169,6 +2169,14 @@ The value is a filename. This is just like > @item PARAM_ENUM > The value is a string, which must be one of a collection of string > constants provided when the parameter is created. > + > +@item PARAM_COLOR > +The value is either a string or an unsigned integer. Integer from 0 to 255 > +means index into terminal's color palette. String can be a hex RGB triplet in > +@samp{#RRGGBB} format or one of the following color names: > +@samp{none} (meaning the terminal's default color), @samp{black}, @samp{red}, > +@samp{green}, @samp{yellow}, @samp{blue}, @samp{magenta}, @samp{cyan}, > +or @samp{white}. > @end vtable > > @node Progspaces In Guile > diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi > index eeb847aeaa8..5f7864f3f2a 100644 > --- a/gdb/doc/python.texi > +++ b/gdb/doc/python.texi > @@ -4651,6 +4651,16 @@ except the special value -1 should be interpreted to mean > @item gdb.PARAM_ENUM > The value is a string, which must be one of a collection string > constants provided when the parameter is created. > + > +@findex PARAM_COLOR > +@findex gdb.PARAM_COLOR > +@item gdb.PARAM_COLOR > +The value is either a string or an unsigned integer. Integer from 0 to 255 > +means index into terminal's color palette. String can be a hex RGB triplet in > +@samp{#RRGGBB} format or one of the following color names: > +@samp{none} (meaning the terminal's default color), @samp{black}, @samp{red}, > +@samp{green}, @samp{yellow}, @samp{blue}, @samp{magenta}, @samp{cyan}, > +or @samp{white}. > @end table > > @node Functions In Python > diff --git a/gdb/guile/scm-param.c b/gdb/guile/scm-param.c > index 54c8c27301a..42820dd666d 100644 > --- a/gdb/guile/scm-param.c > +++ b/gdb/guile/scm-param.c > @@ -48,6 +48,9 @@ union pascm_variable > > /* Hold a string, for enums. */ > const char *cstringval; > + > + /* Hold a color. */ > + ui_file_style::color color; > }; > > /* A GDB parameter. > @@ -129,6 +132,8 @@ make_setting (param_smob *s) > return setting (s->type, s->value.stringval); > else if (var_type_uses (s->type)) > return setting (s->type, &s->value.cstringval); > + else if (var_type_uses (s->type)) > + return setting (s->type, &s->value.color); > else > gdb_assert_not_reached ("unhandled var type"); > } > @@ -190,10 +195,9 @@ static SCM > pascm_make_param_smob (void) > { > param_smob *p_smob = (param_smob *) > - scm_gc_malloc (sizeof (param_smob), param_smob_name); > + scm_gc_calloc (sizeof (param_smob), param_smob_name); > SCM p_scm; > > - memset (p_smob, 0, sizeof (*p_smob)); > p_smob->cmd_class = no_class; > p_smob->type = var_boolean; /* ARI: var_boolean */ > p_smob->set_func = SCM_BOOL_F; > @@ -466,6 +470,13 @@ add_setshow_generic (enum var_types param_type, enum command_class cmd_class, > set_list, show_list); > break; > > + case var_color: > + commands = add_setshow_color_cmd (cmd_name, cmd_class, &self->value.color, > + set_doc, show_doc, help_doc, > + set_func, show_func, > + set_list, show_list); > + break; > + > default: > gdb_assert_not_reached ("bad param_type value"); > } > @@ -545,6 +556,7 @@ static const scheme_integer_constant parameter_types[] = > { "PARAM_OPTIONAL_FILENAME", var_optional_filename }, > { "PARAM_FILENAME", var_filename }, > { "PARAM_ENUM", var_enum }, > + { "PARAM_COLOR", var_color }, > > END_INTEGER_CONSTANTS > }; > @@ -611,6 +623,18 @@ pascm_param_value (const setting &var, int arg_pos, const char *func_name) > return gdbscm_scm_from_host_string (str, strlen (str)); > } > > + case var_color: > + { > + const ui_file_style::color &color = var.get (); > + if (color.is_none () || color.is_basic () || !color.is_simple ()) > + { > + std::string s = color.to_string (); > + return gdbscm_scm_from_host_string (s.c_str (), s.size ()); > + } > + else > + return scm_from_int (color.get_value ()); > + } > + > case var_boolean: > { > if (var.get ()) > @@ -716,6 +740,44 @@ pascm_set_param_value_x (param_smob *p_smob, > break; > } > > + case var_color: > + SCM_ASSERT_TYPE (scm_is_string (value) || scm_is_integer (value), > + value, arg_pos, func_name, > + _("string or integer")); > + > + if (scm_is_integer (value)) > + { > + int i = scm_to_int (value); > + if (i < 0 || i > 255) > + gdbscm_out_of_range_error (func_name, arg_pos, value, > + _("must be in range from 0 to 255")); > + var.set (i); > + } > + else > + { > + SCM exception; > + > + gdb::unique_xmalloc_ptr string > + = gdbscm_scm_to_host_string (value, nullptr, &exception); > + if (string == nullptr) > + gdbscm_throw (exception); > + > + gdbscm_gdb_exception exc {}; > + try > + { > + ui_file_style::color color = parse_var_color (string.get ()); > + var.set (color); > + } > + catch (const gdb_exception &except) > + { > + exc = unpack (except); > + } > + > + GDBSCM_HANDLE_GDB_EXCEPTION (exc); > + } > + > + break; > + > case var_boolean: > SCM_ASSERT_TYPE (gdbscm_is_bool (value), value, arg_pos, func_name, > _("boolean")); > @@ -961,6 +1023,8 @@ gdbscm_make_parameter (SCM name_scm, SCM rest) > scm_set_smob_free (parameter_smob_tag, pascm_free_parameter_smob); > if (var_type_uses (p_smob->type)) > p_smob->value.stringval = new std::string; > + else if (var_type_uses (p_smob->type)) > + p_smob->value.color = ui_file_style::NONE; > > if (initial_value_arg_pos > 0) > { > diff --git a/gdb/python/py-param.c b/gdb/python/py-param.c > index 5d509ba4658..a2d720490c1 100644 > --- a/gdb/python/py-param.c > +++ b/gdb/python/py-param.c > @@ -46,6 +46,7 @@ static struct { > { "PARAM_ZUINTEGER", var_zuinteger }, > { "PARAM_ZUINTEGER_UNLIMITED", var_zuinteger_unlimited }, > { "PARAM_ENUM", var_enum }, > + { "PARAM_COLOR", var_color }, > { NULL, 0 } > }; > > @@ -70,6 +71,9 @@ union parmpy_variable > > /* Hold a string, for enums. */ > const char *cstringval; > + > + /* Hold a color. */ > + ui_file_style::color color; > }; > > /* A GDB parameter. */ > @@ -108,6 +112,8 @@ make_setting (parmpy_object *s) > return setting (s->type, s->value.stringval); > else if (var_type_uses (s->type)) > return setting (s->type, &s->value.cstringval); > + else if (var_type_uses (s->type)) > + return setting (s->type, &s->value.color); > else > gdb_assert_not_reached ("unhandled var type"); > } > @@ -199,6 +205,49 @@ set_parameter_value (parmpy_object *self, PyObject *value) > break; > } > > + case var_color: > + { > + if (gdbpy_is_string (value)) > + { > + gdb::unique_xmalloc_ptr > + str (python_string_to_host_string (value)); > + if (str == NULL) > + return -1; > + try > + { > + self->value.color = parse_var_color (str.get()); > + } > + catch (const gdb_exception &except) > + { > + gdbpy_convert_exception (except); > + return -1; > + } > + } > + else if (PyLong_Check (value)) > + { > + long l; > + if (! gdb_py_int_as_long (value, &l)) > + return -1; > + if (l < 0 || l > 255) > + { > + PyErr_SetString (PyExc_RuntimeError, > + _("Range exceeded.")); > + return -1; > + } > + self->value.color = ui_file_style::color (l); > + } > + else if (value == Py_None) > + self->value.color = ui_file_style::NONE; > + else > + { > + PyErr_SetString (PyExc_RuntimeError, > + _("color arguments must be a string, an integer " > + "or None.")); > + return -1; > + } > + } > + break; > + > case var_boolean: > if (! PyBool_Check (value)) > { > @@ -637,6 +686,15 @@ add_setshow_generic (int parmclass, enum command_class cmdclass, > get_show_value, set_list, show_list); > break; > > + case var_color: > + /* Initialize the value, just in case. */ > + self->value.color = ui_file_style::NONE; > + commands = add_setshow_color_cmd (cmd_name.get (), cmdclass, > + &self->value.color, set_doc, > + show_doc, help_doc, get_set_value, > + get_show_value, set_list, show_list); > + break; > + > default: > gdb_assert_not_reached ("Unhandled parameter class."); > } > @@ -758,7 +816,8 @@ parmpy_init (PyObject *self, PyObject *args, PyObject *kwds) > && parmclass != var_string && parmclass != var_string_noescape > && parmclass != var_optional_filename && parmclass != var_filename > && parmclass != var_zinteger && parmclass != var_zuinteger > - && parmclass != var_zuinteger_unlimited && parmclass != var_enum) > + && parmclass != var_zuinteger_unlimited && parmclass != var_enum > + && parmclass != var_color) > { > PyErr_SetString (PyExc_RuntimeError, > _("Invalid parameter class argument.")); > @@ -779,7 +838,7 @@ parmpy_init (PyObject *self, PyObject *args, PyObject *kwds) > else > obj->enumeration = NULL; > obj->type = (enum var_types) parmclass; > - memset (&obj->value, 0, sizeof (obj->value)); > + obj->value = {}; /* zeros initialization */ > > if (var_type_uses (obj->type)) > obj->value.stringval = new std::string; > diff --git a/gdb/python/python.c b/gdb/python/python.c > index c7d4157b70c..141d495c2e2 100644 > --- a/gdb/python/python.c > +++ b/gdb/python/python.c > @@ -484,6 +484,16 @@ gdbpy_parameter_value (const setting &var) > return host_string_to_python_string (str).release (); > } > > + case var_color: > + { > + const ui_file_style::color &color = var.get (); > + if (color.is_none () || color.is_basic () || !color.is_simple ()) > + return host_string_to_python_string > + (color.to_string ().c_str ()).release (); > + else > + return gdb_py_object_from_longest (color.get_value ()).release (); > + } > + It feels a little weird to me that for this parameter type we can return a string in some cases, and an integer in others. I keep wondering if we should be handling this as a string in all cases? The other option I wonder about is if we should instead return an object of a new gdb.Color type. The gdb.Color type could have __str__ for conversion to a string, but we could extend the type later to allow the integer to be fetched directly, if that was ever important. Potentially the gdb.Color could also have a method for converting the color into an escape sequence, if that was ever important? I'm not really sure what the best solution is here, I just know the string/integer thing feels like it could trip users up, a user might assume the result is always a string because they only use the 8 basic colors, but then, a script is shared, and another user has a color from the 256-bit space, and gets back an integer... Do you see a benefit for returning the different types? Thanks, Andrew > case var_boolean: > { > if (var.get ()) > diff --git a/gdb/testsuite/gdb.base/style.exp b/gdb/testsuite/gdb.base/style.exp > index 2242c5bf743..82458193d8d 100644 > --- a/gdb/testsuite/gdb.base/style.exp > +++ b/gdb/testsuite/gdb.base/style.exp > @@ -298,6 +298,21 @@ proc run_style_tests { } { > set url [limited_style "http:.*html" file] > gdb_test "show version" "${vers}.*<$url>.*" \ > "'show version' is styled" > + > + if { $currently_disabled_style != "version" } { > + # Check that colors in styling can be set as integer and as RGB hex > + # triplet. Check that the version string is styled in the output of > + # 'show version' according to the set colors. > + gdb_test_no_output "set style version intensity normal" > + gdb_test_no_output "set style version background 255" > + gdb_test_no_output "set style version foreground #FED210" > + gdb_test "show style version background" \ > + "The \033\\\[38;2;254;210;16;48;5;255m.*\".*version.*\".*style.*\033\\\[m background color is: 255" \ > + "Version's 256-color background style" > + gdb_test "show style version foreground" \ > + "The \033\\\[38;2;254;210;16;48;5;255m.*\".*version.*\".*style.*\033\\\[m foreground color is: #FED210" \ > + "Version's TrueColor foreground style" > + } > } > } > > diff --git a/gdb/testsuite/gdb.guile/scm-parameter.exp b/gdb/testsuite/gdb.guile/scm-parameter.exp > index cf6f2834373..8a9cbcab605 100644 > --- a/gdb/testsuite/gdb.guile/scm-parameter.exp > +++ b/gdb/testsuite/gdb.guile/scm-parameter.exp > @@ -91,6 +91,32 @@ with_test_prefix "test-enum-param" { > gdb_test "set print test-enum-param three" "Undefined item: \"three\".*" "set invalid enum parameter" > } > > +# Test a color parameter. > + > +gdb_test_multiline "color gdb parameter" \ > + "guile" "" \ > + "(define test-color-param" "" \ > + " (make-parameter \"print test-color-param\"" "" \ > + " #:command-class COMMAND_DATA" "" \ > + " #:parameter-type PARAM_COLOR" "" \ > + " #:doc \"When set, test param does something useful. When disabled, does nothing.\"" "" \ > + " #:show-doc \"Show the state of the test-color-param.\"" "" \ > + " #:set-doc \"Set the state of the test-color-param.\"" "" \ > + " #:show-func (lambda (self value)" "" \ > + " (format #f \"The state of the test-color-param is ~a.\" value))" "" \ > + " #:initial-value \"green\"))" "" \ > + "(register-parameter! test-color-param)" "" \ > + "end" > + > +with_test_prefix "test-color-param" { > + gdb_test "guile (print (parameter-value test-color-param))" "green" "color parameter value (green)" > + gdb_test "show print test-color-param" "The state of the test-color-param is green." "show initial value" > + gdb_test_no_output "set print test-color-param 255" > + gdb_test "show print test-color-param" "The state of the test-color-param is 255." "show new value" > + gdb_test "guile (print (parameter-value test-color-param))" "255" "color parameter value (255)" > + gdb_test "set print test-color-param 256" "integer 256 out of range.*" "set invalid color parameter" > +} > + > # Test a file parameter. > > gdb_test_multiline "file gdb parameter" \ > diff --git a/gdb/testsuite/gdb.python/py-parameter.exp b/gdb/testsuite/gdb.python/py-parameter.exp > index d6db6ac3bb1..0f269dd86a8 100644 > --- a/gdb/testsuite/gdb.python/py-parameter.exp > +++ b/gdb/testsuite/gdb.python/py-parameter.exp > @@ -177,6 +177,51 @@ proc_with_prefix test_enum_parameter { } { > "Undefined item: \"three\".*" "set invalid enum parameter" > } > > +# Test an color parameter. > +proc_with_prefix test_color_parameter { } { > + clean_restart > + > + gdb_test_multiline "color gdb parameter" \ > + "python" "" \ > + "class TestColorParam (gdb.Parameter):" "" \ > + " \"\"\"When set, test param does something useful. When disabled, does nothing.\"\"\"" "" \ > + " show_doc = \"Show the state of the color\"" ""\ > + " set_doc = \"Set the state of the color\"" "" \ > + " def get_show_string (self, pvalue):" ""\ > + " return \"The state of the color is \" + str(pvalue)" ""\ > + " def get_set_string (self):" ""\ > + " return \"The state of the color has been set to \" + str(self.value)" ""\ > + " def __init__ (self, name):" "" \ > + " super (TestColorParam, self).__init__ (name, gdb.COMMAND_DATA, gdb.PARAM_COLOR)" "" \ > + " self.value = \"green\"" "" \ > + "test_color_param = TestColorParam ('print test-color-param')" ""\ > + "end" > + > + gdb_test "python print (test_color_param.value)" "green" \ > + "test color parameter value is green" > + gdb_test "show print test-color-param" \ > + "The state of the color is green.*" \ > + "show parameter is initial value" > + gdb_test "set print test-color-param 255" \ > + "The state of the color has been set to 255" "set color to 255" > + gdb_test "show print test-color-param" \ > + "The state of the color is 255.*" "show parameter is new value" > + gdb_test "python print (test_color_param.value)" "255" \ > + "test color parameter value is 255" > + gdb_test_no_output "python test_color_param.value = 254" \ > + "assign test_color_param.value to 254" > + gdb_test "python print (repr (test_color_param.value))" "254" \ > + "test color parameter value is integer" > + gdb_test_no_output "python test_color_param.value = '#FED210'" \ > + "assign test_color_param.value to #FED210" > + gdb_test "python print (repr (test_color_param.value))" "'#FED210'" \ > + "test color parameter value is string" > + gdb_test "set print test-color-param 256" \ > + "integer 256 out of range.*" "set invalid color parameter" > + gdb_test "python test_color_param.value = 256" \ > + "RuntimeError: Range exceeded.*" "set invalid color value" > +} > + > # Test a file parameter. > proc_with_prefix test_file_parameter { } { > clean_restart > @@ -391,6 +436,7 @@ test_directories > test_data_directory > test_boolean_parameter > test_enum_parameter > +test_color_parameter > test_file_parameter > test_undocumented_parameter > test_really_undocumented_parameter > diff --git a/gdb/ui-style.c b/gdb/ui-style.c > index f1a5b8c4101..167550b2c9a 100644 > --- a/gdb/ui-style.c > +++ b/gdb/ui-style.c > @@ -62,6 +62,33 @@ static const uint8_t bright_colors[][3] = { > { 255, 255, 255 } /* White. */ > }; > > +/* See ui-style.h. */ > +/* Must correspond to ui_file_style::basic_color. */ > +const std::vector ui_file_style::basic_color_enums = { > + "none", > + "black", > + "red", > + "green", > + "yellow", > + "blue", > + "magenta", > + "cyan", > + "white", > + nullptr > +}; > + > +/* Returns text representation of a basic COLOR. */ > + > +static const char * > +basic_color_name (int color) > +{ > + int pos = color - ui_file_style::NONE; > + if (0 <= pos && pos < ui_file_style::basic_color_enums.size ()) > + if (const char *s = ui_file_style::basic_color_enums[pos]) > + return s; > + error (_("Basic color %d has no name."), color); > +} > + > /* See ui-style.h. */ > > bool > @@ -93,6 +120,23 @@ ui_file_style::color::append_ansi (bool is_fg, std::string *str) const > > /* See ui-style.h. */ > > +std::string > +ui_file_style::color::to_string () const > +{ > + if (!m_simple) > + { > + char s[64]; > + snprintf (s, sizeof s, "#%02X%02X%02X", m_red, m_green, m_blue); > + return s; > + } > + else if (is_none () || is_basic ()) > + return basic_color_name (m_value); > + else > + return std::to_string (get_value ()); > +} > + > +/* See ui-style.h. */ > + > void > ui_file_style::color::get_rgb (uint8_t *rgb) const > { > diff --git a/gdb/ui-style.h b/gdb/ui-style.h > index fe1b2af611d..f002facf706 100644 > --- a/gdb/ui-style.h > +++ b/gdb/ui-style.h > @@ -73,6 +73,11 @@ struct ui_file_style > && m_blue == other.m_blue); > } > > + bool operator!= (const color &other) const > + { > + return ! (*this == other); > + } > + > bool operator< (const color &other) const > { > if (m_simple != other.m_simple) > @@ -104,10 +109,17 @@ struct ui_file_style > return m_simple && m_value >= BLACK && m_value <= WHITE; > } > > - /* Return the value of a basic color. */ > + /* Return true if this is one of the simple colors, false > + otherwise. */ > + bool is_simple () const > + { > + return m_simple; > + } > + > + /* Return the value of a simple color. */ > int get_value () const > { > - gdb_assert (is_basic ()); > + gdb_assert (is_simple ()); > return m_value; > } > > @@ -123,6 +135,10 @@ struct ui_file_style > color). */ > bool append_ansi (bool is_fg, std::string *str) const; > > + /* Returns text representation of this object. > + It is "none", name of a basic color, number or a #RRGGBB hex triplet. */ > + std::string to_string () const; > + > private: > > bool m_simple; > @@ -235,6 +251,9 @@ struct ui_file_style > return this; > } > > + /* nullptr-terminated list of names corresponding to enum basic_color. */ > + static const std::vector basic_color_enums; > + > private: > > color m_foreground = NONE; > -- > 2.34.1