diff options
Diffstat (limited to 'gdb/cli/cli-option.c')
-rw-r--r-- | gdb/cli/cli-option.c | 195 |
1 files changed, 168 insertions, 27 deletions
diff --git a/gdb/cli/cli-option.c b/gdb/cli/cli-option.c index 0553928..a30261e 100644 --- a/gdb/cli/cli-option.c +++ b/gdb/cli/cli-option.c @@ -1,6 +1,6 @@ /* CLI options framework, for GDB. - Copyright (C) 2017-2024 Free Software Foundation, Inc. + Copyright (C) 2017-2025 Free Software Foundation, Inc. This file is part of GDB. @@ -43,8 +43,11 @@ union option_value /* For var_enum options. */ const char *enumeration; - /* For var_string options. This is malloc-allocated. */ + /* 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. */ @@ -85,7 +88,7 @@ struct option_def_and_value { if (value.has_value ()) { - if (option.type == var_string) + if (option.type == var_string || option.type == var_filename) delete value->string; } } @@ -102,7 +105,7 @@ private: { if (value.has_value ()) { - if (option.type == var_string) + if (option.type == var_string || option.type == var_filename) value->string = nullptr; } } @@ -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, "--")) @@ -452,6 +484,78 @@ parse_option (gdb::array_view<const option_def_group> options_group, return option_def_and_value {*match, match_ctx, val}; } + case var_filename: + { + if (check_for_argument (args, "--")) + { + /* Treat e.g., "maint test-options -filename --" as if there + was no argument after "-filename". */ + error (_("-%s requires an argument"), match->name); + } + + const char *arg_start = *args; + std::string str = extract_string_maybe_quoted (args); + + /* If we are performing completion, and extracting STR moved ARGS + to the end of the line, then the user is trying to complete the + filename value. + + If ARGS didn't make it to the end of the line then the filename + value is already complete and the user is trying to complete + something later on the line. */ + if (completion != nullptr && **args == '\0') + { + /* Preserve the current custom word point. If the call to + advance_to_filename_maybe_quoted_complete_word_point below + skips to the end of the command line then the custom word + point will have been updated even though we generate no + completions. + + However, *ARGS will also have been updated, and the general + option completion code (which we will return too) also + updates the custom word point based on the adjustment made + to *ARGS. + + And so, if we don't find any completions, we should restore + the custom word point value, this leaves the generic option + completion code free to make its own adjustments. */ + int prev_word_pt = completion->tracker.custom_word_point (); + + /* From ARG_START move forward to the start of the completion + word, this will skip over any opening quote if there is + one. + + If the word to complete is fully quoted, i.e. has an + opening and closing quote, then this will skip over the + word entirely and leave WORD pointing to the end of the + input string. */ + const char *word + = advance_to_filename_maybe_quoted_complete_word_point + (completion->tracker, arg_start); + + if (word == arg_start || *word != '\0') + { + filename_maybe_quoted_completer (nullptr, completion->tracker, + arg_start, word); + + if (completion->tracker.have_completions ()) + return {}; + } + + /* No completions. Restore the custom word point. See the + comment above for why this is needed. */ + completion->tracker.set_custom_word_point (prev_word_pt); + } + + /* Check we did manage to extract something. */ + if (*args == arg_start) + error (_("-%s requires an argument"), match->name); + + option_value val; + val.string = new std::string (std::move (str)); + return option_def_and_value {*match, match_ctx, val}; + } + default: /* Not yet. */ gdb_assert_not_reached ("option type not supported"); @@ -611,7 +715,12 @@ 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) = std::move (*ov->value->string); break; @@ -659,50 +768,77 @@ process_options (const char **args, } } -/* Helper for build_help. Return a fragment of a help string showing - OPT's possible values. Returns NULL if OPT doesn't take an - argument. */ +/* Helper for build_help. Append a fragment of a help string showing + OPT's possible values. LEN_AT_START is the length of HELP at the + start of the current line. This is used when wrapping is + needed. */ -static const char * -get_val_type_str (const option_def &opt, std::string &buffer) +static void +append_val_type_str (std::string &help, const option_def &opt, + size_t len_at_start) { if (!opt.have_argument) - return nullptr; + return; switch (opt.type) { case var_boolean: - return "[on|off]"; + help += " [on|off]"; + break; case var_uinteger: case var_integer: case var_pinteger: { - buffer = "NUMBER"; + help += " NUMBER"; if (opt.extra_literals != nullptr) for (const literal_def *l = opt.extra_literals; l->literal != nullptr; l++) { - buffer += '|'; - buffer += l->literal; + help += '|'; + help += l->literal; } - return buffer.c_str (); } + break; case var_enum: { - buffer = ""; + help += ' '; + /* If wrapping is needed, subsequent lines will be indented + this amount. */ + size_t indent = help.length () - len_at_start; for (size_t i = 0; opt.enums[i] != nullptr; i++) { if (i != 0) - buffer += "|"; - buffer += opt.enums[i]; + { + size_t new_len = help.length () + 1 + strlen (opt.enums[i]); + + if (new_len - len_at_start >= cli_help_line_length) + { + help += "\n"; + len_at_start = help.length (); + + help.append (indent, ' '); + } + help += "|"; + } + help += opt.enums[i]; } - return buffer.c_str (); } + 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: - return "STRING"; + help += " STRING"; + break; + case var_filename: + help += " FILENAME"; + break; default: - return nullptr; + break; } } @@ -740,15 +876,11 @@ build_help_option (gdb::array_view<const option_def> options, if (o.set_doc == nullptr) continue; + size_t initial_len = help.length (); help += " -"; help += o.name; - const char *val_type_str = get_val_type_str (o, buffer); - if (val_type_str != nullptr) - { - help += ' '; - help += val_type_str; - } + append_val_type_str (help, o, initial_len); help += "\n"; append_indented_doc (o.set_doc, help); if (o.help_doc != nullptr) @@ -856,6 +988,15 @@ add_setshow_cmds_for_options (command_class cmd_class, nullptr, option.show_cmd_cb, set_list, show_list); } + else if (option.type == var_filename) + { + add_setshow_filename_cmd (option.name, cmd_class, + option.var_address.string (option, data), + option.set_doc, option.show_doc, + option.help_doc, + nullptr, option.show_cmd_cb, + set_list, show_list); + } else gdb_assert_not_reached ("option type not handled"); } |