]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/completer.h
Introduce class completion_tracker & rewrite completion<->readline interaction
[thirdparty/binutils-gdb.git] / gdb / completer.h
index 463a53d4ad2032e8fd37c455b30d820e3fd27719..4b3b1882101cd33bbab40f88235c20fc630bda8a 100644 (file)
@@ -63,44 +63,184 @@ struct match_list_displayer
   mld_read_key_ftype *read_key;
 };
 
+/* A list of completion candidates.  Each element is a malloc string,
+   because ownership of the strings is transferred to readline, which
+   calls free on each element.  */
+typedef std::vector<gdb::unique_xmalloc_ptr<char>> completion_list;
+
+/* The final result of a completion that is handed over to either
+   readline or the "completion" command (which pretends to be
+   readline).  Mainly a wrapper for a readline-style match list array,
+   though other bits of info are included too.  */
+
+struct completion_result
+{
+  /* Create an empty result.  */
+  completion_result ();
+
+  /* Create a result.  */
+  completion_result (char **match_list, size_t number_matches,
+                    bool completion_suppress_append);
+
+  /* Destroy a result.  */
+  ~completion_result ();
+
+  /* Disable copying, since we don't need it.  */
+  completion_result (const completion_result &rhs) = delete;
+  void operator= (const completion_result &rhs) = delete;
+
+  /* Move a result.  */
+  completion_result (completion_result &&rhs);
+
+  /* Release ownership of the match list array.  */
+  char **release_match_list ();
+
+  /* Sort the match list.  */
+  void sort_match_list ();
+
+private:
+  /* Destroy the match list array and its contents.  */
+  void reset_match_list ();
+
+public:
+  /* (There's no point in making these fields private, since the whole
+     point of this wrapper is to build data in the layout expected by
+     readline.  Making them private would require adding getters for
+     the "complete" command, which would expose the same
+     implementation details anyway.)  */
+
+  /* The match list array, in the format that readline expects.
+     match_list[0] contains the common prefix.  The real match list
+     starts at index 1.  The list is NULL terminated.  If there's only
+     one match, then match_list[1] is NULL.  If there are no matches,
+     then this is NULL.  */
+  char **match_list;
+  /* The number of matched completions in MATCH_LIST.  Does not
+     include the NULL terminator or the common prefix.  */
+  size_t number_matches;
+
+  /* Whether readline should suppress appending a whitespace, when
+     there's only one possible completion.  */
+  bool completion_suppress_append;
+};
+
+/* Object used by completers to build a completion match list to hand
+   over to readline.  It tracks:
+
+   - How many unique completions have been generated, 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.
+*/
+class completion_tracker
+{
+public:
+  completion_tracker ();
+  ~completion_tracker ();
+
+  /* Disable copy.  */
+  completion_tracker (const completion_tracker &rhs) = delete;
+  void operator= (const completion_tracker &rhs) = delete;
+
+  /* Add the completion NAME to the list of generated completions if
+     it is not there already.  If too many completions were already
+     found, this throws an error.  */
+  void add_completion (gdb::unique_xmalloc_ptr<char> name);
+
+  /* Add all completions matches in LIST.  Elements are moved out of
+     LIST.  */
+  void add_completions (completion_list &&list);
+
+  /* True if we have any completion match recorded.  */
+  bool have_completions () const
+  { return !m_entries_vec.empty (); }
+
+  /* Build a completion_result containing the list of completion
+     matches to hand over to readline.  The parameters are as in
+     rl_attempted_completion_function.  */
+  completion_result build_completion_result (const char *text,
+                                            int start, int end);
+
+private:
+
+  /* Add the completion NAME to the list of generated completions if
+     it is not there already.  If false is returned, too many
+     completions were found.  */
+  bool maybe_add_completion (gdb::unique_xmalloc_ptr<char> name);
+
+  /* Given a new match, recompute the lowest common denominator (LCD)
+     to hand over to readline.  */
+  void recompute_lowest_common_denominator (const char *new_match);
+
+  /* The completion matches found so far, in a vector.  */
+  completion_list m_entries_vec;
+
+  /* The completion matches found so far, in a hash table, for
+     duplicate elimination as entries are added.  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.  */
+  htab_t m_entries_hash;
+
+  /* Our idea of lowest common denominator to hand over to readline.  */
+  char *m_lowest_common_denominator = NULL;
+
+  /* If true, the LCD is unique.  I.e., all completion candidates had
+     the same string.  */
+  bool m_lowest_common_denominator_unique = false;
+};
+
 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);
+extern void complete_line (completion_tracker &tracker,
+                          const char *text,
+                          const char *line_buffer,
+                          int point);
 
-extern char *readline_line_completion_function (const char *text,
-                                               int matches);
+extern char **gdb_rl_attempted_completion_function (const char *text,
+                                                   int start, int end);
 
-extern VEC (char_ptr) *noop_completer (struct cmd_list_element *,
-                                      const char *, const char *);
+extern void noop_completer (struct cmd_list_element *,
+                           completion_tracker &tracker,
+                           const char *, const char *);
 
-extern VEC (char_ptr) *filename_completer (struct cmd_list_element *,
-                                          const char *, const char *);
+extern void filename_completer (struct cmd_list_element *,
+                               completion_tracker &tracker,
+                               const char *, const char *);
 
-extern VEC (char_ptr) *expression_completer (struct cmd_list_element *,
-                                            const char *, const char *);
+extern void expression_completer (struct cmd_list_element *,
+                                 completion_tracker &tracker,
+                                 const char *, const char *);
 
-extern VEC (char_ptr) *location_completer (struct cmd_list_element *,
-                                          const char *, const char *);
+extern void location_completer (struct cmd_list_element *,
+                               completion_tracker &tracker,
+                               const char *, const char *);
 
-extern VEC (char_ptr) *symbol_completer (struct cmd_list_element *,
-                                        const char *, const char *);
+extern void symbol_completer (struct cmd_list_element *,
+                             completion_tracker &tracker,
+                             const char *, const char *);
 
-extern VEC (char_ptr) *command_completer (struct cmd_list_element *,
-                                         const char *, const char *);
+extern void command_completer (struct cmd_list_element *,
+                              completion_tracker &tracker,
+                              const char *, const char *);
 
-extern VEC (char_ptr) *signal_completer (struct cmd_list_element *,
-                                        const char *, const char *);
+extern void signal_completer (struct cmd_list_element *,
+                             completion_tracker &tracker,
+                             const char *, const char *);
 
-extern VEC (char_ptr) *reg_or_group_completer (struct cmd_list_element *,
-                                              const char *, const char *);
+extern void reg_or_group_completer (struct cmd_list_element *,
+                                   completion_tracker &tracker,
+                                   const char *, const char *);
 
-extern VEC (char_ptr) *reggroup_completer (struct cmd_list_element *,
-                                          const char *, const char *);
+extern void reggroup_completer (struct cmd_list_element *,
+                               completion_tracker &tracker,
+                               const char *, const char *);
 
 extern const char *get_gdb_completer_quote_characters (void);
 
@@ -134,62 +274,4 @@ extern const char *skip_quoted (const char *);
 
 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) */