diff options
Diffstat (limited to 'gdb/cli')
-rw-r--r-- | gdb/cli/cli-cmds.c | 6 | ||||
-rw-r--r-- | gdb/cli/cli-decode.c | 174 | ||||
-rw-r--r-- | gdb/cli/cli-decode.h | 21 | ||||
-rw-r--r-- | gdb/cli/cli-option.c | 42 | ||||
-rw-r--r-- | gdb/cli/cli-option.h | 21 | ||||
-rw-r--r-- | gdb/cli/cli-setshow.c | 21 | ||||
-rw-r--r-- | gdb/cli/cli-style.c | 49 | ||||
-rw-r--r-- | gdb/cli/cli-style.h | 4 |
8 files changed, 296 insertions, 42 deletions
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c index 0140c71..69a7e8b 100644 --- a/gdb/cli/cli-cmds.c +++ b/gdb/cli/cli-cmds.c @@ -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); diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c index 4fbbfcb..2c52922 100644 --- a/gdb/cli/cli-decode.c +++ b/gdb/cli/cli-decode.c @@ -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. */ @@ -740,6 +741,87 @@ add_setshow_enum_cmd (const char *name, command_class theclass, } /* 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 }; /* Add an auto-boolean command named NAME to both the set and show @@ -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; +} diff --git a/gdb/cli/cli-decode.h b/gdb/cli/cli-decode.h index ec73c11..18ea05d 100644 --- a/gdb/cli/cli-decode.h +++ b/gdb/cli/cli-decode.h @@ -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. */ diff --git a/gdb/cli/cli-option.c b/gdb/cli/cli-option.c index fa00b91..10a5944 100644 --- a/gdb/cli/cli-option.c +++ b/gdb/cli/cli-option.c @@ -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; diff --git a/gdb/cli/cli-option.h b/gdb/cli/cli-option.h index dd3db8b..ac614c3 100644 --- a/gdb/cli/cli-option.h +++ b/gdb/cli/cli-option.h @@ -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 diff --git a/gdb/cli/cli-setshow.c b/gdb/cli/cli-setshow.c index bcc793b..a8f22c9 100644 --- a/gdb/cli/cli-setshow.c +++ b/gdb/cli/cli-setshow.c @@ -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; diff --git a/gdb/cli/cli-style.c b/gdb/cli/cli-style.c index fa582a7..4151082 100644 --- a/gdb/cli/cli-style.c +++ b/gdb/cli/cli-style.c @@ -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, diff --git a/gdb/cli/cli-style.h b/gdb/cli/cli-style.h index 171ec71..a1e538b 100644 --- a/gdb/cli/cli-style.h +++ b/gdb/cli/cli-style.h @@ -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; |