tui-win.c revision 1.1.1.9 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
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
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
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
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
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
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
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
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 **
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
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
321 /* True if TUI resizes should print a message. This is used by the
322 test suite. */
323
324 static bool resize_message;
325
326 static void
327 show_tui_resize_message (struct ui_file *file, int from_tty,
328 struct cmd_list_element *c, const char *value)
329 {
330 gdb_printf (file, _("TUI resize messaging is %s.\n"), value);
331 }
332
333
334
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 for (tui_win_info *win_info : all_tui_windows ())
485 {
486 if (win_info->is_visible ())
487 win_info->refresh_window ();
488 }
489 }
490
491 void
492 tui_rehighlight_all (void)
493 {
494 for (tui_win_info *win_info : all_tui_windows ())
495 win_info->check_and_display_highlight_if_needed ();
496 }
497
498 /* Resize all the windows based on the terminal size. This function
499 gets called from within the readline SIGWINCH handler. */
500 void
501 tui_resize_all (void)
502 {
503 int height_diff, width_diff;
504 int screenheight, screenwidth;
505
506 rl_get_screen_size (&screenheight, &screenwidth);
507 screenwidth += readline_hidden_cols;
508
509 width_diff = screenwidth - tui_term_width ();
510 height_diff = screenheight - tui_term_height ();
511 if (height_diff || width_diff)
512 {
513 #ifdef HAVE_RESIZE_TERM
514 resize_term (screenheight, screenwidth);
515 #endif
516 /* Turn keypad off while we resize. */
517 keypad (TUI_CMD_WIN->handle.get (), FALSE);
518 tui_update_gdb_sizes ();
519 tui_set_term_height_to (screenheight);
520 tui_set_term_width_to (screenwidth);
521
522 /* erase + clearok are used instead of a straightforward clear as
523 AIX 5.3 does not define clear. */
524 erase ();
525 clearok (curscr, TRUE);
526 /* Apply the current layout. The 'false' here allows the command
527 window to resize proportionately with containing terminal, rather
528 than maintaining a fixed size. */
529 tui_apply_current_layout (false); /* Turn keypad back on. */
530 keypad (TUI_CMD_WIN->handle.get (), TRUE);
531 }
532 }
533
534 #ifdef SIGWINCH
535 /* Token for use by TUI's asynchronous SIGWINCH handler. */
536 static struct async_signal_handler *tui_sigwinch_token;
537
538 /* TUI's SIGWINCH signal handler. */
539 static void
540 tui_sigwinch_handler (int signal)
541 {
542 mark_async_signal_handler (tui_sigwinch_token);
543 tui_set_win_resized_to (true);
544 }
545
546 /* Callback for asynchronously resizing TUI following a SIGWINCH signal. */
547 static void
548 tui_async_resize_screen (gdb_client_data arg)
549 {
550 rl_resize_terminal ();
551
552 if (!tui_active)
553 {
554 int screen_height, screen_width;
555
556 rl_get_screen_size (&screen_height, &screen_width);
557 screen_width += readline_hidden_cols;
558 set_screen_width_and_height (screen_width, screen_height);
559
560 /* win_resized is left set so that the next call to tui_enable()
561 resizes the TUI windows. */
562 }
563 else
564 {
565 tui_set_win_resized_to (false);
566 tui_resize_all ();
567 tui_refresh_all_win ();
568 tui_update_gdb_sizes ();
569 if (resize_message)
570 {
571 static int count;
572 printf_unfiltered ("@@ resize done %d, size = %dx%d\n", count,
573 tui_term_width (), tui_term_height ());
574 ++count;
575 }
576 tui_redisplay_readline ();
577 }
578 }
579 #endif
580
581 /* Initialize TUI's SIGWINCH signal handler. Note that the handler is not
582 uninstalled when we exit TUI, so the handler should not assume that TUI is
583 always active. */
584 void
585 tui_initialize_win (void)
586 {
587 #ifdef SIGWINCH
588 tui_sigwinch_token
589 = create_async_signal_handler (tui_async_resize_screen, NULL,
590 "tui-sigwinch");
591
592 {
593 #ifdef HAVE_SIGACTION
594 struct sigaction old_winch;
595
596 memset (&old_winch, 0, sizeof (old_winch));
597 old_winch.sa_handler = &tui_sigwinch_handler;
598 #ifdef SA_RESTART
599 old_winch.sa_flags = SA_RESTART;
600 #endif
601 sigaction (SIGWINCH, &old_winch, NULL);
602 #else
603 signal (SIGWINCH, &tui_sigwinch_handler);
604 #endif
605 }
606 #endif
607 }
608
609
610 static void
611 tui_scroll_forward_command (const char *arg, int from_tty)
612 {
613 int num_to_scroll = 1;
614 struct tui_win_info *win_to_scroll;
615
616 /* Make sure the curses mode is enabled. */
617 tui_enable ();
618 if (arg == NULL)
619 parse_scrolling_args (arg, &win_to_scroll, NULL);
620 else
621 parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
622 win_to_scroll->forward_scroll (num_to_scroll);
623 }
624
625
626 static void
627 tui_scroll_backward_command (const char *arg, int from_tty)
628 {
629 int num_to_scroll = 1;
630 struct tui_win_info *win_to_scroll;
631
632 /* Make sure the curses mode is enabled. */
633 tui_enable ();
634 if (arg == NULL)
635 parse_scrolling_args (arg, &win_to_scroll, NULL);
636 else
637 parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
638 win_to_scroll->backward_scroll (num_to_scroll);
639 }
640
641
642 static void
643 tui_scroll_left_command (const char *arg, int from_tty)
644 {
645 int num_to_scroll;
646 struct tui_win_info *win_to_scroll;
647
648 /* Make sure the curses mode is enabled. */
649 tui_enable ();
650 parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
651 win_to_scroll->left_scroll (num_to_scroll);
652 }
653
654
655 static void
656 tui_scroll_right_command (const char *arg, int from_tty)
657 {
658 int num_to_scroll;
659 struct tui_win_info *win_to_scroll;
660
661 /* Make sure the curses mode is enabled. */
662 tui_enable ();
663 parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
664 win_to_scroll->right_scroll (num_to_scroll);
665 }
666
667
668 /* Answer the window represented by name. */
669 static struct tui_win_info *
670 tui_partial_win_by_name (std::string_view name)
671 {
672 struct tui_win_info *best = nullptr;
673
674 for (tui_win_info *item : all_tui_windows ())
675 {
676 const char *cur_name = item->name ();
677
678 if (name == cur_name)
679 return item;
680 if (startswith (cur_name, name))
681 {
682 if (best != nullptr)
683 error (_("Window name \"%*s\" is ambiguous"),
684 (int) name.size (), name.data ());
685 best = item;
686 }
687 }
688
689 return best;
690 }
691
692 /* Set focus to the window named by 'arg'. */
693 static void
694 tui_set_focus_command (const char *arg, int from_tty)
695 {
696 tui_enable ();
697
698 if (arg == NULL)
699 error_no_arg (_("name of window to focus"));
700
701 struct tui_win_info *win_info = NULL;
702
703 if (startswith ("next", arg))
704 win_info = tui_next_win (tui_win_with_focus ());
705 else if (startswith ("prev", arg))
706 win_info = tui_prev_win (tui_win_with_focus ());
707 else
708 win_info = tui_partial_win_by_name (arg);
709
710 if (win_info == nullptr)
711 {
712 /* When WIN_INFO is nullptr this can either mean that the window name
713 is unknown to GDB, or that the window is not in the current
714 layout. To try and help the user, give a different error
715 depending on which of these is the case. */
716 std::string matching_window_name;
717 bool is_ambiguous = false;
718
719 for (const std::string &name : all_known_window_names ())
720 {
721 /* Look through all windows in the current layout, if the window
722 is in the current layout then we're not interested is it. */
723 for (tui_win_info *item : all_tui_windows ())
724 if (item->name () == name)
725 continue;
726
727 if (startswith (name, arg))
728 {
729 if (matching_window_name.empty ())
730 matching_window_name = name;
731 else
732 is_ambiguous = true;
733 }
734 };
735
736 if (!matching_window_name.empty ())
737 {
738 if (is_ambiguous)
739 error (_("No windows matching \"%s\" in the current layout"),
740 arg);
741 else
742 error (_("Window \"%s\" is not in the current layout"),
743 matching_window_name.c_str ());
744 }
745 else
746 error (_("Unrecognized window name \"%s\""), arg);
747 }
748
749 /* If a window is part of the current layout then it will have a
750 tui_win_info associated with it and be visible, otherwise, there will
751 be no tui_win_info and the above error will have been raised. */
752 gdb_assert (win_info->is_visible ());
753
754 if (!win_info->can_focus ())
755 error (_("Window \"%s\" cannot be focused"), arg);
756
757 tui_set_win_focus_to (win_info);
758 gdb_printf (_("Focus set to %s window.\n"),
759 tui_win_with_focus ()->name ());
760 }
761
762 static void
763 tui_all_windows_info (const char *arg, int from_tty)
764 {
765 if (!tui_active)
766 {
767 gdb_printf (_("The TUI is not active.\n"));
768 return;
769 }
770
771 struct tui_win_info *win_with_focus = tui_win_with_focus ();
772 struct ui_out *uiout = current_uiout;
773
774 ui_out_emit_table table_emitter (uiout, 4, -1, "tui-windows");
775 uiout->table_header (10, ui_left, "name", "Name");
776 uiout->table_header (5, ui_right, "lines", "Lines");
777 uiout->table_header (7, ui_right, "columns", "Columns");
778 uiout->table_header (10, ui_left, "focus", "Focus");
779 uiout->table_body ();
780
781 for (tui_win_info *win_info : all_tui_windows ())
782 if (win_info->is_visible ())
783 {
784 ui_out_emit_tuple tuple_emitter (uiout, nullptr);
785
786 uiout->field_string ("name", win_info->name ());
787 uiout->field_signed ("lines", win_info->height);
788 uiout->field_signed ("columns", win_info->width);
789 if (win_with_focus == win_info)
790 uiout->field_string ("focus", _("(has focus)"));
791 else
792 uiout->field_skip ("focus");
793 uiout->text ("\n");
794 }
795 }
796
797
798 static void
799 tui_refresh_all_command (const char *arg, int from_tty)
800 {
801 /* Make sure the curses mode is enabled. */
802 tui_enable ();
803
804 tui_refresh_all_win ();
805 }
806
807 #define DEFAULT_TAB_LEN 8
808
809 /* The tab width that should be used by the TUI. */
810
811 unsigned int tui_tab_width = DEFAULT_TAB_LEN;
812
813 /* The tab width as set by the user. */
814
815 static unsigned int internal_tab_width = DEFAULT_TAB_LEN;
816
817 /* After the tab width is set, call this to update the relevant
818 windows. */
819
820 static void
821 update_tab_width ()
822 {
823 for (tui_win_info *win_info : all_tui_windows ())
824 {
825 if (win_info->is_visible ())
826 win_info->update_tab_width ();
827 }
828 }
829
830 /* Callback for "set tui tab-width". */
831
832 static void
833 tui_set_tab_width (const char *ignore,
834 int from_tty, struct cmd_list_element *c)
835 {
836 if (internal_tab_width == 0)
837 {
838 internal_tab_width = tui_tab_width;
839 error (_("Tab width must not be 0"));
840 }
841
842 tui_tab_width = internal_tab_width;
843 update_tab_width ();
844 }
845
846 /* Callback for "show tui tab-width". */
847
848 static void
849 tui_show_tab_width (struct ui_file *file, int from_tty,
850 struct cmd_list_element *c, const char *value)
851 {
852 gdb_printf (file, _("TUI tab width is %s spaces.\n"), value);
853
854 }
855
856 /* See tui-win.h. */
857
858 bool compact_source = false;
859
860 /* Callback for "set tui compact-source". */
861
862 static void
863 tui_set_compact_source (const char *ignore, int from_tty,
864 struct cmd_list_element *c)
865 {
866 if (TUI_SRC_WIN != nullptr)
867 TUI_SRC_WIN->refill ();
868 }
869
870 /* Callback for "show tui compact-source". */
871
872 static void
873 tui_show_compact_source (struct ui_file *file, int from_tty,
874 struct cmd_list_element *c, const char *value)
875 {
876 gdb_printf (file, _("TUI source window compactness is %s.\n"), value);
877 }
878
879 bool tui_enable_mouse = true;
880
881 /* Implement 'show tui mouse-events'. */
882
883 static void
884 show_tui_mouse_events (struct ui_file *file, int from_tty,
885 struct cmd_list_element *c, const char *value)
886 {
887 gdb_printf (file, _("TUI mouse events are %s.\n"), value);
888 }
889
890 /* Set the tab width of the specified window. */
891 static void
892 tui_set_tab_width_command (const char *arg, int from_tty)
893 {
894 /* Make sure the curses mode is enabled. */
895 tui_enable ();
896 if (arg != NULL)
897 {
898 int ts;
899
900 ts = atoi (arg);
901 if (ts <= 0)
902 warning (_("Tab widths greater than 0 must be specified."));
903 else
904 {
905 internal_tab_width = ts;
906 tui_tab_width = ts;
907
908 update_tab_width ();
909 }
910 }
911 }
912
913 /* Helper function for the user commands to adjust a window's width or
914 height. The ARG string contains the command line arguments from the
915 user, which should give the name of a window, and how to adjust the
916 size.
917
918 When SET_WIDTH_P is true the width of the window is adjusted based on
919 ARG, and when SET_WIDTH_P is false, the height of the window is adjusted
920 based on ARG.
921
922 On invalid input, or if the size can't be adjusted as requested, then an
923 error is thrown, otherwise, the window sizes are adjusted, and the
924 windows redrawn. */
925
926 static void
927 tui_set_win_size (const char *arg, bool set_width_p)
928 {
929 /* Make sure the curses mode is enabled. */
930 tui_enable ();
931 if (arg == NULL)
932 error_no_arg (_("name of window"));
933
934 const char *buf = arg;
935 const char *buf_ptr = buf;
936 int new_size;
937 struct tui_win_info *win_info;
938
939 buf_ptr = skip_to_space (buf_ptr);
940
941 /* Validate the window name. */
942 std::string_view wname (buf, buf_ptr - buf);
943 win_info = tui_partial_win_by_name (wname);
944
945 if (win_info == NULL)
946 error (_("Unrecognized window name \"%s\""), arg);
947 if (!win_info->is_visible ())
948 error (_("Window \"%s\" is not visible"), arg);
949
950 /* Process the size. */
951 buf_ptr = skip_spaces (buf_ptr);
952
953 if (*buf_ptr != '\0')
954 {
955 bool negate = false;
956 bool fixed_size = true;
957 int input_no;;
958
959 if (*buf_ptr == '+' || *buf_ptr == '-')
960 {
961 if (*buf_ptr == '-')
962 negate = true;
963 fixed_size = false;
964 buf_ptr++;
965 }
966 input_no = atoi (buf_ptr);
967 if (input_no > 0)
968 {
969 if (negate)
970 input_no *= (-1);
971 if (fixed_size)
972 new_size = input_no;
973 else
974 {
975 int curr_size;
976 if (set_width_p)
977 curr_size = win_info->width;
978 else
979 curr_size = win_info->height;
980 new_size = curr_size + input_no;
981 }
982
983 /* Now change the window's height, and adjust
984 all other windows around it. */
985 if (set_width_p)
986 tui_adjust_window_width (win_info, new_size);
987 else
988 tui_adjust_window_height (win_info, new_size);
989 tui_update_gdb_sizes ();
990 }
991 else
992 {
993 if (set_width_p)
994 error (_("Invalid window width specified"));
995 else
996 error (_("Invalid window height specified"));
997 }
998 }
999 }
1000
1001 /* Implement the 'tui window height' command (alias 'winheight'). */
1002
1003 static void
1004 tui_set_win_height_command (const char *arg, int from_tty)
1005 {
1006 /* Pass false as the final argument to set the height. */
1007 tui_set_win_size (arg, false);
1008 }
1009
1010 /* Implement the 'tui window width' command (alias 'winwidth'). */
1011
1012 static void
1013 tui_set_win_width_command (const char *arg, int from_tty)
1014 {
1015 /* Pass true as the final argument to set the width. */
1016 tui_set_win_size (arg, true);
1017 }
1018
1019 /* See tui-data.h. */
1020
1021 int
1022 tui_win_info::max_height () const
1023 {
1024 return tui_term_height ();
1025 }
1026
1027 /* See tui-data.h. */
1028
1029 int
1030 tui_win_info::max_width () const
1031 {
1032 return tui_term_width ();
1033 }
1034
1035 static void
1036 parse_scrolling_args (const char *arg,
1037 struct tui_win_info **win_to_scroll,
1038 int *num_to_scroll)
1039 {
1040 if (num_to_scroll)
1041 *num_to_scroll = 0;
1042 *win_to_scroll = tui_win_with_focus ();
1043
1044 /* First set up the default window to scroll, in case there is no
1045 window name arg. */
1046 if (arg != NULL)
1047 {
1048 char *buf_ptr;
1049
1050 /* Process the number of lines to scroll. */
1051 std::string copy = arg;
1052 buf_ptr = ©[0];
1053 if (isdigit (*buf_ptr))
1054 {
1055 char *num_str;
1056
1057 num_str = buf_ptr;
1058 buf_ptr = strchr (buf_ptr, ' ');
1059 if (buf_ptr != NULL)
1060 {
1061 *buf_ptr = '\0';
1062 if (num_to_scroll)
1063 *num_to_scroll = atoi (num_str);
1064 buf_ptr++;
1065 }
1066 else if (num_to_scroll)
1067 *num_to_scroll = atoi (num_str);
1068 }
1069
1070 /* Process the window name if one is specified. */
1071 if (buf_ptr != NULL)
1072 {
1073 const char *wname;
1074
1075 wname = skip_spaces (buf_ptr);
1076
1077 if (*wname != '\0')
1078 {
1079 *win_to_scroll = tui_partial_win_by_name (wname);
1080
1081 if (*win_to_scroll == NULL)
1082 error (_("Unrecognized window `%s'"), wname);
1083 if (!(*win_to_scroll)->is_visible ())
1084 error (_("Window is not visible"));
1085 else if (*win_to_scroll == TUI_CMD_WIN)
1086 *win_to_scroll = *(tui_source_windows ().begin ());
1087 }
1088 }
1089 }
1090 }
1091
1092 /* The list of 'tui window' sub-commands. */
1093
1094 static cmd_list_element *tui_window_cmds = nullptr;
1095
1096 /* Called to implement 'tui window'. */
1097
1098 static void
1099 tui_window_command (const char *args, int from_tty)
1100 {
1101 help_list (tui_window_cmds, "tui window ", all_commands, gdb_stdout);
1102 }
1103
1104 /* See tui-win.h. */
1105
1106 bool tui_left_margin_verbose = false;
1107
1108 /* Function to initialize gdb commands, for tui window
1109 manipulation. */
1110
1111 void _initialize_tui_win ();
1112 void
1113 _initialize_tui_win ()
1114 {
1115 static struct cmd_list_element *tui_setlist;
1116 static struct cmd_list_element *tui_showlist;
1117
1118 /* Define the classes of commands.
1119 They will appear in the help list in the reverse of this order. */
1120 add_setshow_prefix_cmd ("tui", class_tui,
1121 _("TUI configuration variables."),
1122 _("TUI configuration variables."),
1123 &tui_setlist, &tui_showlist,
1124 &setlist, &showlist);
1125
1126 cmd_list_element *refresh_cmd
1127 = add_cmd ("refresh", class_tui, tui_refresh_all_command,
1128 _("Refresh the terminal display."),
1129 tui_get_cmd_list ());
1130 add_com_alias ("refresh", refresh_cmd, class_tui, 0);
1131
1132 cmd_list_element *tabset_cmd
1133 = add_com ("tabset", class_tui, tui_set_tab_width_command, _("\
1134 Set the width (in characters) of tab stops.\n\
1135 Usage: tabset N"));
1136 deprecate_cmd (tabset_cmd, "set tui tab-width");
1137
1138 /* Setup the 'tui window' list of command. */
1139 add_prefix_cmd ("window", class_tui, tui_window_command,
1140 _("Text User Interface window commands."),
1141 &tui_window_cmds, 1, tui_get_cmd_list ());
1142
1143 cmd_list_element *winheight_cmd
1144 = add_cmd ("height", class_tui, tui_set_win_height_command, _("\
1145 Set or modify the height of a specified window.\n\
1146 Usage: tui window height WINDOW-NAME [+ | -] NUM-LINES\n\
1147 Use \"info win\" to see the names of the windows currently being displayed."),
1148 &tui_window_cmds);
1149 add_com_alias ("winheight", winheight_cmd, class_tui, 0);
1150 add_com_alias ("wh", winheight_cmd, class_tui, 0);
1151 set_cmd_completer (winheight_cmd, winheight_completer);
1152
1153 cmd_list_element *winwidth_cmd
1154 = add_cmd ("width", class_tui, tui_set_win_width_command, _("\
1155 Set or modify the width of a specified window.\n\
1156 Usage: tui window width WINDOW-NAME [+ | -] NUM-LINES\n\
1157 Use \"info win\" to see the names of the windows currently being displayed."),
1158 &tui_window_cmds);
1159 add_com_alias ("winwidth", winwidth_cmd, class_tui, 0);
1160 set_cmd_completer (winwidth_cmd, winheight_completer);
1161
1162 add_info ("win", tui_all_windows_info,
1163 _("List of all displayed windows.\n\
1164 Usage: info win"));
1165 cmd_list_element *focus_cmd
1166 = add_cmd ("focus", class_tui, tui_set_focus_command, _("\
1167 Set focus to named window or next/prev window.\n\
1168 Usage: tui focus [WINDOW-NAME | next | prev]\n\
1169 Use \"info win\" to see the names of the windows currently being displayed."),
1170 tui_get_cmd_list ());
1171 add_com_alias ("focus", focus_cmd, class_tui, 0);
1172 add_com_alias ("fs", focus_cmd, class_tui, 0);
1173 set_cmd_completer (focus_cmd, focus_completer);
1174 add_com ("+", class_tui, tui_scroll_forward_command, _("\
1175 Scroll window forward.\n\
1176 Usage: + [N] [WIN]\n\
1177 Scroll window WIN N lines forwards. Both WIN and N are optional, N\n\
1178 defaults to 1, and WIN defaults to the currently focused window."));
1179 add_com ("-", class_tui, tui_scroll_backward_command, _("\
1180 Scroll window backward.\n\
1181 Usage: - [N] [WIN]\n\
1182 Scroll window WIN N lines backwards. Both WIN and N are optional, N\n\
1183 defaults to 1, and WIN defaults to the currently focused window."));
1184 add_com ("<", class_tui, tui_scroll_left_command, _("\
1185 Scroll window text to the left.\n\
1186 Usage: < [N] [WIN]\n\
1187 Scroll window WIN N characters left. Both WIN and N are optional, N\n\
1188 defaults to 1, and WIN defaults to the currently focused window."));
1189 add_com (">", class_tui, tui_scroll_right_command, _("\
1190 Scroll window text to the right.\n\
1191 Usage: > [N] [WIN]\n\
1192 Scroll window WIN N characters right. Both WIN and N are optional, N\n\
1193 defaults to 1, and WIN defaults to the currently focused window."));
1194
1195 /* Define the tui control variables. */
1196 add_setshow_enum_cmd ("border-kind", no_class, tui_border_kind_enums,
1197 &tui_border_kind, _("\
1198 Set the kind of border for TUI windows."), _("\
1199 Show the kind of border for TUI windows."), _("\
1200 This variable controls the border of TUI windows:\n\
1201 space use a white space\n\
1202 ascii use ascii characters + - | for the border\n\
1203 acs use the Alternate Character Set"),
1204 tui_set_var_cmd,
1205 show_tui_border_kind,
1206 &tui_setlist, &tui_showlist);
1207
1208 const std::string help_attribute_mode (_("\
1209 normal normal display\n\
1210 standout use highlight mode of terminal\n\
1211 reverse use reverse video mode\n\
1212 half use half bright\n\
1213 half-standout use half bright and standout mode\n\
1214 bold use extra bright or bold\n\
1215 bold-standout use extra bright or bold with standout mode"));
1216
1217 const std::string help_tui_border_mode
1218 = (_("\
1219 This variable controls the attributes to use for the window borders:\n")
1220 + help_attribute_mode);
1221
1222 add_setshow_enum_cmd ("border-mode", no_class, tui_border_mode_enums,
1223 &tui_border_mode, _("\
1224 Set the attribute mode to use for the TUI window borders."), _("\
1225 Show the attribute mode to use for the TUI window borders."),
1226 help_tui_border_mode.c_str (),
1227 tui_set_var_cmd,
1228 show_tui_border_mode,
1229 &tui_setlist, &tui_showlist);
1230
1231 const std::string help_tui_active_border_mode
1232 = (_("\
1233 This variable controls the attributes to use for the active window borders:\n")
1234 + help_attribute_mode);
1235
1236 add_setshow_enum_cmd ("active-border-mode", no_class, tui_border_mode_enums,
1237 &tui_active_border_mode, _("\
1238 Set the attribute mode to use for the active TUI window border."), _("\
1239 Show the attribute mode to use for the active TUI window border."),
1240 help_tui_active_border_mode.c_str (),
1241 tui_set_var_cmd,
1242 show_tui_active_border_mode,
1243 &tui_setlist, &tui_showlist);
1244
1245 add_setshow_zuinteger_cmd ("tab-width", no_class,
1246 &internal_tab_width, _("\
1247 Set the tab width, in characters, for the TUI."), _("\
1248 Show the tab width, in characters, for the TUI."), _("\
1249 This variable controls how many spaces are used to display a tab character."),
1250 tui_set_tab_width, tui_show_tab_width,
1251 &tui_setlist, &tui_showlist);
1252
1253 add_setshow_boolean_cmd ("tui-resize-message", class_maintenance,
1254 &resize_message, _("\
1255 Set TUI resize messaging."), _("\
1256 Show TUI resize messaging."), _("\
1257 When enabled GDB will print a message when the terminal is resized."),
1258 nullptr,
1259 show_tui_resize_message,
1260 &maintenance_set_cmdlist,
1261 &maintenance_show_cmdlist);
1262
1263 add_setshow_boolean_cmd ("compact-source", class_tui,
1264 &compact_source, _("\
1265 Set whether the TUI source window is compact."), _("\
1266 Show whether the TUI source window is compact."), _("\
1267 This variable controls whether the TUI source window is shown\n\
1268 in a compact form. The compact form uses less horizontal space."),
1269 tui_set_compact_source, tui_show_compact_source,
1270 &tui_setlist, &tui_showlist);
1271
1272 add_setshow_boolean_cmd ("mouse-events", class_tui,
1273 &tui_enable_mouse, _("\
1274 Set whether TUI mode handles mouse clicks."), _("\
1275 Show whether TUI mode handles mouse clicks."), _("\
1276 When on (default), mouse clicks control the TUI and can be accessed by Python\n\
1277 extensions. When off, mouse clicks are handled by the terminal, enabling\n\
1278 terminal-native text selection."),
1279 nullptr,
1280 show_tui_mouse_events,
1281 &tui_setlist, &tui_showlist);
1282
1283 add_setshow_boolean_cmd ("tui-current-position", class_maintenance,
1284 &style_tui_current_position, _("\
1285 Set whether to style text highlighted by the TUI's current position indicator."),
1286 _("\
1287 Show whether to style text highlighted by the TUI's current position indicator."),
1288 _("\
1289 When enabled, the source and assembly code highlighted by the TUI's current\n\
1290 position indicator is styled."),
1291 set_style_tui_current_position,
1292 show_style_tui_current_position,
1293 &style_set_list,
1294 &style_show_list);
1295
1296 add_setshow_boolean_cmd ("tui-left-margin-verbose", class_maintenance,
1297 &tui_left_margin_verbose, _("\
1298 Set whether the left margin should use '_' and '0' instead of spaces."),
1299 _("\
1300 Show whether the left margin should use '_' and '0' instead of spaces."),
1301 _("\
1302 When enabled, the left margin will use '_' and '0' instead of spaces."),
1303 nullptr,
1304 nullptr,
1305 &maintenance_set_cmdlist,
1306 &maintenance_show_cmdlist);
1307
1308 tui_border_style.changed.attach (tui_rehighlight_all, "tui-win");
1309 tui_active_border_style.changed.attach (tui_rehighlight_all, "tui-win");
1310 }
1311