public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Keith Seitz <keiths@redhat.com>
To: gdb-patches@sourceware.org
Subject: [PATCH v2 17/18] Use the hashtable to accumulate completion results.
Date: Mon, 04 May 2015 19:18:00 -0000	[thread overview]
Message-ID: <20150504191849.20434.62077.stgit@valrhona.uglyboxes.com> (raw)
In-Reply-To: <20150504191734.20434.68053.stgit@valrhona.uglyboxes.com>

The completion API now uses a VEC (char_ptr) to collect results of
completion.  The completion tracker is a hashtable whose elements are
the completions.  Both hold essentially the same data, so there is no
need to keep both around.

This patch introduces some API support for removing the vector of
completions altogether.  While it does not remove the vector or
the vector return result from the completer functions, this patch
does not use the results of the vector at all.  Only the results of
the hashtable inside the completer's private data is used.

The vector will be removed in the next patch.

gdb/ChangeLog

	* cli/cli-decode.c (complete_on_cmdlist): Use get_completion_count
	to ascertain if there are any completion results.
	* completer.c (remove_leading_fn_component): New function.
	(location_completer): Use get_completion_count to figure out
	how many symbols and/or file names were found searching for
	possible completions.
	Traverse the completion tracker hashtable to strip leading
	file name components.  Contents moved to remove_leading_fn_component.
	(free_completer_data): Change argument to proper type.
	(free_entry_callback): New function.
	(free_all_completer_data): New function.
	(vectorize_htab): New function.
	(get_completion_list): New function.
	(get_completion_count): New function.
	(maybe_add_completion): Accumulate completions when not limiting
	the number of completions.
	(complete_line): Ignore the return list from complete_line_internal
	and get the completion results from the tracker.
	Do not count/limit the results at all -- it is no longer necessary.
	Use free_all_completer_data to free any allocated memory during
	completion in the case of an exception.
	Use free_completer_data after get_completion_list to free
	completer data structures.
	(gdb_completion_word_break_characters): Ignore the return list
	from complete_line_internal and get the completion results from
	the tracker.
	Use free_completer_data after get_completion_list to free
	completer data structures.
	* completer.h (get_completion_list): Declare.
	(get_completion_count): Declare.
	* python/py-cmd.c (cmdpy_completer): Use get_completion_count
	to ascertain if there are any completion results.
---
 gdb/cli/cli-decode.c |    2 -
 gdb/completer.c      |  176 ++++++++++++++++++++++++++++----------------------
 gdb/completer.h      |    9 +++
 gdb/python/py-cmd.c  |    2 -
 4 files changed, 111 insertions(+), 78 deletions(-)

diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c
index a09ad5c..daa0080 100644
--- a/gdb/cli/cli-decode.c
+++ b/gdb/cli/cli-decode.c
@@ -1781,7 +1781,7 @@ complete_on_cmdlist (struct completer_data *cdata,
      commands.  If we see no matching commands in the first pass, and
      if we did happen to see a matching deprecated command, we do
      another loop to collect those.  */
-  for (pass = 0; matchlist == 0 && pass < 2; ++pass)
+  for (pass = 0; get_completion_count (cdata) == 0 && pass < 2; ++pass)
     {
       for (ptr = list; ptr; ptr = ptr->next)
 	if (!strncmp (ptr->name, text, textlen)
diff --git a/gdb/completer.c b/gdb/completer.c
index 9a7af74..5682627 100644
--- a/gdb/completer.c
+++ b/gdb/completer.c
@@ -214,6 +214,20 @@ filename_completer (struct completer_data *cdata,
   return return_val;
 }
 
+/* A hashtable traversal function to remove leading file name
+   components, as required by rl_complete.  See more detailed explanation
+   in location_completer for more.  */
+
+static int
+remove_leading_fn_component (void **slot, void *calldata)
+{
+  char *fn = *slot;
+  int offset = *(int *) calldata;
+
+  memmove (fn, fn + offset, strlen (fn) + 1 - offset);
+  return 1;
+}
+
 /* Complete on locations, which might be of two possible forms:
 
        file:line
@@ -303,21 +317,25 @@ location_completer (struct completer_data *cdata,
     {
       list = make_file_symbol_completion_list (cdata, symbol_start, word,
 					       file_to_match);
+      n_syms = get_completion_count (cdata);
+      n_files = 0;
       xfree (file_to_match);
     }
   else
     {
       list = make_symbol_completion_list (cdata, symbol_start, word);
+      n_syms = get_completion_count (cdata);
+      n_files = 0;
       /* If text includes characters which cannot appear in a file
 	 name, they cannot be asking for completion on files.  */
       if (strcspn (text, 
 		   gdb_completer_file_name_break_characters) == text_len)
-	fn_list = make_source_files_completion_list (cdata, text, text);
+	{
+	  fn_list = make_source_files_completion_list (cdata, text, text);
+	  n_files = get_completion_count (cdata) - n_syms;
+	}
     }
 
-  n_syms = VEC_length (char_ptr, list);
-  n_files = VEC_length (char_ptr, fn_list);
-
   /* Catenate fn_list[] onto the end of list[].  */
   if (!n_syms)
     {
@@ -340,7 +358,7 @@ location_completer (struct completer_data *cdata,
     }
   else if (n_files)
     {
-      char *fn;
+      int offset = word - text;
 
       /* If we only have file names as possible completion, we should
 	 bring them in sync with what rl_complete expects.  The
@@ -355,13 +373,10 @@ location_completer (struct completer_data *cdata,
 	 the full "/foo/bar" and "/foo/baz" strings.  This produces
 	 wrong results when, e.g., there's only one possible
 	 completion, because rl_complete will prepend "/foo/" to each
-	 candidate completion.  The loop below removes that leading
+	 candidate completion.  The callback below removes that leading
 	 part.  */
-      for (ix = 0; VEC_iterate (char_ptr, list, ix, fn); ++ix)
-	{
-	  memmove (fn, fn + (word - text),
-		   strlen (fn) + 1 - (word - text));
-	}
+      htab_traverse (cdata->tracker, remove_leading_fn_component,
+		     &offset);
     }
   else if (!n_syms)
     {
@@ -857,14 +872,67 @@ new_completer_data (int size)
 /* Free the completion data represented by P.  */
 
 static void
-free_completer_data (void *p)
+free_completer_data (struct completer_data *cdata)
 {
-  struct completer_data *cdata = p;
-
   htab_delete (cdata->tracker);
   xfree (cdata);
 }
 
+/* A hashtable traversal function to free the elements of the table.  */
+
+static int
+free_entry_callback (void **slot, void *calldata)
+{
+  char *element = *slot;
+
+  xfree (element);
+  return 1;
+}
+
+/* A cleanup function to free all data associated with the completer_data
+   given by P.  */
+
+static void
+free_all_completer_data (void *p)
+{
+  struct completer_data *cdata = p;
+
+  htab_traverse (cdata->tracker, free_entry_callback, NULL);
+  free_completer_data (cdata);
+}
+
+/* A hashtable traversal function to turn the hashtable keys
+   into a vector.  */
+
+static int
+vectorize_htab (void **slot, void *calldata)
+{
+  char *element = *slot;
+  VEC (char_ptr) **vector = calldata;
+
+  VEC_safe_push (char_ptr, *vector, element);
+  return 1;
+}
+
+/* See completer.h.  */
+
+VEC (char_ptr) *
+get_completion_list (const struct completer_data *cdata)
+{
+  VEC (char_ptr) *result = NULL;
+
+  htab_traverse (cdata->tracker, vectorize_htab, &result);
+  return result;
+}
+
+/* See completer.h.  */
+
+size_t
+get_completion_count (const struct completer_data *cdata)
+{
+  return htab_elements (cdata->tracker);
+}
+
 /* 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
@@ -881,12 +949,11 @@ maybe_add_completion (struct completer_data *cdata, char *name)
 {
   void **slot;
 
-  if (max_completions < 0)
-    return MAYBE_ADD_COMPLETION_OK;
   if (max_completions == 0)
     return MAYBE_ADD_COMPLETION_MAX_REACHED;
 
-  if (htab_elements (cdata->tracker) >= max_completions)
+  if (max_completions > 0
+      && htab_elements (cdata->tracker) >= max_completions)
     return MAYBE_ADD_COMPLETION_MAX_REACHED;
 
   slot = htab_find_slot (cdata->tracker, name, INSERT);
@@ -896,7 +963,8 @@ maybe_add_completion (struct completer_data *cdata, char *name)
 
   *slot = name;
 
-  return (htab_elements (cdata->tracker) < max_completions
+  return ((max_completions < 0
+	   || htab_elements (cdata->tracker) < max_completions)
 	  ? MAYBE_ADD_COMPLETION_OK
 	  : MAYBE_ADD_COMPLETION_OK_MAX_REACHED);
 }
@@ -961,66 +1029,20 @@ throw_max_completions_reached_error (void)
 VEC (char_ptr) *
 complete_line (const char *text, const char *line_buffer, int point)
 {
-  VEC (char_ptr) *list;
-  VEC (char_ptr) *result = NULL;
-  struct cleanup *cdata_cleanup, *list_cleanup;
-  char *candidate;
-  int ix;
+  VEC (char_ptr) *result;
+  struct cleanup *cdata_cleanup;
   struct completer_data *cdata;
 
   if (max_completions == 0)
     return NULL;
 
   cdata = new_completer_data (max_completions);
-  cdata_cleanup = make_cleanup (free_completer_data, cdata);
-  list = complete_line_internal (cdata, text, line_buffer, point,
-				 handle_completions);
-  if (max_completions < 0)
-    {
-      do_cleanups (cdata_cleanup);
-      return list;
-    }
-
-  list_cleanup = make_cleanup_free_char_ptr_vec (list);
-
-  /* If complete_line_internal returned more completions than were
-     recorded by the completion tracker, then the completer function that
-     was run does not support completion tracking.  In this case,
-     do a final test for too many completions.
-
-     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.  */
-
-  if (VEC_length (char_ptr, list) > htab_elements (cdata->tracker))
-    {
-      enum add_completion_status max_reached = ADD_COMPLETION_OK;
-
-      /* Clear the tracker so that we can re-use it to count the number
-	 of returned completions.  */
-      htab_empty (cdata->tracker);
-
-      for (ix = 0; (max_reached == ADD_COMPLETION_OK
-		    && VEC_iterate (char_ptr, list, ix, candidate)); ++ix)
-	{
-	  max_reached = add_completion (cdata, &result, xstrdup (candidate));
-	}
-
-      /* The return result has been assembled and the original list from
-	 complete_line_internal is no longer needed.  Free it.  */
-      do_cleanups (list_cleanup);
-    }
-  else
-    {
-      /* There is a valid tracker for the completion -- simply return
-	 the completed list.  */
-      discard_cleanups (list_cleanup);
-      result = list;
-    }
-
-  do_cleanups (cdata_cleanup);
-
+  cdata_cleanup = make_cleanup (free_all_completer_data, cdata);
+  complete_line_internal (cdata, text, line_buffer, point,
+			  handle_completions);
+  result = get_completion_list (cdata);
+  discard_cleanups (cdata_cleanup);
+  free_completer_data (cdata);
   return result;
 }
 
@@ -1123,10 +1145,12 @@ gdb_completion_word_break_characters (void)
   struct cleanup *cleanup;
 
   cdata = new_completer_data (max_completions);
-  cleanup = make_cleanup (free_completer_data, cdata);
-  list = complete_line_internal (cdata, rl_line_buffer, rl_line_buffer,
-				 rl_point, handle_brkchars);
-  do_cleanups (cleanup);
+  cleanup = make_cleanup (free_all_completer_data, cdata);
+  complete_line_internal (cdata, rl_line_buffer, rl_line_buffer,
+			  rl_point, handle_brkchars);
+  list = get_completion_list (cdata);
+  discard_cleanups (cleanup);
+  free_completer_data (cdata);
   gdb_assert (list == NULL);
   return rl_completer_word_break_characters;
 }
diff --git a/gdb/completer.h b/gdb/completer.h
index 29ff2e9..ec551c8 100644
--- a/gdb/completer.h
+++ b/gdb/completer.h
@@ -128,6 +128,15 @@ extern const char *skip_quoted (const char *);
 
 extern int get_maximum_completions (void);
 
+/* Get the list of completions.  */
+
+extern VEC (char_ptr) *
+  get_completion_list (const struct completer_data *cdata);
+
+/* Get the number of completions in CDATA.  */
+
+extern size_t get_completion_count (const struct completer_data *cdata);
+
 /* Return values for add_completion.  */
 
 enum add_completion_status
diff --git a/gdb/python/py-cmd.c b/gdb/python/py-cmd.c
index 04c7309..440994c 100644
--- a/gdb/python/py-cmd.c
+++ b/gdb/python/py-cmd.c
@@ -402,7 +402,7 @@ cmdpy_completer (struct completer_data *cdata,
 
       /* If we got some results, ignore problems.  Otherwise, report
 	 the problem.  */
-      if (result != NULL && PyErr_Occurred ())
+      if (get_completion_count (cdata) > 0 && PyErr_Occurred ())
 	PyErr_Clear ();
     }
 

  parent reply	other threads:[~2015-05-04 19:18 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-05-04 19:18 [PATCH v2 00/18] Implement full completer limiting Keith Seitz
2015-05-04 19:18 ` [PATCH v2 16/18] Make the completion API completely opaque Keith Seitz
2015-05-04 19:18 ` Keith Seitz [this message]
2015-05-04 19:18 ` [PATCH v2 03/18] Implement completion limiting for complete_on_cmdlist Keith Seitz
2015-05-04 19:18 ` [PATCH v2 05/18] Implement completion limiting for ada_make_symbol_completion_list Keith Seitz
2015-05-04 19:18 ` [PATCH v2 01/18] Add struct completer_data to the completion API Keith Seitz
2015-05-04 19:18 ` [PATCH v2 14/18] Implement completion limiting in add_struct_fields Keith Seitz
2015-05-04 19:18 ` [PATCH v2 04/18] Implement completion limiting for add_filename_to_list Keith Seitz
2015-05-04 19:18 ` [PATCH v2 09/18] Implement completion limiting for interpreter_completer Keith Seitz
2015-05-04 19:18 ` [PATCH v2 12/18] Implement completion limiting for sim_command_completer Keith Seitz
2015-05-04 19:18 ` [PATCH v2 15/18] Implement completion limiting for scmcmd_add_completion Keith Seitz
2015-05-04 19:18 ` [PATCH v2 10/18] Implement completion limiting for cmdpy_completer Keith Seitz
2015-05-04 19:18 ` [PATCH v2 02/18] Remove completion_tracker_t from the public completion API Keith Seitz
2015-05-04 19:18 ` [PATCH v2 07/18] Implement completion limiting for filename_completer Keith Seitz
2015-05-04 19:18 ` [PATCH v2 11/18] Implement completion limiting for reg_or_group_completer Keith Seitz
2015-05-04 19:18 ` [PATCH v2 06/18] Implement completion limiting for condition_completer Keith Seitz
2015-05-04 19:18 ` [PATCH v2 08/18] Implement completion limiting for signal_completer Keith Seitz
2015-05-04 19:18 ` [PATCH v2 13/18] Implement completion limiting for complete_on_enum Keith Seitz
2015-05-04 19:19 ` [PATCH v2 18/18] Remove the vector return result from the completion API Keith Seitz
2015-05-22  0:13 [PATCH v2 17/18] Use the hashtable to accumulate completion results Doug Evans

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20150504191849.20434.62077.stgit@valrhona.uglyboxes.com \
    --to=keiths@redhat.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).