@@ -18,11 +18,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
+#include "cli-interp.h"
#include "interps.h"
#include "event-top.h"
#include "ui-out.h"
#include "cli-out.h"
#include "top.h" /* for "execute_command" */
+#include "event-top.h"
#include "infrun.h"
#include "observer.h"
@@ -196,6 +198,7 @@ cli_interpreter_init (struct interp *self, int top_level)
static int
cli_interpreter_resume (void *data)
{
+ struct ui *ui = current_ui;
struct cli_interp *cli = (struct cli_interp *) data;
struct ui_file *stream;
@@ -212,7 +215,9 @@ cli_interpreter_resume (void *data)
stream = NULL;
}
- gdb_setup_readline ();
+ gdb_setup_readline (1);
+
+ ui->input_handler = command_line_handler;
if (stream != NULL)
cli_out_set_stream (cli->cli_uiout, gdb_stdout);
@@ -252,6 +257,12 @@ cli_interpreter_exec (void *data, const char *command_str)
return result;
}
+int
+cli_interpreter_supports_command_editing (struct interp *interp)
+{
+ return 1;
+}
+
static struct gdb_exception
safe_execute_command (struct ui_out *command_uiout, char *command, int from_tty)
{
@@ -296,7 +307,8 @@ static const struct interp_procs cli_interp_procs = {
cli_interpreter_exec, /* exec_proc */
cli_ui_out, /* ui_out_proc */
NULL, /* set_logging_proc */
- cli_command_loop /* command_loop_proc */
+ cli_command_loop, /* command_loop_proc */
+ cli_interpreter_supports_command_editing, /* supports_command_editing_proc */
};
static struct interp *
new file mode 100644
@@ -0,0 +1,25 @@
+/* CLI Definitions for GDB, the GNU debugger.
+
+ Copyright (C) 2016 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/>. */
+
+#ifndef CLI_INTERP_H
+#define CLI_INTERP_H 1
+
+struct interp;
+
+extern int cli_interpreter_supports_command_editing (struct interp *interp);
+
+#endif
@@ -47,8 +47,6 @@
#undef savestring
static void rl_callback_read_char_wrapper (gdb_client_data client_data);
-static void command_line_handler (char *rl);
-static void change_line_handler (void);
static char *top_level_prompt (void);
/* Signal handlers. */
@@ -87,7 +85,7 @@ static void async_sigterm_handler (gdb_client_data arg);
ezannoni: as of 1999-04-29 I expect that this
variable will not be used after gdb is changed to use the event
loop as default engine, and event-top.c is merged into top.c. */
-int async_command_editing_p;
+int set_editing_cmd_var;
/* This is used to display the notification of the completion of an
asynchronous execution command. */
@@ -151,34 +149,45 @@ cli_command_loop (void *data)
therefore bypassing readline, and letting gdb handle the input
itself, via gdb_readline_no_editing_callback. Also it is used in
the opposite case in which the user sets editing on again, by
- restoring readline handling of the input. */
-static void
-change_line_handler (void)
+ restoring readline handling of the input.
+
+ NOTE: this operates on input_fd, not instream. If we are reading
+ commands from a file, instream will point to the file. However, we
+ always read commands from a file with editing off. This means that
+ the 'set editing on/off' will have effect only on the interactive
+ session. */
+
+void
+change_line_handler (int editing)
{
struct ui *ui = current_ui;
- /* NOTE: this operates on input_fd, not instream. If we are reading
- commands from a file, instream will point to the file. However in
- async mode, we always read commands from a file with editing
- off. This means that the 'set editing on/off' will have effect
- only on the interactive session. */
+ /* We can only have one instance of readline, so we only allow
+ editing on the main UI. */
+ if (ui != main_ui)
+ return;
+
+ /* Don't try enabling editing if the interpreter doesn't support it
+ (e.g., MI). */
+ if (!interp_supports_command_editing (top_level_interpreter ())
+ || !interp_supports_command_editing (command_interp ()))
+ return;
- if (async_command_editing_p)
+ if (editing)
{
+ gdb_assert (ui == main_ui);
+
/* Turn on editing by using readline. */
ui->call_readline = rl_callback_read_char_wrapper;
- ui->input_handler = command_line_handler;
}
else
{
/* Turn off editing by using gdb_readline_no_editing_callback. */
- gdb_rl_callback_handler_remove ();
+ if (ui->command_editing)
+ gdb_rl_callback_handler_remove ();
ui->call_readline = gdb_readline_no_editing_callback;
-
- /* Set up the command handler as well, in case we are called as
- first thing from .gdbinit. */
- ui->input_handler = command_line_handler;
}
+ ui->command_editing = editing;
}
/* The functions below are wrappers for rl_callback_handler_remove and
@@ -199,6 +208,10 @@ static int callback_handler_installed;
void
gdb_rl_callback_handler_remove (void)
{
+ struct ui *ui = current_ui;
+
+ gdb_assert (ui == main_ui);
+
rl_callback_handler_remove ();
callback_handler_installed = 0;
}
@@ -212,6 +225,8 @@ gdb_rl_callback_handler_install (const char *prompt)
{
struct ui *ui = current_ui;
+ gdb_assert (ui == main_ui);
+
/* Calling rl_callback_handler_install resets readline's input
buffer. Calling this when we were already processing input
therefore loses input. */
@@ -226,6 +241,10 @@ gdb_rl_callback_handler_install (const char *prompt)
void
gdb_rl_callback_handler_reinstall (void)
{
+ struct ui *ui = current_ui;
+
+ gdb_assert (ui == main_ui);
+
if (!callback_handler_installed)
{
/* Passing NULL as prompt argument tells readline to not display
@@ -287,7 +306,8 @@ display_gdb_prompt (const char *new_prompt)
the above two functions. Calling
rl_callback_handler_remove(), does the job. */
- gdb_rl_callback_handler_remove ();
+ if (current_ui->command_editing)
+ gdb_rl_callback_handler_remove ();
do_cleanups (old_chain);
return;
}
@@ -300,7 +320,7 @@ display_gdb_prompt (const char *new_prompt)
else
actual_gdb_prompt = xstrdup (new_prompt);
- if (async_command_editing_p)
+ if (current_ui->command_editing)
{
gdb_rl_callback_handler_remove ();
gdb_rl_callback_handler_install (actual_gdb_prompt);
@@ -990,19 +1010,12 @@ async_float_handler (gdb_client_data arg)
}
-/* Called by do_setshow_command. */
-void
-set_async_editing_command (char *args, int from_tty,
- struct cmd_list_element *c)
-{
- change_line_handler ();
-}
-
/* Set things up for readline to be invoked via the alternate
interface, i.e. via a callback function (rl_callback_read_char),
and hook up instream to the event loop. */
+
void
-gdb_setup_readline (void)
+gdb_setup_readline (int editing)
{
struct ui *ui = current_ui;
@@ -1017,32 +1030,28 @@ gdb_setup_readline (void)
gdb_stdtarg = gdb_stderr; /* for moment */
gdb_stdtargerr = gdb_stderr; /* for moment */
- /* If the input stream is connected to a terminal, turn on
- editing. */
- if (ISATTY (ui->instream))
+ /* If the input stream is connected to a terminal, turn on editing.
+ However, that is only allowed on the main UI, as we can only have
+ one instance of readline. */
+ if (ISATTY (ui->instream) && editing && ui == main_ui)
{
/* Tell gdb that we will be using the readline library. This
could be overwritten by a command in .gdbinit like 'set
editing on' or 'off'. */
- async_command_editing_p = 1;
-
+ ui->command_editing = 1;
+
/* When a character is detected on instream by select or poll,
readline will be invoked via this callback function. */
ui->call_readline = rl_callback_read_char_wrapper;
+
+ /* Tell readline to use the same input stream that gdb uses. */
+ rl_instream = ui->instream;
}
else
{
- async_command_editing_p = 0;
+ ui->command_editing = 0;
ui->call_readline = gdb_readline_no_editing_callback;
}
-
- /* When readline has read an end-of-line character, it passes the
- complete line to gdb for processing; command_line_handler is the
- function that does this. */
- ui->input_handler = command_line_handler;
-
- /* Tell readline to use the same input stream that gdb uses. */
- rl_instream = ui->instream;
/* Now create the event source for this UI's input file descriptor.
Another source is going to be the target program (inferior), but
@@ -1054,6 +1063,7 @@ gdb_setup_readline (void)
/* Disable command input through the standard CLI channels. Used in
the suspend proc for interpreters that use the standard gdb readline
interface, like the cli & the mi. */
+
void
gdb_disable_readline (void)
{
@@ -1072,6 +1082,7 @@ gdb_disable_readline (void)
gdb_stdtargerr = NULL;
#endif
- gdb_rl_callback_handler_remove ();
+ if (ui->command_editing)
+ gdb_rl_callback_handler_remove ();
delete_file_handler (ui->input_fd);
}
@@ -28,12 +28,12 @@ struct cmd_list_element;
FIXME: these should really go into top.h. */
extern void display_gdb_prompt (const char *new_prompt);
-void gdb_setup_readline (void);
-void gdb_disable_readline (void);
+extern void gdb_setup_readline (int);
+extern void gdb_disable_readline (void);
extern void async_init_signals (void);
-extern void set_async_editing_command (char *args, int from_tty,
- struct cmd_list_element *c);
+extern void change_line_handler (int);
+extern void command_line_handler (char *rl);
extern void command_handler (char *command);
/* Signal to catch ^Z typed while reading a command: SIGTSTP or SIGCONT. */
@@ -54,7 +54,7 @@ extern void async_enable_stdin (void);
/* Exported variables from event-top.c.
FIXME: these should really go into top.h. */
-extern int async_command_editing_p;
+extern int set_editing_cmd_var;
extern int exec_done_display_p;
extern struct prompts the_prompts;
extern void (*after_char_processing_hook) (void);
@@ -3801,7 +3801,7 @@ reinstall_readline_callback_handler_cleanup (void *arg)
return;
}
- if (async_command_editing_p && !sync_execution)
+ if (current_ui->command_editing && !sync_execution)
gdb_rl_callback_handler_reinstall ();
}
@@ -395,6 +395,16 @@ current_interp_command_loop (void)
interp->procs->command_loop_proc (interp->data);
}
+/* See interp.h */
+
+int
+interp_supports_command_editing (struct interp *interp)
+{
+ if (interp->procs->supports_command_editing_proc != NULL)
+ return interp->procs->supports_command_editing_proc (interp);
+ return 0;
+}
+
int
interp_quiet_p (struct interp *interp)
{
@@ -50,6 +50,8 @@ typedef int (interp_set_logging_ftype) (struct interp *self, int start_log,
struct ui_file *out,
struct ui_file *logfile);
+typedef int (interp_supports_command_editing_ftype) (struct interp *self);
+
struct interp_procs
{
interp_init_ftype *init_proc;
@@ -69,6 +71,11 @@ struct interp_procs
interp_set_logging_ftype *set_logging_proc;
interp_command_loop_ftype *command_loop_proc;
+
+ /* Returns true if this interpreter supports using the readline
+ library; false if it uses GDB's own simplified readline
+ emulation. */
+ interp_supports_command_editing_ftype *supports_command_editing_proc;
};
extern struct interp *interp_new (const char *name,
@@ -104,6 +111,10 @@ extern struct interp *command_interp (void);
extern void clear_interpreter_hooks (void);
+/* Returns true if INTERP supports using the readline library; false
+ if it uses GDB's own simplified form of readline. */
+extern int interp_supports_command_editing (struct interp *interp);
+
/* well-known interpreters */
#define INTERP_CONSOLE "console"
#define INTERP_MI1 "mi1"
@@ -155,13 +155,10 @@ mi_interpreter_resume (void *data)
/* As per hack note in mi_interpreter_init, swap in the output
channels... */
- gdb_setup_readline ();
+ gdb_setup_readline (0);
- /* These overwrite some of the initialization done in
- _intialize_event_loop. */
ui->call_readline = gdb_readline_no_editing_callback;
ui->input_handler = mi_execute_command_input_handler;
- async_command_editing_p = 0;
/* FIXME: This is a total hack for now. PB's use of the MI
implicitly relies on a bug in the async support which allows
asynchronous commands to leak through the commmand loop. The bug
@@ -779,7 +779,7 @@ gdb_readline_wrapper_line (char *line)
we're handling an asynchronous target event and running in the
background, just before returning to the event loop to process
further input (or more target events). */
- if (async_command_editing_p)
+ if (current_ui->command_editing)
gdb_rl_callback_handler_remove ();
}
@@ -799,7 +799,8 @@ gdb_readline_wrapper_cleanup (void *arg)
struct gdb_readline_wrapper_cleanup *cleanup
= (struct gdb_readline_wrapper_cleanup *) arg;
- rl_already_prompted = cleanup->already_prompted_orig;
+ if (ui->command_editing)
+ rl_already_prompted = cleanup->already_prompted_orig;
gdb_assert (ui->input_handler == gdb_readline_wrapper_line);
ui->input_handler = cleanup->handler_orig;
@@ -837,7 +838,10 @@ gdb_readline_wrapper (const char *prompt)
cleanup->handler_orig = ui->input_handler;
ui->input_handler = gdb_readline_wrapper_line;
- cleanup->already_prompted_orig = rl_already_prompted;
+ if (ui->command_editing)
+ cleanup->already_prompted_orig = rl_already_prompted;
+ else
+ cleanup->already_prompted_orig = 0;
cleanup->target_is_async_orig = target_is_async_p ();
@@ -849,7 +853,8 @@ gdb_readline_wrapper (const char *prompt)
/* Display our prompt and prevent double prompt display. */
display_gdb_prompt (prompt);
- rl_already_prompted = 1;
+ if (ui->command_editing)
+ rl_already_prompted = 1;
if (after_char_processing_hook)
(*after_char_processing_hook) ();
@@ -1411,12 +1416,18 @@ quit_confirm (void)
static void
undo_terminal_modifications_before_exit (void)
{
+ struct ui *saved_top_level = current_ui;
+
target_terminal_ours ();
+
+ current_ui = main_ui;
+
#if defined(TUI)
tui_disable ();
#endif
- if (async_command_editing_p)
- gdb_disable_readline ();
+ gdb_disable_readline ();
+
+ current_ui = saved_top_level;
}
@@ -1730,13 +1741,24 @@ show_prompt (struct ui_file *file, int from_tty,
fprintf_filtered (file, _("Gdb's prompt is \"%s\".\n"), value);
}
+/* "set editing" command. */
+
+static void
+set_editing (char *args, int from_tty, struct cmd_list_element *c)
+{
+ change_line_handler (set_editing_cmd_var);
+ /* Update the control variable so that MI's =cmd-param-changed event
+ shows the correct value. */
+ set_editing_cmd_var = current_ui->command_editing;
+}
+
static void
-show_async_command_editing_p (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
+show_editing (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("Editing of command lines as "
"they are typed is %s.\n"),
- value);
+ current_ui->command_editing ? _("on") : _("off"));
}
static void
@@ -1827,14 +1849,14 @@ used inside of user-defined commands that should not be repeated when\n\
hitting return."));
add_setshow_boolean_cmd ("editing", class_support,
- &async_command_editing_p, _("\
+ &set_editing_cmd_var, _("\
Set editing of command lines as they are typed."), _("\
Show editing of command lines as they are typed."), _("\
Use \"on\" to enable the editing, and \"off\" to disable it.\n\
Without an argument, command line editing is enabled. To edit, use\n\
EMACS-like or VI-like commands like control-P or ESC."),
- set_async_editing_command,
- show_async_command_editing_p,
+ set_editing,
+ show_editing,
&setlist, &showlist);
add_setshow_boolean_cmd ("save", no_class, &write_history_p, _("\
@@ -54,6 +54,11 @@ struct ui
processing. */
void (*input_handler) (char *);
+ /* True if this UI is using the readline library for command
+ editing; false if using GDB's own simple readline emulation, with
+ no editing support. */
+ int command_editing;
+
/* Each UI has its own independent set of interpreters. */
struct ui_interp_info *interp_info;
@@ -18,6 +18,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
+#include "cli/cli-interp.h"
#include "interps.h"
#include "top.h"
#include "event-top.h"
@@ -216,6 +217,7 @@ tui_init (struct interp *self, int top_level)
static int
tui_resume (void *data)
{
+ struct ui *ui = current_ui;
struct ui_file *stream;
/* gdb_setup_readline will change gdb_stdout. If the TUI was
@@ -229,7 +231,9 @@ tui_resume (void *data)
stream = NULL;
}
- gdb_setup_readline ();
+ gdb_setup_readline (1);
+
+ ui->input_handler = command_line_handler;
if (stream != NULL)
cli_out_set_stream (tui_old_uiout, gdb_stdout);
@@ -269,7 +273,8 @@ static const struct interp_procs tui_interp_procs = {
tui_exec,
tui_ui_out,
NULL,
- cli_command_loop
+ cli_command_loop,
+ cli_interpreter_supports_command_editing,
};
static struct interp *
@@ -616,7 +616,7 @@ tui_getc (FILE *fp)
if (ch == KEY_BACKSPACE)
return '\b';
- if (async_command_editing_p && key_is_start_sequence (ch))
+ if (current_ui->command_editing && key_is_start_sequence (ch))
{
int ch_pending;