[PATCH] MI: Add new command -complete

Jan Vrany
2019-01-03T22:30:32Z

There is a CLI command 'complete' intended to use with emacs. Such a command
would also be useful for MI frontends, when separate CLI and MI channels cannot
be used. For example, on Windows (because of lack of PTYs) or when GDB is used
through SSH session.

This commit adds a new '-complete' MI command which is implemented using
CLI's 'complete'.

gdb/Changelog:
2019-01-03 Jan Vrany <jan.vrany@fit.cvut.cz>

* cli/cli-cmds.h: Export complete_command.
* cli/cli-cmds.c (complete_command): Update to print completions
on MI channel if requested.
* mi/mi-cmds.c: Define new -complete command implemented using
it CLI command 'complete'.
* NEWS: Mention new -complete command.

gdb/doc/ChangeLog:
2019-01-03 Jan Vrany <jan.vrany@fit.cvut.cz>

* gdb.texinfo (Miscellaneous GDB/MI Commands): Document new
MI command -complete.

gdb/testsuite/ChangeLog:
2019-01-03 Jan Vrany <jan.vrany@fit.cvut.cz>

* gdb.mi/mi-complete.exp: New file.
---
gdb/ChangeLog | 9 +++
gdb/NEWS | 7 ++
gdb/cli/cli-cmds.c | 95 +++++++++++++++++++---------
gdb/cli/cli-cmds.h | 4 ++
gdb/doc/ChangeLog | 5 ++
gdb/doc/gdb.texinfo | 32 ++++++++++
gdb/mi/mi-cmds.c | 3 +
gdb/testsuite/ChangeLog | 4 ++
gdb/testsuite/gdb.mi/mi-complete.exp | 71 +++++++++++++++++++++
9 files changed, 199 insertions(+), 31 deletions(-)
create mode 100644 gdb/testsuite/gdb.mi/mi-complete.exp

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 08c7c6c1f4..322b539417 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,12 @@
+2019-01-03 Jan Vrany <jan.vrany@fit.cvut.cz>
+
+ * cli/cli-cmds.h: Export complete_command.
+ * cli/cli-cmds.c (complete_command): Update to print completions
+ on MI channel if requested.
+ * mi/mi-cmds.c: Define new -complete command implemented using
+ it CLI command 'complete'.
+ * NEWS: Mention new -complete command.
+
2018-12-17 Andrew Burgess <andrew.burgess@embecosm.com>

* dwarf2read.c (struct dwarf2_cu): Convert the fields 'mark',
diff --git a/gdb/NEWS b/gdb/NEWS
index 913f3ae3b6..6b561af71f 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -96,6 +96,13 @@ maint show dwarf unwinders
info proc files
Display a list of open files for a process.

+* New MI commands
+
+-complete
+ This lists all the possible completions for the rest of the line, if it
+ were to be given as a command itself. This is intended for use by MI frontends
+ in cases when separate CLI and MI channels cannot be used.
+
* Changed commands

target remote FILENAME
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 135f550b80..468f66dac6 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -223,16 +223,22 @@ help_command (const char *command, int from_tty)
/* Note: The "complete" command is used by Emacs to implement completion.
[Is that why this function writes output with *_unfiltered?] */

-static void
+void
complete_command (const char *arg, int from_tty)
{
+ struct ui_out *uiout = current_uiout;
+ bool is_mi_like = uiout->is_mi_like_p ();
+
dont_repeat ();

if (max_completions == 0)
{
- /* Only print this for non-mi frontends. An MI frontend may not
- be able to handle this. */
- if (!current_uiout->is_mi_like_p ())
+ if (is_mi_like)
+ {
+ error (_("max-completions is zero,"
+ " completion is disabled.\n"));
+ }
+ else
{
printf_unfiltered (_("max-completions is zero,"
" completion is disabled.\n"));
@@ -278,34 +284,61 @@ complete_command (const char *arg, int from_tty)
completion_result result
= tracker->build_completion_result (word, word - arg, strlen (arg));

- if (result.number_matches != 0)
- {
- if (result.number_matches == 1)
- printf_unfiltered ("%s%s\n", arg_prefix.c_str (), result.match_list[0]);
- else
- {
- result.sort_match_list ();
-
- for (size_t i = 0; i < result.number_matches; i++)
- {
- 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 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 (), word,
- get_max_completions_reached_message ());
- }
+ {
+ ui_out_emit_list completions_emitter (uiout, "completions");
+ if (result.number_matches != 0)
+ {
+ if (result.number_matches == 1)
+ {
+ if (is_mi_like)
+ uiout->field_fmt(NULL, "%s%s", arg_prefix.c_str (),
+ result.match_list[0]);
+ else
+ printf_unfiltered ("%s%s\n", arg_prefix.c_str (),
+ result.match_list[0]);
+ }
+ else
+ {
+ result.sort_match_list ();
+
+ for (size_t i = 0; i < result.number_matches; i++)
+ {
+ if (is_mi_like)
+ {
+ uiout->field_fmt(NULL, "%s%s", arg_prefix.c_str (),
+ result.match_list[i + 1]);
+ }
+ else
+ {
+ 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)
+ {
+ if (is_mi_like)
+ uiout->field_string("max_completions_reached", "1");
+ else
+ {
+ /* 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 (), word,
+ get_max_completions_reached_message ());
+ }
+ }
+ else
+ {
+ if (is_mi_like)
+ uiout->field_string("max_completions_reached", "0");
+ }
}

int
diff --git a/gdb/cli/cli-cmds.h b/gdb/cli/cli-cmds.h
index 3fa188dba6..bcd12c0c0b 100644
--- a/gdb/cli/cli-cmds.h
+++ b/gdb/cli/cli-cmds.h
@@ -106,6 +106,10 @@ void init_cmd_lists (void);

void init_cli_cmds (void);

+/* Exported to gdb/mi/mi-cmds.c */
+
+void complete_command (const char *, int);
+
int is_complete_command (struct cmd_list_element *cmd);

/* Exported to gdb/main.c */
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 68d3068c72..da81f6a6c1 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,8 @@
+2019-01-03 Jan Vrany <jan.vrany@fit.cvut.cz>
+
+ * gdb.texinfo (Miscellaneous GDB/MI Commands): Document new
+ MI command -complete.
+
2018-12-13 John Baldwin <jhb@FreeBSD.org>

* gdb.texinfo (Set Catchpoints): Add an anchor for 'catch syscall'.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index d766e44e63..7f88273145 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -34236,6 +34236,38 @@ fullname="/home/nickrob/myprog.c",line="73",arch="i386:x86_64"@}
(gdb)
@end smallexample

+@subheading The @code{-complete} Command
+@findex -complete
+
+@subheading Synopsis
+
+@smallexample
+-complete @var{command}
+@end smallexample
+
+Show a list of completions for partially typed CLI @var{command}. The
+@var{command} should be given in verbatim without any quoting / escaping.
+
+This command is intended for @sc{gdb/mi} frontends that cannot use two separate
+CLI and MI channels - for example: because of lack of PTYs like on Windows or
+because @sc{gdb} is used remotely via a SSH connection.
+
+@subheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{complete}.
+
+@subheading Example
+
+@smallexample
+(gdb)
+-complete br
+^done,completions=["break","break-range"],max_completions_reached="0"
+(gdb)
+-complete b madv
+^done,completions=["b madvise"],max_completions_reached="0"
+(gdb)
+@end smallexample
+
@node Annotations
@chapter @value{GDBN} Annotations

diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c
index 51014eded2..7b510f71d4 100644
--- a/gdb/mi/mi-cmds.c
+++ b/gdb/mi/mi-cmds.c
@@ -20,9 +20,11 @@

#include "defs.h"
#include "top.h"
+#include "cli/cli-cmds.h"
#include "mi-cmds.h"
#include "mi-main.h"

+
struct mi_cmd;
static struct mi_cmd **lookup_table (const char *command);
static void build_table (struct mi_cmd *commands);
@@ -75,6 +77,7 @@ static struct mi_cmd mi_cmds[] =
&mi_suppress_notification.breakpoint),
DEF_MI_CMD_MI_1 ("catch-unload", mi_cmd_catch_unload,
&mi_suppress_notification.breakpoint),
+ DEF_MI_CMD_CLI ("complete", "complete", 1),
DEF_MI_CMD_MI ("data-disassemble", mi_cmd_disassemble),
DEF_MI_CMD_MI ("data-evaluate-expression", mi_cmd_data_evaluate_expression),
DEF_MI_CMD_MI ("data-list-changed-registers",
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index ab3a74fffd..40da71b2c5 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2019-01-03 Jan Vrany <jan.vrany@fit.cvut.cz>
+
+ * gdb.mi/mi-complete.exp: New file.
+
2018-12-12 Andrew Burgess <andrew.burgess@embecosm.com>

* gdb.base/annota1.exp: Update a test regexp.
diff --git a/gdb/testsuite/gdb.mi/mi-complete.exp b/gdb/testsuite/gdb.mi/mi-complete.exp
new file mode 100644
index 0000000000..14c763a966
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-complete.exp
@@ -0,0 +1,71 @@
+# Copyright 2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Verify -data-evaluate-expression. There are really minimal tests.
+
+# The goal is not to test gdb functionality, which is done by other tests,
+# but to verify the correct output response to MI operations.
+#
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
+gdb_exit
+if [mi_gdb_start] {
+ continue
+}
+
+standard_testfile basics.c
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ untested "failed to compile"
+ return -1
+}
+
+mi_run_to_main
+
+mi_gdb_test "1-complete br" \
+ "1\\^done,completions=\\\[.*\"break\",.*\"break-range\".*\\\],max_completions_reached=\"0\"" \
+ "-complete br"
+
+# Check empty completion list
+mi_gdb_test "5-complete bogus" \
+ "5\\^done,completions=\\\[\\\],max_completions_reached=\"0\"" \
+ "-complete bogus"
+
+
+# Check completions for commands with space
+mi_gdb_test "4-complete b mai" \
+ "4\\^done,completions=\\\[.*\"b main\".*\\\],max_completions_reached=\"0\"" \
+ "-complete b mai"
+
+mi_gdb_test "-info-gdb-mi-command complete" \
+ "\\^done,command=\{exists=\"true\"\}" \
+ "-info-gdb-mi-command complete"
+
+# Limit max completions and check that max_completions_reached=\"0\" is set
+# to 1.
+send_gdb "set max-completions 1\n"
+
+mi_gdb_test "2-complete br" \
+ ".*2\\^done,completions=\\\[\"br\[A-Za-z0-9-\]+\"\\\],max_completions_reached=\"1\"" \
+ "-complete br (max-completions 1)"
+
+# Disable completions and check an error is returned
+send_gdb "set max-completions 0\n"
+
+mi_gdb_test "3-complete br" \
+ ".*3\\^error,msg=\".*" \
+ "-complete br (max-completions 1)"
--
2.20.1