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