From: Andrei Pikas <gdb@mail.api.win>
To: gdb-patches@sourceware.org
Cc: eliz@gnu.org, Andrei Pikas <gdb@mail.api.win>
Subject: [PATCH v3 (documentation fixed)] Add an option with a color type.
Date: Mon, 22 Aug 2022 00:07:03 +0300 [thread overview]
Message-ID: <20220821210703.22790-1-gdb@mail.api.win> (raw)
In-Reply-To: <835yindr0c.fsf@gnu.org>
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 <gdb:parameter> 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<ui_file_style::color> ().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<ui_file_style::color>
+ (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<ui_file_style::color>::set set_func,
+ setting_func_types<ui_file_style::color>::get get_func,
+ show_value_ftype *show_func,
+ cmd_list_element **set_list,
+ cmd_list_element **show_list)
+{
+ auto cmds = add_setshow_cmd_full<ui_file_style::color>
+ (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<ui_file_style::basic_color> (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<int> (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<const option_def_group> 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<option_def_and_value> &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<typename Context>
+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<ui_file_style::color, Context>;
+ }
+};
+
/* 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<const char *> (match);
}
break;
+ case var_color:
+ {
+ ui_file_style::color color = parse_var_color (arg);
+ option_changed = c->var->set<ui_file_style::color> (color);
+ }
+ break;
case var_zuinteger_unlimited:
option_changed = c->var->set<int>
(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<const char *> ());
break;
+ case var_color:
+ {
+ const ui_file_style::color &color
+ = c->var->get<ui_file_style::color> ();
+ gdb::observers::command_param_changed.notify
+ (name, color.to_string ().c_str ());
+ }
+ break;
case var_boolean:
{
const char *opt = c->var->get<bool> () ? "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<ui_file_style::color> ();
+ stb.puts (value.to_string ().c_str ());
+ }
+ break;
case var_boolean:
stb.puts (var.get<bool> () ? "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<const char *> (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<ui_file_style::color> (var_types t)
+{
+ return t == var_color;
+}
+
template<bool is_scalar, typename T> struct setting_func_types_1;
template<typename T>
@@ -665,6 +675,20 @@ extern set_show_commands add_setshow_enum_cmd
setting_func_types<const char *>::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<ui_file_style::color>::set set_func,
+ setting_func_types<ui_file_style::color>::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<const char *> (s->type))
return setting (s->type, &s->value.cstringval);
+ else if (var_type_uses<ui_file_style::color> (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<ui_file_style::color> ();
+ 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<bool> ())
@@ -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<ui_file_style::color> (i);
+ }
+ else
+ {
+ SCM exception;
+
+ gdb::unique_xmalloc_ptr<char> 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<ui_file_style::color> (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<std::string> (p_smob->type))
p_smob->value.stringval = new std::string;
+ else if (var_type_uses<ui_file_style::color> (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<const char *> (s->type))
return setting (s->type, &s->value.cstringval);
+ else if (var_type_uses<ui_file_style::color> (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<char>
+ 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<std::string> (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<ui_file_style::color> ();
+ 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 ();
+ }
+
case var_boolean:
{
if (var.get<bool> ())
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<const char *> 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<const char *> basic_color_enums;
+
private:
color m_foreground = NONE;
--
2.34.1
next prev parent reply other threads:[~2022-08-21 21:07 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-08-15 21:15 [PATCH] " Andrei Pikas
2022-08-17 17:40 ` Andrew Burgess
2022-08-17 18:46 ` Andrei Pikas
2022-08-20 12:19 ` [PATCH v2] " Andrei Pikas
2022-08-20 12:43 ` Eli Zaretskii
2022-08-21 20:09 ` Andrei Pikas
2022-08-22 2:26 ` Eli Zaretskii
2022-08-21 21:07 ` Andrei Pikas [this message]
2022-08-22 11:54 ` [PATCH v3 (documentation fixed)] " Eli Zaretskii
2022-08-22 16:26 ` Philippe Waroquiers
2022-08-23 11:29 ` Andrew Burgess
2022-09-13 0:44 ` [PATCH v4 (documentation + approximation + convenience variable + python and guile types)] " Andrei Pikas
2022-08-17 17:57 ` [PATCH] " Eli Zaretskii
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220821210703.22790-1-gdb@mail.api.win \
--to=gdb@mail.api.win \
--cc=eliz@gnu.org \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).