From: Andrew Burgess Date: Sat, 12 Apr 2025 08:15:53 +0000 (+0100) Subject: gdb/python/guile: user created prefix commands get help list X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0b5023cc71d3af8b18e10e6599a3f9381bc15265;p=thirdparty%2Fbinutils-gdb.git gdb/python/guile: user created prefix commands get help list Consider GDB's builtin prefix set/show prefix sub-commands, if they are invoked with no sub-command name then they work like this: (gdb) show print print address: Printing of addresses is on. print array: Pretty formatting of arrays is off. print array-indexes: Printing of array indexes is off. print asm-demangle: Demangling of C++/ObjC names in disassembly listings is off. ... cut lots of lines ... (gdb) set print List of set print subcommands: set print address -- Set printing of addresses. set print array -- Set pretty formatting of arrays. set print array-indexes -- Set printing of array indexes. set print asm-demangle -- Set demangling of C++/ObjC names in disassembly listings. ... cut lots of lines ... Type "help set print" followed by set print subcommand name for full documentation. Type "apropos word" to search for commands related to "word". Type "apropos -v word" for full documentation of commands related to "word". Command name abbreviations are allowed if unambiguous. (gdb) That is 'show print' lists the values of all settings under the 'print' prefix, and 'set print' lists the help text for all settings under the 'set print' prefix. Now, if we try to create something similar using the Python API: (gdb) python gdb.ParameterPrefix("my-prefix", gdb.COMMAND_NONE) (gdb) python gdb.Parameter("my-prefix foo", gdb.COMMAND_OBSCURE, gdb.PARAM_BOOLEAN) (gdb) show my-prefix (gdb) set my-prefix Neither 'show my-prefix' or 'set my-prefix' gives us the same details relating to the sub-commands that we get with the builtin prefix commands. This commit aims to address this. Currently, in cmdpy_init, when a new command is created, we always set the commands callback function to cmdpy_function. It is within cmdpy_function that we spot that the command is a prefix command, and that there is no gdb.Command.invoke method, and so return early. This commit changes things so that the rules are now: 1. For NON prefix commands, we continue to use cmdpy_function. 2. For prefix commands that do have a gdb.Command.invoke method (i.e. can handle unknown sub-commands), continue to use cmdpy_function. 3. For all other prefix commands, don't use cmdpy_function, instead use GDB's normal callback function for set/show prefixes. This requires splitting the current call to add_prefix_cmd into either a call to add_prefix_cmd, add_show_prefix_cmd, or add_basic_prefix_cmd, as appropriate. After these changes, we now see this: (gdb) python gdb.ParameterPrefix("my-prefix", gdb.COMMAND_NONE) │ (gdb) python gdb.Parameter("my-prefix foo", gdb.COMMAND_OBSCURE, gdb.PARAM_BOOLEAN) (gdb) show my-prefix │ my-prefix foo: The current value of 'my-prefix foo' is "off". (gdb) set my-prefix List of "set my-prefix" subcommands: set my-prefix foo -- Set the current value of 'my-prefix foo'. Type "help set my-prefix" followed by subcommand name for full documentation. Type "apropos word" to search for commands related to "word". Type "apropos -v word" for full documentation of commands related to "word". Command name abbreviations are allowed if unambiguous. (gdb) Which matches how a prefix defined within GDB would act. I have made the same changes to the Guile API. --- diff --git a/gdb/NEWS b/gdb/NEWS index 970a527a64c..24d00892564 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -150,6 +150,12 @@ info threads [-gid] [-stopped] [-running] [ID]... and 'show' gdb.Command prefixes, suitable for use with new gdb.Parameters. + ** Prefix commands (gdb.Command sub-classes) that don't have an + invoke method will now behave like builtin prefix commands when + invoked without a sub-command name. This means printing the help + text for all sub-commands, unless the prefix command is a 'show' + command, in which case the value of all sub-commands is printed. + * Guile API ** New type for dealing with colors. @@ -162,6 +168,12 @@ info threads [-gid] [-stopped] [-running] [ID]... empty string for make-parameter means GDB will only display the #:set_doc or #:show_doc strings in the set/show help output. + ** Prefix commands (using make-command) that don't have a #:invoke + property will now behave like builtin prefix commands when + invoked without a sub-command name. This means printing the help + text for all sub-commands, unless the prefix command is a 'show' + command, in which case the value of all sub-commands is printed. + * New remote packets binary-upload in qSupported reply diff --git a/gdb/doc/guile.texi b/gdb/doc/guile.texi index 7b3f0a9757b..96772296b03 100644 --- a/gdb/doc/guile.texi +++ b/gdb/doc/guile.texi @@ -1772,6 +1772,16 @@ invoking it interactively. If this function throws an exception, it is turned into a @value{GDBN} @code{error} call. Otherwise, the return value is ignored. +For non-prefix commands, @var{invoke} is required. For prefix +commands @var{invoke} is optional. Only prefix commands that need to +handle unknown sub-commands should supply @var{invoke}. + +For prefix commands that don't supply @var{invoke}, if the prefix +command is used without a sub-command name then @value{GDBN} will +display the help text for every sub-command, unless the prefix command +is a @kbd{show} sub-command, in which case @value{GDBN} will list the +values of all sub-commands. + The argument @var{command-class} is one of the @samp{COMMAND_} constants defined below. This argument tells @value{GDBN} how to categorize the new command in the help system. The default is @code{COMMAND_NONE}. diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi index 7f801ab3f23..8f1da601476 100644 --- a/gdb/doc/python.texi +++ b/gdb/doc/python.texi @@ -4525,6 +4525,7 @@ You can implement new @value{GDBN} CLI commands in Python. A CLI command is implemented using an instance of the @code{gdb.Command} class, most commonly using a subclass. +@anchor{Command.__init__} @defun Command.__init__ (name, command_class @r{[}, completer_class @r{[}, prefix@r{]]}) The object initializer for @code{Command} registers the new command with @value{GDBN}. This initializer is normally invoked from the @@ -4583,6 +4584,17 @@ that the command came from elsewhere. If this method throws an exception, it is turned into a @value{GDBN} @code{error} call. Otherwise, the return value is ignored. +For non-prefix commands (@pxref{Command.__init__}), the @code{invoke} +method is required. For prefix commands the @code{invoke} method is +optional. Only prefix commands that need to handle unknown +sub-commands should implement the @code{invoke} method. + +For prefix commands that don't implement @code{invoke}, if the prefix +command is used without a sub-command name then @value{GDBN} will +display the help text for every sub-command, unless the prefix command +is a @kbd{show} sub-command, in which case @value{GDBN} will list the +values of all sub-commands. + @findex gdb.string_to_argv To break @var{argument} up into an argv-like string use @code{gdb.string_to_argv}. This function behaves identically to diff --git a/gdb/guile/scm-cmd.c b/gdb/guile/scm-cmd.c index 453394ccb19..565d58890b8 100644 --- a/gdb/guile/scm-cmd.c +++ b/gdb/guile/scm-cmd.c @@ -753,18 +753,47 @@ gdbscm_register_command_x (SCM self) { if (c_smob->is_prefix) { - /* If we have our own "invoke" method, then allow unknown - sub-commands. */ - int allow_unknown = gdbscm_is_true (c_smob->invoke); + bool has_invoke = gdbscm_is_true (c_smob->invoke) == 1; - cmd = add_prefix_cmd (c_smob->cmd_name, c_smob->cmd_class, - NULL, c_smob->doc, &c_smob->sub_list, - allow_unknown, cmd_list); + if (has_invoke) + { + cmd = add_prefix_cmd (c_smob->cmd_name, c_smob->cmd_class, + NULL, c_smob->doc, &c_smob->sub_list, + 1 /* allow_unknown */, cmd_list); + cmd->func = cmdscm_function; + } + else + { + /* If there is no 'invoke' method, then create the prefix + using the standard prefix callbacks. This means that for + 'set prefix' the user will get the help text listing all + of the sub-commands, and for 'show prefix', the user will + see all of the sub-command values. */ + cmd_list_element *first = *cmd_list; + while (first->prefix != nullptr) + first = first->prefix; + + bool is_show = first->subcommands == &showlist; + + if (is_show) + cmd = add_show_prefix_cmd (c_smob->cmd_name, + c_smob->cmd_class, + c_smob->doc, + &c_smob->sub_list, + 0 /* allow_unknown */, cmd_list); + else + cmd = add_basic_prefix_cmd (c_smob->cmd_name, + c_smob->cmd_class, + c_smob->doc, + &c_smob->sub_list, + 0 /* allow_unknown */, cmd_list); + } } else { cmd = add_cmd (c_smob->cmd_name, c_smob->cmd_class, c_smob->doc, cmd_list); + cmd->func = cmdscm_function; } } catch (const gdb_exception &except) @@ -777,7 +806,6 @@ gdbscm_register_command_x (SCM self) So no more errors after this point. */ /* There appears to be no API to set this. */ - cmd->func = cmdscm_function; cmd->destroyer = cmdscm_destroyer; c_smob->command = cmd; diff --git a/gdb/python/py-cmd.c b/gdb/python/py-cmd.c index c53138a525f..5b4f8138aea 100644 --- a/gdb/python/py-cmd.c +++ b/gdb/python/py-cmd.c @@ -105,19 +105,17 @@ cmdpy_function (const char *args, int from_tty, cmd_list_element *command) gdbpy_enter enter_py; - if (! obj) + if (obj == nullptr) error (_("Invalid invocation of Python command object.")); - if (! PyObject_HasAttr ((PyObject *) obj, invoke_cst)) - { - if (obj->command->is_prefix ()) - { - /* A prefix command does not need an invoke method. */ - return; - } - error (_("Python command object missing 'invoke' method.")); - } - if (! args) + /* If we get here for a prefix command then the prefix command had an + 'invoke' method when it was created. If the 'invoke' method is now + missing, then the user has done something weird (like deleting the + invoke method, yuck!). */ + if (!PyObject_HasAttr ((PyObject *) obj, invoke_cst)) + error (_("Python command object missing 'invoke' method.")); + + if (args == nullptr) args = ""; gdbpy_ref<> argobj (PyUnicode_Decode (args, strlen (args), host_charset (), NULL)); @@ -507,26 +505,61 @@ cmdpy_init (PyObject *self, PyObject *args, PyObject *kw) if (is_prefix) { - int allow_unknown; - - /* If we have our own "invoke" method, then allow unknown - sub-commands. */ - allow_unknown = PyObject_HasAttr (self, invoke_cst); - cmd = add_prefix_cmd (cmd_name.get (), - (enum command_class) cmdtype, - NULL, docstring.release (), &obj->sub_list, - allow_unknown, cmd_list); + bool has_invoke = PyObject_HasAttr (self, invoke_cst) == 1; + if (has_invoke) + { + /* If there's an 'invoke' method, then create the prefix + command, but call cmdpy_function to dispatch to the invoke + method when the user runs the prefix with no sub-command. */ + cmd = add_prefix_cmd (cmd_name.get (), + (enum command_class) cmdtype, + nullptr, + docstring.release (), &obj->sub_list, + 1 /* allow_unknown */, cmd_list); + cmd->func = cmdpy_function; + } + else + { + /* If there is no 'invoke' method, then create the prefix + using the standard prefix callbacks. This means that for + 'set prefix' the user will get the help text listing all + of the sub-commands, and for 'show prefix', the user will + see all of the sub-command values. */ + cmd_list_element *first = *cmd_list; + while (first->prefix != nullptr) + first = first->prefix; + + bool is_show = first->subcommands == &showlist; + + if (is_show) + cmd = add_show_prefix_cmd (cmd_name.get (), + (enum command_class) cmdtype, + docstring.release (), + &obj->sub_list, + 0 /* allow_unknown */, cmd_list); + else + cmd = add_basic_prefix_cmd (cmd_name.get (), + (enum command_class) cmdtype, + docstring.release (), + &obj->sub_list, + 0 /* allow_unknown */, cmd_list); + } } else - cmd = add_cmd (cmd_name.get (), (enum command_class) cmdtype, - docstring.release (), cmd_list); + { + /* For non-prefix commands, arrange to call cmdpy_function, which + invokes the Python 'invoke' method, or raises an exception if + the 'invoke' method is missing. */ + cmd = add_cmd (cmd_name.get (), (enum command_class) cmdtype, + docstring.release (), cmd_list); + cmd->func = cmdpy_function; + } /* If successful, the above takes ownership of the name, since we set name_allocated, so release it. */ cmd_name.release (); - /* There appears to be no API to set this. */ - cmd->func = cmdpy_function; + /* There appears to be no API to set these member variables. */ cmd->destroyer = cmdpy_destroyer; cmd->doc_allocated = 1; cmd->name_allocated = 1; diff --git a/gdb/testsuite/gdb.guile/scm-parameter.exp b/gdb/testsuite/gdb.guile/scm-parameter.exp index 06eebddf242..bf0d7df5f26 100644 --- a/gdb/testsuite/gdb.guile/scm-parameter.exp +++ b/gdb/testsuite/gdb.guile/scm-parameter.exp @@ -478,6 +478,79 @@ with_test_prefix "empty doc string" { gdb_test "help show empty-doc-string" "^Show doc string\\." } +with_test_prefix "set/show parameter" { + # This first set/show prefix command doesn't have an invoke + # method. As such, GDB installs the default invoke behaviour; set + # prints the full list of sub-commands, and show prints all the + # sub-command values. + gdb_test_multiline "Setup set/show parameter prefix with no invoke" \ + "guile" "" \ + "(register-command! (make-command \"set test-prefix\"" "" \ + " #:prefix? #t" "" \ + " #:command-class COMMAND_NONE))" ""\ + "(register-command! (make-command \"show test-prefix\"" "" \ + " #:prefix? #t" "" \ + " #:command-class COMMAND_NONE))" ""\ + "(register-parameter! (make-parameter \"test-prefix param-1\"" "" \ + " #:command-class COMMAND_NONE" "" \ + " #:parameter-type PARAM_BOOLEAN))" "" \ + "(register-parameter! (make-parameter \"test-prefix param-2\"" "" \ + " #:command-class COMMAND_NONE" "" \ + " #:parameter-type PARAM_UINTEGER))" "" \ + "(register-parameter! (make-parameter \"test-prefix param-3\"" "" \ + " #:command-class COMMAND_NONE" "" \ + " #:parameter-type PARAM_STRING))" "" \ + "end" "" + + gdb_test "set test-prefix" \ + [multi_line \ + "List of \"set test-prefix\" subcommands:" \ + "" \ + "set test-prefix param-1 -- Set the current value of 'test-prefix param-1'." \ + "set test-prefix param-2 -- Set the current value of 'test-prefix param-2'." \ + "set test-prefix param-3 -- Set the current value of 'test-prefix param-3'." \ + "" \ + "Type \"help set test-prefix\" followed by subcommand name for full documentation\\." \ + "Type \"apropos word\" to search for commands related to \"word\"\\." \ + "Type \"apropos -v word\" for full documentation of commands related to \"word\"\\." \ + "Command name abbreviations are allowed if unambiguous\\."] + + gdb_test "show test-prefix" \ + [multi_line \ + "test-prefix param-1: The current value of 'test-prefix param-1' is off\\." \ + "test-prefix param-2: The current value of 'test-prefix param-2' is 0\\." \ + "test-prefix param-3: The current value of 'test-prefix param-3' is \"\"\\."] + + # This next set/show prefix has an invoke method, which will be + # called instead of the default behaviour tested above. + gdb_test_multiline "Setup set/show parameter prefix with invoke" \ + "guile" "" \ + "(register-command! (make-command \"set test-prefix-2\"" "" \ + " #:prefix? #t" "" \ + " #:command-class COMMAND_NONE" ""\ + " #:invoke (lambda (self arg from-tty)" "" \ + " (display \"invoke -- set\\n\"))))" "" \ + "(register-command! (make-command \"show test-prefix-2\"" "" \ + " #:prefix? #t" "" \ + " #:command-class COMMAND_NONE" ""\ + " #:invoke (lambda (self arg from-tty)" "" \ + " (display \"invoke -- show\\n\"))))" "" \ + "(register-parameter! (make-parameter \"test-prefix-2 param-1\"" "" \ + " #:command-class COMMAND_NONE" "" \ + " #:parameter-type PARAM_BOOLEAN))" "" \ + "(register-parameter! (make-parameter \"test-prefix-2 param-2\"" "" \ + " #:command-class COMMAND_NONE" "" \ + " #:parameter-type PARAM_UINTEGER))" "" \ + "(register-parameter! (make-parameter \"test-prefix-2 param-3\"" "" \ + " #:command-class COMMAND_NONE" "" \ + " #:parameter-type PARAM_STRING))" "" \ + "end" "" + + gdb_test "set test-prefix-2" "^invoke -- set" + + gdb_test "show test-prefix-2" "^invoke -- show" +} + rename scm_param_test_maybe_no_output "" # Test a color parameter. diff --git a/gdb/testsuite/gdb.python/py-cmd.exp b/gdb/testsuite/gdb.python/py-cmd.exp index 5ed52a2fc67..5ac57122f99 100644 --- a/gdb/testsuite/gdb.python/py-cmd.exp +++ b/gdb/testsuite/gdb.python/py-cmd.exp @@ -354,5 +354,63 @@ proc_with_prefix test_unknown_prefix {} { } } +# Check what happens if a command object is called without an 'invoke' +# method. +proc_with_prefix test_deleting_invoke_methods {} { + clean_restart + + gdb_test_multiline "create 'foo' prefix command" \ + "python" "" \ + "class test_prefix(gdb.Command):" "" \ + " def __init__ (self):" "" \ + " super().__init__ (\"foo\", gdb.COMMAND_USER, prefix=True)" "" \ + " def invoke (self, arg, from_tty):" "" \ + " print(\"In 'foo' invoke: %s\" % arg)" "" \ + "foo = test_prefix()" "" \ + "end" "" + + gdb_test_multiline "create 'foo bar' command" \ + "python" "" \ + "class test_cmd(gdb.Command):" "" \ + " def __init__ (self):" "" \ + " super().__init__ (\"foo bar\", gdb.COMMAND_USER)" "" \ + " def invoke (self, arg, from_tty):" "" \ + " print(\"In 'foo bar' invoke: %s\" % arg)" "" \ + "foo_bar = test_cmd()" "" \ + "end" "" + + gdb_test "foo def" "In 'foo' invoke: def" \ + "call 'foo' with an unknown sub-command" + + gdb_test "foo bar def" "In 'foo bar' invoke: def" \ + "call 'foo bar' with arguments" + + gdb_test_no_output "python del(foo_bar.__class__.invoke)" \ + "delete invoke from test_cmd class" + + with_test_prefix "after deleting test_cmd.invoke" { + gdb_test "foo def" "In 'foo' invoke: def" \ + "call 'foo' with an unknown sub-command" + + gdb_test "foo bar def" \ + "^Python command object missing 'invoke' method\\." \ + "call 'foo bar' with arguments" + } + + gdb_test_no_output "python del(foo.__class__.invoke)" \ + "delete invoke from test_prefix class" + + with_test_prefix "after deleting test_prefix.invoke" { + gdb_test "foo def" \ + "^Python command object missing 'invoke' method\\." \ + "call 'foo' with an unknown sub-command" + + gdb_test "foo bar def" \ + "^Python command object missing 'invoke' method\\." \ + "call 'foo bar' with arguments" + } +} + test_command_redefining_itself test_unknown_prefix +test_deleting_invoke_methods diff --git a/gdb/testsuite/gdb.python/py-parameter-prefix.exp b/gdb/testsuite/gdb.python/py-parameter-prefix.exp index aa2f84a099a..69cbb90ab21 100644 --- a/gdb/testsuite/gdb.python/py-parameter-prefix.exp +++ b/gdb/testsuite/gdb.python/py-parameter-prefix.exp @@ -23,25 +23,26 @@ require allow_python_tests clean_restart -# Helper proc to generate the output of 'help MODE PREFIX', where MODE -# will be either 'set' or 'show'. The HELP_TEXT is the expected help -# text for this prefix command, this should not be a regexp, as this -# proc converts the text to a regexp. -# -# Return a single regexp which should match the output. -proc make_help_re { mode prefix help_text } { +# Helper proc to generate the output of 'show PREFIX' commands for the +# case where the prefix command doesn't handle unknown sub-commands. +# In this case GDB will list the value of every sub-command under +# PREFIX. +proc make_show_prefix_re { prefix } { + return "$prefix param-1:\\s+The current value of '$prefix param-1' is \"off\"\\." +} + +# Helper proc to generate the help text that describes all of the sub +# commands under PREFIX. The MODE is either 'set' or 'show'. This +# output will appear for 'help MODE PREFIX' and also for 'set PREFIX'. +proc make_sub_cmd_help_re { mode prefix } { if { $mode == "set" } { set word "Set" } else { set word "Show" } - set help_re [string_to_regexp $help_text] - return \ [multi_line \ - "$help_re" \ - "" \ "List of \"$mode $prefix\" subcommands:" \ "" \ "$mode $prefix param-1 -- $word the current value of '$prefix param-1'\\." \ @@ -52,6 +53,22 @@ proc make_help_re { mode prefix help_text } { "Command name abbreviations are allowed if unambiguous\\."] } +# Helper proc to generate the output of 'help MODE PREFIX', where MODE +# will be either 'set' or 'show'. The HELP_TEXT is the expected help +# text for this prefix command, this should not be a regexp, as this +# proc converts the text to a regexp. +# +# Return a single regexp which should match the output. +proc make_help_re { mode prefix help_text } { + set help_re [string_to_regexp $help_text] + + return \ + [multi_line \ + "$help_re" \ + "" \ + [make_sub_cmd_help_re $mode $prefix]] +} + # Create gdb.ParameterPrefix without using a sub-class, both with, and # without a doc string. For the doc string case, test single line, # and multi-line doc strings. @@ -92,6 +109,14 @@ proc_with_prefix test_basic_usage {} { "^Undefined $mode $prefix command: \"xxx\"\\. Try \"help $mode $prefix\"\\." } } + + foreach prefix { prefix-1 prefix-2 prefix-3 } { + gdb_test "set $prefix" \ + [make_sub_cmd_help_re "set" $prefix] + + gdb_test "show $prefix" \ + [make_show_prefix_re $prefix] + } } # Create a sub-class of gdb.ParameterPrefix, but don't do anything @@ -153,6 +178,14 @@ proc_with_prefix test_simple_sub_class {} { "^Undefined $mode $prefix command: \"xxx\"\\. Try \"help $mode $prefix\"\\." } } + + foreach prefix { prefix-4 prefix-5 prefix-6 prefix-7 } { + gdb_test "set $prefix" \ + [make_sub_cmd_help_re "set" $prefix] + + gdb_test "show $prefix" \ + [make_show_prefix_re $prefix] + } } # Create a sub-class of gdb.ParameterPrefix, and make use of @@ -220,6 +253,24 @@ proc_with_prefix test_prefix_with_invoke {} { send_gdb "\n" gdb_test "" "^\r\ninvoke_show \\(d\\): \"xxx yyy\" True" \ "repeat show prefix-10 xxx yyy" + + gdb_test "set prefix-8" \ + "^invoke_set \\(a\\): \"\" True" + + gdb_test "show prefix-8" \ + [make_show_prefix_re "prefix-8"] + + gdb_test "set prefix-9" \ + [make_sub_cmd_help_re "set" "prefix-9"] + + gdb_test "show prefix-9" \ + "^invoke_show \\(b\\): \"\" True" + + gdb_test "set prefix-10" \ + "^invoke_set \\(c\\): \"\" True" + + gdb_test "show prefix-10" \ + "^invoke_show \\(d\\): \"\" True" } # Create ParameterPrefix sub-classes that make use of the diff --git a/gdb/testsuite/gdb.python/py-parameter.exp b/gdb/testsuite/gdb.python/py-parameter.exp index 2ca56dc83fc..214c570724a 100644 --- a/gdb/testsuite/gdb.python/py-parameter.exp +++ b/gdb/testsuite/gdb.python/py-parameter.exp @@ -793,6 +793,67 @@ proc_with_prefix test_unknown_prefix {} { } } +# Test the default behaviour of a set/show parameter prefix command. +proc_with_prefix test_set_show_parameters {} { + # This first set/show prefix command doesn't have an invoke + # method. As such, GDB installs the default invoke behaviour; set + # prints the full list of sub-commands, and show prints all the + # sub-command values. + gdb_test_multiline "Setup set/show parameter prefix with no invoke" \ + "python" "" \ + "class TestParamPrefix(gdb.Command):" "" \ + " \"\"\"TestParamPrefix documentation string.\"\"\"" "" \ + " def __init__(self, name):" "" \ + " super().__init__(name, gdb.COMMAND_NONE, prefix = True)" "" \ + "TestParamPrefix('set test-prefix')" "" \ + "TestParamPrefix('show test-prefix')" "" \ + "gdb.Parameter('test-prefix param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + "gdb.Parameter('test-prefix param-2', gdb.COMMAND_NONE, gdb.PARAM_INTEGER)" "" \ + "gdb.Parameter('test-prefix param-3', gdb.COMMAND_NONE, gdb.PARAM_STRING)" "" \ + "end" + + gdb_test "set test-prefix" \ + [multi_line \ + "List of \"set test-prefix\" subcommands:" \ + "" \ + "set test-prefix param-1 -- Set the current value of 'test-prefix param-1'." \ + "set test-prefix param-2 -- Set the current value of 'test-prefix param-2'." \ + "set test-prefix param-3 -- Set the current value of 'test-prefix param-3'." \ + "" \ + "Type \"help set test-prefix\" followed by subcommand name for full documentation\\." \ + "Type \"apropos word\" to search for commands related to \"word\"\\." \ + "Type \"apropos -v word\" for full documentation of commands related to \"word\"\\." \ + "Command name abbreviations are allowed if unambiguous\\."] + + gdb_test "show test-prefix" \ + [multi_line \ + "test-prefix param-1: The current value of 'test-prefix param-1' is \"off\"\\." \ + "test-prefix param-2: The current value of 'test-prefix param-2' is \"0\"\\." \ + "test-prefix param-3: The current value of 'test-prefix param-3' is \"\"\\."] + + # This next set/show prefix has an invoke method, which will be + # called instead of the default behaviour tested above. + gdb_test_multiline "Setup set/show parameter prefix with invoke" \ + "python" "" \ + "class TestParamPrefix(gdb.Command):" "" \ + " \"\"\"TestParamPrefix documentation string.\"\"\"" "" \ + " def __init__(self, name, mode):" "" \ + " self._mode = mode" "" \ + " super().__init__(self._mode + ' ' + name, gdb.COMMAND_NONE, prefix = True)" "" \ + " def invoke(self, args, from_tty):" "" \ + " print('invoke -- ' + self._mode)" "" \ + "TestParamPrefix('test-prefix-2', 'set')" "" \ + "TestParamPrefix('test-prefix-2', 'show')" "" \ + "gdb.Parameter('test-prefix-2 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + "gdb.Parameter('test-prefix-2 param-2', gdb.COMMAND_NONE, gdb.PARAM_INTEGER)" "" \ + "gdb.Parameter('test-prefix-2 param-3', gdb.COMMAND_NONE, gdb.PARAM_STRING)" "" \ + "end" + + gdb_test "set test-prefix-2" "^invoke -- set" + + gdb_test "show test-prefix-2" "^invoke -- show" +} + test_directories test_data_directory test_boolean_parameter @@ -810,5 +871,6 @@ test_throwing_parameter test_language test_ambiguous_parameter test_unknown_prefix +test_set_show_parameters rename py_param_test_maybe_no_output ""