[v2,19/24] Introduce complete_command

Message ID 20190530195333.20448-20-palves@redhat.com
State Superseded
Headers show
Series
  • gdb::option framework, "print -OPT", other cmd options
Related show

Commit Message

Pedro Alves May 30, 2019, 7:53 p.m.
This adds a completion helper routine that makes it possible for a
command that takes another command as argument, such as "frame apply
all COMMAND" as "thread apply all COMMAND", to complete on COMMAND,
and have the completion machinery recurse and complete COMMAND as if
you tried to complete "(gdb) COMMAND".  I.e., we'll be able to
complete like this, for example:

 (gdb) thread apply all -[TAB]
 -c           -ascending   -q           -s
 (gdb) thread apply all -ascending frame apply all -[TAB]
 -c           -limit       -past-entry  -past-main   -q           -s
 (gdb) thread apply all -ascending frame apply all -past-main print -[TAB]
 -address         -elements        -pretty          -symbol
 -array           -null-stop       -repeats         -union
 -array-indexes   -object          -static-members  -vtbl
 (gdb) thread apply all -ascending frame apply all -past-main print glo[TAB]
 global1         global2

Above, the completer function understands that "thread apply all" is a
command, and then parses "-ascending" successfully and understand that
the rest of the string is "thread apply all"'s operand.  And then, the
process repeats for the "frame apply" command, and on and on.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* completer.c (complete_command): New.
	(gdb_completion_word_break_characters_throw): Add assertion.
	* completer.h (complete_command): Declare.
---
 gdb/completer.c | 36 ++++++++++++++++++++++++++++++++++++
 gdb/completer.h | 11 +++++++++++
 2 files changed, 47 insertions(+)

-- 
2.14.5

Comments

Tom Tromey June 3, 2019, 7:28 p.m. | #1
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:


Pedro> This adds a completion helper routine that makes it possible for a
Pedro> command that takes another command as argument, such as "frame apply
Pedro> all COMMAND" as "thread apply all COMMAND", to complete on COMMAND,
Pedro> and have the completion machinery recurse and complete COMMAND as if
Pedro> you tried to complete "(gdb) COMMAND".  I.e., we'll be able to
Pedro> complete like this, for example:

Pedro> 	* completer.c (complete_command): New.

I think that the function should have a different name.  Traditionally,
*_command is the name of the command "*" in gdb, and there's already a
function called complete_command.  Overloading makes this not matter too
much, but I also think it's best to reserve overloading for functions
that are semantically similar.

Tom
Pedro Alves June 4, 2019, 10:10 p.m. | #2
On 6/3/19 8:28 PM, Tom Tromey wrote:
>>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:

> 

> Pedro> This adds a completion helper routine that makes it possible for a

> Pedro> command that takes another command as argument, such as "frame apply

> Pedro> all COMMAND" as "thread apply all COMMAND", to complete on COMMAND,

> Pedro> and have the completion machinery recurse and complete COMMAND as if

> Pedro> you tried to complete "(gdb) COMMAND".  I.e., we'll be able to

> Pedro> complete like this, for example:

> 

> Pedro> 	* completer.c (complete_command): New.

> 

> I think that the function should have a different name.  Traditionally,

> *_command is the name of the command "*" in gdb, and there's already a

> function called complete_command.  Overloading makes this not matter too

> much, but I also think it's best to reserve overloading for functions

> that are semantically similar.


Hmmm.  Somehow I forgot the "complete" command.  Bizarre, since the
approach here is actually stolen from the same trick that I had
applied to make the "complete" command complete command arguments
correctly a couple years ago.  Eh.

The name I had chosen as following the complete_xxx pattern in the
completer.h functions -- complete_expression, complete_symbol,
complete_source_filenames, complete_files_symbols, etc.

Not sure what to call this.  It ultimately call complete_line, and it's
used to complete nested commands so, maybe

  complete_nested_command_line 

?

Thanks,
Pedro Alves
Tom Tromey June 5, 2019, 1:53 a.m. | #3
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:


Pedro> Not sure what to call this.  It ultimately call complete_line, and it's
Pedro> used to complete nested commands so, maybe

Pedro>   complete_nested_command_line 

Pedro> ?

Works for me.

Tom

Patch

diff --git a/gdb/completer.c b/gdb/completer.c
index 4e92e499b3a..f875295f6eb 100644
--- a/gdb/completer.c
+++ b/gdb/completer.c
@@ -423,6 +423,39 @@  completion_tracker::completes_to_completion_word (const char *word)
   return false;
 }
 
+/* See completer.h.  */
+
+void
+complete_command (completion_tracker &tracker, const char *text)
+{
+  /* Must be called from a custom-word-point completer.  */
+  gdb_assert (tracker.use_custom_word_point ());
+
+  /* Disable the custom word point temporarily, because we want to
+     probe whether the command we're completing itself uses a custom
+     word point.  */
+  tracker.set_use_custom_word_point (false);
+  size_t save_custom_word_point = tracker.custom_word_point ();
+
+  int quote_char = '\0';
+  const char *word = completion_find_completion_word (tracker, text,
+						      &quote_char);
+
+  if (tracker.use_custom_word_point ())
+    {
+      /* The command we're completing uses a custom word point, so the
+	 tracker already contains the matches.  We're done.  */
+      return;
+    }
+
+  /* Restore the custom word point settings.  */
+  tracker.set_custom_word_point (save_custom_word_point);
+  tracker.set_use_custom_word_point (true);
+
+  /* Run the handle_completions completer phase.  */
+  complete_line (tracker, word, text, strlen (text));
+}
+
 /* Complete on linespecs, which might be of two possible forms:
 
        file:line
@@ -1905,6 +1938,9 @@  gdb_completion_word_break_characters_throw ()
     {
       gdb_assert (tracker.custom_word_point () > 0);
       rl_point = tracker.custom_word_point () - 1;
+
+      gdb_assert (rl_point >= 0 && rl_point < strlen (rl_line_buffer));
+
       gdb_custom_word_point_brkchars[0] = rl_line_buffer[rl_point];
       rl_completer_word_break_characters = gdb_custom_word_point_brkchars;
       rl_completer_quote_characters = NULL;
diff --git a/gdb/completer.h b/gdb/completer.h
index 58fe84f4fee..1b7176f031a 100644
--- a/gdb/completer.h
+++ b/gdb/completer.h
@@ -611,6 +611,17 @@  extern completion_list complete_source_filenames (const char *text);
 extern void complete_expression (completion_tracker &tracker,
 				 const char *text, const char *word);
 
+/* Called by custom word point completers that want to recurse into
+   the completion machinery to complete a command.  Used to complete
+   COMMAND in "thread apply all COMMAND", for example.  Note that
+   unlike command_completer, this fully recurses into the proper
+   completer for COMMAND, so that e.g.,
+
+     (gdb) thread apply all print -[TAB]
+
+   does the right thing and show the print options.  */
+extern void complete_command (completion_tracker &tracker, const char *text);
+
 extern const char *skip_quoted_chars (const char *, const char *,
 				      const char *);