diff options
author | Pedro Alves <palves@redhat.com> | 2017-07-17 20:08:02 +0100 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2017-07-17 20:29:37 +0100 |
commit | c45ec17c07d8aa4554b0b2ca67a5f4dc2c87acc4 (patch) | |
tree | a57b4007fe95470fca71df4958c9285141033c52 /gdb/completer.c | |
parent | be966d4207ff8df6572a23b911e5a69a2ab9370f (diff) | |
download | gdb-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.c | 79 |
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); } |