gdb: improve command completion for 'print', 'x', and 'display'

The /FMT specification on the print command currently breaks command
completion, so:

  (gdb) p var.<TAB><TAB>
  .... list of fields in var .....

But,

  (gdb) p/d var.<TAB><TAB>
  ..... list of all symbols .....

After this commit this issue is now resolved.

There are some other details around tab-completion and /FMT which
hopefully this commit improves.  So, before:

  (gdb) p/<TAB><TAB>
  .... lists all symbols .....

After:

  (gdb) p/<TAB><TAB>		# Nothing changes...

The thinking here is that after a / the user must type a FMT, but we
don't offer tab completion on FMT characters.  Placing a symbol
directly after a / will not do what the user expects, so offering that
seems wrong.

Similarly, before we had:

  (gdb) p/d<TAB><TAB>
  ... lists all symbols starting with 'd' ....

But afterwards:

  (gdb) p/d<TAB><TAB>		# Adds a single space, so we get:
  (gdb) p/d <CURSOR>

As before, typing a symbol where FMT is expected will not do what the
user expects.  If the user has added a FMT string then upon tab
completion GDB assumes the FMT string is complete and prepares the
user to type an expression.

In this commit I have also added completion functions for the 'x' and
'display' commands.  These commands also support /FMT specifiers and
so share some code with 'print'.

gdb/ChangeLog:

	* printcmd.c: Include 'safe-ctype.c'.
	(skip_over_slash_fmt): New function.
	(print_command_completer): Call skip_over_slash_fmt.
	(display_and_x_command_completer): New function.
	(_initialize_printcmd): Add command completion for 'x' and
	'display'.

gdb/testsuite/ChangeLog:

	* gdb.base/completion.exp: Add new tests.
This commit is contained in:
Andrew Burgess
2020-11-16 11:36:56 +00:00
parent 0bfc584f66
commit 037d7135de
4 changed files with 121 additions and 2 deletions

View File

@ -1,3 +1,12 @@
2020-11-17 Andrew Burgess <andrew.burgess@embecosm.com>
* printcmd.c: Include 'safe-ctype.c'.
(skip_over_slash_fmt): New function.
(print_command_completer): Call skip_over_slash_fmt.
(display_and_x_command_completer): New function.
(_initialize_printcmd): Add command completion for 'x' and
'display'.
2020-11-16 Pedro Alves <pedro@palves.net> 2020-11-16 Pedro Alves <pedro@palves.net>
* frame.c (get_prev_frame): Move get_frame_id call from here ... * frame.c (get_prev_frame): Move get_frame_id call from here ...

View File

@ -53,6 +53,7 @@
#include "source.h" #include "source.h"
#include "gdbsupport/byte-vector.h" #include "gdbsupport/byte-vector.h"
#include "gdbsupport/gdb_optional.h" #include "gdbsupport/gdb_optional.h"
#include "safe-ctype.h"
/* Last specified output format. */ /* Last specified output format. */
@ -1233,6 +1234,62 @@ print_command_1 (const char *args, int voidprint)
print_value (val, print_opts); print_value (val, print_opts);
} }
/* Called from command completion function to skip over /FMT
specifications, allowing the rest of the line to be completed. Returns
true if the /FMT is at the end of the current line and there is nothing
left to complete, otherwise false is returned.
In either case *ARGS can be updated to point after any part of /FMT that
is present.
This function is designed so that trying to complete '/' will offer no
completions, the user needs to insert the format specification
themselves. Trying to complete '/FMT' (where FMT is any non-empty set
of alpha-numeric characters) will cause readline to insert a single
space, setting the user up to enter the expression. */
static bool
skip_over_slash_fmt (completion_tracker &tracker, const char **args)
{
const char *text = *args;
if (text[0] == '/')
{
bool in_fmt;
tracker.set_use_custom_word_point (true);
if (ISALNUM (text[1]) || ISSPACE (text[1]))
{
/* Skip over the actual format specification. */
while (*text != '\0' && !ISSPACE (*text))
++text;
if (*text == '\0')
{
in_fmt = true;
tracker.add_completion (make_unique_xstrdup (text));
}
else
{
in_fmt = false;
while (ISSPACE (*text))
++text;
}
}
else if (text[1] == '\0')
{
in_fmt = true;
++text;
}
tracker.advance_custom_word_point_by (text - *args);
*args = text;
return in_fmt;
}
return false;
}
/* See valprint.h. */ /* See valprint.h. */
void void
@ -1245,6 +1302,9 @@ print_command_completer (struct cmd_list_element *ignore,
(tracker, &text, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER, group)) (tracker, &text, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER, group))
return; return;
if (skip_over_slash_fmt (tracker, &text))
return;
const char *word = advance_to_expression_complete_word_point (tracker, text); const char *word = advance_to_expression_complete_word_point (tracker, text);
expression_completer (ignore, tracker, text, word); expression_completer (ignore, tracker, text, word);
} }
@ -1735,6 +1795,21 @@ x_command (const char *exp, int from_tty)
set_internalvar (lookup_internalvar ("__"), last_examine_value.get ()); set_internalvar (lookup_internalvar ("__"), last_examine_value.get ());
} }
} }
/* Command completion for the 'display' and 'x' commands. */
static void
display_and_x_command_completer (struct cmd_list_element *ignore,
completion_tracker &tracker,
const char *text, const char * /*word*/)
{
if (skip_over_slash_fmt (tracker, &text))
return;
const char *word = advance_to_expression_complete_word_point (tracker, text);
expression_completer (ignore, tracker, text, word);
}
/* Add an expression to the auto-display chain. /* Add an expression to the auto-display chain.
@ -2713,7 +2788,7 @@ Describe what symbol is at location ADDR.\n\
Usage: info symbol ADDR\n\ Usage: info symbol ADDR\n\
Only for symbols with fixed locations (global or static scope).")); Only for symbols with fixed locations (global or static scope)."));
add_com ("x", class_vars, x_command, _("\ c = add_com ("x", class_vars, x_command, _("\
Examine memory: x/FMT ADDRESS.\n\ Examine memory: x/FMT ADDRESS.\n\
ADDRESS is an expression for the memory address to examine.\n\ ADDRESS is an expression for the memory address to examine.\n\
FMT is a repeat count followed by a format letter and a size letter.\n\ FMT is a repeat count followed by a format letter and a size letter.\n\
@ -2727,6 +2802,7 @@ examined backward from the address.\n\n\
Defaults for format and size letters are those previously used.\n\ Defaults for format and size letters are those previously used.\n\
Default count is 1. Default address is following last thing printed\n\ Default count is 1. Default address is following last thing printed\n\
with this command or \"print\".")); with this command or \"print\"."));
set_cmd_completer_handle_brkchars (c, display_and_x_command_completer);
add_info ("display", info_display_command, _("\ add_info ("display", info_display_command, _("\
Expressions to display when program stops, with code numbers.\n\ Expressions to display when program stops, with code numbers.\n\
@ -2741,7 +2817,7 @@ No argument means cancel all automatic-display expressions.\n\
Do \"info display\" to see current list of code numbers."), Do \"info display\" to see current list of code numbers."),
&cmdlist); &cmdlist);
add_com ("display", class_vars, display_command, _("\ c = add_com ("display", class_vars, display_command, _("\
Print value of expression EXP each time the program stops.\n\ Print value of expression EXP each time the program stops.\n\
Usage: display[/FMT] EXP\n\ Usage: display[/FMT] EXP\n\
/FMT may be used before EXP as in the \"print\" command.\n\ /FMT may be used before EXP as in the \"print\" command.\n\
@ -2750,6 +2826,7 @@ as in the \"x\" command, and then EXP is used to get the address to examine\n\
and examining is done as in the \"x\" command.\n\n\ and examining is done as in the \"x\" command.\n\n\
With no argument, display all currently requested auto-display expressions.\n\ With no argument, display all currently requested auto-display expressions.\n\
Use \"undisplay\" to cancel display requests previously made.")); Use \"undisplay\" to cancel display requests previously made."));
set_cmd_completer_handle_brkchars (c, display_and_x_command_completer);
add_cmd ("display", class_vars, enable_display_command, _("\ add_cmd ("display", class_vars, enable_display_command, _("\
Enable some expressions to be displayed when program stops.\n\ Enable some expressions to be displayed when program stops.\n\

View File

@ -1,3 +1,7 @@
2020-11-17 Andrew Burgess <andrew.burgess@embecosm.com>
* gdb.base/completion.exp: Add new tests.
2020-11-16 Tom Tromey <tromey@adacore.com> 2020-11-16 Tom Tromey <tromey@adacore.com>
* gdb.dwarf2/data-loc.exp: Update expected output. Remove C * gdb.dwarf2/data-loc.exp: Update expected output. Remove C

View File

@ -172,6 +172,11 @@ if { ![readline_is_used] } {
return -1 return -1
} }
# The bulk of this test script pre-dates the completion-support
# library, and should probably (where possible) be converted.
# However, for now, new tests are being added using this library.
load_lib completion-support.exp
set test "complete 'hfgfh'" set test "complete 'hfgfh'"
send_gdb "hfgfh\t" send_gdb "hfgfh\t"
gdb_test_multiple "" "$test" { gdb_test_multiple "" "$test" {
@ -922,3 +927,27 @@ gdb_test_multiple "" "$test" {
pass "$test" pass "$test"
} }
} }
# Test completion of 'p', 'x', and 'display' all using a /FMT.
foreach_with_prefix spc { " " "" } {
test_gdb_complete_multiple "p${spc}/d some_union_global." "" "f" {
"f1"
"f2"
}
test_gdb_complete_none "p${spc}/"
test_gdb_complete_unique "p${spc}/d" "p${spc}/d"
test_gdb_complete_unique "x${spc}/1w values\[0\].b"\
"x${spc}/1w values\[0\].b_field"
test_gdb_complete_unique "display${spc}/x values\[0\].z"\
"display${spc}/x values\[0\].z_field"
}
# Test 'p' using both options and /FMT.
test_gdb_complete_multiple "p -array on -- /d some_union_global." \
"" "f" {
"f1"
"f2"
}