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