Move TUI command window code
[external/binutils.git] / gdb / tui / tui-interp.c
1 /* TUI Interpreter definitions for GDB, the GNU debugger.
2
3    Copyright (C) 2003-2019 Free Software Foundation, Inc.
4
5    This file is part of GDB.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19
20 #include "defs.h"
21 #include "cli/cli-interp.h"
22 #include "interps.h"
23 #include "top.h"
24 #include "event-top.h"
25 #include "event-loop.h"
26 #include "ui-out.h"
27 #include "cli-out.h"
28 #include "tui/tui-data.h"
29 #include "readline/readline.h"
30 #include "tui/tui-win.h"
31 #include "tui/tui.h"
32 #include "tui/tui-io.h"
33 #include "infrun.h"
34 #include "observable.h"
35 #include "gdbthread.h"
36 #include "inferior.h"
37 #include "main.h"
38
39 /* Set to 1 when the TUI mode must be activated when we first start
40    gdb.  */
41 static int tui_start_enabled = 0;
42
43 class tui_interp final : public cli_interp_base
44 {
45 public:
46   explicit tui_interp (const char *name)
47     : cli_interp_base (name)
48   {}
49
50   void init (bool top_level) override;
51   void resume () override;
52   void suspend () override;
53   gdb_exception exec (const char *command_str) override;
54   ui_out *interp_ui_out () override;
55 };
56
57 /* Returns the INTERP if the INTERP is a TUI, and returns NULL
58    otherwise.  */
59
60 static tui_interp *
61 as_tui_interp (struct interp *interp)
62 {
63   return dynamic_cast<tui_interp *> (interp);
64 }
65
66 /* Cleanup the tui before exiting.  */
67
68 static void
69 tui_exit (void)
70 {
71   /* Disable the tui.  Curses mode is left leaving the screen in a
72      clean state (see endwin()).  */
73   tui_disable ();
74 }
75
76 /* Observers for several run control events.  If the interpreter is
77    quiet (i.e., another interpreter is being run with
78    interpreter-exec), print nothing.  */
79
80 /* Observer for the normal_stop notification.  */
81
82 static void
83 tui_on_normal_stop (struct bpstats *bs, int print_frame)
84 {
85   if (!print_frame)
86     return;
87
88   SWITCH_THRU_ALL_UIS ()
89     {
90       struct interp *interp = top_level_interpreter ();
91       struct interp *tui = as_tui_interp (interp);
92       struct thread_info *thread;
93
94       if (tui == NULL)
95         continue;
96
97       thread = inferior_thread ();
98       if (should_print_stop_to_console (interp, thread))
99         print_stop_event (tui->interp_ui_out ());
100     }
101 }
102
103 /* Observer for the signal_received notification.  */
104
105 static void
106 tui_on_signal_received (enum gdb_signal siggnal)
107 {
108   SWITCH_THRU_ALL_UIS ()
109     {
110       struct interp *tui = as_tui_interp (top_level_interpreter ());
111
112       if (tui == NULL)
113         continue;
114
115       print_signal_received_reason (tui->interp_ui_out (), siggnal);
116     }
117 }
118
119 /* Observer for the end_stepping_range notification.  */
120
121 static void
122 tui_on_end_stepping_range (void)
123 {
124   SWITCH_THRU_ALL_UIS ()
125     {
126       struct interp *tui = as_tui_interp (top_level_interpreter ());
127
128       if (tui == NULL)
129         continue;
130
131       print_end_stepping_range_reason (tui->interp_ui_out ());
132     }
133 }
134
135 /* Observer for the signal_exited notification.  */
136
137 static void
138 tui_on_signal_exited (enum gdb_signal siggnal)
139 {
140   SWITCH_THRU_ALL_UIS ()
141     {
142       struct interp *tui = as_tui_interp (top_level_interpreter ());
143
144       if (tui == NULL)
145         continue;
146
147       print_signal_exited_reason (tui->interp_ui_out (), siggnal);
148     }
149 }
150
151 /* Observer for the exited notification.  */
152
153 static void
154 tui_on_exited (int exitstatus)
155 {
156   SWITCH_THRU_ALL_UIS ()
157     {
158       struct interp *tui = as_tui_interp (top_level_interpreter ());
159
160       if (tui == NULL)
161         continue;
162
163       print_exited_reason (tui->interp_ui_out (), exitstatus);
164     }
165 }
166
167 /* Observer for the no_history notification.  */
168
169 static void
170 tui_on_no_history (void)
171 {
172   SWITCH_THRU_ALL_UIS ()
173     {
174       struct interp *tui = as_tui_interp (top_level_interpreter ());
175
176       if (tui == NULL)
177         continue;
178
179       print_no_history_reason (tui->interp_ui_out ());
180     }
181 }
182
183 /* Observer for the sync_execution_done notification.  */
184
185 static void
186 tui_on_sync_execution_done (void)
187 {
188   struct interp *tui = as_tui_interp (top_level_interpreter ());
189
190   if (tui == NULL)
191     return;
192
193   display_gdb_prompt (NULL);
194 }
195
196 /* Observer for the command_error notification.  */
197
198 static void
199 tui_on_command_error (void)
200 {
201   struct interp *tui = as_tui_interp (top_level_interpreter ());
202
203   if (tui == NULL)
204     return;
205
206   display_gdb_prompt (NULL);
207 }
208
209 /* Observer for the user_selected_context_changed notification.  */
210
211 static void
212 tui_on_user_selected_context_changed (user_selected_what selection)
213 {
214   /* This event is suppressed.  */
215   if (cli_suppress_notification.user_selected_context)
216     return;
217
218   thread_info *tp = inferior_ptid != null_ptid ? inferior_thread () : NULL;
219
220   SWITCH_THRU_ALL_UIS ()
221     {
222       struct interp *tui = as_tui_interp (top_level_interpreter ());
223
224       if (tui == NULL)
225         continue;
226
227       if (selection & USER_SELECTED_INFERIOR)
228         print_selected_inferior (tui->interp_ui_out ());
229
230       if (tp != NULL
231           && ((selection & (USER_SELECTED_THREAD | USER_SELECTED_FRAME))))
232         print_selected_thread_frame (tui->interp_ui_out (), selection);
233
234     }
235 }
236
237 /* These implement the TUI interpreter.  */
238
239 void
240 tui_interp::init (bool top_level)
241 {
242   /* Install exit handler to leave the screen in a good shape.  */
243   atexit (tui_exit);
244
245   tui_initialize_static_data ();
246
247   tui_initialize_io ();
248   tui_initialize_win ();
249   if (ui_file_isatty (gdb_stdout))
250     tui_initialize_readline ();
251 }
252
253 void
254 tui_interp::resume ()
255 {
256   struct ui *ui = current_ui;
257   struct ui_file *stream;
258
259   /* gdb_setup_readline will change gdb_stdout.  If the TUI was
260      previously writing to gdb_stdout, then set it to the new
261      gdb_stdout afterwards.  */
262
263   stream = tui_old_uiout->set_stream (gdb_stdout);
264   if (stream != gdb_stdout)
265     {
266       tui_old_uiout->set_stream (stream);
267       stream = NULL;
268     }
269
270   gdb_setup_readline (1);
271
272   ui->input_handler = command_line_handler;
273
274   if (stream != NULL)
275     tui_old_uiout->set_stream (gdb_stdout);
276
277   if (tui_start_enabled)
278     tui_enable ();
279 }
280
281 void
282 tui_interp::suspend ()
283 {
284   tui_start_enabled = tui_active;
285   tui_disable ();
286 }
287
288 ui_out *
289 tui_interp::interp_ui_out ()
290 {
291   if (tui_active)
292     return tui_out;
293   else
294     return tui_old_uiout;
295 }
296
297 gdb_exception
298 tui_interp::exec (const char *command_str)
299 {
300   internal_error (__FILE__, __LINE__, _("tui_exec called"));
301 }
302
303
304 /* Factory for TUI interpreters.  */
305
306 static struct interp *
307 tui_interp_factory (const char *name)
308 {
309   return new tui_interp (name);
310 }
311
312 void
313 _initialize_tui_interp (void)
314 {
315   interp_factory_register (INTERP_TUI, tui_interp_factory);
316
317   if (interpreter_p && strcmp (interpreter_p, INTERP_TUI) == 0)
318     tui_start_enabled = 1;
319
320   if (interpreter_p && strcmp (interpreter_p, INTERP_CONSOLE) == 0)
321     {
322       xfree (interpreter_p);
323       interpreter_p = xstrdup (INTERP_TUI);
324     }
325
326   /* If changing this, remember to update cli-interp.c as well.  */
327   gdb::observers::normal_stop.attach (tui_on_normal_stop);
328   gdb::observers::signal_received.attach (tui_on_signal_received);
329   gdb::observers::end_stepping_range.attach (tui_on_end_stepping_range);
330   gdb::observers::signal_exited.attach (tui_on_signal_exited);
331   gdb::observers::exited.attach (tui_on_exited);
332   gdb::observers::no_history.attach (tui_on_no_history);
333   gdb::observers::sync_execution_done.attach (tui_on_sync_execution_done);
334   gdb::observers::command_error.attach (tui_on_command_error);
335   gdb::observers::user_selected_context_changed.attach
336     (tui_on_user_selected_context_changed);
337 }