1 /* TUI window generic functions.
2
3 Copyright (C) 1998-2024 Free Software Foundation, Inc.
4
5 Contributed by Hewlett-Packard Company.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21
22 /* This module contains procedures for handling tui window functions
23 like resize, scrolling, scrolling, changing focus, etc.
24
25 Author: Susan B. Macchia */
26
27 #include "command.h"
28 #include "symtab.h"
29 #include "breakpoint.h"
30 #include "frame.h"
31 #include "cli/cli-cmds.h"
32 #include "cli/cli-style.h"
33 #include "top.h"
34 #include "source.h"
35 #include "gdbsupport/event-loop.h"
36 #include "async-event.h"
37 #include "utils.h"
38
39 #include "tui/tui.h"
40 #include "tui/tui-io.h"
41 #include "tui/tui-command.h"
42 #include "tui/tui-data.h"
43 #include "tui/tui-layout.h"
44 #include "tui/tui-wingeneral.h"
45 #include "tui/tui-status.h"
46 #include "tui/tui-regs.h"
47 #include "tui/tui-disasm.h"
48 #include "tui/tui-source.h"
49 #include "tui/tui-winsource.h"
50 #include "tui/tui-win.h"
51
52 #include "gdb_curses.h"
53 #include <ctype.h>
54 #include "readline/readline.h"
55 #include <string_view>
56
57 #include <signal.h>
58
59 static void tui_set_tab_width_command (const char *, int);
60 static void tui_refresh_all_command (const char *, int);
61 static void tui_all_windows_info (const char *, int);
62 static void tui_scroll_forward_command (const char *, int);
63 static void tui_scroll_backward_command (const char *, int);
64 static void tui_scroll_left_command (const char *, int);
65 static void tui_scroll_right_command (const char *, int);
66 static void parse_scrolling_args (const char *,
67 struct tui_win_info **,
68 int *);
69
70
71 #ifndef ACS_LRCORNER
72 # define ACS_LRCORNER '+'
73 #endif
74 #ifndef ACS_LLCORNER
75 # define ACS_LLCORNER '+'
76 #endif
77 #ifndef ACS_ULCORNER
78 # define ACS_ULCORNER '+'
79 #endif
80 #ifndef ACS_URCORNER
81 # define ACS_URCORNER '+'
82 #endif
83 #ifndef ACS_HLINE
84 # define ACS_HLINE '-'
85 #endif
86 #ifndef ACS_VLINE
87 # define ACS_VLINE '|'
88 #endif
89
90 /* Possible values for tui-border-kind variable. */
91 static const char *const tui_border_kind_enums[] = {
92 "space",
93 "ascii",
94 "acs",
95 NULL
96 };
97
98 /* Possible values for tui-border-mode and tui-active-border-mode. */
99 static const char *const tui_border_mode_enums[] = {
100 "normal",
101 "standout",
102 "reverse",
103 "half",
104 "half-standout",
105 "bold",
106 "bold-standout",
107 NULL
108 };
109
110 struct tui_translate
111 {
112 const char *name;
113 int value;
114 };
115
116 /* Translation table for border-mode variables.
117 The list of values must be terminated by a NULL. */
118 static struct tui_translate tui_border_mode_translate[] = {
119 { "normal", A_NORMAL },
120 { "standout", A_STANDOUT },
121 { "reverse", A_REVERSE },
122 { "half", A_DIM },
123 { "half-standout", A_DIM | A_STANDOUT },
124 { "bold", A_BOLD },
125 { "bold-standout", A_BOLD | A_STANDOUT },
126 { 0, 0 }
127 };
128
129 /* Translation tables for border-kind (acs excluded), one for vline, hline and
130 corners (see wborder, border curses operations). */
131 static struct tui_translate tui_border_kind_translate_vline[] = {
132 { "space", ' ' },
133 { "ascii", '|' },
134 { 0, 0 }
135 };
136
137 static struct tui_translate tui_border_kind_translate_hline[] = {
138 { "space", ' ' },
139 { "ascii", '-' },
140 { 0, 0 }
141 };
142
143 static struct tui_translate tui_border_kind_translate_corner[] = {
144 { "space", ' ' },
145 { "ascii", '+' },
146 { 0, 0 }
147 };
148
149
150 /* Tui configuration variables controlled with set/show command. */
151 static const char *tui_active_border_mode = "bold-standout";
152 static void
show_tui_active_border_mode(struct ui_file * file,int from_tty,struct cmd_list_element * c,const char * value)153 show_tui_active_border_mode (struct ui_file *file,
154 int from_tty,
155 struct cmd_list_element *c,
156 const char *value)
157 {
158 gdb_printf (file, _("\
159 The attribute mode to use for the active TUI window border is \"%s\".\n"),
160 value);
161 }
162
163 static const char *tui_border_mode = "normal";
164 static void
show_tui_border_mode(struct ui_file * file,int from_tty,struct cmd_list_element * c,const char * value)165 show_tui_border_mode (struct ui_file *file,
166 int from_tty,
167 struct cmd_list_element *c,
168 const char *value)
169 {
170 gdb_printf (file, _("\
171 The attribute mode to use for the TUI window borders is \"%s\".\n"),
172 value);
173 }
174
175 static const char *tui_border_kind = "acs";
176 static void
show_tui_border_kind(struct ui_file * file,int from_tty,struct cmd_list_element * c,const char * value)177 show_tui_border_kind (struct ui_file *file,
178 int from_tty,
179 struct cmd_list_element *c,
180 const char *value)
181 {
182 gdb_printf (file, _("The kind of border for TUI windows is \"%s\".\n"),
183 value);
184 }
185
186 /* Implementation of the "set/show style tui-current-position" commands. */
187
188 bool style_tui_current_position = false;
189
190 static void
show_style_tui_current_position(ui_file * file,int from_tty,cmd_list_element * c,const char * value)191 show_style_tui_current_position (ui_file *file,
192 int from_tty,
193 cmd_list_element *c,
194 const char *value)
195 {
196 gdb_printf (file, _("\
197 Styling the text highlighted by the TUI's current position indicator is %s.\n"),
198 value);
199 }
200
201 static void
set_style_tui_current_position(const char * ignore,int from_tty,cmd_list_element * c)202 set_style_tui_current_position (const char *ignore, int from_tty,
203 cmd_list_element *c)
204 {
205 if (TUI_SRC_WIN != nullptr)
206 TUI_SRC_WIN->refill ();
207 if (TUI_DISASM_WIN != nullptr)
208 TUI_DISASM_WIN->refill ();
209 }
210
211 /* Tui internal configuration variables. These variables are updated
212 by tui_update_variables to reflect the tui configuration
213 variables. */
214 chtype tui_border_vline;
215 chtype tui_border_hline;
216 chtype tui_border_ulcorner;
217 chtype tui_border_urcorner;
218 chtype tui_border_llcorner;
219 chtype tui_border_lrcorner;
220
221 int tui_border_attrs;
222 int tui_active_border_attrs;
223
224 /* Identify the item in the translation table, and return the corresponding value. */
225 static int
translate(const char * name,struct tui_translate * table)226 translate (const char *name, struct tui_translate *table)
227 {
228 while (table->name)
229 {
230 if (name && strcmp (table->name, name) == 0)
231 return table->value;
232 table++;
233 }
234
235 gdb_assert_not_reached ("");
236 }
237
238 /* Translate NAME to a value. If NAME is "acs", use ACS_CHAR. Otherwise, use
239 translation table TABLE. */
240 static int
translate_acs(const char * name,struct tui_translate * table,int acs_char)241 translate_acs (const char *name, struct tui_translate *table, int acs_char)
242 {
243 /* The ACS characters are determined at run time by curses terminal
244 management. */
245 if (strcmp (name, "acs") == 0)
246 return acs_char;
247
248 return translate (name, table);
249 }
250
251 /* Update the tui internal configuration according to gdb settings.
252 Returns 1 if the configuration has changed and the screen should
253 be redrawn. */
254 bool
tui_update_variables()255 tui_update_variables ()
256 {
257 bool need_redraw = false;
258 int val;
259
260 val = translate (tui_border_mode, tui_border_mode_translate);
261 need_redraw |= assign_return_if_changed<int> (tui_border_attrs, val);
262
263 val = translate (tui_active_border_mode, tui_border_mode_translate);
264 need_redraw |= assign_return_if_changed<int> (tui_active_border_attrs, val);
265
266 /* If one corner changes, all characters are changed. Only check the first
267 one. */
268 val = translate_acs (tui_border_kind, tui_border_kind_translate_corner,
269 ACS_LRCORNER);
270 need_redraw |= assign_return_if_changed<chtype> (tui_border_lrcorner, val);
271
272 tui_border_llcorner
273 = translate_acs (tui_border_kind, tui_border_kind_translate_corner,
274 ACS_LLCORNER);
275
276 tui_border_ulcorner
277 = translate_acs (tui_border_kind, tui_border_kind_translate_corner,
278 ACS_ULCORNER);
279
280 tui_border_urcorner =
281 translate_acs (tui_border_kind, tui_border_kind_translate_corner,
282 ACS_URCORNER);
283
284 tui_border_hline
285 = translate_acs (tui_border_kind, tui_border_kind_translate_hline,
286 ACS_HLINE);
287
288 tui_border_vline
289 = translate_acs (tui_border_kind, tui_border_kind_translate_vline,
290 ACS_VLINE);
291
292 return need_redraw;
293 }
294
295 static struct cmd_list_element *tuilist;
296
297 struct cmd_list_element **
tui_get_cmd_list(void)298 tui_get_cmd_list (void)
299 {
300 if (tuilist == 0)
301 add_basic_prefix_cmd ("tui", class_tui,
302 _("Text User Interface commands."),
303 &tuilist, 0, &cmdlist);
304 return &tuilist;
305 }
306
307 /* The set_func hook of "set tui ..." commands that affect the window
308 borders on the TUI display. */
309
310 static void
tui_set_var_cmd(const char * null_args,int from_tty,struct cmd_list_element * c)311 tui_set_var_cmd (const char *null_args,
312 int from_tty, struct cmd_list_element *c)
313 {
314 if (tui_update_variables () && tui_active)
315 tui_rehighlight_all ();
316 }
317
318
319
320 /* True if TUI resizes should print a message. This is used by the
321 test suite. */
322
323 static bool resize_message;
324
325 static void
show_tui_resize_message(struct ui_file * file,int from_tty,struct cmd_list_element * c,const char * value)326 show_tui_resize_message (struct ui_file *file, int from_tty,
327 struct cmd_list_element *c, const char *value)
328 {
329 gdb_printf (file, _("TUI resize messaging is %s.\n"), value);
330 }
331
332
333
334 /* Generic window name completion function. Complete window name pointed
335 to by TEXT and WORD.
336
337 If EXCLUDE_CANNOT_FOCUS_P is true, then windows that can't take focus
338 will be excluded from the completions, otherwise they will be included.
339
340 If INCLUDE_NEXT_PREV_P is true then the special window names 'next' and
341 'prev' will also be considered as possible completions of the window
342 name. This is independent of EXCLUDE_CANNOT_FOCUS_P. */
343
344 static void
window_name_completer(completion_tracker & tracker,bool include_next_prev_p,bool exclude_cannot_focus_p,const char * text,const char * word)345 window_name_completer (completion_tracker &tracker,
346 bool include_next_prev_p,
347 bool exclude_cannot_focus_p,
348 const char *text, const char *word)
349 {
350 std::vector<const char *> completion_name_vec;
351
352 for (tui_win_info *win_info : all_tui_windows ())
353 {
354 const char *completion_name = NULL;
355
356 /* Don't include an invisible window. */
357 if (!win_info->is_visible ())
358 continue;
359
360 /* If requested, exclude windows that can't be focused. */
361 if (exclude_cannot_focus_p && !win_info->can_focus ())
362 continue;
363
364 completion_name = win_info->name ();
365 gdb_assert (completion_name != NULL);
366 completion_name_vec.push_back (completion_name);
367 }
368
369 /* If no windows are considered visible then the TUI has not yet been
370 initialized. But still "focus src" and "focus cmd" will work because
371 invoking the focus command will entail initializing the TUI which sets the
372 default layout to "src". */
373 if (completion_name_vec.empty ())
374 {
375 completion_name_vec.push_back (SRC_NAME);
376 completion_name_vec.push_back (CMD_NAME);
377 }
378
379 if (include_next_prev_p)
380 {
381 completion_name_vec.push_back ("next");
382 completion_name_vec.push_back ("prev");
383 }
384
385
386 completion_name_vec.push_back (NULL);
387 complete_on_enum (tracker, completion_name_vec.data (), text, word);
388 }
389
390 /* Complete possible window names to focus on. TEXT is the complete text
391 entered so far, WORD is the word currently being completed. */
392
393 static void
focus_completer(struct cmd_list_element * ignore,completion_tracker & tracker,const char * text,const char * word)394 focus_completer (struct cmd_list_element *ignore,
395 completion_tracker &tracker,
396 const char *text, const char *word)
397 {
398 window_name_completer (tracker, true, true, text, word);
399 }
400
401 /* Complete possible window names for winheight command. TEXT is the
402 complete text entered so far, WORD is the word currently being
403 completed. */
404
405 static void
winheight_completer(struct cmd_list_element * ignore,completion_tracker & tracker,const char * text,const char * word)406 winheight_completer (struct cmd_list_element *ignore,
407 completion_tracker &tracker,
408 const char *text, const char *word)
409 {
410 /* The first word is the window name. That we can complete. Subsequent
411 words can't be completed. */
412 if (word != text)
413 return;
414
415 window_name_completer (tracker, false, false, text, word);
416 }
417
418 /* Update gdb's knowledge of the terminal size. */
419 void
tui_update_gdb_sizes(void)420 tui_update_gdb_sizes (void)
421 {
422 int width, height;
423
424 if (tui_active)
425 {
426 width = TUI_CMD_WIN->width;
427 height = TUI_CMD_WIN->height;
428 }
429 else
430 {
431 width = tui_term_width ();
432 height = tui_term_height ();
433 }
434
435 set_screen_width_and_height (width, height);
436 }
437
438
439 void
forward_scroll(int num_to_scroll)440 tui_win_info::forward_scroll (int num_to_scroll)
441 {
442 if (num_to_scroll == 0)
443 num_to_scroll = height - 3;
444
445 do_scroll_vertical (num_to_scroll);
446 }
447
448 void
backward_scroll(int num_to_scroll)449 tui_win_info::backward_scroll (int num_to_scroll)
450 {
451 if (num_to_scroll == 0)
452 num_to_scroll = height - 3;
453
454 do_scroll_vertical (-num_to_scroll);
455 }
456
457
458 void
left_scroll(int num_to_scroll)459 tui_win_info::left_scroll (int num_to_scroll)
460 {
461 if (num_to_scroll == 0)
462 num_to_scroll = 1;
463
464 do_scroll_horizontal (num_to_scroll);
465 }
466
467
468 void
right_scroll(int num_to_scroll)469 tui_win_info::right_scroll (int num_to_scroll)
470 {
471 if (num_to_scroll == 0)
472 num_to_scroll = 1;
473
474 do_scroll_horizontal (-num_to_scroll);
475 }
476
477
478 void
tui_refresh_all_win(void)479 tui_refresh_all_win (void)
480 {
481 clearok (curscr, TRUE);
482 for (tui_win_info *win_info : all_tui_windows ())
483 {
484 if (win_info->is_visible ())
485 win_info->refresh_window ();
486 }
487 }
488
489 void
tui_rehighlight_all(void)490 tui_rehighlight_all (void)
491 {
492 for (tui_win_info *win_info : all_tui_windows ())
493 win_info->check_and_display_highlight_if_needed ();
494 }
495
496 /* Resize all the windows based on the terminal size. This function
497 gets called from within the readline SIGWINCH handler. */
498 void
tui_resize_all(void)499 tui_resize_all (void)
500 {
501 int height_diff, width_diff;
502 int screenheight, screenwidth;
503
504 rl_get_screen_size (&screenheight, &screenwidth);
505 screenwidth += readline_hidden_cols;
506
507 width_diff = screenwidth - tui_term_width ();
508 height_diff = screenheight - tui_term_height ();
509 if (height_diff || width_diff)
510 {
511 #ifdef HAVE_RESIZE_TERM
512 resize_term (screenheight, screenwidth);
513 #endif
514 /* Turn keypad off while we resize. */
515 keypad (TUI_CMD_WIN->handle.get (), FALSE);
516 tui_update_gdb_sizes ();
517 tui_set_term_height_to (screenheight);
518 tui_set_term_width_to (screenwidth);
519
520 /* erase + clearok are used instead of a straightforward clear as
521 AIX 5.3 does not define clear. */
522 erase ();
523 clearok (curscr, TRUE);
524 /* Apply the current layout. The 'false' here allows the command
525 window to resize proportionately with containing terminal, rather
526 than maintaining a fixed size. */
527 tui_apply_current_layout (false); /* Turn keypad back on. */
528 keypad (TUI_CMD_WIN->handle.get (), TRUE);
529 }
530 }
531
532 #ifdef SIGWINCH
533 /* Token for use by TUI's asynchronous SIGWINCH handler. */
534 static struct async_signal_handler *tui_sigwinch_token;
535
536 /* TUI's SIGWINCH signal handler. */
537 static void
tui_sigwinch_handler(int signal)538 tui_sigwinch_handler (int signal)
539 {
540 mark_async_signal_handler (tui_sigwinch_token);
541 tui_set_win_resized_to (true);
542 }
543
544 /* Callback for asynchronously resizing TUI following a SIGWINCH signal. */
545 static void
tui_async_resize_screen(gdb_client_data arg)546 tui_async_resize_screen (gdb_client_data arg)
547 {
548 rl_resize_terminal ();
549
550 if (!tui_active)
551 {
552 int screen_height, screen_width;
553
554 rl_get_screen_size (&screen_height, &screen_width);
555 screen_width += readline_hidden_cols;
556 set_screen_width_and_height (screen_width, screen_height);
557
558 /* win_resized is left set so that the next call to tui_enable()
559 resizes the TUI windows. */
560 }
561 else
562 {
563 tui_set_win_resized_to (false);
564 tui_resize_all ();
565 tui_refresh_all_win ();
566 tui_update_gdb_sizes ();
567 if (resize_message)
568 {
569 static int count;
570 printf_unfiltered ("@@ resize done %d, size = %dx%d\n", count,
571 tui_term_width (), tui_term_height ());
572 ++count;
573 }
574 tui_redisplay_readline ();
575 }
576 }
577 #endif
578
579 /* Initialize TUI's SIGWINCH signal handler. Note that the handler is not
580 uninstalled when we exit TUI, so the handler should not assume that TUI is
581 always active. */
582 void
tui_initialize_win(void)583 tui_initialize_win (void)
584 {
585 #ifdef SIGWINCH
586 tui_sigwinch_token
587 = create_async_signal_handler (tui_async_resize_screen, NULL,
588 "tui-sigwinch");
589
590 {
591 #ifdef HAVE_SIGACTION
592 struct sigaction old_winch;
593
594 memset (&old_winch, 0, sizeof (old_winch));
595 old_winch.sa_handler = &tui_sigwinch_handler;
596 #ifdef SA_RESTART
597 old_winch.sa_flags = SA_RESTART;
598 #endif
599 sigaction (SIGWINCH, &old_winch, NULL);
600 #else
601 signal (SIGWINCH, &tui_sigwinch_handler);
602 #endif
603 }
604 #endif
605 }
606
607
608 static void
tui_scroll_forward_command(const char * arg,int from_tty)609 tui_scroll_forward_command (const char *arg, int from_tty)
610 {
611 int num_to_scroll = 1;
612 struct tui_win_info *win_to_scroll;
613
614 /* Make sure the curses mode is enabled. */
615 tui_enable ();
616 if (arg == NULL)
617 parse_scrolling_args (arg, &win_to_scroll, NULL);
618 else
619 parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
620 win_to_scroll->forward_scroll (num_to_scroll);
621 }
622
623
624 static void
tui_scroll_backward_command(const char * arg,int from_tty)625 tui_scroll_backward_command (const char *arg, int from_tty)
626 {
627 int num_to_scroll = 1;
628 struct tui_win_info *win_to_scroll;
629
630 /* Make sure the curses mode is enabled. */
631 tui_enable ();
632 if (arg == NULL)
633 parse_scrolling_args (arg, &win_to_scroll, NULL);
634 else
635 parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
636 win_to_scroll->backward_scroll (num_to_scroll);
637 }
638
639
640 static void
tui_scroll_left_command(const char * arg,int from_tty)641 tui_scroll_left_command (const char *arg, int from_tty)
642 {
643 int num_to_scroll;
644 struct tui_win_info *win_to_scroll;
645
646 /* Make sure the curses mode is enabled. */
647 tui_enable ();
648 parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
649 win_to_scroll->left_scroll (num_to_scroll);
650 }
651
652
653 static void
tui_scroll_right_command(const char * arg,int from_tty)654 tui_scroll_right_command (const char *arg, int from_tty)
655 {
656 int num_to_scroll;
657 struct tui_win_info *win_to_scroll;
658
659 /* Make sure the curses mode is enabled. */
660 tui_enable ();
661 parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
662 win_to_scroll->right_scroll (num_to_scroll);
663 }
664
665
666 /* Answer the window represented by name. */
667 static struct tui_win_info *
tui_partial_win_by_name(std::string_view name)668 tui_partial_win_by_name (std::string_view name)
669 {
670 struct tui_win_info *best = nullptr;
671
672 for (tui_win_info *item : all_tui_windows ())
673 {
674 const char *cur_name = item->name ();
675
676 if (name == cur_name)
677 return item;
678 if (startswith (cur_name, name))
679 {
680 if (best != nullptr)
681 error (_("Window name \"%*s\" is ambiguous"),
682 (int) name.size (), name.data ());
683 best = item;
684 }
685 }
686
687 return best;
688 }
689
690 /* Set focus to the window named by 'arg'. */
691 static void
tui_set_focus_command(const char * arg,int from_tty)692 tui_set_focus_command (const char *arg, int from_tty)
693 {
694 tui_enable ();
695
696 if (arg == NULL)
697 error_no_arg (_("name of window to focus"));
698
699 struct tui_win_info *win_info = NULL;
700
701 if (startswith ("next", arg))
702 win_info = tui_next_win (tui_win_with_focus ());
703 else if (startswith ("prev", arg))
704 win_info = tui_prev_win (tui_win_with_focus ());
705 else
706 win_info = tui_partial_win_by_name (arg);
707
708 if (win_info == nullptr)
709 {
710 /* When WIN_INFO is nullptr this can either mean that the window name
711 is unknown to GDB, or that the window is not in the current
712 layout. To try and help the user, give a different error
713 depending on which of these is the case. */
714 std::string matching_window_name;
715 bool is_ambiguous = false;
716
717 for (const std::string &name : all_known_window_names ())
718 {
719 /* Look through all windows in the current layout, if the window
720 is in the current layout then we're not interested is it. */
721 for (tui_win_info *item : all_tui_windows ())
722 if (item->name () == name)
723 continue;
724
725 if (startswith (name, arg))
726 {
727 if (matching_window_name.empty ())
728 matching_window_name = name;
729 else
730 is_ambiguous = true;
731 }
732 };
733
734 if (!matching_window_name.empty ())
735 {
736 if (is_ambiguous)
737 error (_("No windows matching \"%s\" in the current layout"),
738 arg);
739 else
740 error (_("Window \"%s\" is not in the current layout"),
741 matching_window_name.c_str ());
742 }
743 else
744 error (_("Unrecognized window name \"%s\""), arg);
745 }
746
747 /* If a window is part of the current layout then it will have a
748 tui_win_info associated with it and be visible, otherwise, there will
749 be no tui_win_info and the above error will have been raised. */
750 gdb_assert (win_info->is_visible ());
751
752 if (!win_info->can_focus ())
753 error (_("Window \"%s\" cannot be focused"), arg);
754
755 tui_set_win_focus_to (win_info);
756 gdb_printf (_("Focus set to %s window.\n"),
757 tui_win_with_focus ()->name ());
758 }
759
760 static void
tui_all_windows_info(const char * arg,int from_tty)761 tui_all_windows_info (const char *arg, int from_tty)
762 {
763 if (!tui_active)
764 {
765 gdb_printf (_("The TUI is not active.\n"));
766 return;
767 }
768
769 struct tui_win_info *win_with_focus = tui_win_with_focus ();
770 struct ui_out *uiout = current_uiout;
771
772 ui_out_emit_table table_emitter (uiout, 4, -1, "tui-windows");
773 uiout->table_header (10, ui_left, "name", "Name");
774 uiout->table_header (5, ui_right, "lines", "Lines");
775 uiout->table_header (7, ui_right, "columns", "Columns");
776 uiout->table_header (10, ui_left, "focus", "Focus");
777 uiout->table_body ();
778
779 for (tui_win_info *win_info : all_tui_windows ())
780 if (win_info->is_visible ())
781 {
782 ui_out_emit_tuple tuple_emitter (uiout, nullptr);
783
784 uiout->field_string ("name", win_info->name ());
785 uiout->field_signed ("lines", win_info->height);
786 uiout->field_signed ("columns", win_info->width);
787 if (win_with_focus == win_info)
788 uiout->field_string ("focus", _("(has focus)"));
789 else
790 uiout->field_skip ("focus");
791 uiout->text ("\n");
792 }
793 }
794
795
796 static void
tui_refresh_all_command(const char * arg,int from_tty)797 tui_refresh_all_command (const char *arg, int from_tty)
798 {
799 /* Make sure the curses mode is enabled. */
800 tui_enable ();
801
802 tui_refresh_all_win ();
803 }
804
805 #define DEFAULT_TAB_LEN 8
806
807 /* The tab width that should be used by the TUI. */
808
809 unsigned int tui_tab_width = DEFAULT_TAB_LEN;
810
811 /* The tab width as set by the user. */
812
813 static unsigned int internal_tab_width = DEFAULT_TAB_LEN;
814
815 /* After the tab width is set, call this to update the relevant
816 windows. */
817
818 static void
update_tab_width()819 update_tab_width ()
820 {
821 for (tui_win_info *win_info : all_tui_windows ())
822 {
823 if (win_info->is_visible ())
824 win_info->update_tab_width ();
825 }
826 }
827
828 /* Callback for "set tui tab-width". */
829
830 static void
tui_set_tab_width(const char * ignore,int from_tty,struct cmd_list_element * c)831 tui_set_tab_width (const char *ignore,
832 int from_tty, struct cmd_list_element *c)
833 {
834 if (internal_tab_width == 0)
835 {
836 internal_tab_width = tui_tab_width;
837 error (_("Tab width must not be 0"));
838 }
839
840 tui_tab_width = internal_tab_width;
841 update_tab_width ();
842 }
843
844 /* Callback for "show tui tab-width". */
845
846 static void
tui_show_tab_width(struct ui_file * file,int from_tty,struct cmd_list_element * c,const char * value)847 tui_show_tab_width (struct ui_file *file, int from_tty,
848 struct cmd_list_element *c, const char *value)
849 {
850 gdb_printf (file, _("TUI tab width is %s spaces.\n"), value);
851
852 }
853
854 /* See tui-win.h. */
855
856 bool compact_source = false;
857
858 /* Callback for "set tui compact-source". */
859
860 static void
tui_set_compact_source(const char * ignore,int from_tty,struct cmd_list_element * c)861 tui_set_compact_source (const char *ignore, int from_tty,
862 struct cmd_list_element *c)
863 {
864 if (TUI_SRC_WIN != nullptr)
865 TUI_SRC_WIN->refill ();
866 }
867
868 /* Callback for "show tui compact-source". */
869
870 static void
tui_show_compact_source(struct ui_file * file,int from_tty,struct cmd_list_element * c,const char * value)871 tui_show_compact_source (struct ui_file *file, int from_tty,
872 struct cmd_list_element *c, const char *value)
873 {
874 gdb_printf (file, _("TUI source window compactness is %s.\n"), value);
875 }
876
877 bool tui_enable_mouse = true;
878
879 /* Implement 'show tui mouse-events'. */
880
881 static void
show_tui_mouse_events(struct ui_file * file,int from_tty,struct cmd_list_element * c,const char * value)882 show_tui_mouse_events (struct ui_file *file, int from_tty,
883 struct cmd_list_element *c, const char *value)
884 {
885 gdb_printf (file, _("TUI mouse events are %s.\n"), value);
886 }
887
888 /* Set the tab width of the specified window. */
889 static void
tui_set_tab_width_command(const char * arg,int from_tty)890 tui_set_tab_width_command (const char *arg, int from_tty)
891 {
892 /* Make sure the curses mode is enabled. */
893 tui_enable ();
894 if (arg != NULL)
895 {
896 int ts;
897
898 ts = atoi (arg);
899 if (ts <= 0)
900 warning (_("Tab widths greater than 0 must be specified."));
901 else
902 {
903 internal_tab_width = ts;
904 tui_tab_width = ts;
905
906 update_tab_width ();
907 }
908 }
909 }
910
911 /* Helper function for the user commands to adjust a window's width or
912 height. The ARG string contains the command line arguments from the
913 user, which should give the name of a window, and how to adjust the
914 size.
915
916 When SET_WIDTH_P is true the width of the window is adjusted based on
917 ARG, and when SET_WIDTH_P is false, the height of the window is adjusted
918 based on ARG.
919
920 On invalid input, or if the size can't be adjusted as requested, then an
921 error is thrown, otherwise, the window sizes are adjusted, and the
922 windows redrawn. */
923
924 static void
tui_set_win_size(const char * arg,bool set_width_p)925 tui_set_win_size (const char *arg, bool set_width_p)
926 {
927 /* Make sure the curses mode is enabled. */
928 tui_enable ();
929 if (arg == NULL)
930 error_no_arg (_("name of window"));
931
932 const char *buf = arg;
933 const char *buf_ptr = buf;
934 int new_size;
935 struct tui_win_info *win_info;
936
937 buf_ptr = skip_to_space (buf_ptr);
938
939 /* Validate the window name. */
940 std::string_view wname (buf, buf_ptr - buf);
941 win_info = tui_partial_win_by_name (wname);
942
943 if (win_info == NULL)
944 error (_("Unrecognized window name \"%s\""), arg);
945 if (!win_info->is_visible ())
946 error (_("Window \"%s\" is not visible"), arg);
947
948 /* Process the size. */
949 buf_ptr = skip_spaces (buf_ptr);
950
951 if (*buf_ptr != '\0')
952 {
953 bool negate = false;
954 bool fixed_size = true;
955 int input_no;;
956
957 if (*buf_ptr == '+' || *buf_ptr == '-')
958 {
959 if (*buf_ptr == '-')
960 negate = true;
961 fixed_size = false;
962 buf_ptr++;
963 }
964 input_no = atoi (buf_ptr);
965 if (input_no > 0)
966 {
967 if (negate)
968 input_no *= (-1);
969 if (fixed_size)
970 new_size = input_no;
971 else
972 {
973 int curr_size;
974 if (set_width_p)
975 curr_size = win_info->width;
976 else
977 curr_size = win_info->height;
978 new_size = curr_size + input_no;
979 }
980
981 /* Now change the window's height, and adjust
982 all other windows around it. */
983 if (set_width_p)
984 tui_adjust_window_width (win_info, new_size);
985 else
986 tui_adjust_window_height (win_info, new_size);
987 tui_update_gdb_sizes ();
988 }
989 else
990 {
991 if (set_width_p)
992 error (_("Invalid window width specified"));
993 else
994 error (_("Invalid window height specified"));
995 }
996 }
997 }
998
999 /* Implement the 'tui window height' command (alias 'winheight'). */
1000
1001 static void
tui_set_win_height_command(const char * arg,int from_tty)1002 tui_set_win_height_command (const char *arg, int from_tty)
1003 {
1004 /* Pass false as the final argument to set the height. */
1005 tui_set_win_size (arg, false);
1006 }
1007
1008 /* Implement the 'tui window width' command (alias 'winwidth'). */
1009
1010 static void
tui_set_win_width_command(const char * arg,int from_tty)1011 tui_set_win_width_command (const char *arg, int from_tty)
1012 {
1013 /* Pass true as the final argument to set the width. */
1014 tui_set_win_size (arg, true);
1015 }
1016
1017 /* See tui-data.h. */
1018
1019 int
max_height()1020 tui_win_info::max_height () const
1021 {
1022 return tui_term_height ();
1023 }
1024
1025 /* See tui-data.h. */
1026
1027 int
max_width()1028 tui_win_info::max_width () const
1029 {
1030 return tui_term_width ();
1031 }
1032
1033 static void
parse_scrolling_args(const char * arg,struct tui_win_info ** win_to_scroll,int * num_to_scroll)1034 parse_scrolling_args (const char *arg,
1035 struct tui_win_info **win_to_scroll,
1036 int *num_to_scroll)
1037 {
1038 if (num_to_scroll)
1039 *num_to_scroll = 0;
1040 *win_to_scroll = tui_win_with_focus ();
1041
1042 /* First set up the default window to scroll, in case there is no
1043 window name arg. */
1044 if (arg != NULL)
1045 {
1046 char *buf_ptr;
1047
1048 /* Process the number of lines to scroll. */
1049 std::string copy = arg;
1050 buf_ptr = ©[0];
1051 if (isdigit (*buf_ptr))
1052 {
1053 char *num_str;
1054
1055 num_str = buf_ptr;
1056 buf_ptr = strchr (buf_ptr, ' ');
1057 if (buf_ptr != NULL)
1058 {
1059 *buf_ptr = '\0';
1060 if (num_to_scroll)
1061 *num_to_scroll = atoi (num_str);
1062 buf_ptr++;
1063 }
1064 else if (num_to_scroll)
1065 *num_to_scroll = atoi (num_str);
1066 }
1067
1068 /* Process the window name if one is specified. */
1069 if (buf_ptr != NULL)
1070 {
1071 const char *wname;
1072
1073 wname = skip_spaces (buf_ptr);
1074
1075 if (*wname != '\0')
1076 {
1077 *win_to_scroll = tui_partial_win_by_name (wname);
1078
1079 if (*win_to_scroll == NULL)
1080 error (_("Unrecognized window `%s'"), wname);
1081 if (!(*win_to_scroll)->is_visible ())
1082 error (_("Window is not visible"));
1083 else if (*win_to_scroll == TUI_CMD_WIN)
1084 *win_to_scroll = *(tui_source_windows ().begin ());
1085 }
1086 }
1087 }
1088 }
1089
1090 /* The list of 'tui window' sub-commands. */
1091
1092 static cmd_list_element *tui_window_cmds = nullptr;
1093
1094 /* Called to implement 'tui window'. */
1095
1096 static void
tui_window_command(const char * args,int from_tty)1097 tui_window_command (const char *args, int from_tty)
1098 {
1099 help_list (tui_window_cmds, "tui window ", all_commands, gdb_stdout);
1100 }
1101
1102 /* See tui-win.h. */
1103
1104 bool tui_left_margin_verbose = false;
1105
1106 /* Function to initialize gdb commands, for tui window
1107 manipulation. */
1108
1109 void _initialize_tui_win ();
1110 void
_initialize_tui_win()1111 _initialize_tui_win ()
1112 {
1113 static struct cmd_list_element *tui_setlist;
1114 static struct cmd_list_element *tui_showlist;
1115
1116 /* Define the classes of commands.
1117 They will appear in the help list in the reverse of this order. */
1118 add_setshow_prefix_cmd ("tui", class_tui,
1119 _("TUI configuration variables."),
1120 _("TUI configuration variables."),
1121 &tui_setlist, &tui_showlist,
1122 &setlist, &showlist);
1123
1124 cmd_list_element *refresh_cmd
1125 = add_cmd ("refresh", class_tui, tui_refresh_all_command,
1126 _("Refresh the terminal display."),
1127 tui_get_cmd_list ());
1128 add_com_alias ("refresh", refresh_cmd, class_tui, 0);
1129
1130 cmd_list_element *tabset_cmd
1131 = add_com ("tabset", class_tui, tui_set_tab_width_command, _("\
1132 Set the width (in characters) of tab stops.\n\
1133 Usage: tabset N"));
1134 deprecate_cmd (tabset_cmd, "set tui tab-width");
1135
1136 /* Setup the 'tui window' list of command. */
1137 add_prefix_cmd ("window", class_tui, tui_window_command,
1138 _("Text User Interface window commands."),
1139 &tui_window_cmds, 1, tui_get_cmd_list ());
1140
1141 cmd_list_element *winheight_cmd
1142 = add_cmd ("height", class_tui, tui_set_win_height_command, _("\
1143 Set or modify the height of a specified window.\n\
1144 Usage: tui window height WINDOW-NAME [+ | -] NUM-LINES\n\
1145 Use \"info win\" to see the names of the windows currently being displayed."),
1146 &tui_window_cmds);
1147 add_com_alias ("winheight", winheight_cmd, class_tui, 0);
1148 add_com_alias ("wh", winheight_cmd, class_tui, 0);
1149 set_cmd_completer (winheight_cmd, winheight_completer);
1150
1151 cmd_list_element *winwidth_cmd
1152 = add_cmd ("width", class_tui, tui_set_win_width_command, _("\
1153 Set or modify the width of a specified window.\n\
1154 Usage: tui window width WINDOW-NAME [+ | -] NUM-LINES\n\
1155 Use \"info win\" to see the names of the windows currently being displayed."),
1156 &tui_window_cmds);
1157 add_com_alias ("winwidth", winwidth_cmd, class_tui, 0);
1158 set_cmd_completer (winwidth_cmd, winheight_completer);
1159
1160 add_info ("win", tui_all_windows_info,
1161 _("List of all displayed windows.\n\
1162 Usage: info win"));
1163 cmd_list_element *focus_cmd
1164 = add_cmd ("focus", class_tui, tui_set_focus_command, _("\
1165 Set focus to named window or next/prev window.\n\
1166 Usage: tui focus [WINDOW-NAME | next | prev]\n\
1167 Use \"info win\" to see the names of the windows currently being displayed."),
1168 tui_get_cmd_list ());
1169 add_com_alias ("focus", focus_cmd, class_tui, 0);
1170 add_com_alias ("fs", focus_cmd, class_tui, 0);
1171 set_cmd_completer (focus_cmd, focus_completer);
1172 add_com ("+", class_tui, tui_scroll_forward_command, _("\
1173 Scroll window forward.\n\
1174 Usage: + [N] [WIN]\n\
1175 Scroll window WIN N lines forwards. Both WIN and N are optional, N\n\
1176 defaults to 1, and WIN defaults to the currently focused window."));
1177 add_com ("-", class_tui, tui_scroll_backward_command, _("\
1178 Scroll window backward.\n\
1179 Usage: - [N] [WIN]\n\
1180 Scroll window WIN N lines backwards. Both WIN and N are optional, N\n\
1181 defaults to 1, and WIN defaults to the currently focused window."));
1182 add_com ("<", class_tui, tui_scroll_left_command, _("\
1183 Scroll window text to the left.\n\
1184 Usage: < [N] [WIN]\n\
1185 Scroll window WIN N characters left. Both WIN and N are optional, N\n\
1186 defaults to 1, and WIN defaults to the currently focused window."));
1187 add_com (">", class_tui, tui_scroll_right_command, _("\
1188 Scroll window text to the right.\n\
1189 Usage: > [N] [WIN]\n\
1190 Scroll window WIN N characters right. Both WIN and N are optional, N\n\
1191 defaults to 1, and WIN defaults to the currently focused window."));
1192
1193 /* Define the tui control variables. */
1194 add_setshow_enum_cmd ("border-kind", no_class, tui_border_kind_enums,
1195 &tui_border_kind, _("\
1196 Set the kind of border for TUI windows."), _("\
1197 Show the kind of border for TUI windows."), _("\
1198 This variable controls the border of TUI windows:\n\
1199 space use a white space\n\
1200 ascii use ascii characters + - | for the border\n\
1201 acs use the Alternate Character Set"),
1202 tui_set_var_cmd,
1203 show_tui_border_kind,
1204 &tui_setlist, &tui_showlist);
1205
1206 const std::string help_attribute_mode (_("\
1207 normal normal display\n\
1208 standout use highlight mode of terminal\n\
1209 reverse use reverse video mode\n\
1210 half use half bright\n\
1211 half-standout use half bright and standout mode\n\
1212 bold use extra bright or bold\n\
1213 bold-standout use extra bright or bold with standout mode"));
1214
1215 const std::string help_tui_border_mode
1216 = (_("\
1217 This variable controls the attributes to use for the window borders:\n")
1218 + help_attribute_mode);
1219
1220 add_setshow_enum_cmd ("border-mode", no_class, tui_border_mode_enums,
1221 &tui_border_mode, _("\
1222 Set the attribute mode to use for the TUI window borders."), _("\
1223 Show the attribute mode to use for the TUI window borders."),
1224 help_tui_border_mode.c_str (),
1225 tui_set_var_cmd,
1226 show_tui_border_mode,
1227 &tui_setlist, &tui_showlist);
1228
1229 const std::string help_tui_active_border_mode
1230 = (_("\
1231 This variable controls the attributes to use for the active window borders:\n")
1232 + help_attribute_mode);
1233
1234 add_setshow_enum_cmd ("active-border-mode", no_class, tui_border_mode_enums,
1235 &tui_active_border_mode, _("\
1236 Set the attribute mode to use for the active TUI window border."), _("\
1237 Show the attribute mode to use for the active TUI window border."),
1238 help_tui_active_border_mode.c_str (),
1239 tui_set_var_cmd,
1240 show_tui_active_border_mode,
1241 &tui_setlist, &tui_showlist);
1242
1243 add_setshow_zuinteger_cmd ("tab-width", no_class,
1244 &internal_tab_width, _("\
1245 Set the tab width, in characters, for the TUI."), _("\
1246 Show the tab width, in characters, for the TUI."), _("\
1247 This variable controls how many spaces are used to display a tab character."),
1248 tui_set_tab_width, tui_show_tab_width,
1249 &tui_setlist, &tui_showlist);
1250
1251 add_setshow_boolean_cmd ("tui-resize-message", class_maintenance,
1252 &resize_message, _("\
1253 Set TUI resize messaging."), _("\
1254 Show TUI resize messaging."), _("\
1255 When enabled GDB will print a message when the terminal is resized."),
1256 nullptr,
1257 show_tui_resize_message,
1258 &maintenance_set_cmdlist,
1259 &maintenance_show_cmdlist);
1260
1261 add_setshow_boolean_cmd ("compact-source", class_tui,
1262 &compact_source, _("\
1263 Set whether the TUI source window is compact."), _("\
1264 Show whether the TUI source window is compact."), _("\
1265 This variable controls whether the TUI source window is shown\n\
1266 in a compact form. The compact form uses less horizontal space."),
1267 tui_set_compact_source, tui_show_compact_source,
1268 &tui_setlist, &tui_showlist);
1269
1270 add_setshow_boolean_cmd ("mouse-events", class_tui,
1271 &tui_enable_mouse, _("\
1272 Set whether TUI mode handles mouse clicks."), _("\
1273 Show whether TUI mode handles mouse clicks."), _("\
1274 When on (default), mouse clicks control the TUI and can be accessed by Python\n\
1275 extensions. When off, mouse clicks are handled by the terminal, enabling\n\
1276 terminal-native text selection."),
1277 nullptr,
1278 show_tui_mouse_events,
1279 &tui_setlist, &tui_showlist);
1280
1281 add_setshow_boolean_cmd ("tui-current-position", class_maintenance,
1282 &style_tui_current_position, _("\
1283 Set whether to style text highlighted by the TUI's current position indicator."),
1284 _("\
1285 Show whether to style text highlighted by the TUI's current position indicator."),
1286 _("\
1287 When enabled, the source and assembly code highlighted by the TUI's current\n\
1288 position indicator is styled."),
1289 set_style_tui_current_position,
1290 show_style_tui_current_position,
1291 &style_set_list,
1292 &style_show_list);
1293
1294 add_setshow_boolean_cmd ("tui-left-margin-verbose", class_maintenance,
1295 &tui_left_margin_verbose, _("\
1296 Set whether the left margin should use '_' and '0' instead of spaces."),
1297 _("\
1298 Show whether the left margin should use '_' and '0' instead of spaces."),
1299 _("\
1300 When enabled, the left margin will use '_' and '0' instead of spaces."),
1301 nullptr,
1302 nullptr,
1303 &maintenance_set_cmdlist,
1304 &maintenance_show_cmdlist);
1305
1306 tui_border_style.changed.attach (tui_rehighlight_all, "tui-win");
1307 tui_active_border_style.changed.attach (tui_rehighlight_all, "tui-win");
1308 }
1309