Re: [PATCH] MI: Add new command -complete

Jan Vrany
2019-01-16T09:21:58Z

Polite ping.

Jan

On Thu, 2019-01-03 at 22:29 +0000, Jan Vrany wrote:
> 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)"