aboutsummaryrefslogtreecommitdiff
path: root/gdb/completer.c
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2017-07-17 20:08:02 +0100
committerPedro Alves <palves@redhat.com>2017-07-17 20:29:37 +0100
commitc45ec17c07d8aa4554b0b2ca67a5f4dc2c87acc4 (patch)
treea57b4007fe95470fca71df4958c9285141033c52 /gdb/completer.c
parentbe966d4207ff8df6572a23b911e5a69a2ab9370f (diff)
downloadgdb-c45ec17c07d8aa4554b0b2ca67a5f4dc2c87acc4.zip
gdb-c45ec17c07d8aa4554b0b2ca67a5f4dc2c87acc4.tar.gz
gdb-c45ec17c07d8aa4554b0b2ca67a5f4dc2c87acc4.tar.bz2
A smarter linespec completer
Continuing the theme of the explicit locations patch, this patch gets rid of the need for quoting function names in linespec TAB completion. To recap, when you have overloads in your program, and you want to set a breakpoint in one of them: void function(int); // set breakpoint here. void function(long); (gdb) b function(i[TAB] <all the symbols in the program that start with "i" are uselessly shown...> This patch gets rid of the need for quoting by switching the linespec completer to use the custom completion word point mechanism added in the previous explicit location patch (extending it as needed), to correctly determine the right completion word point. In the case above, we want the completer to figure out that it's completing a function name that starts with "function(i", and it now does. We also want the completer to know when it's potentially completing a source file name, for: (gdb) break source.[TAB] -> source.c: (gdb) break source.c: # Type line number or function name now And we want it to know to complete label names, which it doesn't today: (gdb) break function:lab[TAB] etc., etc. So what we want is for completion to grok the input string as closely to how the linespec parser groks it. With that in mind, the solution suggests itself - make the linespec completer use the same parsing code as normal linespec parsing. That's what the patch does. The old completer is replaced by one that reuses the actual linespec parser as much as possible. This (ideally) eliminate differences between what completion understands and actually setting breakpoints understands by design. The completer now offers sensible completion candidates depending on which component of the linespec is being completed, source filename, function, line number, expression, and (a new addition), labels. For example, when completing the function part, we now show the full name of the method as completion candidates, instead of showing whatever comes after what readline considered the word break character: (gdb) break klass::method[TAB] klass:method1(int) klass:method2() If input is past the function, then we now offer keyword condidates: (gdb) b function(int) [TAB] if task thread If input is past a keyword, we offer expression completion, which is different from linespec completion: (gdb) b main if 1 + glo[TAB] global (e.g., completes on types, struct data fields, etc.) As mentioned, this teaches the linespec completer about completing label symbols too: (gdb) b source.c:function:lab[TAB] A nice convenience is that when completion uniquely matches a source name, gdb adds the ":" automatically for you: (gdb) b filenam[TAB] (gdb) b filename.c: # ':' auto-added, cursor right after it. It's the little details. :-) I worked on this patch in parallel with writing the (big) testcase added closer to the end of the series, which exercises many many tricky cases around quoting and whitespace insertion placement. In general, I think it now all Just Works. gdb/ChangeLog: 2017-07-17 Pedro Alves <palves@redhat.com> * completer.c (complete_source_filenames): New function. (complete_address_and_linespec_locations): New function. (location_completer): Use complete_address_and_linespec_locations. (completion_tracker::build_completion_result): Honor the tracker's request to suppress append. * completer.h (completion_tracker::suppress_append_ws) (completion_tracker::set_suppress_append_ws): New methods. (completion_tracker::m_suppress_append_ws): New field. (complete_source_filenames): New declaration. * linespec.c (linespec_complete_what): New. (struct ls_parser) <complete_what, completion_word, completion_quote_char, completion_quote_end, completion_tracker>: New fields. (string_find_incomplete_keyword_at_end): New. (linespec_lexer_lex_string): Record quote char. If in completion mode, don't throw. (linespec_lexer_consume_token): Advance the completion word point. (linespec_lexer_peek_token): Save/restore completion info. (save_stream_and_consume_token): New. (set_completion_after_number): New. (linespec_parse_basic): Set what to complete next depending on token. Handle function and label completions specially. (parse_linespec): Disable objc shortcut in completion mode. Set what to complete next depending on token type. Skip keyword if in completion mode. (complete_linespec_component, linespec_complete): New. * linespec.h (linespec_complete): Declare. gdb/testsuite/ChangeLog: 2017-07-17 Pedro Alves <palves@redhat.com> * gdb.base/completion.exp: Adjust expected output. * gdb.linespec/ls-errs.exp: Don't send tab characters, now that the completer works.
Diffstat (limited to 'gdb/completer.c')
-rw-r--r--gdb/completer.c79
1 files changed, 47 insertions, 32 deletions
diff --git a/gdb/completer.c b/gdb/completer.c
index c2bb4ee..ba2e860 100644
--- a/gdb/completer.c
+++ b/gdb/completer.c
@@ -45,9 +45,6 @@
#include "completer.h"
-static void complete_expression (completion_tracker &tracker,
- const char *text, const char *word);
-
/* Misc state that needs to be tracked across several different
readline completer entry point calls, all related to a single
completion invocation. */
@@ -558,8 +555,46 @@ complete_files_symbols (completion_tracker &tracker,
}
}
+/* See completer.h. */
+
+completion_list
+complete_source_filenames (const char *text)
+{
+ size_t text_len = strlen (text);
+
+ /* If text includes characters which cannot appear in a file name,
+ the user cannot be asking for completion on files. */
+ if (strcspn (text,
+ gdb_completer_file_name_break_characters)
+ == text_len)
+ return make_source_files_completion_list (text, text);
+
+ return {};
+}
+
+/* Complete address and linespec locations. */
+
+static void
+complete_address_and_linespec_locations (completion_tracker &tracker,
+ const char *text)
+{
+ if (*text == '*')
+ {
+ tracker.advance_custom_word_point_by (1);
+ text++;
+ const char *word
+ = advance_to_expression_complete_word_point (tracker, text);
+ complete_expression (tracker, text, word);
+ }
+ else
+ {
+ linespec_complete (tracker, text);
+ }
+}
+
/* The explicit location options. Note that indexes into this array
must match the explicit_location_match_type enumerators. */
+
static const char *const explicit_options[] =
{
"-source",
@@ -801,7 +836,7 @@ complete_explicit_location (completion_tracker &tracker,
void
location_completer (struct cmd_list_element *ignore,
completion_tracker &tracker,
- const char *text, const char *word_entry)
+ const char *text, const char * /* word */)
{
int found_probe_option = -1;
@@ -872,27 +907,7 @@ location_completer (struct cmd_list_element *ignore,
else
{
/* This is an address or linespec location. */
- if (*text == '*')
- {
- tracker.advance_custom_word_point_by (1);
- text++;
- const char *word
- = advance_to_expression_complete_word_point (tracker, text);
- complete_expression (tracker, text, word);
- }
- else
- {
- /* Fall back to the old linespec completer, for now. */
-
- if (word_entry == NULL)
- {
- /* We're in the handle_brkchars phase. */
- tracker.set_use_custom_word_point (false);
- return;
- }
-
- complete_files_symbols (tracker, text, word_entry);
- }
+ complete_address_and_linespec_locations (tracker, text);
}
/* Add matches for option names, if either:
@@ -984,11 +999,9 @@ add_struct_fields (struct type *type, completion_list &output,
}
}
-/* Complete on expressions. Often this means completing on symbol
- names, but some language parsers also have support for completing
- field names. */
+/* See completer.h. */
-static void
+void
complete_expression (completion_tracker &tracker,
const char *text, const char *word)
{
@@ -1944,10 +1957,12 @@ completion_tracker::build_completion_result (const char *text,
buf, (char *) NULL);
match_list[1] = NULL;
- /* If we already have a space at the end of the match, tell
- readline to skip appending another. */
+ /* If the tracker wants to, or we already have a space at the
+ end of the match, tell readline to skip appending
+ another. */
bool completion_suppress_append
- = (match_list[0][strlen (match_list[0]) - 1] == ' ');
+ = (suppress_append_ws ()
+ || match_list[0][strlen (match_list[0]) - 1] == ' ');
return completion_result (match_list, 1, completion_suppress_append);
}