#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. */
/* The name of a function or method. */
MATCH_FUNCTION,
+ /* The fully-qualified name of a function or method. */
+ MATCH_QUALIFIED,
+
/* A line number. */
MATCH_LINE,
const char *text, const char *word)
{
int subsequent_name;
- VEC (char_ptr) *return_val = NULL;
subsequent_name = 0;
while (1)
{
- char *p, *q;
-
- p = rl_filename_completion_function (text, subsequent_name);
- if (p == NULL)
+ gdb::unique_xmalloc_ptr<char> p_rl
+ (rl_filename_completion_function (text, subsequent_name));
+ if (p_rl == NULL)
break;
/* We need to set subsequent_name to a non-zero value before the
continue line below, because otherwise, if the first file
subsequent_name = 1;
/* Like emacs, don't complete on old versions. Especially
useful in the "source" command. */
+ const char *p = p_rl.get ();
if (p[strlen (p) - 1] == '~')
- {
- xfree (p);
- continue;
- }
+ continue;
- if (word == text)
- /* Return exactly p. */
- q = p;
- else if (word > text)
- {
- /* Return some portion of p. */
- q = (char *) xmalloc (strlen (p) + 5);
- strcpy (q, p + (word - text));
- xfree (p);
- }
- else
- {
- /* Return some of TEXT plus p. */
- q = (char *) xmalloc (strlen (p) + (text - word) + 5);
- strncpy (q, word, text - word);
- q[text - word] = '\0';
- strcat (q, p);
- xfree (p);
- }
- tracker.add_completion (gdb::unique_xmalloc_ptr<char> (q));
+ tracker.add_completion
+ (make_completion_match_str (std::move (p_rl), text, word));
}
#if 0
/* There is no way to do this just long enough to affect quote
complete_files_symbols (completion_tracker &tracker,
const char *text, const char *word)
{
- int ix;
completion_list fn_list;
const char *p;
int quote_found = 0;
{
collect_file_symbol_completion_matches (tracker,
complete_symbol_mode::EXPRESSION,
+ symbol_name_match_type::EXPRESSION,
symbol_start, word,
file_to_match);
xfree (file_to_match);
collect_symbol_completion_matches (tracker,
complete_symbol_mode::EXPRESSION,
+ symbol_name_match_type::EXPRESSION,
symbol_start, word);
/* If text includes characters which cannot appear in a file
name, they cannot be asking for completion on files. */
if (!fn_list.empty () && !tracker.have_completions ())
{
- char *fn;
-
/* If we only have file names as possible completion, we should
bring them in sync with what rl_complete expects. The
problem is that if the user types "break /foo/b TAB", and the
on the entire text as a symbol. */
collect_symbol_completion_matches (tracker,
complete_symbol_mode::EXPRESSION,
+ symbol_name_match_type::EXPRESSION,
orig_text, word);
}
}
+/* 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,
+ symbol_name_match_type match_type)
+{
+ 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, match_type);
+ }
+}
+
/* 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",
"-function",
+ "-qualified",
"-line",
"-label",
NULL
const struct explicit_location *explicit_loc
= get_explicit_location (location);
+ /* True if the option expects an argument. */
+ bool needs_arg = true;
+
/* Note, in the various MATCH_* below, we complete on
explicit_loc->foo instead of WORD, because only the former will
have already skipped past any quote char. */
{
const char *function = string_or_empty (explicit_loc->function_name);
linespec_complete_function (tracker, function,
+ explicit_loc->func_name_match_type,
explicit_loc->source_filename);
}
break;
+ case MATCH_QUALIFIED:
+ needs_arg = false;
+ break;
case MATCH_LINE:
/* Nothing to offer. */
break;
case MATCH_LABEL:
- /* Not supported. */
+ {
+ const char *label = string_or_empty (explicit_loc->label_name);
+ linespec_complete_label (tracker, language,
+ explicit_loc->source_filename,
+ explicit_loc->function_name,
+ explicit_loc->func_name_match_type,
+ label);
+ }
break;
default:
gdb_assert_not_reached ("unhandled explicit_location_match_type");
}
- if (tracker.completes_to_completion_word (word))
+ if (!needs_arg || tracker.completes_to_completion_word (word))
{
tracker.discard_completions ();
tracker.advance_custom_word_point_by (strlen (word));
keyword. */
if (keyword != word)
{
- keyword = skip_spaces_const (keyword);
+ keyword = skip_spaces (keyword);
tracker.advance_custom_word_point_by (keyword - word);
complete_on_enum (tracker, linespec_keywords, keyword, keyword);
const char * const *keywords, const char **text_p)
{
const char *text = *text_p;
- const char *after = skip_to_space_const (text);
+ const char *after = skip_to_space (text);
size_t len = after - text;
if (text[len] != ' ')
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;
tracker.advance_custom_word_point_by (1);
}
- if (location != NULL)
+ if (completion_info.saw_explicit_location_option)
{
if (*copy != '\0')
{
}
}
- else
+ /* This is an address or linespec location. */
+ else if (location != NULL)
{
- /* 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);
- }
+ /* Handle non-explicit location options. */
+
+ int keyword = skip_keyword (tracker, explicit_options, &text);
+ if (keyword == -1)
+ complete_on_enum (tracker, explicit_options, text, text);
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;
- }
+ tracker.advance_custom_word_point_by (copy - text);
+ text = copy;
- complete_files_symbols (tracker, text, word_entry);
+ symbol_name_match_type match_type
+ = get_explicit_location (location.get ())->func_name_match_type;
+ complete_address_and_linespec_locations (tracker, text, match_type);
}
}
+ else
+ {
+ /* No options. */
+ complete_address_and_linespec_locations (tracker, text,
+ symbol_name_match_type::WILD);
+ }
/* Add matches for option names, if either:
}
}
-/* 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)
{
}
else if (fieldname && code != TYPE_CODE_UNDEF)
{
- VEC (char_ptr) *result;
struct cleanup *cleanup = make_cleanup (xfree, fieldname);
collect_symbol_completion_matches_type (tracker, fieldname, fieldname,
const char *text, const char *word)
{
collect_symbol_completion_matches (tracker, complete_symbol_mode::EXPRESSION,
+ symbol_name_match_type::EXPRESSION,
text, word);
}
word = tmp_command + point - strlen (text);
}
- if (point == 0)
+ /* Move P up to the start of the command. */
+ p = skip_spaces (p);
+
+ if (*p == '\0')
{
- /* An empty line we want to consider ambiguous; that is, it
- could be any command. */
+ /* An empty line is ambiguous; that is, it could be any
+ command. */
c = CMD_LIST_AMBIGUOUS;
result_list = 0;
}
if (except.error != MAX_COMPLETIONS_REACHED_ERROR)
throw_exception (except);
}
+ END_CATCH
}
/* See completer.h. */
/* See completer.h. */
bool
-completion_tracker::maybe_add_completion (gdb::unique_xmalloc_ptr<char> name)
+completion_tracker::maybe_add_completion
+ (gdb::unique_xmalloc_ptr<char> name,
+ completion_match_for_lcd *match_for_lcd)
{
void **slot;
slot = htab_find_slot (m_entries_hash, name.get (), INSERT);
if (*slot == HTAB_EMPTY_ENTRY)
{
- const char *match_for_lcd_str = name.get ();
+ const char *match_for_lcd_str = NULL;
+
+ if (match_for_lcd != NULL)
+ match_for_lcd_str = match_for_lcd->finish ();
+
+ if (match_for_lcd_str == NULL)
+ match_for_lcd_str = name.get ();
recompute_lowest_common_denominator (match_for_lcd_str);
/* See completer.h. */
void
-completion_tracker::add_completion (gdb::unique_xmalloc_ptr<char> name)
+completion_tracker::add_completion (gdb::unique_xmalloc_ptr<char> name,
+ completion_match_for_lcd *match_for_lcd)
{
- if (!maybe_add_completion (std::move (name)))
+ if (!maybe_add_completion (std::move (name), match_for_lcd))
throw_error (MAX_COMPLETIONS_REACHED_ERROR, _("Max completions reached."));
}
add_completion (std::move (candidate));
}
+/* Helper for the make_completion_match_str overloads. Returns NULL
+ as an indication that we want MATCH_NAME exactly. It is up to the
+ caller to xstrdup that string if desired. */
+
+static char *
+make_completion_match_str_1 (const char *match_name,
+ const char *text, const char *word)
+{
+ char *newobj;
+
+ if (word == text)
+ {
+ /* Return NULL as an indication that we want MATCH_NAME
+ exactly. */
+ return NULL;
+ }
+ else if (word > text)
+ {
+ /* Return some portion of MATCH_NAME. */
+ newobj = xstrdup (match_name + (word - text));
+ }
+ else
+ {
+ /* Return some of WORD plus MATCH_NAME. */
+ size_t len = strlen (match_name);
+ newobj = (char *) xmalloc (text - word + len + 1);
+ memcpy (newobj, word, text - word);
+ memcpy (newobj + (text - word), match_name, len + 1);
+ }
+
+ return newobj;
+}
+
+/* See completer.h. */
+
+gdb::unique_xmalloc_ptr<char>
+make_completion_match_str (const char *match_name,
+ const char *text, const char *word)
+{
+ char *newobj = make_completion_match_str_1 (match_name, text, word);
+ if (newobj == NULL)
+ newobj = xstrdup (match_name);
+ return gdb::unique_xmalloc_ptr<char> (newobj);
+}
+
+/* See completer.h. */
+
+gdb::unique_xmalloc_ptr<char>
+make_completion_match_str (gdb::unique_xmalloc_ptr<char> &&match_name,
+ const char *text, const char *word)
+{
+ char *newobj = make_completion_match_str_1 (match_name.get (), text, word);
+ if (newobj == NULL)
+ return std::move (match_name);
+ return gdb::unique_xmalloc_ptr<char> (newobj);
+}
+
/* Generate completions all at once. Does nothing if max_completions
is 0. If max_completions is non-negative, this will collect at
most max_completions strings.
{
while (p_orig < orig_end && *p_orig == ' ')
res += *p_orig++;
- p_lcd = skip_spaces_const (p_lcd);
+ p_lcd = skip_spaces (p_lcd);
}
else
{
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);
}
return ret;
}
-/* Compare C strings for std::sort. */
-
-static bool
-compare_cstrings (const char *str1, const char *str2)
-{
- return strcmp (str1, str2) < 0;
-}
-
/* See completer.h */
void
}
}
}
-\f
-extern initialize_file_ftype _initialize_completer; /* -Wmissing-prototypes */
void
_initialize_completer (void)