Add max-completions parameter, and implement tab-completion limiting.
authorGary Benson <gbenson@redhat.com>
Sat, 31 Jan 2015 23:07:22 +0000 (15:07 -0800)
committerDoug Evans <xdje42@gmail.com>
Sat, 31 Jan 2015 23:07:22 +0000 (15:07 -0800)
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.

gdb/NEWS
gdb/cli/cli-cmds.c
gdb/common/common-exceptions.h
gdb/completer.c
gdb/completer.h
gdb/doc/gdb.texinfo
gdb/symtab.c
gdb/testsuite/gdb.base/completion.exp
gdb/testsuite/gdb.linespec/ls-errs.exp
gdb/tui/tui-io.c

index cba21b6645dd09e83943b71d42ad4c3d3c00cad4..f19577a3a6d0ea9ff1015255eafbd965580afa2d 100644 (file)
--- a/gdb/NEWS
+++ b/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.
index e20d8dd1a27c017f5b30c7cfa6b069ff513e6d69..e46f0362cfb534bd898507a6e8eebeeaaeb549d9 100644 (file)
@@ -236,7 +236,8 @@ help_command (char *command, int from_tty)
   help_cmd (command, gdb_stdout);
 }
 \f
-/* 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 ());
+       }
     }
 }
 
index 4f60ad817cb8515409a3f960d6660e01dfcd053f..e349ed087f5d7dd92282eefa6f8c86fe4ab35c51 100644 (file)
@@ -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
 };
index 59374393e1d03cdddf9b32e7b48c28ba16575c0b..bfd2788ecce5a6873ee6e083ad5941f52f783ecd 100644 (file)
@@ -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. ***");
+}
 \f
 /* 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);
+       }
+    }
+}
+\f
+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);
 }
index dbb1cfb441cd5f55ba2443c1a3409a2ac2994ef7..56e1a2b5d110ba2837f04e939725d516e1897124 100644 (file)
@@ -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) */
index 171c61c3d7aca58f0e2d66225db3271afa18241e..aee17d3b752e6a2597e72b3971fc04d6eac3a1da 100644 (file)
@@ -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
index abff265db2897b8368b11799c4fee650d4983203..84e268087aea08d00cd2beb804371dc7afe9b115 100644 (file)
@@ -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) *
index 1123b993c9bf5e6957047b0625cecc74d84eb04e..f77bfe23e5cc01a39ea5e41888b6fd034f195800 100644 (file)
@@ -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"
+    }
+}
index 322598eddf8c02bfe768952af0574be33ff79d5e..019312c97233a8be3351ddebab632fba36fe1552 100644 (file)
@@ -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
index 831705cfa7f0f46035e52cf6c3c43e43363e2f59..2b5a166455254630635563489e8e59db86067895 100644 (file)
@@ -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;