Add an option with a color type.

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 the responsibility of the user to verify that the terminal supports
the specified colors.

PATCH v5 changes: documentation fixed.
PATCH v6 changes: documentation fixed.
PATCH v7 changes: rebase onto master and fixes after review.
PATCH v8 changes: fixes after review.
This commit is contained in:
Andrei Pikas
2024-10-05 22:27:44 +03:00
committed by Tom Tromey
parent 338e0b05d8
commit 6447969d0a
34 changed files with 2437 additions and 172 deletions

View File

@@ -2398,6 +2398,11 @@ value_from_setting (const setting &var, struct gdbarch *gdbarch)
return current_language->value_string (gdbarch, value, len);
}
case var_color:
{
std::string s = var.get<ui_file_style::color> ().to_string ();
return current_language->value_string (gdbarch, s.c_str (), s.size ());
}
default:
gdb_assert_not_reached ("bad var_type");
}
@@ -2445,6 +2450,7 @@ str_value_from_setting (const setting &var, struct gdbarch *gdbarch)
case var_pinteger:
case var_boolean:
case var_auto_boolean:
case var_color:
{
std::string cmd_val = get_setshow_command_value_string (var);

View File

@@ -23,6 +23,7 @@
#include "cli/cli-cmds.h"
#include "cli/cli-decode.h"
#include "cli/cli-style.h"
#include "cli/cli-utils.h"
#include <optional>
/* Prototypes for local functions. */
@@ -739,6 +740,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 };
@@ -2756,3 +2838,95 @@ 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 nullptr 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 %sinteger 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 (color_space::XTERM_256COLOR,
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;
}

View File

@@ -309,6 +309,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. */

View File

@@ -45,6 +45,9 @@ union option_value
/* For var_string and var_filename options. This is allocated with new. */
std::string *string;
/* For var_color options. */
ui_file_style::color color = ui_file_style::NONE;
};
/* Holds an options definition and its value. */
@@ -433,6 +436,35 @@ 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;
ui_file_style::color color = parse_cli_var_color (args);
ui_file_style::color approx_color = color.approximate (colorsupport ());
val.color = approx_color;
return option_def_and_value {*match, match_ctx, val};
}
case var_string:
{
if (check_for_argument (args, "--"))
@@ -683,6 +715,10 @@ save_option_value_in_ctx (std::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:
case var_filename:
*ov->option.var_address.string (ov->option, ov->ctx)
@@ -789,6 +825,12 @@ append_val_type_str (std::string &help, const option_def &opt,
}
}
break;
case var_color:
help += ' ';
for (size_t i = 0; ui_file_style::basic_color_enums[i]; ++i)
help.append (ui_file_style::basic_color_enums[i]).append ("|");
help += "NUMBER|#RRGGBB";
break;
case var_string:
help += "STRING";
break;

View File

@@ -91,6 +91,7 @@ public:
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;
@@ -328,6 +329,26 @@ struct filename_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

View File

@@ -443,6 +443,13 @@ 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);
ui_file_style::color approx_color = color.approximate (colorsupport ());
option_changed = c->var->set<ui_file_style::color> (approx_color);
}
break;
default:
error (_("gdb internal error: bad var_type in do_setshow_command"));
}
@@ -520,6 +527,14 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c)
interps_notify_param_changed
(name, c->var->get<const char *> ());
break;
case var_color:
{
const ui_file_style::color &color
= c->var->get<ui_file_style::color> ();
interps_notify_param_changed
(name, color.to_string ().c_str ());
}
break;
case var_boolean:
{
const char *opt = c->var->get<bool> () ? "on" : "off";
@@ -585,6 +600,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;

View File

@@ -42,20 +42,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[] = {
@@ -139,8 +125,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])
{
}
@@ -151,32 +137,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)
@@ -188,7 +159,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. */
@@ -261,9 +232,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,
@@ -273,9 +243,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,

View File

@@ -67,9 +67,9 @@ private:
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;