On 2019-11-28 3:08 p.m., Philippe Waroquiers wrote:
> diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c
> index 06cdcd6bfe..066a596fdc 100644
> --- a/gdb/cli/cli-script.c
> +++ b/gdb/cli/cli-script.c
> @@ -29,6 +29,7 @@
> #include "cli/cli-cmds.h"
> #include "cli/cli-decode.h"
> #include "cli/cli-script.h"
> +#include "cli/cli-style.h"
>
> #include "extension.h"
> #include "interps.h"
> @@ -1395,7 +1396,17 @@ do_define_command (const char *comname, int from_tty,
> int q;
>
> if (c->theclass == class_user || c->theclass == class_alias)
> - q = query (_("Redefine command \"%s\"? "), c->name);
> + {
> + /* if C is a prefix command that was previously defined,
> + tell the user its subcommands will be kept, and ask
> + if ok to redefine the command. */
> + if (c->prefixlist != nullptr)
> + q = c->user_commands.get () == nullptr
> + || query (_("Keeping subcommands of prefix command \"%s\".\n"
> + "Redefine command \"%s\"? "), c->name, c->name);
Just a nit here before you push, format the multi-line expression line like this, with
a parenthesis:
q = (c->user_commands.get () == nullptr
|| query (_("Keeping subcommands of prefix command \"%s\".\n"
"Redefine command \"%s\"? "), c->name, c->name));
Simon
@@ -29,6 +29,7 @@
#include "cli/cli-cmds.h"
#include "cli/cli-decode.h"
#include "cli/cli-script.h"
+#include "cli/cli-style.h"
#include "extension.h"
#include "interps.h"
@@ -1395,7 +1396,17 @@ do_define_command (const char *comname, int from_tty,
int q;
if (c->theclass == class_user || c->theclass == class_alias)
- q = query (_("Redefine command \"%s\"? "), c->name);
+ {
+ /* if C is a prefix command that was previously defined,
+ tell the user its subcommands will be kept, and ask
+ if ok to redefine the command. */
+ if (c->prefixlist != nullptr)
+ q = c->user_commands.get () == nullptr
+ || query (_("Keeping subcommands of prefix command \"%s\".\n"
+ "Redefine command \"%s\"? "), c->name, c->name);
+ else
+ q = query (_("Redefine command \"%s\"? "), c->name);
+ }
else
q = query (_("Really redefine built-in command \"%s\"? "), c->name);
if (!q)
@@ -1446,10 +1457,27 @@ do_define_command (const char *comname, int from_tty,
else
cmds = *commands;
- newc = add_cmd (comname, class_user, user_defined_command,
- (c && c->theclass == class_user)
- ? c->doc : xstrdup ("User-defined."), list);
- newc->user_commands = std::move (cmds);
+ {
+ struct cmd_list_element **c_prefixlist
+ = c == nullptr ? nullptr : c->prefixlist;
+ const char *c_prefixname = c == nullptr ? nullptr : c->prefixname;
+
+ newc = add_cmd (comname, class_user, user_defined_command,
+ (c != nullptr && c->theclass == class_user)
+ ? c->doc : xstrdup ("User-defined."), list);
+ newc->user_commands = std::move (cmds);
+
+ /* If we define or re-define a command that was previously defined
+ as a prefix, keep the prefix information. */
+ if (c_prefixlist != nullptr)
+ {
+ newc->prefixlist = c_prefixlist;
+ newc->prefixname = c_prefixname;
+ /* allow_unknown: see explanation in equivalent logic in
+ define_prefix_command (). */
+ newc->allow_unknown = newc->user_commands.get () != nullptr;
+ }
+ }
/* If this new command is a hook, then mark both commands as being
tied. */
@@ -1524,6 +1552,54 @@ document_command (const char *comname, int from_tty)
c->doc = doc;
}
}
+
+/* Implementation of the "define-prefix" command. */
+
+static void
+define_prefix_command (const char *comname, int from_tty)
+{
+ struct cmd_list_element *c, **list;
+ const char *tem;
+ const char *comfull;
+
+ comfull = comname;
+ list = validate_comname (&comname);
+
+ /* Look it up, and verify that we got an exact match. */
+ tem = comname;
+ c = lookup_cmd (&tem, *list, "", -1, 1);
+ if (c != nullptr && strcmp (comname, c->name) != 0)
+ c = nullptr;
+
+ if (c != nullptr && c->theclass != class_user)
+ error (_("Command \"%s\" is built-in."), comfull);
+
+ if (c != nullptr && c->prefixlist != nullptr)
+ {
+ /* c is already a user defined prefix command. */
+ return;
+ }
+
+ /* If the command does not exist at all, create it. */
+ if (c == nullptr)
+ {
+ comname = xstrdup (comname);
+ c = add_cmd (comname, class_user, user_defined_command,
+ xstrdup ("User-defined."), list);
+ }
+
+ /* Allocate the c->prefixlist, which marks the command as a prefix
+ command. */
+ c->prefixlist = new struct cmd_list_element*;
+ *(c->prefixlist) = nullptr;
+ c->prefixname = xstrprintf ("%s ", comfull);
+ /* If the prefix command C is not a command, then it must be followed
+ by known subcommands. Otherwise, if C is also a normal command,
+ it can be followed by C args that must not cause a 'subcommand'
+ not recognised error, and thus we must allow unknown. */
+ c->allow_unknown = c->user_commands.get () != nullptr;
+}
+
/* Used to implement source_command. */
@@ -1564,7 +1640,21 @@ void
show_user_1 (struct cmd_list_element *c, const char *prefix, const char *name,
struct ui_file *stream)
{
- struct command_line *cmdlines;
+ if (cli_user_command_p (c))
+ {
+ struct command_line *cmdlines = c->user_commands.get ();
+
+ fprintf_filtered (stream, "User %scommand \"",
+ c->prefixlist == NULL ? "" : "prefix ");
+ fprintf_styled (stream, title_style.style (), "%s%s",
+ prefix, name);
+ fprintf_filtered (stream, "\":\n");
+ if (cmdlines)
+ {
+ print_command_lines (current_uiout, cmdlines, 1);
+ fputs_filtered ("\n", stream);
+ }
+ }
if (c->prefixlist != NULL)
{
@@ -1573,25 +1663,23 @@ show_user_1 (struct cmd_list_element *c, const char *prefix, const char *name,
for (c = *c->prefixlist; c != NULL; c = c->next)
if (c->theclass == class_user || c->prefixlist != NULL)
show_user_1 (c, prefixname, c->name, gdb_stdout);
- return;
}
- cmdlines = c->user_commands.get ();
- fprintf_filtered (stream, "User command \"%s%s\":\n", prefix, name);
-
- if (!cmdlines)
- return;
- print_command_lines (current_uiout, cmdlines, 1);
- fputs_filtered ("\n", stream);
}
void
_initialize_cli_script (void)
{
- add_com ("document", class_support, document_command, _("\
+ struct cmd_list_element *c;
+
+ /* "document", "define" and "define-prefix" use command_completer,
+ as this helps the user to either type the command name and/or
+ its prefixes. */
+ c = add_com ("document", class_support, document_command, _("\
Document a user-defined command.\n\
Give command name as argument. Give documentation on following lines.\n\
End with a line of just \"end\"."));
+ set_cmd_completer (c, command_completer);
define_cmd_element = add_com ("define", class_support, define_command, _("\
Define a new command name. Command name is argument.\n\
Definition appears on following lines, one command per line.\n\
@@ -1600,6 +1688,14 @@ Use the \"document\" command to give documentation for the new command.\n\
Commands defined in this way may accept an unlimited number of arguments\n\
accessed via $arg0 .. $argN. $argc tells how many arguments have\n\
been passed."));
+ set_cmd_completer (define_cmd_element, command_completer);
+ c = add_com ("define-prefix", class_support, define_prefix_command,
+ _("\
+Define or mark a command as a user-defined prefix command.\n\
+User defined prefix commands can be used as prefix commands for\n\
+other user defined commands.\n\
+If the command already exists, it is changed to a prefix command."));
+ set_cmd_completer (c, command_completer);
while_cmd_element = add_com ("while", class_support, while_command, _("\
Execute nested commands WHILE the conditional expression is non zero.\n\
@@ -627,6 +627,18 @@ execute_command (const char *p, int from_tty)
/* c->user_commands would be NULL in the case of a python command. */
if (c->theclass == class_user && c->user_commands)
execute_user_command (c, arg);
+ else if (c->theclass == class_user
+ && c->prefixlist && !c->allow_unknown)
+ /* If this is a user defined prefix that does not allow unknown
+ (in other words, C is a prefix command and not a command
+ that can be followed by its args), report the list of
+ subcommands. */
+ {
+ printf_unfiltered
+ ("\"%.*s\" must be followed by the name of a subcommand.\n",
+ (int) strlen (c->prefixname) - 1, c->prefixname);
+ help_list (*c->prefixlist, c->prefixname, all_commands, gdb_stdout);
+ }
else if (c->type == set_cmd)
do_set_command (arg, from_tty, c);
else if (c->type == show_cmd)