aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog12
-rw-r--r--gdb/cli/cli-cmds.c34
-rw-r--r--gdb/completer.c173
-rw-r--r--gdb/completer.h10
4 files changed, 210 insertions, 19 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 2ab9a4a..554a9e5 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,17 @@
2017-07-17 Pedro Alves <palves@redhat.com>
+ * cli/cli-cmds.c (complete_command): Use a completion tracker
+ along with completion_find_completion_word for handle_brkchars
+ phase.
+ * completer.c (RL_QF_SINGLE_QUOTE, RL_QF_DOUBLE_QUOTE)
+ (RL_QF_BACKSLASH, RL_QF_OTHER_QUOTE): New.
+ (struct gdb_rl_completion_word_info): New.
+ (gdb_rl_find_completion_word): New.
+ (completion_find_completion_word): New.
+ * completer.h (completion_find_completion_word): Declare.
+
+2017-07-17 Pedro Alves <palves@redhat.com>
+
* ada-lang.c (symbol_completion_match): Adjust comments.
(symbol_completion_add): Replace vector parameter with
completion_tracker parameter. Use it.
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index fa5dd4c..fb41e24 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -246,7 +246,6 @@ static void
complete_command (char *arg_entry, int from_tty)
{
const char *arg = arg_entry;
- int argpoint;
dont_repeat ();
@@ -264,36 +263,31 @@ complete_command (char *arg_entry, int from_tty)
if (arg == NULL)
arg = "";
- argpoint = strlen (arg);
-
- /* complete_line assumes that its first argument is somewhere
- within, and except for filenames at the beginning of, the word to
- be completed. The following crude imitation of readline's
- word-breaking tries to accomodate this. */
- const char *point = arg + argpoint;
- while (point > arg)
- {
- if (strchr (rl_completer_word_break_characters, point[-1]) != 0)
- break;
- point--;
- }
+ completion_tracker tracker_handle_brkchars;
completion_tracker tracker_handle_completions;
+ int quote_char = '\0';
+ const char *word;
+
TRY
{
- complete_line (tracker_handle_completions, point, arg, strlen (arg));
+ word = completion_find_completion_word (tracker_handle_brkchars,
+ arg, &quote_char);
+
+ /* Completers must be called twice. */
+ complete_line (tracker_handle_completions, word, arg, strlen (arg));
}
CATCH (ex, RETURN_MASK_ALL)
{
return;
}
- std::string arg_prefix (arg, point - arg);
+ std::string arg_prefix (arg, word - arg);
completion_result result
= (tracker_handle_completions.build_completion_result
- (point, point - arg, strlen (arg)));
+ (word, word - arg, strlen (arg)));
if (result.number_matches != 0)
{
@@ -308,16 +302,18 @@ complete_command (char *arg_entry, int from_tty)
printf_unfiltered ("%s%s",
arg_prefix.c_str (),
result.match_list[i + 1]);
+ if (quote_char)
+ printf_unfiltered ("%c", quote_char);
printf_unfiltered ("\n");
}
}
if (result.number_matches == max_completions)
{
- /* ARG_PREFIX and POINT are included in the output so that emacs
+ /* ARG_PREFIX and WORD are included in the output so that emacs
will include the message in the output. */
printf_unfiltered (_("%s%s %s\n"),
- arg_prefix.c_str (), point,
+ arg_prefix.c_str (), word,
get_max_completions_reached_message ());
}
}
diff --git a/gdb/completer.c b/gdb/completer.c
index 85e6d88..196610d 100644
--- a/gdb/completer.c
+++ b/gdb/completer.c
@@ -212,6 +212,160 @@ filename_completer_handle_brkchars (struct cmd_list_element *ignore,
(gdb_completer_file_name_break_characters);
}
+/* Possible values for the found_quote flags word used by the completion
+ functions. It says what kind of (shell-like) quoting we found anywhere
+ in the line. */
+#define RL_QF_SINGLE_QUOTE 0x01
+#define RL_QF_DOUBLE_QUOTE 0x02
+#define RL_QF_BACKSLASH 0x04
+#define RL_QF_OTHER_QUOTE 0x08
+
+/* Find the bounds of the current word for completion purposes, and
+ return a pointer to the end of the word. This mimics (and is a
+ modified version of) readline's _rl_find_completion_word internal
+ function.
+
+ This function skips quoted substrings (characters between matched
+ pairs of characters in rl_completer_quote_characters). We try to
+ find an unclosed quoted substring on which to do matching. If one
+ is not found, we use the word break characters to find the
+ boundaries of the current word. QC, if non-null, is set to the
+ opening quote character if we found an unclosed quoted substring,
+ '\0' otherwise. DP, if non-null, is set to the value of the
+ delimiter character that caused a word break. */
+
+struct gdb_rl_completion_word_info
+{
+ const char *word_break_characters;
+ const char *quote_characters;
+ const char *basic_quote_characters;
+};
+
+static const char *
+gdb_rl_find_completion_word (struct gdb_rl_completion_word_info *info,
+ int *qc, int *dp,
+ const char *line_buffer)
+{
+ int scan, end, found_quote, delimiter, pass_next, isbrk;
+ char quote_char;
+ const char *brkchars;
+ int point = strlen (line_buffer);
+
+ /* The algorithm below does '--point'. Avoid buffer underflow with
+ the empty string. */
+ if (point == 0)
+ {
+ if (qc != NULL)
+ *qc = '\0';
+ if (dp != NULL)
+ *dp = '\0';
+ return line_buffer;
+ }
+
+ end = point;
+ found_quote = delimiter = 0;
+ quote_char = '\0';
+
+ brkchars = info->word_break_characters;
+
+ if (info->quote_characters != NULL)
+ {
+ /* We have a list of characters which can be used in pairs to
+ quote substrings for the completer. Try to find the start of
+ an unclosed quoted substring. */
+ /* FOUND_QUOTE is set so we know what kind of quotes we
+ found. */
+ for (scan = pass_next = 0;
+ scan < end;
+ scan++)
+ {
+ if (pass_next)
+ {
+ pass_next = 0;
+ continue;
+ }
+
+ /* Shell-like semantics for single quotes -- don't allow
+ backslash to quote anything in single quotes, especially
+ not the closing quote. If you don't like this, take out
+ the check on the value of quote_char. */
+ if (quote_char != '\'' && line_buffer[scan] == '\\')
+ {
+ pass_next = 1;
+ found_quote |= RL_QF_BACKSLASH;
+ continue;
+ }
+
+ if (quote_char != '\0')
+ {
+ /* Ignore everything until the matching close quote
+ char. */
+ if (line_buffer[scan] == quote_char)
+ {
+ /* Found matching close. Abandon this
+ substring. */
+ quote_char = '\0';
+ point = end;
+ }
+ }
+ else if (strchr (info->quote_characters, line_buffer[scan]))
+ {
+ /* Found start of a quoted substring. */
+ quote_char = line_buffer[scan];
+ point = scan + 1;
+ /* Shell-like quoting conventions. */
+ if (quote_char == '\'')
+ found_quote |= RL_QF_SINGLE_QUOTE;
+ else if (quote_char == '"')
+ found_quote |= RL_QF_DOUBLE_QUOTE;
+ else
+ found_quote |= RL_QF_OTHER_QUOTE;
+ }
+ }
+ }
+
+ if (point == end && quote_char == '\0')
+ {
+ /* We didn't find an unclosed quoted substring upon which to do
+ completion, so use the word break characters to find the
+ substring on which to complete. */
+ while (--point)
+ {
+ scan = line_buffer[point];
+
+ if (strchr (brkchars, scan) != 0)
+ break;
+ }
+ }
+
+ /* If we are at an unquoted word break, then advance past it. */
+ scan = line_buffer[point];
+
+ if (scan)
+ {
+ isbrk = strchr (brkchars, scan) != 0;
+
+ if (isbrk)
+ {
+ /* If the character that caused the word break was a quoting
+ character, then remember it as the delimiter. */
+ if (info->basic_quote_characters
+ && strchr (info->basic_quote_characters, scan)
+ && (end - point) > 1)
+ delimiter = scan;
+
+ point++;
+ }
+ }
+
+ if (qc != NULL)
+ *qc = quote_char;
+ if (dp != NULL)
+ *dp = delimiter;
+
+ return line_buffer + point;
+}
+
/* Complete on linespecs, which might be of two possible forms:
file:line
@@ -1306,6 +1460,25 @@ gdb_completion_word_break_characters ()
/* See completer.h. */
+const char *
+completion_find_completion_word (completion_tracker &tracker, const char *text,
+ int *quote_char)
+{
+ size_t point = strlen (text);
+
+ complete_line_internal (tracker, NULL, text, point, handle_brkchars);
+
+ gdb_rl_completion_word_info info;
+
+ info.word_break_characters = rl_completer_word_break_characters;
+ info.quote_characters = gdb_completer_quote_characters;
+ info.basic_quote_characters = rl_basic_quote_characters;
+
+ return gdb_rl_find_completion_word (&info, quote_char, NULL, text);
+}
+
+/* See completer.h. */
+
void
completion_tracker::recompute_lowest_common_denominator (const char *new_match)
{
diff --git a/gdb/completer.h b/gdb/completer.h
index 4b3b188..cf93cf0 100644
--- a/gdb/completer.h
+++ b/gdb/completer.h
@@ -203,6 +203,16 @@ extern void complete_line (completion_tracker &tracker,
const char *line_buffer,
int point);
+/* Find the bounds of the word in TEXT for completion purposes, and
+ return a pointer to the end of the word. Calls the completion
+ machinery for a handle_brkchars phase (using TRACKER) to figure out
+ the right work break characters for the command in TEXT.
+ QUOTE_CHAR, if non-null, is set to the opening quote character if
+ we found an unclosed quoted substring, '\0' otherwise. */
+extern const char *completion_find_completion_word (completion_tracker &tracker,
+ const char *text,
+ int *quote_char);
+
extern char **gdb_rl_attempted_completion_function (const char *text,
int start, int end);