diff options
Diffstat (limited to 'gdb/cli')
-rw-r--r-- | gdb/cli/cli-cmds.c | 201 | ||||
-rw-r--r-- | gdb/cli/cli-cmds.h | 8 | ||||
-rw-r--r-- | gdb/cli/cli-decode.c | 356 | ||||
-rw-r--r-- | gdb/cli/cli-decode.h | 37 | ||||
-rw-r--r-- | gdb/cli/cli-dump.c | 14 | ||||
-rw-r--r-- | gdb/cli/cli-interp.c | 10 | ||||
-rw-r--r-- | gdb/cli/cli-interp.h | 8 | ||||
-rw-r--r-- | gdb/cli/cli-logging.c | 6 | ||||
-rw-r--r-- | gdb/cli/cli-option.c | 195 | ||||
-rw-r--r-- | gdb/cli/cli-option.h | 49 | ||||
-rw-r--r-- | gdb/cli/cli-script.c | 75 | ||||
-rw-r--r-- | gdb/cli/cli-script.h | 24 | ||||
-rw-r--r-- | gdb/cli/cli-setshow.c | 46 | ||||
-rw-r--r-- | gdb/cli/cli-setshow.h | 8 | ||||
-rw-r--r-- | gdb/cli/cli-style.c | 292 | ||||
-rw-r--r-- | gdb/cli/cli-style.h | 66 | ||||
-rw-r--r-- | gdb/cli/cli-utils.c | 10 | ||||
-rw-r--r-- | gdb/cli/cli-utils.h | 10 |
18 files changed, 1095 insertions, 320 deletions
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c index 3af794c..5e887f5 100644 --- a/gdb/cli/cli-cmds.c +++ b/gdb/cli/cli-cmds.c @@ -1,6 +1,6 @@ /* GDB CLI commands. - Copyright (C) 2000-2024 Free Software Foundation, Inc. + Copyright (C) 2000-2025 Free Software Foundation, Inc. This file is part of GDB. @@ -51,11 +51,11 @@ #include "cli/cli-cmds.h" #include "cli/cli-style.h" #include "cli/cli-utils.h" -#include "cli/cli-style.h" #include "extension.h" #include "gdbsupport/pathstuff.h" #include "gdbsupport/gdb_tilde_expand.h" +#include "gdbsupport/eintr.h" #ifdef TUI #include "tui/tui.h" @@ -215,7 +215,7 @@ error_no_arg (const char *why) static void info_command (const char *arg, int from_tty) { - help_list (infolist, "info ", all_commands, gdb_stdout); + help_list (infolist, "info", all_commands, gdb_stdout); } /* See cli/cli-cmds.h. */ @@ -423,31 +423,7 @@ complete_command (const char *arg, int from_tty) { std::string arg_prefix (arg, word - arg); - if (result.number_matches == 1) - printf_unfiltered ("%s%s\n", arg_prefix.c_str (), result.match_list[0]); - else - { - result.sort_match_list (); - - for (size_t i = 0; i < result.number_matches; i++) - { - printf_unfiltered ("%s%s", - arg_prefix.c_str (), - result.match_list[i + 1]); - if (quote_char) - printf_unfiltered ("%c", quote_char); - printf_unfiltered ("\n"); - } - } - - if (result.number_matches == max_completions) - { - /* ARG_PREFIX and WORD are included in the output so that emacs - will include the message in the output. */ - printf_unfiltered (_("%s%s %s\n"), - arg_prefix.c_str (), word, - get_max_completions_reached_message ()); - } + result.print_matches (arg_prefix, word, quote_char); } } @@ -857,7 +833,7 @@ echo_command (const char *text, int from_tty) gdb_printf ("%c", c); } - gdb_stdout->reset_style (); + gdb_stdout->emit_style_escape (ui_file_style ()); /* Force this output to appear now. */ gdb_flush (gdb_stdout); @@ -946,7 +922,11 @@ run_under_shell (const char *arg, int from_tty) } if (pid != -1) - waitpid (pid, &status, 0); + { + int ret = gdb::waitpid (pid, &status, 0); + if (ret == -1) + perror_with_name ("Cannot get status of shell command"); + } else error (_("Fork failed")); return status; @@ -972,6 +952,21 @@ shell_command (const char *arg, int from_tty) shell_escape (arg, from_tty); } +/* Completion for the shell command. Currently, this just uses filename + completion, but we could, potentially, complete command names from $PATH + for the first word, which would make this even more shell like. */ + +static void +shell_command_completer (struct cmd_list_element *ignore, + completion_tracker &tracker, + const char *text, const char * /* word */) +{ + tracker.set_use_custom_word_point (true); + const char *word + = advance_to_filename_maybe_quoted_complete_word_point (tracker, text); + filename_maybe_quoted_completer (ignore, tracker, text, word); +} + static void edit_command (const char *arg, int from_tty) { @@ -984,7 +979,7 @@ edit_command (const char *arg, int from_tty) if (arg == 0) { set_default_source_symtab_and_line (); - sal = get_current_source_symtab_and_line (); + sal = get_current_source_symtab_and_line (current_program_space); } /* Bare "edit" edits file with present line. */ @@ -993,7 +988,8 @@ edit_command (const char *arg, int from_tty) { if (sal.symtab == 0) error (_("No default source file yet.")); - sal.line += get_lines_to_list () / 2; + if (get_first_line_listed () != 0) + sal.line = get_first_line_listed () + get_lines_to_list () / 2; } else { @@ -1041,16 +1037,23 @@ edit_command (const char *arg, int from_tty) gdbarch = sal.symtab->compunit ()->objfile ()->arch (); sym = find_pc_function (sal.pc); if (sym) - gdb_printf ("%s is in %s (%s:%d).\n", - paddress (gdbarch, sal.pc), - sym->print_name (), - symtab_to_filename_for_display (sal.symtab), - sal.line); + gdb_printf ("%ps is in %ps (%ps:%ps).\n", + styled_string (address_style.style (), + paddress (gdbarch, sal.pc)), + styled_string (function_name_style.style (), + sym->print_name ()), + styled_string (file_name_style.style (), + symtab_to_filename_for_display (sal.symtab)), + styled_string (line_number_style.style (), + pulongest (sal.line))); else - gdb_printf ("%s is at %s:%d.\n", - paddress (gdbarch, sal.pc), - symtab_to_filename_for_display (sal.symtab), - sal.line); + gdb_printf ("%ps is at %ps:%ps.\n", + styled_string (address_style.style (), + paddress (gdbarch, sal.pc)), + styled_string (file_name_style.style (), + symtab_to_filename_for_display (sal.symtab)), + styled_string (line_number_style.style (), + pulongest (sal.line))); } /* If what was given does not imply a symtab, it must be an @@ -1142,19 +1145,14 @@ pipe_command (const char *arg, int from_tty) if (to_shell_command == nullptr) error (_("Error launching \"%s\""), shell_command); - try - { - stdio_file pipe_file (to_shell_command); + int exit_status; + { + SCOPE_EXIT { exit_status = pclose (to_shell_command); }; - execute_command_to_ui_file (&pipe_file, gdb_cmd.c_str (), from_tty); - } - catch (...) - { - pclose (to_shell_command); - throw; - } + stdio_file pipe_file (to_shell_command); - int exit_status = pclose (to_shell_command); + execute_command_to_ui_file (&pipe_file, gdb_cmd.c_str (), from_tty); + } if (exit_status < 0) error (_("shell command \"%s\" failed: %s"), shell_command, @@ -1195,8 +1193,32 @@ pipe_command_completer (struct cmd_list_element *ignore, return; } - /* We're past the delimiter. What follows is a shell command, which - we don't know how to complete. */ + /* We're past the delimiter now, or at least, DELIM points to the + delimiter string. Update TEXT to point to the start of whatever + appears after the delimiter. */ + text = skip_spaces (delim + strlen (delimiter)); + + /* We really are past the delimiter now, so offer completions. This is + like GDB's "shell" command, currently we only offer filename + completion, but in the future this could be improved by offering + completion of command names from $PATH. + + What we don't do here is offer completions for the empty string. It + is assumed that the first word after the delimiter is going to be a + command name from $PATH, not a filename, so if the user has typed + nothing (yet) and tries to complete, there's no point offering a list + of files from the current directory. + + Once the user has started to type something though, then we do start + offering filename completions. */ + if (*text == '\0') + return; + + tracker.set_use_custom_word_point (true); + tracker.advance_custom_word_point_by (text - org_text); + const char *word + = advance_to_filename_maybe_quoted_complete_word_point (tracker, text); + filename_maybe_quoted_completer (ignore, tracker, text, word); } /* Helper for the list_command function. Prints the lines around (and @@ -1240,7 +1262,8 @@ list_command (const char *arg, int from_tty) if (get_first_line_listed () == 0 && (arg == nullptr || arg[0] != '.')) { set_default_source_symtab_and_line (); - list_around_line (arg, get_current_source_symtab_and_line ()); + list_around_line + (arg, get_current_source_symtab_and_line (current_program_space)); } /* "l" and "l +" lists the next few lines, unless we're listing past @@ -1248,7 +1271,8 @@ list_command (const char *arg, int from_tty) else if (arg == nullptr || arg[0] == '+') { set_default_source_symtab_and_line (); - const symtab_and_line cursal = get_current_source_symtab_and_line (); + const symtab_and_line cursal + = get_current_source_symtab_and_line (current_program_space); if (last_symtab_line (cursal.symtab) >= cursal.line) print_source_lines (cursal.symtab, source_lines_range (cursal.line), 0); @@ -1262,7 +1286,8 @@ list_command (const char *arg, int from_tty) else if (arg[0] == '-') { set_default_source_symtab_and_line (); - const symtab_and_line cursal = get_current_source_symtab_and_line (); + const symtab_and_line cursal + = get_current_source_symtab_and_line (current_program_space); if (get_first_line_listed () == 1) error (_("Already at the start of %s."), @@ -1295,7 +1320,7 @@ list_command (const char *arg, int from_tty) { /* The inferior is not running, so reset the current source location to the default (usually the main function). */ - clear_current_source_symtab_and_line (); + clear_current_source_symtab_and_line (current_program_space); try { set_default_source_symtab_and_line (); @@ -1305,7 +1330,8 @@ list_command (const char *arg, int from_tty) error (_("Insufficient debug info for showing source " "lines at default location")); } - cursal = get_current_source_symtab_and_line (); + cursal + = get_current_source_symtab_and_line (current_program_space); gdb_assert (cursal.symtab != nullptr); } @@ -1327,7 +1353,8 @@ list_command (const char *arg, int from_tty) and clear NO_END; however, if one of the arguments is blank, set DUMMY_BEG or DUMMY_END to record that fact. */ - if (!have_full_symbols () && !have_partial_symbols ()) + if (!have_full_symbols (current_program_space) + && !have_partial_symbols (current_program_space)) error (_("No symbol table is loaded. Use the \"file\" command.")); std::vector<symtab_and_line> sals; @@ -1563,17 +1590,19 @@ print_disassembly (struct gdbarch *gdbarch, const char *name, static void disassemble_current_function (gdb_disassembly_flags flags) { - frame_info_ptr frame; - struct gdbarch *gdbarch; - CORE_ADDR low, high, pc; - const char *name; - const struct block *block; + frame_info_ptr frame = get_selected_frame (_("No frame selected.")); + struct gdbarch *gdbarch = get_frame_arch (frame); + CORE_ADDR pc = get_frame_address_in_block (frame); - frame = get_selected_frame (_("No frame selected.")); - gdbarch = get_frame_arch (frame); - pc = get_frame_address_in_block (frame); - if (find_pc_partial_function (pc, &name, &low, &high, &block) == 0) + const general_symbol_info *gsi; + const struct block *block; + CORE_ADDR low, high; + if (find_pc_partial_function_sym (pc, &gsi, &low, &high, &block) == 0) error (_("No function contains program counter for selected frame.")); + + gdb_assert (gsi != nullptr); + const char *name = asm_demangle ? gsi->print_name () : gsi->linkage_name (); + #if defined(TUI) /* NOTE: cagney/2003-02-13 The `tui_active' was previously `tui_version'. */ @@ -2141,9 +2170,11 @@ print_sal_location (const symtab_and_line &sal) const char *sym_name = NULL; if (sal.symbol != NULL) sym_name = sal.symbol->print_name (); - gdb_printf (_("file: \"%s\", line number: %d, symbol: \"%s\"\n"), + gdb_printf (_("file: \"%s\", line number: %ps, symbol: \"%s\"\n"), symtab_to_filename_for_display (sal.symtab), - sal.line, sym_name != NULL ? sym_name : "???"); + styled_string (line_number_style.style (), + pulongest (sal.line)), + sym_name != NULL ? sym_name : "???"); } /* Print a list of files and line numbers which a user may choose from @@ -2406,6 +2437,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"); } @@ -2453,6 +2489,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); @@ -2580,9 +2617,7 @@ shell_internal_fn (struct gdbarch *gdbarch, return value::allocate_optimized_out (int_type); } -void _initialize_cli_cmds (); -void -_initialize_cli_cmds () +INIT_GDB_FILE (cli_cmds) { struct cmd_list_element *c; @@ -2638,7 +2673,7 @@ The debugger's current working directory specifies where scripts and other\n\ files that can be loaded by GDB are located.\n\ In order to change the inferior's current working directory, the recommended\n\ way is to use the \"set cwd\" command."), &cmdlist); - set_cmd_completer (c, filename_completer); + set_cmd_completer (c, deprecated_filename_completer); add_com ("echo", class_support, echo_command, _("\ Print a constant string. Give string as argument.\n\ @@ -2654,9 +2689,9 @@ to be printed or after trailing whitespace.")); Set mode for script filename extension recognition."), _("\ Show mode for script filename extension recognition."), _("\ off == no filename extension recognition (all sourced files are GDB scripts)\n\ -soft == evaluate script according to filename extension, fallback to GDB script" - "\n\ -strict == evaluate script according to filename extension, error if not supported" +soft == evaluate script according to filename extension, fallback to GDB script\n\ +strict == evaluate script according to filename extension,\n\ + error if not supported" ), NULL, show_script_ext_mode, @@ -2751,9 +2786,10 @@ as 0 or -1 depending on the setting."), gdb_setting_internal_fn, NULL); add_internal_function ("_gdb_maint_setting_str", _("\ -$_gdb_maint_setting_str - returns the value of a GDB maintenance setting as a string.\n\ +$_gdb_maint_setting_str - returns the value of a GDB maintenance setting.\n\ Usage: $_gdb_maint_setting_str (setting)\n\ \n\ +Like \"$_gdb_maint_setting\", but the return value is always a string.\n\ auto-boolean values are \"off\", \"on\", \"auto\".\n\ boolean values are \"off\", \"on\".\n\ Some integer settings accept an unlimited value, returned\n\ @@ -2804,7 +2840,7 @@ the previous command number shown."), = add_com ("shell", class_support, shell_command, _("\ Execute the rest of the line as a shell command.\n\ With no arguments, run an inferior shell.")); - set_cmd_completer (shell_cmd, filename_completer); + set_cmd_completer_handle_brkchars (shell_cmd, shell_command_completer); add_com_alias ("!", shell_cmd, class_support, 0); @@ -2893,7 +2929,8 @@ you must type \"disassemble 'foo.c'::bar\" and not \"disassemble foo.c:bar\".")) c = add_com ("make", class_support, make_command, _("\ Run the ``make'' program using the rest of the line as arguments.")); - set_cmd_completer (c, filename_completer); + set_cmd_completer (c, deprecated_filename_completer); + c = add_cmd ("user", no_class, show_user, _("\ Show definitions of non-python/scheme user defined commands.\n\ Argument is the name of the user defined command.\n\ @@ -2977,5 +3014,5 @@ Note that the file \"%s\" is read automatically in this way\n\ when GDB is started."), GDBINIT).release (); c = add_cmd ("source", class_support, source_command, source_help_text, &cmdlist); - set_cmd_completer (c, filename_completer); + set_cmd_completer (c, deprecated_filename_completer); } diff --git a/gdb/cli/cli-cmds.h b/gdb/cli/cli-cmds.h index 8f26ca3..33d13fb 100644 --- a/gdb/cli/cli-cmds.h +++ b/gdb/cli/cli-cmds.h @@ -1,5 +1,5 @@ /* Header file for GDB CLI command implementation library. - Copyright (C) 2000-2024 Free Software Foundation, Inc. + Copyright (C) 2000-2025 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,8 +14,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef CLI_CLI_CMDS_H -#define CLI_CLI_CMDS_H +#ifndef GDB_CLI_CLI_CMDS_H +#define GDB_CLI_CLI_CMDS_H #include "gdbsupport/filestuff.h" #include <optional> @@ -202,4 +202,4 @@ extern void with_command_completer_1 (const char *set_cmd_prefix, completion_tracker &tracker, const char *text); -#endif /* CLI_CLI_CMDS_H */ +#endif /* GDB_CLI_CLI_CMDS_H */ diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c index d9a2ab4..48a3466 100644 --- a/gdb/cli/cli-decode.c +++ b/gdb/cli/cli-decode.c @@ -1,6 +1,6 @@ /* Handle lists of commands, their decoding and documentation, for GDB. - Copyright (C) 1986-2024 Free Software Foundation, Inc. + Copyright (C) 1986-2025 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -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. */ @@ -127,8 +128,10 @@ set_cmd_completer_handle_brkchars (struct cmd_list_element *cmd, cmd->completer_handle_brkchars = func; } +/* See cli-decode.h. */ + std::string -cmd_list_element::prefixname () const +cmd_list_element::prefixname_no_space () const { if (!this->is_prefix ()) /* Not a prefix command. */ @@ -136,14 +139,27 @@ cmd_list_element::prefixname () const std::string prefixname; if (this->prefix != nullptr) - prefixname = this->prefix->prefixname (); + { + prefixname = this->prefix->prefixname_no_space (); + prefixname += " "; + } prefixname += this->name; - prefixname += " "; return prefixname; } +/* See cli-decode.h. */ + +std::string +cmd_list_element::prefixname () const +{ + std::string result = prefixname_no_space (); + if (!result.empty ()) + result += " "; + return result; +} + /* See cli/cli-decode.h. */ std::vector<std::string> @@ -380,7 +396,7 @@ do_prefix_cmd (const char *args, int from_tty, struct cmd_list_element *c) while (c->is_alias ()) c = c->alias_target; - help_list (*c->subcommands, c->prefixname ().c_str (), + help_list (*c->subcommands, c->prefixname_no_space ().c_str (), all_commands, gdb_stdout); } @@ -740,6 +756,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 @@ -866,7 +963,7 @@ add_setshow_filename_cmd (const char *name, enum command_class theclass, nullptr, nullptr, set_func, show_func, set_list, show_list); - set_cmd_completer (commands.set, filename_completer); + set_cmd_completer (commands.set, deprecated_filename_completer); return commands; } @@ -890,7 +987,7 @@ add_setshow_filename_cmd (const char *name, command_class theclass, nullptr, show_func, set_list, show_list); - set_cmd_completer (cmds.set, filename_completer); + set_cmd_completer (cmds.set, deprecated_filename_completer); return cmds; } @@ -1015,7 +1112,7 @@ add_setshow_optional_filename_cmd (const char *name, enum command_class theclass nullptr, nullptr, set_func, show_func, set_list, show_list); - set_cmd_completer (commands.set, filename_completer); + set_cmd_completer (commands.set, deprecated_filename_completer); return commands; } @@ -1039,7 +1136,7 @@ add_setshow_optional_filename_cmd (const char *name, command_class theclass, set_func, get_func, nullptr, show_func, set_list,show_list); - set_cmd_completer (cmds.set, filename_completer); + set_cmd_completer (cmds.set, deprecated_filename_completer); return cmds; } @@ -1530,7 +1627,7 @@ add_com_suppress_notification (const char *name, enum command_class theclass, &cmdlist, suppress_notification); } -/* Print the prefix of C followed by name of C in title style. */ +/* Print the prefix of C followed by name of C in command style. */ static void fput_command_name_styled (const cmd_list_element &c, struct ui_file *stream) @@ -1538,7 +1635,7 @@ fput_command_name_styled (const cmd_list_element &c, struct ui_file *stream) std::string prefixname = c.prefix == nullptr ? "" : c.prefix->prefixname (); - fprintf_styled (stream, title_style.style (), "%s%s", + fprintf_styled (stream, command_style.style (), "%s%s", prefixname.c_str (), c.name); } @@ -1803,7 +1900,7 @@ help_cmd (const char *command, struct ui_file *stream) /* If this is a prefix command, print it's subcommands. */ if (c->is_prefix ()) - help_list (*c->subcommands, c->prefixname ().c_str (), + help_list (*c->subcommands, c->prefixname_no_space ().c_str (), all_commands, stream); /* If this is a class name, print all of the commands in the class. */ @@ -1824,71 +1921,72 @@ help_cmd (const char *command, struct ui_file *stream) c->hook_post->name); } -/* - * Get a specific kind of help on a command list. - * - * LIST is the list. - * CMDTYPE is the prefix to use in the title string. - * THECLASS is the class with which to list the nodes of this list (see - * documentation for help_cmd_list below), As usual, ALL_COMMANDS for - * everything, ALL_CLASSES for just classes, and non-negative for only things - * in a specific class. - * and STREAM is the output stream on which to print things. - * If you call this routine with a class >= 0, it recurses. - */ +/* Get a specific kind of help on a command list. + + LIST is the list. + CMDTYPE is the prefix to use in the title string. It should not + end in a space. + THECLASS is the class with which to list the nodes of this list (see + documentation for help_cmd_list below), As usual, ALL_COMMANDS for + everything, ALL_CLASSES for just classes, and non-negative for only things + in a specific class. + and STREAM is the output stream on which to print things. + If you call this routine with a class >= 0, it recurses. */ void help_list (struct cmd_list_element *list, const char *cmdtype, enum command_class theclass, struct ui_file *stream) { - int len; - char *cmdtype1, *cmdtype2; - - /* If CMDTYPE is "foo ", CMDTYPE1 gets " foo" and CMDTYPE2 gets "foo sub". - */ - len = strlen (cmdtype); - cmdtype1 = (char *) alloca (len + 1); - cmdtype1[0] = 0; - cmdtype2 = (char *) alloca (len + 4); - cmdtype2[0] = 0; - if (len) + int len = strlen (cmdtype); + const char *space = ""; + const char *prefix = ""; + if (len > 0) { - cmdtype1[0] = ' '; - memcpy (cmdtype1 + 1, cmdtype, len - 1); - cmdtype1[len] = 0; - memcpy (cmdtype2, cmdtype, len - 1); - strcpy (cmdtype2 + len - 1, " sub"); + prefix = "sub"; + space = " "; } if (theclass == all_classes) - gdb_printf (stream, "List of classes of %scommands:\n\n", cmdtype2); + gdb_printf (stream, "List of classes of %scommands:\n\n", + prefix); + else if (len == 0) + gdb_printf (stream, "List of commands:\n\n"); else - gdb_printf (stream, "List of %scommands:\n\n", cmdtype2); + gdb_printf (stream, "List of \"%ps\" %scommands:\n\n", + styled_string (command_style.style (), cmdtype), + prefix); help_cmd_list (list, theclass, theclass >= 0, stream); if (theclass == all_classes) { gdb_printf (stream, "\n\ -Type \"help%s\" followed by a class name for a list of commands in ", - cmdtype1); +Type \"%p[help%s%s%p]\" followed by a class name for a list of commands in ", + command_style.style ().ptr (), + space, cmdtype, + nullptr); stream->wrap_here (0); gdb_printf (stream, "that class."); gdb_printf (stream, "\n\ -Type \"help all\" for the list of all commands."); +Type \"%ps\" for the list of all commands.", + styled_string (command_style.style (), "help all")); } - gdb_printf (stream, "\nType \"help%s\" followed by %scommand name ", - cmdtype1, cmdtype2); + gdb_printf (stream, "\nType \"%p[help%s%s%p]\" followed by %scommand name ", + command_style.style ().ptr (), space, cmdtype, nullptr, + prefix); stream->wrap_here (0); gdb_puts ("for ", stream); stream->wrap_here (0); gdb_puts ("full ", stream); stream->wrap_here (0); gdb_puts ("documentation.\n", stream); - gdb_puts ("Type \"apropos word\" to search " - "for commands related to \"word\".\n", stream); - gdb_puts ("Type \"apropos -v word\" for full documentation", stream); + gdb_printf (stream, + "Type \"%ps\" to search " + "for commands related to \"word\".\n", + styled_string (command_style.style (), "apropos word")); + gdb_printf (stream, "Type \"%ps\" for full documentation", + styled_string (command_style.style (), "apropos -v word")); stream->wrap_here (0); gdb_puts (" of commands related to \"word\".\n", stream); gdb_puts ("Command name abbreviations are allowed if unambiguous.\n", @@ -1943,40 +2041,28 @@ void print_doc_line (struct ui_file *stream, const char *str, bool for_value_prefix) { - static char *line_buffer = 0; - static int line_size; - const char *p; + const char *p = strchr (str, '\n'); - if (!line_buffer) - { - line_size = 80; - line_buffer = (char *) xmalloc (line_size); - } + /* Only copy the input string if we really need to. */ + std::optional<std::string> line_buffer; + if (p != nullptr) + line_buffer = std::string (str, p); + else if (for_value_prefix) + line_buffer = str; - /* Searches for the first end of line or the end of STR. */ - p = str; - while (*p && *p != '\n') - p++; - if (p - str > line_size - 1) - { - line_size = p - str + 1; - xfree (line_buffer); - line_buffer = (char *) xmalloc (line_size); - } - strncpy (line_buffer, str, p - str); if (for_value_prefix) { - if (islower (line_buffer[0])) - line_buffer[0] = toupper (line_buffer[0]); - gdb_assert (p > str); - if (line_buffer[p - str - 1] == '.') - line_buffer[p - str - 1] = '\0'; - else - line_buffer[p - str] = '\0'; + char &c = (*line_buffer)[0]; + if (islower (c)) + c = toupper (c); + if (line_buffer->back () == '.') + line_buffer->pop_back (); } - else - line_buffer[p - str] = '\0'; - gdb_puts (line_buffer, stream); + + gdb_puts (line_buffer.has_value () + ? line_buffer->c_str () + : str, + stream); } /* Print one-line help for command C. @@ -2354,7 +2440,7 @@ lookup_cmd (const char **line, struct cmd_list_element *list, } else if (c == CMD_LIST_AMBIGUOUS) { - /* Ambigous. Local values should be off subcommands or called + /* Ambiguous. Local values should be off subcommands or called values. */ int local_allow_unknown = (last_list ? last_list->allow_unknown : allow_unknown); @@ -2502,21 +2588,21 @@ deprecated_cmd_warning (const char *text, struct cmd_list_element *list) if (cmd->cmd_deprecated) gdb_printf (_("Warning: command '%ps' (%ps) is deprecated.\n"), - styled_string (title_style.style (), + styled_string (command_style.style (), tmp_cmd_str.c_str ()), - styled_string (title_style.style (), + styled_string (command_style.style (), tmp_alias_str.c_str ())); else gdb_printf (_("Warning: '%ps', an alias for the command '%ps', " "is deprecated.\n"), - styled_string (title_style.style (), + styled_string (command_style.style (), tmp_alias_str.c_str ()), - styled_string (title_style.style (), + styled_string (command_style.style (), tmp_cmd_str.c_str ())); } else gdb_printf (_("Warning: command '%ps' is deprecated.\n"), - styled_string (title_style.style (), + styled_string (command_style.style (), tmp_cmd_str.c_str ())); /* Now display a second line indicating what the user should use instead. @@ -2529,7 +2615,7 @@ deprecated_cmd_warning (const char *text, struct cmd_list_element *list) replacement = cmd->replacement; if (replacement != nullptr) gdb_printf (_("Use '%ps'.\n\n"), - styled_string (title_style.style (), + styled_string (command_style.style (), replacement)); else gdb_printf (_("No alternative known.\n\n")); @@ -2749,3 +2835,101 @@ 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")); + + uint32_t rgb; + uint8_t r, g, b; + int scanned_chars = 0; + int parsed_args = sscanf (*args, "#%6" SCNx32 "%n", + &rgb, &scanned_chars); + + if (parsed_args != 1 || scanned_chars != 7) + error_no_arg (_("invalid RGB hex triplet format")); + + gdb_assert ((rgb >> 24) == 0); + r = (rgb >> 16) & 0xff; + g = (rgb >> 8) & 0xff; + b = rgb & 0xff; + + *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 7365c3f..9be446f 100644 --- a/gdb/cli/cli-decode.h +++ b/gdb/cli/cli-decode.h @@ -1,6 +1,6 @@ /* Header file for GDB command decoding library. - Copyright (C) 2000-2024 Free Software Foundation, Inc. + Copyright (C) 2000-2025 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,8 +15,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef CLI_CLI_DECODE_H -#define CLI_CLI_DECODE_H +#ifndef GDB_CLI_CLI_DECODE_H +#define GDB_CLI_CLI_DECODE_H /* This file defines the private interfaces for any code implementing command internals. */ @@ -29,6 +29,9 @@ #include "gdbsupport/intrusive_list.h" #include "gdbsupport/buildargv.h" +/* The allowed length of a line in a documentation string. */ +constexpr int cli_help_line_length = 80; + /* Not a set/show command. Note that some commands which begin with "set" or "show" might be in this category, if their syntax does not fall into one of the following categories. */ @@ -59,6 +62,8 @@ struct cmd_list_element type (not_set_cmd), doc (doc_) { + gdb_assert (name != nullptr); + gdb_assert (doc != nullptr); memset (&function, 0, sizeof (function)); } @@ -80,6 +85,9 @@ struct cmd_list_element For non-prefix commands, return an empty string. */ std::string prefixname () const; + /* Like prefixname, but do not append a trailing space. */ + std::string prefixname_no_space () const; + /* Return a vector of strings describing the components of the full name of this command. For example, if this command is 'set AA BB CC', then the vector will contain 4 elements 'set', 'AA', 'BB', and 'CC' @@ -306,6 +314,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. */ @@ -313,4 +342,4 @@ extern int cli_user_command_p (struct cmd_list_element *); extern int find_command_name_length (const char *); -#endif /* CLI_CLI_DECODE_H */ +#endif /* GDB_CLI_CLI_DECODE_H */ diff --git a/gdb/cli/cli-dump.c b/gdb/cli/cli-dump.c index 9b44c6e..afbbea6 100644 --- a/gdb/cli/cli-dump.c +++ b/gdb/cli/cli-dump.c @@ -1,6 +1,6 @@ /* Dump-to-file commands, for GDB, the GNU debugger. - Copyright (C) 2002-2024 Free Software Foundation, Inc. + Copyright (C) 2002-2025 Free Software Foundation, Inc. Contributed by Red Hat. @@ -348,7 +348,7 @@ add_dump_command (const char *name, struct dump_context *d; c = add_cmd (name, all_commands, descr, &dump_cmdlist); - c->completer = filename_completer; + set_cmd_completer (c, deprecated_filename_completer); d = XNEW (struct dump_context); d->func = func; d->mode = FOPEN_WB; @@ -356,7 +356,7 @@ add_dump_command (const char *name, c->func = call_dump_func; c = add_cmd (name, all_commands, descr, &append_cmdlist); - c->completer = filename_completer; + set_cmd_completer (c, deprecated_filename_completer); d = XNEW (struct dump_context); d->func = func; d->mode = FOPEN_AB; @@ -397,7 +397,7 @@ restore_one_section (bfd *ibfd, asection *isec, if (sec_end <= load_start || (load_end > 0 && sec_start >= load_end)) { - /* No, no useable data in this section. */ + /* No, no usable data in this section. */ gdb_printf (_("skipping section %s...\n"), bfd_section_name (isec)); return; @@ -564,9 +564,7 @@ restore_command (const char *args, int from_tty) } } -void _initialize_cli_dump (); -void -_initialize_cli_dump () +INIT_GDB_FILE (cli_dump) { struct cmd_list_element *c; @@ -705,6 +703,6 @@ Arguments are FILE OFFSET START END where all except FILE are optional.\n\ OFFSET will be added to the base address of the file (default zero).\n\ If START and END are given, only the file contents within that range\n\ (file relative) will be restored to target memory.")); - c->completer = filename_completer; + set_cmd_completer (c, deprecated_filename_completer); /* FIXME: completers for other commands. */ } diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c index fa5d70e..d7b73df 100644 --- a/gdb/cli/cli-interp.c +++ b/gdb/cli/cli-interp.c @@ -1,6 +1,6 @@ /* CLI Definitions for GDB, the GNU debugger. - Copyright (C) 2002-2024 Free Software Foundation, Inc. + Copyright (C) 2002-2025 Free Software Foundation, Inc. This file is part of GDB. @@ -228,7 +228,7 @@ cli_interp::exec (const char *command_str) interpreter which has a new ui_file for gdb_stdout, use that one instead of the default. - It is important that it gets reset everytime, since the user + It is important that it gets reset every time, since the user could set gdb to use a different interpreter. */ ui_file *old_stream = m_cli_uiout->set_stream (gdb_stdout); SCOPE_EXIT { m_cli_uiout->set_stream (old_stream); }; @@ -269,7 +269,7 @@ cli_interp_base::set_logging (ui_file_up logfile, bool logging_redirect, if (logfile != nullptr) { gdb_assert (m_saved_output == nullptr); - m_saved_output.reset (new saved_output_files); + m_saved_output = std::make_unique<saved_output_files> (); m_saved_output->out = gdb_stdout; m_saved_output->err = gdb_stderr; m_saved_output->log = gdb_stdlog; @@ -321,9 +321,7 @@ cli_interp_factory (const char *name) /* Standard gdb initialization hook. */ -void _initialize_cli_interp (); -void -_initialize_cli_interp () +INIT_GDB_FILE (cli_interp) { interp_factory_register (INTERP_CONSOLE, cli_interp_factory); } diff --git a/gdb/cli/cli-interp.h b/gdb/cli/cli-interp.h index 03b592f..8f41725 100644 --- a/gdb/cli/cli-interp.h +++ b/gdb/cli/cli-interp.h @@ -1,6 +1,6 @@ /* CLI Definitions for GDB, the GNU debugger. - Copyright (C) 2016-2024 Free Software Foundation, Inc. + Copyright (C) 2016-2025 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,8 +15,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef CLI_CLI_INTERP_H -#define CLI_CLI_INTERP_H +#ifndef GDB_CLI_CLI_INTERP_H +#define GDB_CLI_CLI_INTERP_H #include "interps.h" @@ -68,4 +68,4 @@ private: extern int should_print_stop_to_console (struct interp *interp, struct thread_info *tp); -#endif /* CLI_CLI_INTERP_H */ +#endif /* GDB_CLI_CLI_INTERP_H */ diff --git a/gdb/cli/cli-logging.c b/gdb/cli/cli-logging.c index 2c54cea..d6eb6c2 100644 --- a/gdb/cli/cli-logging.c +++ b/gdb/cli/cli-logging.c @@ -1,6 +1,6 @@ /* Command-line output logging for GDB, the GNU debugger. - Copyright (C) 2003-2024 Free Software Foundation, Inc. + Copyright (C) 2003-2025 Free Software Foundation, Inc. This file is part of GDB. @@ -202,9 +202,7 @@ show_logging_enabled (struct ui_file *file, int from_tty, gdb_printf (file, _("off: Logging is disabled.\n")); } -void _initialize_cli_logging (); -void -_initialize_cli_logging () +INIT_GDB_FILE (cli_logging) { static struct cmd_list_element *set_logging_cmdlist, *show_logging_cmdlist; 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"); } diff --git a/gdb/cli/cli-option.h b/gdb/cli/cli-option.h index bbe281d..6a56d5a 100644 --- a/gdb/cli/cli-option.h +++ b/gdb/cli/cli-option.h @@ -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. @@ -17,8 +17,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef CLI_OPTION_H -#define CLI_OPTION_H 1 +#ifndef GDB_CLI_CLI_OPTION_H +#define GDB_CLI_CLI_OPTION_H #include <optional> #include "gdbsupport/array-view.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; @@ -308,6 +309,46 @@ struct string_option_def : option_def } }; +/* A var_filename command line option. */ + +template<typename Context> +struct filename_option_def : option_def +{ + filename_option_def (const char *long_option_, + std::string *(*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_filename, nullptr, + (erased_get_var_address_ftype *) get_var_address_cb_, + show_cmd_cb_, + set_doc_, show_doc_, help_doc_) + { + var_address.string = detail::get_var_address<std::string, Context>; + } +}; + +/* 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, nullptr, + (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 @@ -379,4 +420,4 @@ extern void add_setshow_cmds_for_options (command_class cmd_class, void *data, } /* namespace option */ } /* namespace gdb */ -#endif /* CLI_OPTION_H */ +#endif /* GDB_CLI_CLI_OPTION_H */ diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c index 329f780..3ea80a5 100644 --- a/gdb/cli/cli-script.c +++ b/gdb/cli/cli-script.c @@ -1,6 +1,6 @@ /* GDB CLI command scripting. - Copyright (C) 1986-2024 Free Software Foundation, Inc. + Copyright (C) 1986-2025 Free Software Foundation, Inc. This file is part of GDB. @@ -422,14 +422,14 @@ execute_control_commands (struct command_line *cmdlines, int from_tty) std::string execute_control_commands_to_string (struct command_line *commands, - int from_tty) + int from_tty, bool term_out) { std::string result; execute_fn_to_string (result, [&] () { execute_control_commands (commands, from_tty); - }, false); + }, term_out); return result; } @@ -660,9 +660,13 @@ execute_control_command_1 (struct command_line *cmd, int from_tty) } case compile_control: +#if defined(HAVE_COMPILE) eval_compile_command (cmd, NULL, cmd->control_u.compile.scope, cmd->control_u.compile.scope_data); ret = simple_control; +#else + error (_("compile support has not been compiled into gdb")); +#endif break; case define_control: @@ -1621,6 +1625,65 @@ define_prefix_command (const char *comname, int from_tty) c->allow_unknown = c->user_commands.get () != nullptr; } +/* See cli/cli-script.h. */ + +bool +commands_equal (const command_line *a, const command_line *b) +{ + if ((a == nullptr) != (b == nullptr)) + return false; + + while (a != nullptr) + { + /* We are either at the end of both command lists, or there's + another command in both lists. */ + if ((a->next == nullptr) != (b->next == nullptr)) + return false; + + /* There's a command line for both, or neither. */ + if ((a->line == nullptr) != (b->line == nullptr)) + return false; + + /* Check control_type matches. */ + if (a->control_type != b->control_type) + return false; + + if (a->control_type == compile_control) + { + if (a->control_u.compile.scope != b->control_u.compile.scope) + return false; + + /* This is where we "fail safe". The scope_data is a 'void *' + pointer which changes in meaning based on the value of + 'scope'. It is possible that two different 'void *' pointers + could point to the equal scope data, however, we just assume + that if the pointers are different, then the scope_data is + different. This could be improved in the future. */ + if (a->control_u.compile.scope_data + != b->control_u.compile.scope_data) + return false; + } + + /* Check lines are identical. */ + if (a->line != nullptr && strcmp (a->line, b->line) != 0) + return false; + + /* Check body_list_0. */ + if (!commands_equal (a->body_list_0.get (), b->body_list_0.get ())) + return false; + + /* Check body_list_1. */ + if (!commands_equal (a->body_list_1.get (), b->body_list_1.get ())) + return false; + + /* Move to the next element in each chain. */ + a = a->next; + b = b->next; + } + + return true; +} + /* Used to implement source_command. */ @@ -1667,7 +1730,7 @@ show_user_1 (struct cmd_list_element *c, const char *prefix, const char *name, gdb_printf (stream, "User %scommand \"", c->is_prefix () ? "prefix" : ""); - fprintf_styled (stream, title_style.style (), "%s%s", + fprintf_styled (stream, command_style.style (), "%s%s", prefix, name); gdb_printf (stream, "\":\n"); if (cmdlines) @@ -1688,9 +1751,7 @@ show_user_1 (struct cmd_list_element *c, const char *prefix, const char *name, } -void _initialize_cli_script (); -void -_initialize_cli_script () +INIT_GDB_FILE (cli_script) { struct cmd_list_element *c; diff --git a/gdb/cli/cli-script.h b/gdb/cli/cli-script.h index 512e37b..1ce0754 100644 --- a/gdb/cli/cli-script.h +++ b/gdb/cli/cli-script.h @@ -1,5 +1,5 @@ /* Header file for GDB CLI command implementation library. - Copyright (C) 2000-2024 Free Software Foundation, Inc. + Copyright (C) 2000-2025 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,8 +14,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef CLI_CLI_SCRIPT_H -#define CLI_CLI_SCRIPT_H +#ifndef GDB_CLI_CLI_SCRIPT_H +#define GDB_CLI_CLI_SCRIPT_H #include "compile/compile.h" #include "gdbsupport/function-view.h" @@ -143,10 +143,12 @@ extern void execute_control_commands (struct command_line *cmdlines, /* Run execute_control_commands for COMMANDS. Capture its output into the returned string, do not display it to the screen. BATCH_FLAG - will be temporarily set to true. */ + will be temporarily set to true. When TERM_OUT is true the output is + collected with terminal behavior (e.g. with styling). When TERM_OUT is + false raw output will be collected (e.g. no styling). */ extern std::string execute_control_commands_to_string - (struct command_line *commands, int from_tty); + (struct command_line *commands, int from_tty, bool term_out); /* Exported to gdb/breakpoint.c */ @@ -182,4 +184,14 @@ extern void print_command_trace (const char *cmd, ...) extern void reset_command_nest_depth (void); -#endif /* CLI_CLI_SCRIPT_H */ +/* Return true if A and B are identical. Some commands carry around a + 'void *' compilation context, in this case this function doesn't try to + validate if the context is actually the same or not, and will just + return false indicating the commands have changed. That is, a return + value of true is a guarantee that the commands are equal, a return + value of false means the commands are possibly different (and in most + cases are different). */ + +extern bool commands_equal (const command_line *a, const command_line *b); + +#endif /* GDB_CLI_CLI_SCRIPT_H */ diff --git a/gdb/cli/cli-setshow.c b/gdb/cli/cli-setshow.c index bcc793b..4d4695f 100644 --- a/gdb/cli/cli-setshow.c +++ b/gdb/cli/cli-setshow.c @@ -1,6 +1,6 @@ /* Handle set and show GDB commands. - Copyright (C) 2000-2024 Free Software Foundation, Inc. + Copyright (C) 2000-2025 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -27,6 +27,7 @@ #include "cli/cli-decode.h" #include "cli/cli-cmds.h" #include "cli/cli-setshow.h" +#include "cli/cli-style.h" #include "cli/cli-utils.h" /* Return true if the change of command parameter should be notified. */ @@ -137,12 +138,16 @@ deprecated_show_value_hack (struct ui_file *ignore_file, { case var_string: case var_string_noescape: - case var_optional_filename: - case var_filename: case var_enum: gdb_printf ((" is \"%s\".\n"), value); break; + case var_optional_filename: + case var_filename: + gdb_printf ((" is \"%ps\".\n"), + styled_string (file_name_style.style (), value)); + break; + default: gdb_printf ((" is %s.\n"), value); break; @@ -443,6 +448,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 +532,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 +605,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; @@ -681,6 +707,7 @@ cmd_show_list (struct cmd_list_element *list, int from_tty) struct ui_out *uiout = current_uiout; ui_out_emit_tuple tuple_emitter (uiout, "showlist"); + const ui_file_style cmd_style = command_style.style (); for (; list != NULL; list = list->next) { /* We skip show command aliases to avoid showing duplicated values. */ @@ -701,15 +728,18 @@ cmd_show_list (struct cmd_list_element *list, int from_tty) { ui_out_emit_tuple option_emitter (uiout, "option"); - if (list->prefix != nullptr) + if (!uiout->is_mi_like_p () && list->prefix != nullptr) { /* If we find a prefix, output it (with "show " skipped). */ std::string prefixname = list->prefix->prefixname (); - prefixname = (!list->prefix->is_prefix () ? "" - : strstr (prefixname.c_str (), "show ") + 5); - uiout->text (prefixname); + if (startswith (prefixname, "show ")) + prefixname = prefixname.substr (5); + /* In non-MI mode, we include the full name here. */ + prefixname += list->name; + uiout->field_string ("name", prefixname, cmd_style); } - uiout->field_string ("name", list->name); + else + uiout->field_string ("name", list->name, cmd_style); uiout->text (": "); if (list->type == show_cmd) do_show_command (NULL, from_tty, list); diff --git a/gdb/cli/cli-setshow.h b/gdb/cli/cli-setshow.h index 4b8875d..886f89f 100644 --- a/gdb/cli/cli-setshow.h +++ b/gdb/cli/cli-setshow.h @@ -1,5 +1,5 @@ /* Header file for GDB CLI set and show commands implementation. - Copyright (C) 2000-2024 Free Software Foundation, Inc. + Copyright (C) 2000-2025 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,8 +14,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef CLI_CLI_SETSHOW_H -#define CLI_CLI_SETSHOW_H +#ifndef GDB_CLI_CLI_SETSHOW_H +#define GDB_CLI_CLI_SETSHOW_H #include <string> @@ -60,4 +60,4 @@ extern std::string get_setshow_command_value_string (const setting &var); extern void cmd_show_list (struct cmd_list_element *list, int from_tty); -#endif /* CLI_CLI_SETSHOW_H */ +#endif /* GDB_CLI_CLI_SETSHOW_H */ diff --git a/gdb/cli/cli-style.c b/gdb/cli/cli-style.c index 5928998..d6829f0 100644 --- a/gdb/cli/cli-style.c +++ b/gdb/cli/cli-style.c @@ -1,6 +1,6 @@ /* CLI colorizing - Copyright (C) 2018-2024 Free Software Foundation, Inc. + Copyright (C) 2018-2025 Free Software Foundation, Inc. This file is part of GDB. @@ -23,13 +23,14 @@ #include "cli/cli-style.h" #include "source-cache.h" #include "observable.h" +#include "charset.h" /* True if styling is enabled. */ #if defined (__MSDOS__) -bool cli_styling = false; +static bool cli_styling = false; #else -bool cli_styling = true; +static bool cli_styling = true; #endif /* True if source styling is enabled. Note that this is only @@ -42,19 +43,9 @@ 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 -}; +/* User-settable variable controlling emoji output. */ + +static auto_boolean emoji_styling = AUTO_BOOLEAN_AUTO; /* Names of intensities; must correspond to ui_file_style::intensity. */ @@ -65,6 +56,81 @@ static const char * const cli_intensities[] = { nullptr }; +/* When true styling is being temporarily suppressed. */ + +static bool scoped_disable_styling_p = false; + +/* See cli/cli-style.h. */ + +scoped_disable_styling::scoped_disable_styling () +{ + m_old_value = scoped_disable_styling_p; + scoped_disable_styling_p = true; +} + +/* See cli/cli-style.h. */ + +scoped_disable_styling::~scoped_disable_styling () +{ + scoped_disable_styling_p = m_old_value; +} + +/* Return true if GDB's output terminal should support styling, otherwise, + return false. This function really checks for things that indicate + styling might not be supported, so a return value of false indicates + we've seen something to indicate we should not perform styling. A + return value of true is the default. */ + +static bool +terminal_supports_styling () +{ + const char *term = getenv ("TERM"); + + /* Windows doesn't by default define $TERM, but can support styles + regardless. */ +#ifndef _WIN32 + if (term == nullptr || strcmp (term, "dumb") == 0) + return false; +#else + /* But if they do define $TERM, let us behave the same as on Posix + platforms, for the benefit of programs which invoke GDB as their + back-end. */ + if (term != nullptr && strcmp (term, "dumb") == 0) + return false; +#endif + + return true; +} + +/* See cli/cli-style.h. */ + +void +disable_cli_styling () +{ + cli_styling = false; +} + +/* See cli/cli-style.h. */ + +bool +term_cli_styling () +{ + return cli_styling && !scoped_disable_styling_p; +} + +/* See cli/cli-style.h. */ + +void +disable_styling_from_environment () +{ + const char *no_color = getenv ("NO_COLOR"); + if (no_color != nullptr && *no_color != '\0') + cli_styling = false; + + if (!terminal_supports_styling ()) + cli_styling = false; +} + /* See cli-style.h. */ cli_style_option file_name_style ("filename", ui_file_style::GREEN); @@ -91,6 +157,10 @@ cli_style_option title_style ("title", ui_file_style::BOLD); /* See cli-style.h. */ +cli_style_option command_style ("command", ui_file_style::BOLD); + +/* See cli-style.h. */ + cli_style_option tui_border_style ("tui-border", ui_file_style::CYAN); /* See cli-style.h. */ @@ -126,13 +196,17 @@ cli_style_option disasm_comment_style ("comment", ui_file_style::WHITE, /* See cli-style.h. */ +cli_style_option line_number_style ("line-number", ui_file_style::DIM); + +/* See cli-style.h. */ + cli_style_option::cli_style_option (const char *name, ui_file_style::basic_color fg, 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]) { } @@ -143,32 +217,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) @@ -180,7 +239,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. */ @@ -253,9 +312,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, @@ -265,9 +323,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, @@ -309,7 +366,20 @@ static cmd_list_element *style_disasm_show_list; static void set_style_enabled (const char *args, int from_tty, struct cmd_list_element *c) { - g_source_cache.clear (); + /* This finds the 'set style enabled' command. */ + struct cmd_list_element *set_style_enabled_cmd + = lookup_cmd_exact ("enabled", style_set_list); + + /* If the user does 'set style enabled on', but the terminal doesn't + appear to support styling, then warn the user. */ + if (c == set_style_enabled_cmd && cli_styling + && !terminal_supports_styling ()) + warning ("The current terminal doesn't support styling. Styled output " + "might not appear as expected."); + + /* It is not necessary to flush the source cache here. The source cache + tracks whether entries are styled or not. */ + gdb::observers::styling_changed.notify (); } @@ -345,9 +415,86 @@ show_style_disassembler (struct ui_file *file, int from_tty, gdb_printf (file, _("Disassembler output styling is disabled.\n")); } -void _initialize_cli_style (); +/* Implement 'show style emoji'. */ + +static void +show_emoji_styling (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + if (emoji_styling == AUTO_BOOLEAN_TRUE) + gdb_printf (file, _("CLI emoji styling is enabled.\n")); + else if (emoji_styling == AUTO_BOOLEAN_FALSE) + gdb_printf (file, _("CLI emoji styling is disabled.\n")); + else + gdb_printf (file, _("CLI emoji styling is automatic (currently %s).\n"), + emojis_ok () ? _("enabled") : _("disabled")); +} + +/* See cli-style.h. */ + +bool +emojis_ok () +{ + if (!cli_styling || emoji_styling == AUTO_BOOLEAN_FALSE) + return false; + if (emoji_styling == AUTO_BOOLEAN_TRUE) + return true; + return strcmp (host_charset (), "UTF-8") == 0; +} + +/* See cli-style.h. */ + +void +no_emojis () +{ + emoji_styling = AUTO_BOOLEAN_FALSE; +} + +/* Emoji warning prefix. */ +static std::string warning_prefix = "⚠️ "; + +/* Implement 'show style warning-prefix'. */ + +static void +show_warning_prefix (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + gdb_printf (file, _("Warning prefix is \"%s\".\n"), + warning_prefix.c_str ()); +} + +/* See cli-style.h. */ + +void +print_warning_prefix (ui_file *file) +{ + if (emojis_ok ()) + gdb_puts (warning_prefix.c_str (), file); +} + +/* Emoji error prefix. */ +static std::string error_prefix = "❌️ "; + +/* Implement 'show style error-prefix'. */ + +static void +show_error_prefix (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + gdb_printf (file, _("Error prefix is \"%s\".\n"), + error_prefix.c_str ()); +} + +/* See cli-style.h. */ + void -_initialize_cli_style () +print_error_prefix (ui_file *file) +{ + if (emojis_ok ()) + gdb_puts (error_prefix.c_str (), file); +} + +INIT_GDB_FILE (cli_style) { add_setshow_prefix_cmd ("style", no_class, _("\ @@ -366,6 +513,13 @@ If enabled, output to the terminal is styled."), set_style_enabled, show_style_enabled, &style_set_list, &style_show_list); + add_setshow_auto_boolean_cmd ("emoji", no_class, &emoji_styling, _("\ +Set whether emoji output is enabled."), _("\ +Show whether emoji output is enabled."), _("\ +If enabled, emojis may be displayed."), + nullptr, show_emoji_styling, + &style_set_list, &style_show_list); + add_setshow_boolean_cmd ("sources", no_class, &source_styling, _("\ Set whether source code styling is enabled."), _("\ Show whether source code styling is enabled."), _("\ @@ -394,9 +548,17 @@ Configure various disassembler style-related variables."), add_setshow_boolean_cmd ("enabled", no_class, &disassembler_styling, _("\ Set whether disassembler output styling is enabled."), _("\ Show whether disassembler output styling is enabled."), _("\ -If enabled, disassembler output is styled. Disassembler highlighting\n\ -requires the Python Pygments library, if this library is not available\n\ -then disassembler highlighting will not be possible." +If enabled, disassembler output is styled.\n\ +\n\ +Disassembler styling requires a library that is able to style the current\n\ +instruction architecture. By default, GDB will use its builtin library\n\ +for disassembler styling, but this cannot style every architecture.\n\ +\n\ +For architectures that cannot be styled by the builtin disassembler library\n\ +GDB will use the Python Pygments library, if this library is available.\n\ +\n\ +If neither option is able to style the current architecture, then\n\ +disassembler output will be unstyled, even when this option is enabled." ), set_style_enabled, show_style_disassembler, &style_disasm_set_list, &style_disasm_show_list); @@ -435,6 +597,13 @@ readability."), &style_set_list, &style_show_list, false); + command_style.add_setshow_commands (no_class, _("\ +Command display styling.\n\ +Configure the colors and display intensity for GDB commands mentioned\n\ +in the output."), + &style_set_list, &style_show_list, + false); + highlight_style.add_setshow_commands (no_class, _("\ Highlight display styling.\n\ Configure highlight colors and display intensity\n\ @@ -529,6 +698,14 @@ then this style has no effect."), &style_disasm_show_list, false); + line_number_style.add_setshow_commands (no_class, _("\ +Line number display styling.\n\ +Configure colors and display intensity for line numbers\n\ +The \"line-number\" style is used when GDB displays line numbers\n\ +coming from your source code."), + &style_set_list, &style_show_list, + false); + /* Setup 'disassembler address' style and 'disassembler symbol' style, these are aliases for 'address' and 'function' styles respectively. */ add_alias_cmd ("address", address_prefix_cmds.set, no_class, 0, @@ -539,4 +716,23 @@ then this style has no effect."), &style_disasm_set_list); add_alias_cmd ("symbol", function_prefix_cmds.show, no_class, 0, &style_disasm_show_list); + + add_setshow_string_cmd ("warning-prefix", no_class, + &warning_prefix, + _("Set the warning prefix text."), + _("Show the warning prefix text."), + _("\ +The warning prefix text is displayed before any warning, when\n\ +emoji output is enabled."), + nullptr, show_warning_prefix, + &style_set_list, &style_show_list); + add_setshow_string_cmd ("error-prefix", no_class, + &error_prefix, + _("Set the error prefix text."), + _("Show the error prefix text."), + _("\ +The error prefix text is displayed before any error, when\n\ +emoji output is enabled."), + nullptr, show_error_prefix, + &style_set_list, &style_show_list); } diff --git a/gdb/cli/cli-style.h b/gdb/cli/cli-style.h index 1663b4e..b1a950a 100644 --- a/gdb/cli/cli-style.h +++ b/gdb/cli/cli-style.h @@ -1,6 +1,6 @@ /* CLI stylizing - Copyright (C) 2018-2024 Free Software Foundation, Inc. + Copyright (C) 2018-2025 Free Software Foundation, Inc. This file is part of GDB. @@ -17,8 +17,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef CLI_CLI_STYLE_H -#define CLI_CLI_STYLE_H +#ifndef GDB_CLI_CLI_STYLE_H +#define GDB_CLI_CLI_STYLE_H #include "ui-file.h" #include "command.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; @@ -118,6 +118,9 @@ extern cli_style_option highlight_style; /* The title style. */ extern cli_style_option title_style; +/* Style used for commands. */ +extern cli_style_option command_style; + /* The metadata style. */ extern cli_style_option metadata_style; @@ -145,13 +148,60 @@ extern cli_style_option tui_active_border_style; /* The style to use for the GDB version string. */ extern cli_style_option version_style; +/* The style for a line number. */ +extern cli_style_option line_number_style; + /* True if source styling is enabled. */ extern bool source_styling; /* True if disassembler styling is enabled. */ extern bool disassembler_styling; -/* True if styling is enabled. */ -extern bool cli_styling; +/* Check for environment variables that indicate styling should start as + disabled. If any are found then disable styling. Styling is never + enabled by this call. If styling was already disabled then it remains + disabled after this call. */ +extern void disable_styling_from_environment (); + +/* Equivalent to 'set style enabled off'. Can be used during GDB's start + up if a command line option, or environment variable, indicates that + styling should be turned off. */ +extern void disable_cli_styling (); + +/* Return true styled output is currently enabled. */ +extern bool term_cli_styling (); + +/* Allow styling to be temporarily suppressed without changing the value of + 'set style enabled' user setting. This is useful in, for example, the + Python gdb.execute() call which can produce unstyled output. */ +struct scoped_disable_styling +{ + /* Temporarily suppress styling without changing the value of 'set + style enabled' user setting. */ + scoped_disable_styling (); + + /* If the constructor started suppressing styling, then styling is + resumed after this destructor call. */ + ~scoped_disable_styling (); + +private: + + /* The value to restore in the destructor. */ + bool m_old_value; +}; + +/* Return true if emoji styling is allowed. */ +extern bool emojis_ok (); + +/* Disable emoji styling. This is here so that Windows can disable + emoji when the console is in use. It shouldn't be called + elsewhere. */ +extern void no_emojis (); + +/* Print the warning prefix, if desired. */ +extern void print_warning_prefix (ui_file *file); + +/* Print the error prefix, if desired. */ +extern void print_error_prefix (ui_file *file); -#endif /* CLI_CLI_STYLE_H */ +#endif /* GDB_CLI_CLI_STYLE_H */ diff --git a/gdb/cli/cli-utils.c b/gdb/cli/cli-utils.c index 45b3084..23706e0 100644 --- a/gdb/cli/cli-utils.c +++ b/gdb/cli/cli-utils.c @@ -1,6 +1,6 @@ /* CLI utilities. - Copyright (C) 2011-2024 Free Software Foundation, Inc. + Copyright (C) 2011-2025 Free Software Foundation, Inc. This file is part of GDB. @@ -197,10 +197,10 @@ info_print_args_help (const char *prefix, bool document_n_flag) { return xstrprintf (_("\ -%sIf NAMEREGEXP is provided, only prints the %s whose name\n\ -matches NAMEREGEXP.\n\ -If -t TYPEREGEXP is provided, only prints the %s whose type\n\ -matches TYPEREGEXP. Note that the matching is done with the type\n\ +%sIf NAMEREGEXP is provided, only prints the %s\n\ +whose name matches NAMEREGEXP.\n\ +If -t TYPEREGEXP is provided, only prints the %s\n\ +whose type matches TYPEREGEXP. Note that the matching is done with the type\n\ printed by the 'whatis' command.\n\ By default, the command might produce headers and/or messages indicating\n\ why no %s can be printed.\n\ diff --git a/gdb/cli/cli-utils.h b/gdb/cli/cli-utils.h index 54b45fd..f9b0123 100644 --- a/gdb/cli/cli-utils.h +++ b/gdb/cli/cli-utils.h @@ -1,6 +1,6 @@ /* CLI utilities. - Copyright (C) 2011-2024 Free Software Foundation, Inc. + Copyright (C) 2011-2025 Free Software Foundation, Inc. This file is part of GDB. @@ -17,8 +17,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef CLI_CLI_UTILS_H -#define CLI_CLI_UTILS_H +#ifndef GDB_CLI_CLI_UTILS_H +#define GDB_CLI_CLI_UTILS_H #include "completer.h" @@ -82,7 +82,7 @@ public: /* STRING is the string to be parsed. */ void init (const char *string); - /* While processing a range, this fuction is called iteratively; At + /* While processing a range, this function is called iteratively; At each call it will return the next value in the range. At the beginning of parsing a range, the char pointer @@ -225,4 +225,4 @@ struct qcs_flags message. */ extern void validate_flags_qcs (const char *which_command, qcs_flags *flags); -#endif /* CLI_CLI_UTILS_H */ +#endif /* GDB_CLI_CLI_UTILS_H */ |