mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-02-17 13:10:12 +08:00
Add max-completions parameter, and implement tab-completion limiting.
This commit adds a new exception, MAX_COMPLETIONS_REACHED_ERROR, to be thrown whenever the completer has generated too many candidates to be useful. A new user-settable variable, "max_completions", is added to control this behaviour. A top-level completion limit is added to complete_line_internal, as the final check to ensure the user never sees too many completions. An additional limit is added to default_make_symbol_completion_list_break_on, to halt time-consuming symbol table expansions. gdb/ChangeLog: PR cli/9007 PR cli/11920 PR cli/15548 * cli/cli-cmds.c (complete_command): Notify user if max-completions reached. * common/common-exceptions.h (enum errors) <MAX_COMPLETIONS_REACHED_ERROR>: New value. * completer.h (get_max_completions_reached_message): New declaration. (max_completions): Likewise. (completion_tracker_t): New typedef. (new_completion_tracker): New declaration. (make_cleanup_free_completion_tracker): Likewise. (maybe_add_completion_enum): New enum. (maybe_add_completion): New declaration. (throw_max_completions_reached_error): Likewise. * completer.c (max_completions): New global variable. (new_completion_tracker): New function. (free_completion_tracker): Likewise. (make_cleanup_free_completion_tracker): Likewise. (maybe_add_completions): Likewise. (throw_max_completions_reached_error): Likewise. (complete_line): Remove duplicates and limit result to max_completions entries. (get_max_completions_reached_message): New function. (gdb_display_match_list): Handle max_completions. (_initialize_completer): New declaration and function. * symtab.c: Include completer.h. (completion_tracker): New static variable. (completion_list_add_name): Call maybe_add_completion. (default_make_symbol_completion_list_break_on_1): Renamed from default_make_symbol_completion_list_break_on. Maintain completion_tracker across calls to completion_list_add_name. (default_make_symbol_completion_list_break_on): New function. * top.c (init_main): Set rl_completion_display_matches_hook. * tui/tui-io.c: Include completer.h. (tui_old_rl_display_matches_hook): New static global. (tui_rl_display_match_list): Notify user if max-completions reached. (tui_setup_io): Save/restore rl_completion_display_matches_hook. * NEWS (New Options): Mention set/show max-completions. gdb/doc/ChangeLog: * gdb.texinfo (Command Completion): Document new "set/show max-completions" option. gdb/testsuite/ChangeLog: * gdb.base/completion.exp: Disable completion limiting for existing tests. Add new tests to check completion limiting. * gdb.linespec/ls-errs.exp: Disable completion limiting.
This commit is contained in:
parent
e11c72c7e4
commit
ef0b411a11
7
gdb/NEWS
7
gdb/NEWS
@ -26,6 +26,13 @@ maint flush-symbol-cache
|
||||
|
||||
* New options
|
||||
|
||||
set max-completions
|
||||
show max-completions
|
||||
Set the maximum number of candidates to be considered during
|
||||
completion. The default value is 200. This limit allows GDB
|
||||
to avoid generating large completion lists, the computation of
|
||||
which can cause the debugger to become temporarily unresponsive.
|
||||
|
||||
maint set symbol-cache-size
|
||||
maint show symbol-cache-size
|
||||
Control the size of the symbol cache.
|
||||
|
@ -236,7 +236,8 @@ help_command (char *command, int from_tty)
|
||||
help_cmd (command, gdb_stdout);
|
||||
}
|
||||
|
||||
/* The "complete" command is used by Emacs to implement completion. */
|
||||
/* Note: The "complete" command is used by Emacs to implement completion.
|
||||
[Is that why this function writes output with *_unfiltered?] */
|
||||
|
||||
static void
|
||||
complete_command (char *arg, int from_tty)
|
||||
@ -247,6 +248,18 @@ complete_command (char *arg, int from_tty)
|
||||
|
||||
dont_repeat ();
|
||||
|
||||
if (max_completions == 0)
|
||||
{
|
||||
/* Only print this for non-mi frontends. An MI frontend may not
|
||||
be able to handle this. */
|
||||
if (!ui_out_is_mi_like_p (current_uiout))
|
||||
{
|
||||
printf_unfiltered (_("max-completions is zero,"
|
||||
" completion is disabled.\n"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (arg == NULL)
|
||||
arg = "";
|
||||
argpoint = strlen (arg);
|
||||
@ -293,6 +306,15 @@ complete_command (char *arg, int from_tty)
|
||||
|
||||
xfree (prev);
|
||||
VEC_free (char_ptr, completions);
|
||||
|
||||
if (size == max_completions)
|
||||
{
|
||||
/* ARG_PREFIX and POINT are included in the output so that emacs
|
||||
will include the message in the output. */
|
||||
printf_unfiltered (_("%s%s %s\n"),
|
||||
arg_prefix, point,
|
||||
get_max_completions_reached_message ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,6 +99,12 @@ enum errors {
|
||||
/* Requested feature, method, mechanism, etc. is not supported. */
|
||||
NOT_SUPPORTED_ERROR,
|
||||
|
||||
/* The number of candidates generated during line completion has
|
||||
reached the user's specified limit. This isn't an error, this exception
|
||||
is used to halt searching for more completions, but for consistency
|
||||
"_ERROR" is appended to the name. */
|
||||
MAX_COMPLETIONS_REACHED_ERROR,
|
||||
|
||||
/* Add more errors here. */
|
||||
NR_ERRORS
|
||||
};
|
||||
|
201
gdb/completer.c
201
gdb/completer.c
@ -781,9 +781,93 @@ complete_line_internal (const char *text,
|
||||
|
||||
return list;
|
||||
}
|
||||
/* Generate completions all at once. Returns a vector of strings.
|
||||
Each element is allocated with xmalloc. It can also return NULL if
|
||||
there are no completions.
|
||||
|
||||
/* See completer.h. */
|
||||
|
||||
int max_completions = 200;
|
||||
|
||||
/* See completer.h. */
|
||||
|
||||
completion_tracker_t
|
||||
new_completion_tracker (void)
|
||||
{
|
||||
if (max_completions <= 0)
|
||||
return NULL;
|
||||
|
||||
return htab_create_alloc (max_completions,
|
||||
htab_hash_string, (htab_eq) streq,
|
||||
NULL, xcalloc, xfree);
|
||||
}
|
||||
|
||||
/* Cleanup routine to free a completion tracker and reset the pointer
|
||||
to NULL. */
|
||||
|
||||
static void
|
||||
free_completion_tracker (void *p)
|
||||
{
|
||||
completion_tracker_t *tracker_ptr = p;
|
||||
|
||||
htab_delete (*tracker_ptr);
|
||||
*tracker_ptr = NULL;
|
||||
}
|
||||
|
||||
/* See completer.h. */
|
||||
|
||||
struct cleanup *
|
||||
make_cleanup_free_completion_tracker (completion_tracker_t *tracker_ptr)
|
||||
{
|
||||
if (*tracker_ptr == NULL)
|
||||
return make_cleanup (null_cleanup, NULL);
|
||||
|
||||
return make_cleanup (free_completion_tracker, tracker_ptr);
|
||||
}
|
||||
|
||||
/* See completer.h. */
|
||||
|
||||
enum maybe_add_completion_enum
|
||||
maybe_add_completion (completion_tracker_t tracker, char *name)
|
||||
{
|
||||
void **slot;
|
||||
|
||||
if (max_completions < 0)
|
||||
return MAYBE_ADD_COMPLETION_OK;
|
||||
if (max_completions == 0)
|
||||
return MAYBE_ADD_COMPLETION_MAX_REACHED;
|
||||
|
||||
gdb_assert (tracker != NULL);
|
||||
|
||||
if (htab_elements (tracker) >= max_completions)
|
||||
return MAYBE_ADD_COMPLETION_MAX_REACHED;
|
||||
|
||||
slot = htab_find_slot (tracker, name, INSERT);
|
||||
|
||||
if (*slot != HTAB_EMPTY_ENTRY)
|
||||
return MAYBE_ADD_COMPLETION_DUPLICATE;
|
||||
|
||||
*slot = name;
|
||||
|
||||
return (htab_elements (tracker) < max_completions
|
||||
? MAYBE_ADD_COMPLETION_OK
|
||||
: MAYBE_ADD_COMPLETION_OK_MAX_REACHED);
|
||||
}
|
||||
|
||||
void
|
||||
throw_max_completions_reached_error (void)
|
||||
{
|
||||
throw_error (MAX_COMPLETIONS_REACHED_ERROR, _("Max completions reached."));
|
||||
}
|
||||
|
||||
/* Generate completions all at once. Returns a vector of unique strings
|
||||
allocated with xmalloc. Returns NULL if there are no completions
|
||||
or if max_completions is 0. If max_completions is non-negative, this will
|
||||
return at most max_completions + 1 strings.
|
||||
|
||||
If max_completions strings are collected, an extra string is added which
|
||||
is a text message to inform the user that the list may be truncated.
|
||||
This extra string serves two purposes:
|
||||
1) Inform the user.
|
||||
2) Prevent readline from being able to find a common prefix to advance
|
||||
point to, since it's working with an incomplete list.
|
||||
|
||||
TEXT is the caller's idea of the "word" we are looking at.
|
||||
|
||||
@ -796,8 +880,58 @@ complete_line_internal (const char *text,
|
||||
VEC (char_ptr) *
|
||||
complete_line (const char *text, const char *line_buffer, int point)
|
||||
{
|
||||
return complete_line_internal (text, line_buffer,
|
||||
point, handle_completions);
|
||||
VEC (char_ptr) *list;
|
||||
VEC (char_ptr) *result = NULL;
|
||||
struct cleanup *cleanups;
|
||||
completion_tracker_t tracker;
|
||||
char *candidate;
|
||||
int ix, max_reached;
|
||||
|
||||
if (max_completions == 0)
|
||||
return NULL;
|
||||
list = complete_line_internal (text, line_buffer, point,
|
||||
handle_completions);
|
||||
if (max_completions < 0)
|
||||
return list;
|
||||
|
||||
tracker = new_completion_tracker ();
|
||||
cleanups = make_cleanup_free_completion_tracker (&tracker);
|
||||
make_cleanup_free_char_ptr_vec (list);
|
||||
|
||||
/* Do a final test for too many completions. Individual completers may
|
||||
do some of this, but are not required to. Duplicates are also removed
|
||||
here. Otherwise the user is left scratching his/her head: readline and
|
||||
complete_command will remove duplicates, and if removal of duplicates
|
||||
there brings the total under max_completions the user may think gdb quit
|
||||
searching too early. */
|
||||
|
||||
for (ix = 0, max_reached = 0;
|
||||
!max_reached && VEC_iterate (char_ptr, list, ix, candidate);
|
||||
++ix)
|
||||
{
|
||||
enum maybe_add_completion_enum add_status;
|
||||
|
||||
add_status = maybe_add_completion (tracker, candidate);
|
||||
|
||||
switch (add_status)
|
||||
{
|
||||
case MAYBE_ADD_COMPLETION_OK:
|
||||
VEC_safe_push (char_ptr, result, xstrdup (candidate));
|
||||
break;
|
||||
case MAYBE_ADD_COMPLETION_OK_MAX_REACHED:
|
||||
VEC_safe_push (char_ptr, result, xstrdup (candidate));
|
||||
max_reached = 1;
|
||||
break;
|
||||
case MAYBE_ADD_COMPLETION_MAX_REACHED:
|
||||
gdb_assert_not_reached ("more than max completions reached");
|
||||
case MAYBE_ADD_COMPLETION_DUPLICATE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
do_cleanups (cleanups);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Complete on command names. Used by "help". */
|
||||
@ -1020,6 +1154,15 @@ skip_quoted (const char *str)
|
||||
{
|
||||
return skip_quoted_chars (str, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Return a message indicating that the maximum number of completions
|
||||
has been reached and that there may be more. */
|
||||
|
||||
const char *
|
||||
get_max_completions_reached_message (void)
|
||||
{
|
||||
return _("*** List may be truncated, max-completions reached. ***");
|
||||
}
|
||||
|
||||
/* GDB replacement for rl_display_match_list.
|
||||
Readline doesn't provide a clean interface for TUI(curses).
|
||||
@ -1413,9 +1556,10 @@ gdb_complete_get_screenwidth (const struct match_list_displayer *displayer)
|
||||
}
|
||||
|
||||
/* GDB version of readline/complete.c:rl_display_match_list.
|
||||
See gdb_display_match_list for a description of MATCHES, LEN, MAX. */
|
||||
See gdb_display_match_list for a description of MATCHES, LEN, MAX.
|
||||
Returns non-zero if all matches are displayed. */
|
||||
|
||||
static void
|
||||
static int
|
||||
gdb_display_match_list_1 (char **matches, int len, int max,
|
||||
const struct match_list_displayer *displayer)
|
||||
{
|
||||
@ -1501,7 +1645,7 @@ gdb_display_match_list_1 (char **matches, int len, int max,
|
||||
{
|
||||
lines = gdb_display_match_list_pager (lines, displayer);
|
||||
if (lines < 0)
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1523,7 +1667,7 @@ gdb_display_match_list_1 (char **matches, int len, int max,
|
||||
{
|
||||
lines = gdb_display_match_list_pager (lines, displayer);
|
||||
if (lines < 0)
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1533,6 +1677,8 @@ gdb_display_match_list_1 (char **matches, int len, int max,
|
||||
}
|
||||
displayer->crlf (displayer);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Utility for displaying completion list matches, used by both CLI and TUI.
|
||||
@ -1545,6 +1691,13 @@ void
|
||||
gdb_display_match_list (char **matches, int len, int max,
|
||||
const struct match_list_displayer *displayer)
|
||||
{
|
||||
/* Readline will never call this if complete_line returned NULL. */
|
||||
gdb_assert (max_completions != 0);
|
||||
|
||||
/* complete_line will never return more than this. */
|
||||
if (max_completions > 0)
|
||||
gdb_assert (len <= max_completions);
|
||||
|
||||
if (rl_completion_query_items > 0 && len >= rl_completion_query_items)
|
||||
{
|
||||
char msg[100];
|
||||
@ -1567,5 +1720,33 @@ gdb_display_match_list (char **matches, int len, int max,
|
||||
}
|
||||
}
|
||||
|
||||
gdb_display_match_list_1 (matches, len, max, displayer);
|
||||
if (gdb_display_match_list_1 (matches, len, max, displayer))
|
||||
{
|
||||
/* Note: MAX_COMPLETIONS may be -1 or zero, but LEN is always > 0. */
|
||||
if (len == max_completions)
|
||||
{
|
||||
/* The maximum number of completions has been reached. Warn the user
|
||||
that there may be more. */
|
||||
const char *message = get_max_completions_reached_message ();
|
||||
|
||||
displayer->puts (displayer, message);
|
||||
displayer->crlf (displayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern initialize_file_ftype _initialize_completer; /* -Wmissing-prototypes */
|
||||
|
||||
void
|
||||
_initialize_completer (void)
|
||||
{
|
||||
add_setshow_zuinteger_unlimited_cmd ("max-completions", no_class,
|
||||
&max_completions, _("\
|
||||
Set maximum number of completion candidates."), _("\
|
||||
Show maximum number of completion candidates."), _("\
|
||||
Use this to limit the number of candidates considered\n\
|
||||
during completion. Specifying \"unlimited\" or -1\n\
|
||||
disables limiting. Note that setting either no limit or\n\
|
||||
a very large limit can make completion slow."),
|
||||
NULL, NULL, &setlist, &showlist);
|
||||
}
|
||||
|
@ -66,6 +66,8 @@ struct match_list_displayer
|
||||
extern void gdb_display_match_list (char **matches, int len, int max,
|
||||
const struct match_list_displayer *);
|
||||
|
||||
extern const char *get_max_completions_reached_message (void);
|
||||
|
||||
extern VEC (char_ptr) *complete_line (const char *text,
|
||||
const char *line_buffer,
|
||||
int point);
|
||||
@ -112,4 +114,68 @@ extern const char *skip_quoted_chars (const char *, const char *,
|
||||
|
||||
extern const char *skip_quoted (const char *);
|
||||
|
||||
/* Maximum number of candidates to consider before the completer
|
||||
bails by throwing MAX_COMPLETIONS_REACHED_ERROR. Negative values
|
||||
disable limiting. */
|
||||
|
||||
extern int max_completions;
|
||||
|
||||
/* Object to track how many unique completions have been generated.
|
||||
Used to limit the size of generated completion lists. */
|
||||
|
||||
typedef htab_t completion_tracker_t;
|
||||
|
||||
/* Create a new completion tracker.
|
||||
The result is a hash table to track added completions, or NULL
|
||||
if max_completions <= 0. If max_completions < 0, tracking is disabled.
|
||||
If max_completions == 0, the max is indeed zero. */
|
||||
|
||||
extern completion_tracker_t new_completion_tracker (void);
|
||||
|
||||
/* Make a cleanup to free a completion tracker, and reset its pointer
|
||||
to NULL. */
|
||||
|
||||
extern struct cleanup *make_cleanup_free_completion_tracker
|
||||
(completion_tracker_t *tracker_ptr);
|
||||
|
||||
/* Return values for maybe_add_completion. */
|
||||
|
||||
enum maybe_add_completion_enum
|
||||
{
|
||||
/* NAME has been recorded and max_completions has not been reached,
|
||||
or completion tracking is disabled (max_completions < 0). */
|
||||
MAYBE_ADD_COMPLETION_OK,
|
||||
|
||||
/* NAME has been recorded and max_completions has been reached
|
||||
(thus the caller can stop searching). */
|
||||
MAYBE_ADD_COMPLETION_OK_MAX_REACHED,
|
||||
|
||||
/* max-completions entries has been reached.
|
||||
Whether NAME is a duplicate or not is not determined. */
|
||||
MAYBE_ADD_COMPLETION_MAX_REACHED,
|
||||
|
||||
/* NAME has already been recorded.
|
||||
Note that this is never returned if completion tracking is disabled
|
||||
(max_completions < 0). */
|
||||
MAYBE_ADD_COMPLETION_DUPLICATE
|
||||
};
|
||||
|
||||
/* Add the completion NAME to the list of generated completions if
|
||||
it is not there already.
|
||||
If max_completions is negative, nothing is done, not even watching
|
||||
for duplicates, and MAYBE_ADD_COMPLETION_OK is always returned.
|
||||
|
||||
If MAYBE_ADD_COMPLETION_MAX_REACHED is returned, callers are required to
|
||||
record at least one more completion. The final list will be pruned to
|
||||
max_completions, but recording at least one more than max_completions is
|
||||
the signal to the completion machinery that too many completions were
|
||||
found. */
|
||||
|
||||
extern enum maybe_add_completion_enum
|
||||
maybe_add_completion (completion_tracker_t tracker, char *name);
|
||||
|
||||
/* Wrapper to throw MAX_COMPLETIONS_REACHED_ERROR. */
|
||||
|
||||
extern void throw_max_completions_reached_error (void);
|
||||
|
||||
#endif /* defined (COMPLETER_H) */
|
||||
|
@ -1600,6 +1600,38 @@ means @kbd{@key{META} ?}. You can type this either by holding down a
|
||||
key designated as the @key{META} shift on your keyboard (if there is
|
||||
one) while typing @kbd{?}, or as @key{ESC} followed by @kbd{?}.
|
||||
|
||||
If the number of possible completions is large, @value{GDBN} will
|
||||
print as much of the list as it has collected, as well as a message
|
||||
indicating that the list may be truncated.
|
||||
|
||||
@smallexample
|
||||
(@value{GDBP}) b m@key{TAB}@key{TAB}
|
||||
main
|
||||
<... the rest of the possible completions ...>
|
||||
*** List may be truncated, max-completions reached. ***
|
||||
(@value{GDBP}) b m
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
This behavior can be controlled with the following commands:
|
||||
|
||||
@table @code
|
||||
@kindex set max-completions
|
||||
@item set max-completions @var{limit}
|
||||
@itemx set max-completions unlimited
|
||||
Set the maximum number of completion candidates. @value{GDBN} will
|
||||
stop looking for more completions once it collects this many candidates.
|
||||
This is useful when completing on things like function names as collecting
|
||||
all the possible candidates can be time consuming.
|
||||
The default value is 200. A value of zero disables tab-completion.
|
||||
Note that setting either no limit or a very large limit can make
|
||||
completion slow.
|
||||
@kindex show max-completions
|
||||
@item show max-completions
|
||||
Show the maximum number of candidates that @value{GDBN} will collect and show
|
||||
during completion.
|
||||
@end table
|
||||
|
||||
@cindex quotes in commands
|
||||
@cindex completion of quoted strings
|
||||
Sometimes the string you need, while logically a ``word'', may contain
|
||||
|
74
gdb/symtab.c
74
gdb/symtab.c
@ -60,6 +60,7 @@
|
||||
#include "macroscope.h"
|
||||
|
||||
#include "parser-defs.h"
|
||||
#include "completer.h"
|
||||
|
||||
/* Forward declarations for local functions. */
|
||||
|
||||
@ -5001,6 +5002,15 @@ static VEC (char_ptr) *return_val;
|
||||
completion_list_add_name \
|
||||
(MSYMBOL_NATURAL_NAME (symbol), (sym_text), (len), (text), (word))
|
||||
|
||||
/* Tracker for how many unique completions have been generated. Used
|
||||
to terminate completion list generation early if the list has grown
|
||||
to a size so large as to be useless. This helps avoid GDB seeming
|
||||
to lock up in the event the user requests to complete on something
|
||||
vague that necessitates the time consuming expansion of many symbol
|
||||
tables. */
|
||||
|
||||
static completion_tracker_t completion_tracker;
|
||||
|
||||
/* Test to see if the symbol specified by SYMNAME (which is already
|
||||
demangled for C++ symbols) matches SYM_TEXT in the first SYM_TEXT_LEN
|
||||
characters. If so, add it to the current completion list. */
|
||||
@ -5019,6 +5029,7 @@ completion_list_add_name (const char *symname,
|
||||
|
||||
{
|
||||
char *new;
|
||||
enum maybe_add_completion_enum add_status;
|
||||
|
||||
if (word == sym_text)
|
||||
{
|
||||
@ -5040,7 +5051,22 @@ completion_list_add_name (const char *symname,
|
||||
strcat (new, symname);
|
||||
}
|
||||
|
||||
VEC_safe_push (char_ptr, return_val, new);
|
||||
add_status = maybe_add_completion (completion_tracker, new);
|
||||
|
||||
switch (add_status)
|
||||
{
|
||||
case MAYBE_ADD_COMPLETION_OK:
|
||||
VEC_safe_push (char_ptr, return_val, new);
|
||||
break;
|
||||
case MAYBE_ADD_COMPLETION_OK_MAX_REACHED:
|
||||
VEC_safe_push (char_ptr, return_val, new);
|
||||
throw_max_completions_reached_error ();
|
||||
case MAYBE_ADD_COMPLETION_MAX_REACHED:
|
||||
throw_max_completions_reached_error ();
|
||||
case MAYBE_ADD_COMPLETION_DUPLICATE:
|
||||
xfree (new);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5253,11 +5279,11 @@ symtab_expansion_callback (struct compunit_symtab *symtab,
|
||||
datum->code);
|
||||
}
|
||||
|
||||
VEC (char_ptr) *
|
||||
default_make_symbol_completion_list_break_on (const char *text,
|
||||
const char *word,
|
||||
const char *break_on,
|
||||
enum type_code code)
|
||||
static void
|
||||
default_make_symbol_completion_list_break_on_1 (const char *text,
|
||||
const char *word,
|
||||
const char *break_on,
|
||||
enum type_code code)
|
||||
{
|
||||
/* Problem: All of the symbols have to be copied because readline
|
||||
frees them. I'm not going to worry about this; hopefully there
|
||||
@ -5275,7 +5301,7 @@ default_make_symbol_completion_list_break_on (const char *text,
|
||||
/* Length of sym_text. */
|
||||
int sym_text_len;
|
||||
struct add_name_data datum;
|
||||
struct cleanup *back_to;
|
||||
struct cleanup *cleanups;
|
||||
|
||||
/* Now look for the symbol we are supposed to complete on. */
|
||||
{
|
||||
@ -5310,7 +5336,7 @@ default_make_symbol_completion_list_break_on (const char *text,
|
||||
/* A double-quoted string is never a symbol, nor does it make sense
|
||||
to complete it any other way. */
|
||||
{
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -5346,8 +5372,8 @@ default_make_symbol_completion_list_break_on (const char *text,
|
||||
}
|
||||
gdb_assert (sym_text[sym_text_len] == '\0' || sym_text[sym_text_len] == '(');
|
||||
|
||||
return_val = NULL;
|
||||
back_to = make_cleanup (do_free_completion_list, &return_val);
|
||||
completion_tracker = new_completion_tracker ();
|
||||
cleanups = make_cleanup_free_completion_tracker (&completion_tracker);
|
||||
|
||||
datum.sym_text = sym_text;
|
||||
datum.sym_text_len = sym_text_len;
|
||||
@ -5461,8 +5487,34 @@ default_make_symbol_completion_list_break_on (const char *text,
|
||||
macro_for_each (macro_user_macros, add_macro_name, &datum);
|
||||
}
|
||||
|
||||
do_cleanups (cleanups);
|
||||
}
|
||||
|
||||
VEC (char_ptr) *
|
||||
default_make_symbol_completion_list_break_on (const char *text,
|
||||
const char *word,
|
||||
const char *break_on,
|
||||
enum type_code code)
|
||||
{
|
||||
struct cleanup *back_to;
|
||||
volatile struct gdb_exception except;
|
||||
|
||||
return_val = NULL;
|
||||
back_to = make_cleanup (do_free_completion_list, &return_val);
|
||||
|
||||
TRY_CATCH (except, RETURN_MASK_ERROR)
|
||||
{
|
||||
default_make_symbol_completion_list_break_on_1 (text, word,
|
||||
break_on, code);
|
||||
}
|
||||
if (except.reason < 0)
|
||||
{
|
||||
if (except.error != MAX_COMPLETIONS_REACHED_ERROR)
|
||||
throw_exception (except);
|
||||
}
|
||||
|
||||
discard_cleanups (back_to);
|
||||
return (return_val);
|
||||
return return_val;
|
||||
}
|
||||
|
||||
VEC (char_ptr) *
|
||||
|
@ -67,6 +67,7 @@ if ![runto_main] then {
|
||||
}
|
||||
|
||||
set timeout 30
|
||||
gdb_test_no_output "set max-completions unlimited"
|
||||
|
||||
gdb_test_no_output "complete print values\[0\].x." \
|
||||
"field completion with invalid field"
|
||||
@ -775,4 +776,86 @@ gdb_test_multiple "" "$test" {
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
#
|
||||
# Completion limiting.
|
||||
#
|
||||
|
||||
gdb_test_no_output "set max-completions 5"
|
||||
|
||||
set test "command-name completion limiting using tab character"
|
||||
send_gdb "p\t"
|
||||
gdb_test_multiple "" "$test" {
|
||||
-re "^p\\\x07$" {
|
||||
send_gdb "\t"
|
||||
gdb_test_multiple "" "$test" {
|
||||
-re "List may be truncated, max-completions reached.*\r\n$gdb_prompt p$" {
|
||||
# Complete the command and ignore the output to resync
|
||||
# gdb for the next test.
|
||||
send_gdb "\n"
|
||||
gdb_test_multiple "" "$test" {
|
||||
-re "$gdb_prompt $" {
|
||||
pass "$test"
|
||||
}
|
||||
}
|
||||
}
|
||||
-re "$gdb_prompt p$" {
|
||||
# Complete the command and ignore the output to resync
|
||||
# gdb for the next test.
|
||||
send_gdb "\n"
|
||||
gdb_test_multiple "" "$test" {
|
||||
-re "$gdb_prompt $" {
|
||||
fail "$test"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set test "command-name completion limiting using complete command"
|
||||
send_gdb "complete p\n"
|
||||
gdb_test_multiple "" "$test" {
|
||||
-re "List may be truncated, max-completions reached.*\r\n$gdb_prompt $" {
|
||||
pass "$test"
|
||||
}
|
||||
}
|
||||
|
||||
gdb_test_no_output "set max-completions 3"
|
||||
|
||||
set test "symbol-name completion limiting using tab character"
|
||||
send_gdb "p marker\t"
|
||||
gdb_test_multiple "" "$test" {
|
||||
-re "^p marker\\\x07$" {
|
||||
send_gdb "\t"
|
||||
gdb_test_multiple "" "$test" {
|
||||
-re "List may be truncated, max-completions reached.*\r\n$gdb_prompt p marker$" {
|
||||
# Complete the command and ignore the output to resync
|
||||
# gdb for the next test.
|
||||
send_gdb "\n"
|
||||
gdb_test_multiple "" "$test" {
|
||||
-re "$gdb_prompt $" {
|
||||
pass "$test"
|
||||
}
|
||||
}
|
||||
}
|
||||
-re "$gdb_prompt p marker$" {
|
||||
# Complete the command and ignore the output to resync
|
||||
# gdb for the next test.
|
||||
send_gdb "\n"
|
||||
gdb_test_multiple "" "$test" {
|
||||
-re "$gdb_prompt $" {
|
||||
fail "$test"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set test "symbol-name completion limiting using complete command"
|
||||
send_gdb "complete p mark\n"
|
||||
gdb_test_multiple "" "$test" {
|
||||
-re "List may be truncated, max-completions reached.*\r\n$gdb_prompt $" {
|
||||
pass "$test"
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,9 @@ if {[prepare_for_testing $testfile $exefile $srcfile \
|
||||
# Turn off the pending breakpoint queries.
|
||||
gdb_test_no_output "set breakpoint pending off"
|
||||
|
||||
# Turn off completion limiting
|
||||
gdb_test_no_output "set max-completions unlimited"
|
||||
|
||||
# We intentionally do not use gdb_breakpoint for these tests.
|
||||
|
||||
# Break at 'linespec' and expect the message in ::error_messages indexed by
|
||||
|
@ -132,6 +132,7 @@ static rl_getc_func_t *tui_old_rl_getc_function;
|
||||
static rl_voidfunc_t *tui_old_rl_redisplay_function;
|
||||
static rl_vintfunc_t *tui_old_rl_prep_terminal;
|
||||
static rl_voidfunc_t *tui_old_rl_deprep_terminal;
|
||||
static rl_compdisp_func_t *tui_old_rl_display_matches_hook;
|
||||
static int tui_old_rl_echoing_p;
|
||||
|
||||
/* Readline output stream.
|
||||
@ -468,6 +469,7 @@ tui_setup_io (int mode)
|
||||
tui_old_rl_deprep_terminal = rl_deprep_term_function;
|
||||
tui_old_rl_prep_terminal = rl_prep_term_function;
|
||||
tui_old_rl_getc_function = rl_getc_function;
|
||||
tui_old_rl_display_matches_hook = rl_completion_display_matches_hook;
|
||||
tui_old_rl_outstream = rl_outstream;
|
||||
tui_old_rl_echoing_p = _rl_echoing_p;
|
||||
rl_redisplay_function = tui_redisplay_readline;
|
||||
@ -511,8 +513,8 @@ tui_setup_io (int mode)
|
||||
rl_deprep_term_function = tui_old_rl_deprep_terminal;
|
||||
rl_prep_term_function = tui_old_rl_prep_terminal;
|
||||
rl_getc_function = tui_old_rl_getc_function;
|
||||
rl_completion_display_matches_hook = tui_old_rl_display_matches_hook;
|
||||
rl_outstream = tui_old_rl_outstream;
|
||||
rl_completion_display_matches_hook = 0;
|
||||
_rl_echoing_p = tui_old_rl_echoing_p;
|
||||
rl_already_prompted = 0;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user