Allow using less horizontal space in TUI source window
[deliverable/binutils-gdb.git] / gdb / tui / tui-win.c
1 /* TUI window generic functions.
2
3 Copyright (C) 1998-2019 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 "top.h"
34 #include "source.h"
35 #include "event-loop.h"
36 #include "gdbcmd.h"
37
38 #include "tui/tui.h"
39 #include "tui/tui-io.h"
40 #include "tui/tui-command.h"
41 #include "tui/tui-data.h"
42 #include "tui/tui-layout.h"
43 #include "tui/tui-wingeneral.h"
44 #include "tui/tui-stack.h"
45 #include "tui/tui-regs.h"
46 #include "tui/tui-disasm.h"
47 #include "tui/tui-source.h"
48 #include "tui/tui-winsource.h"
49 #include "tui/tui-win.h"
50
51 #include "gdb_curses.h"
52 #include <ctype.h>
53 #include "readline/readline.h"
54 #include "gdbsupport/gdb_string_view.h"
55
56 #include <signal.h>
57
58 static enum tui_status tui_adjust_win_heights (struct tui_win_info *,
59 int);
60 static int new_height_ok (struct tui_win_info *, int);
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 #define WIN_HEIGHT_USAGE "Usage: winheight WINDOW-NAME [+ | -] NUM-LINES\n"
74 #define FOCUS_USAGE "Usage: focus [WINDOW-NAME | next | prev]\n"
75
76 #ifndef ACS_LRCORNER
77 # define ACS_LRCORNER '+'
78 #endif
79 #ifndef ACS_LLCORNER
80 # define ACS_LLCORNER '+'
81 #endif
82 #ifndef ACS_ULCORNER
83 # define ACS_ULCORNER '+'
84 #endif
85 #ifndef ACS_URCORNER
86 # define ACS_URCORNER '+'
87 #endif
88 #ifndef ACS_HLINE
89 # define ACS_HLINE '-'
90 #endif
91 #ifndef ACS_VLINE
92 # define ACS_VLINE '|'
93 #endif
94
95 /* Possible values for tui-border-kind variable. */
96 static const char *const tui_border_kind_enums[] = {
97 "space",
98 "ascii",
99 "acs",
100 NULL
101 };
102
103 /* Possible values for tui-border-mode and tui-active-border-mode. */
104 static const char *const tui_border_mode_enums[] = {
105 "normal",
106 "standout",
107 "reverse",
108 "half",
109 "half-standout",
110 "bold",
111 "bold-standout",
112 NULL
113 };
114
115 struct tui_translate
116 {
117 const char *name;
118 int value;
119 };
120
121 /* Translation table for border-mode variables.
122 The list of values must be terminated by a NULL.
123 After the NULL value, an entry defines the default. */
124 struct tui_translate tui_border_mode_translate[] = {
125 { "normal", A_NORMAL },
126 { "standout", A_STANDOUT },
127 { "reverse", A_REVERSE },
128 { "half", A_DIM },
129 { "half-standout", A_DIM | A_STANDOUT },
130 { "bold", A_BOLD },
131 { "bold-standout", A_BOLD | A_STANDOUT },
132 { 0, 0 },
133 { "normal", A_NORMAL }
134 };
135
136 /* Translation tables for border-kind, one for each border
137 character (see wborder, border curses operations).
138 -1 is used to indicate the ACS because ACS characters
139 are determined at run time by curses (depends on terminal). */
140 struct tui_translate tui_border_kind_translate_vline[] = {
141 { "space", ' ' },
142 { "ascii", '|' },
143 { "acs", -1 },
144 { 0, 0 },
145 { "ascii", '|' }
146 };
147
148 struct tui_translate tui_border_kind_translate_hline[] = {
149 { "space", ' ' },
150 { "ascii", '-' },
151 { "acs", -1 },
152 { 0, 0 },
153 { "ascii", '-' }
154 };
155
156 struct tui_translate tui_border_kind_translate_ulcorner[] = {
157 { "space", ' ' },
158 { "ascii", '+' },
159 { "acs", -1 },
160 { 0, 0 },
161 { "ascii", '+' }
162 };
163
164 struct tui_translate tui_border_kind_translate_urcorner[] = {
165 { "space", ' ' },
166 { "ascii", '+' },
167 { "acs", -1 },
168 { 0, 0 },
169 { "ascii", '+' }
170 };
171
172 struct tui_translate tui_border_kind_translate_llcorner[] = {
173 { "space", ' ' },
174 { "ascii", '+' },
175 { "acs", -1 },
176 { 0, 0 },
177 { "ascii", '+' }
178 };
179
180 struct tui_translate tui_border_kind_translate_lrcorner[] = {
181 { "space", ' ' },
182 { "ascii", '+' },
183 { "acs", -1 },
184 { 0, 0 },
185 { "ascii", '+' }
186 };
187
188
189 /* Tui configuration variables controlled with set/show command. */
190 const char *tui_active_border_mode = "bold-standout";
191 static void
192 show_tui_active_border_mode (struct ui_file *file,
193 int from_tty,
194 struct cmd_list_element *c,
195 const char *value)
196 {
197 fprintf_filtered (file, _("\
198 The attribute mode to use for the active TUI window border is \"%s\".\n"),
199 value);
200 }
201
202 const char *tui_border_mode = "normal";
203 static void
204 show_tui_border_mode (struct ui_file *file,
205 int from_tty,
206 struct cmd_list_element *c,
207 const char *value)
208 {
209 fprintf_filtered (file, _("\
210 The attribute mode to use for the TUI window borders is \"%s\".\n"),
211 value);
212 }
213
214 const char *tui_border_kind = "acs";
215 static void
216 show_tui_border_kind (struct ui_file *file,
217 int from_tty,
218 struct cmd_list_element *c,
219 const char *value)
220 {
221 fprintf_filtered (file, _("The kind of border for TUI windows is \"%s\".\n"),
222 value);
223 }
224
225
226 /* Tui internal configuration variables. These variables are updated
227 by tui_update_variables to reflect the tui configuration
228 variables. */
229 chtype tui_border_vline;
230 chtype tui_border_hline;
231 chtype tui_border_ulcorner;
232 chtype tui_border_urcorner;
233 chtype tui_border_llcorner;
234 chtype tui_border_lrcorner;
235
236 int tui_border_attrs;
237 int tui_active_border_attrs;
238
239 /* Identify the item in the translation table.
240 When the item is not recognized, use the default entry. */
241 static struct tui_translate *
242 translate (const char *name, struct tui_translate *table)
243 {
244 while (table->name)
245 {
246 if (name && strcmp (table->name, name) == 0)
247 return table;
248 table++;
249 }
250
251 /* Not found, return default entry. */
252 table++;
253 return table;
254 }
255
256 /* Update the tui internal configuration according to gdb settings.
257 Returns 1 if the configuration has changed and the screen should
258 be redrawn. */
259 int
260 tui_update_variables (void)
261 {
262 int need_redraw = 0;
263 struct tui_translate *entry;
264
265 entry = translate (tui_border_mode, tui_border_mode_translate);
266 if (tui_border_attrs != entry->value)
267 {
268 tui_border_attrs = entry->value;
269 need_redraw = 1;
270 }
271 entry = translate (tui_active_border_mode, tui_border_mode_translate);
272 if (tui_active_border_attrs != entry->value)
273 {
274 tui_active_border_attrs = entry->value;
275 need_redraw = 1;
276 }
277
278 /* If one corner changes, all characters are changed.
279 Only check the first one. The ACS characters are determined at
280 run time by curses terminal management. */
281 entry = translate (tui_border_kind, tui_border_kind_translate_lrcorner);
282 if (tui_border_lrcorner != (chtype) entry->value)
283 {
284 tui_border_lrcorner = (entry->value < 0) ? ACS_LRCORNER : entry->value;
285 need_redraw = 1;
286 }
287 entry = translate (tui_border_kind, tui_border_kind_translate_llcorner);
288 tui_border_llcorner = (entry->value < 0) ? ACS_LLCORNER : entry->value;
289
290 entry = translate (tui_border_kind, tui_border_kind_translate_ulcorner);
291 tui_border_ulcorner = (entry->value < 0) ? ACS_ULCORNER : entry->value;
292
293 entry = translate (tui_border_kind, tui_border_kind_translate_urcorner);
294 tui_border_urcorner = (entry->value < 0) ? ACS_URCORNER : entry->value;
295
296 entry = translate (tui_border_kind, tui_border_kind_translate_hline);
297 tui_border_hline = (entry->value < 0) ? ACS_HLINE : entry->value;
298
299 entry = translate (tui_border_kind, tui_border_kind_translate_vline);
300 tui_border_vline = (entry->value < 0) ? ACS_VLINE : entry->value;
301
302 return need_redraw;
303 }
304
305 static void
306 set_tui_cmd (const char *args, int from_tty)
307 {
308 }
309
310 static void
311 show_tui_cmd (const char *args, int from_tty)
312 {
313 }
314
315 static struct cmd_list_element *tuilist;
316
317 static void
318 tui_command (const char *args, int from_tty)
319 {
320 printf_unfiltered (_("\"tui\" must be followed by the name of a "
321 "tui command.\n"));
322 help_list (tuilist, "tui ", all_commands, gdb_stdout);
323 }
324
325 struct cmd_list_element **
326 tui_get_cmd_list (void)
327 {
328 if (tuilist == 0)
329 add_prefix_cmd ("tui", class_tui, tui_command,
330 _("Text User Interface commands."),
331 &tuilist, "tui ", 0, &cmdlist);
332 return &tuilist;
333 }
334
335 /* The set_func hook of "set tui ..." commands that affect the window
336 borders on the TUI display. */
337
338 static void
339 tui_set_var_cmd (const char *null_args,
340 int from_tty, struct cmd_list_element *c)
341 {
342 if (tui_update_variables () && tui_active)
343 tui_rehighlight_all ();
344 }
345
346 \f
347
348 /* True if TUI resizes should print a message. This is used by the
349 test suite. */
350
351 static bool resize_message;
352
353 static void
354 show_tui_resize_message (struct ui_file *file, int from_tty,
355 struct cmd_list_element *c, const char *value)
356 {
357 fprintf_filtered (file, _("TUI resize messaging is %s.\n"), value);
358 }
359
360 \f
361
362 /* Generic window name completion function. Complete window name pointed
363 to by TEXT and WORD. If INCLUDE_NEXT_PREV_P is true then the special
364 window names 'next' and 'prev' will also be considered as possible
365 completions of the window name. */
366
367 static void
368 window_name_completer (completion_tracker &tracker,
369 int include_next_prev_p,
370 const char *text, const char *word)
371 {
372 std::vector<const char *> completion_name_vec;
373
374 for (tui_win_info *win_info : all_tui_windows ())
375 {
376 const char *completion_name = NULL;
377
378 /* We can't focus on an invisible window. */
379 if (!win_info->is_visible ())
380 continue;
381
382 completion_name = win_info->name ();
383 gdb_assert (completion_name != NULL);
384 completion_name_vec.push_back (completion_name);
385 }
386
387 /* If no windows are considered visible then the TUI has not yet been
388 initialized. But still "focus src" and "focus cmd" will work because
389 invoking the focus command will entail initializing the TUI which sets the
390 default layout to SRC_COMMAND. */
391 if (completion_name_vec.empty ())
392 {
393 completion_name_vec.push_back (SRC_NAME);
394 completion_name_vec.push_back (CMD_NAME);
395 }
396
397 if (include_next_prev_p)
398 {
399 completion_name_vec.push_back ("next");
400 completion_name_vec.push_back ("prev");
401 }
402
403
404 completion_name_vec.push_back (NULL);
405 complete_on_enum (tracker, completion_name_vec.data (), text, word);
406 }
407
408 /* Complete possible window names to focus on. TEXT is the complete text
409 entered so far, WORD is the word currently being completed. */
410
411 static void
412 focus_completer (struct cmd_list_element *ignore,
413 completion_tracker &tracker,
414 const char *text, const char *word)
415 {
416 window_name_completer (tracker, 1, text, word);
417 }
418
419 /* Complete possible window names for winheight command. TEXT is the
420 complete text entered so far, WORD is the word currently being
421 completed. */
422
423 static void
424 winheight_completer (struct cmd_list_element *ignore,
425 completion_tracker &tracker,
426 const char *text, const char *word)
427 {
428 /* The first word is the window name. That we can complete. Subsequent
429 words can't be completed. */
430 if (word != text)
431 return;
432
433 window_name_completer (tracker, 0, text, word);
434 }
435
436 /* Update gdb's knowledge of the terminal size. */
437 void
438 tui_update_gdb_sizes (void)
439 {
440 int width, height;
441
442 if (tui_active)
443 {
444 width = TUI_CMD_WIN->width;
445 height = TUI_CMD_WIN->height;
446 }
447 else
448 {
449 width = tui_term_width ();
450 height = tui_term_height ();
451 }
452
453 set_screen_width_and_height (width, height);
454 }
455
456
457 /* Set the logical focus to win_info. */
458 void
459 tui_set_win_focus_to (struct tui_win_info *win_info)
460 {
461 if (win_info != NULL)
462 {
463 struct tui_win_info *win_with_focus = tui_win_with_focus ();
464
465 tui_unhighlight_win (win_with_focus);
466 tui_set_win_with_focus (win_info);
467 tui_highlight_win (win_info);
468 }
469 }
470
471
472 void
473 tui_win_info::forward_scroll (int num_to_scroll)
474 {
475 if (num_to_scroll == 0)
476 num_to_scroll = height - 3;
477
478 do_scroll_vertical (num_to_scroll);
479 }
480
481 void
482 tui_win_info::backward_scroll (int num_to_scroll)
483 {
484 if (num_to_scroll == 0)
485 num_to_scroll = height - 3;
486
487 do_scroll_vertical (-num_to_scroll);
488 }
489
490
491 void
492 tui_win_info::left_scroll (int num_to_scroll)
493 {
494 if (num_to_scroll == 0)
495 num_to_scroll = 1;
496
497 do_scroll_horizontal (num_to_scroll);
498 }
499
500
501 void
502 tui_win_info::right_scroll (int num_to_scroll)
503 {
504 if (num_to_scroll == 0)
505 num_to_scroll = 1;
506
507 do_scroll_horizontal (-num_to_scroll);
508 }
509
510
511 void
512 tui_refresh_all_win (void)
513 {
514 clearok (curscr, TRUE);
515 tui_refresh_all ();
516 }
517
518 void
519 tui_rehighlight_all (void)
520 {
521 for (tui_win_info *win_info : all_tui_windows ())
522 win_info->check_and_display_highlight_if_needed ();
523 }
524
525 /* Resize all the windows based on the terminal size. This function
526 gets called from within the readline SIGWINCH handler. */
527 void
528 tui_resize_all (void)
529 {
530 int height_diff, width_diff;
531 int screenheight, screenwidth;
532
533 rl_get_screen_size (&screenheight, &screenwidth);
534 width_diff = screenwidth - tui_term_width ();
535 height_diff = screenheight - tui_term_height ();
536 if (height_diff || width_diff)
537 {
538 enum tui_layout_type cur_layout = tui_current_layout ();
539 struct tui_win_info *win_with_focus = tui_win_with_focus ();
540 struct tui_win_info *first_win;
541 struct tui_win_info *second_win;
542 tui_source_window_base *src_win;
543 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
544 int new_height, split_diff, cmd_split_diff, num_wins_displayed = 2;
545
546 #ifdef HAVE_RESIZE_TERM
547 resize_term (screenheight, screenwidth);
548 #endif
549 /* Turn keypad off while we resize. */
550 if (win_with_focus != TUI_CMD_WIN)
551 keypad (TUI_CMD_WIN->handle.get (), FALSE);
552 tui_update_gdb_sizes ();
553 tui_set_term_height_to (screenheight);
554 tui_set_term_width_to (screenwidth);
555 if (cur_layout == SRC_DISASSEM_COMMAND
556 || cur_layout == SRC_DATA_COMMAND
557 || cur_layout == DISASSEM_DATA_COMMAND)
558 num_wins_displayed++;
559 split_diff = height_diff / num_wins_displayed;
560 cmd_split_diff = split_diff;
561 if (height_diff % num_wins_displayed)
562 {
563 if (height_diff < 0)
564 cmd_split_diff--;
565 else
566 cmd_split_diff++;
567 }
568 /* Now adjust each window. */
569 /* erase + clearok are used instead of a straightforward clear as
570 AIX 5.3 does not define clear. */
571 erase ();
572 clearok (curscr, TRUE);
573 switch (cur_layout)
574 {
575 case SRC_COMMAND:
576 case DISASSEM_COMMAND:
577 src_win = *(tui_source_windows ().begin ());
578 /* Check for invalid heights. */
579 if (height_diff == 0)
580 new_height = src_win->height;
581 else if ((src_win->height + split_diff) >=
582 (screenheight - MIN_CMD_WIN_HEIGHT - 1))
583 new_height = screenheight - MIN_CMD_WIN_HEIGHT - 1;
584 else if ((src_win->height + split_diff) <= 0)
585 new_height = MIN_WIN_HEIGHT;
586 else
587 new_height = src_win->height + split_diff;
588
589 src_win->resize (new_height, screenwidth, 0, 0);
590
591 locator->resize (1, screenwidth, 0, new_height);
592
593 new_height = screenheight - (new_height + 1);
594 TUI_CMD_WIN->resize (new_height, screenwidth,
595 0, locator->origin.y + 1);
596 break;
597 default:
598 if (cur_layout == SRC_DISASSEM_COMMAND)
599 {
600 src_win = TUI_SRC_WIN;
601 first_win = src_win;
602 second_win = TUI_DISASM_WIN;
603 }
604 else
605 {
606 first_win = TUI_DATA_WIN;
607 src_win = *(tui_source_windows ().begin ());
608 second_win = src_win;
609 }
610 /* Change the first window's height/width. */
611 /* Check for invalid heights. */
612 if (height_diff == 0)
613 new_height = first_win->height;
614 else if ((first_win->height +
615 second_win->height + (split_diff * 2)) >=
616 (screenheight - MIN_CMD_WIN_HEIGHT - 1))
617 new_height = (screenheight - MIN_CMD_WIN_HEIGHT - 1) / 2;
618 else if ((first_win->height + split_diff) <= 0)
619 new_height = MIN_WIN_HEIGHT;
620 else
621 new_height = first_win->height + split_diff;
622
623 first_win->resize (new_height, screenwidth, 0, 0);
624
625 /* Change the second window's height/width. */
626 /* Check for invalid heights. */
627 if (height_diff == 0)
628 new_height = second_win->height;
629 else if ((first_win->height +
630 second_win->height + (split_diff * 2)) >=
631 (screenheight - MIN_CMD_WIN_HEIGHT - 1))
632 {
633 new_height = screenheight - MIN_CMD_WIN_HEIGHT - 1;
634 if (new_height % 2)
635 new_height = (new_height / 2) + 1;
636 else
637 new_height /= 2;
638 }
639 else if ((second_win->height + split_diff) <= 0)
640 new_height = MIN_WIN_HEIGHT;
641 else
642 new_height = second_win->height + split_diff;
643
644 second_win->resize (new_height, screenwidth,
645 0, first_win->height - 1);
646
647 locator->resize (1, screenwidth,
648 0, second_win->origin.y + new_height);
649
650 /* Change the command window's height/width. */
651 new_height = screenheight - (locator->origin.y + 1);
652 TUI_CMD_WIN->resize (new_height, screenwidth,
653 0, locator->origin.y + 1);
654 break;
655 }
656
657 tui_delete_invisible_windows ();
658 /* Turn keypad back on, unless focus is in the command
659 window. */
660 if (win_with_focus != TUI_CMD_WIN)
661 keypad (TUI_CMD_WIN->handle.get (), TRUE);
662 }
663 }
664
665 #ifdef SIGWINCH
666 /* Token for use by TUI's asynchronous SIGWINCH handler. */
667 static struct async_signal_handler *tui_sigwinch_token;
668
669 /* TUI's SIGWINCH signal handler. */
670 static void
671 tui_sigwinch_handler (int signal)
672 {
673 mark_async_signal_handler (tui_sigwinch_token);
674 tui_set_win_resized_to (true);
675 }
676
677 /* Callback for asynchronously resizing TUI following a SIGWINCH signal. */
678 static void
679 tui_async_resize_screen (gdb_client_data arg)
680 {
681 rl_resize_terminal ();
682
683 if (!tui_active)
684 {
685 int screen_height, screen_width;
686
687 rl_get_screen_size (&screen_height, &screen_width);
688 set_screen_width_and_height (screen_width, screen_height);
689
690 /* win_resized is left set so that the next call to tui_enable()
691 resizes the TUI windows. */
692 }
693 else
694 {
695 tui_set_win_resized_to (false);
696 tui_resize_all ();
697 tui_refresh_all_win ();
698 tui_update_gdb_sizes ();
699 if (resize_message)
700 {
701 static int count;
702 printf_unfiltered ("@@ resize done %d, size = %dx%d\n", count,
703 tui_term_width (), tui_term_height ());
704 ++count;
705 }
706 tui_redisplay_readline ();
707 }
708 }
709 #endif
710
711 /* Initialize TUI's SIGWINCH signal handler. Note that the handler is not
712 uninstalled when we exit TUI, so the handler should not assume that TUI is
713 always active. */
714 void
715 tui_initialize_win (void)
716 {
717 #ifdef SIGWINCH
718 tui_sigwinch_token
719 = create_async_signal_handler (tui_async_resize_screen, NULL);
720
721 {
722 #ifdef HAVE_SIGACTION
723 struct sigaction old_winch;
724
725 memset (&old_winch, 0, sizeof (old_winch));
726 old_winch.sa_handler = &tui_sigwinch_handler;
727 #ifdef SA_RESTART
728 old_winch.sa_flags = SA_RESTART;
729 #endif
730 sigaction (SIGWINCH, &old_winch, NULL);
731 #else
732 signal (SIGWINCH, &tui_sigwinch_handler);
733 #endif
734 }
735 #endif
736 }
737
738
739 static void
740 tui_scroll_forward_command (const char *arg, int from_tty)
741 {
742 int num_to_scroll = 1;
743 struct tui_win_info *win_to_scroll;
744
745 /* Make sure the curses mode is enabled. */
746 tui_enable ();
747 if (arg == NULL)
748 parse_scrolling_args (arg, &win_to_scroll, NULL);
749 else
750 parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
751 win_to_scroll->forward_scroll (num_to_scroll);
752 }
753
754
755 static void
756 tui_scroll_backward_command (const char *arg, int from_tty)
757 {
758 int num_to_scroll = 1;
759 struct tui_win_info *win_to_scroll;
760
761 /* Make sure the curses mode is enabled. */
762 tui_enable ();
763 if (arg == NULL)
764 parse_scrolling_args (arg, &win_to_scroll, NULL);
765 else
766 parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
767 win_to_scroll->backward_scroll (num_to_scroll);
768 }
769
770
771 static void
772 tui_scroll_left_command (const char *arg, int from_tty)
773 {
774 int num_to_scroll;
775 struct tui_win_info *win_to_scroll;
776
777 /* Make sure the curses mode is enabled. */
778 tui_enable ();
779 parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
780 win_to_scroll->left_scroll (num_to_scroll);
781 }
782
783
784 static void
785 tui_scroll_right_command (const char *arg, int from_tty)
786 {
787 int num_to_scroll;
788 struct tui_win_info *win_to_scroll;
789
790 /* Make sure the curses mode is enabled. */
791 tui_enable ();
792 parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
793 win_to_scroll->right_scroll (num_to_scroll);
794 }
795
796
797 /* Answer the window represented by name. */
798 static struct tui_win_info *
799 tui_partial_win_by_name (gdb::string_view name)
800 {
801 if (name != NULL)
802 {
803 for (tui_win_info *item : all_tui_windows ())
804 {
805 const char *cur_name = item->name ();
806
807 if (startswith (cur_name, name))
808 return item;
809 }
810 }
811
812 return NULL;
813 }
814
815 /* Set focus to the window named by 'arg'. */
816 static void
817 tui_set_focus_command (const char *arg, int from_tty)
818 {
819 tui_enable ();
820
821 if (arg != NULL)
822 {
823 struct tui_win_info *win_info = NULL;
824
825 if (subset_compare (arg, "next"))
826 win_info = tui_next_win (tui_win_with_focus ());
827 else if (subset_compare (arg, "prev"))
828 win_info = tui_prev_win (tui_win_with_focus ());
829 else
830 win_info = tui_partial_win_by_name (arg);
831
832 if (win_info == NULL)
833 error (_("Unrecognized window name \"%s\""), arg);
834 if (!win_info->is_visible ())
835 error (_("Window \"%s\" is not visible"), arg);
836
837 tui_set_win_focus_to (win_info);
838 keypad (TUI_CMD_WIN->handle.get (), win_info != TUI_CMD_WIN);
839 printf_filtered (_("Focus set to %s window.\n"),
840 tui_win_with_focus ()->name ());
841 }
842 else
843 error (_("Incorrect Number of Arguments.\n%s"), FOCUS_USAGE);
844 }
845
846 static void
847 tui_all_windows_info (const char *arg, int from_tty)
848 {
849 struct tui_win_info *win_with_focus = tui_win_with_focus ();
850 struct ui_out *uiout = current_uiout;
851
852 ui_out_emit_table table_emitter (uiout, 3, -1, "tui-windows");
853 uiout->table_header (10, ui_left, "name", "Name");
854 uiout->table_header (5, ui_right, "lines", "Lines");
855 uiout->table_header (10, ui_left, "focus", "Focus");
856 uiout->table_body ();
857
858 for (tui_win_info *win_info : all_tui_windows ())
859 if (win_info->is_visible ())
860 {
861 ui_out_emit_tuple tuple_emitter (uiout, nullptr);
862
863 uiout->field_string ("name", win_info->name ());
864 uiout->field_signed ("lines", win_info->height);
865 if (win_with_focus == win_info)
866 uiout->field_string ("focus", _("(has focus)"));
867 else
868 uiout->field_skip ("focus");
869 uiout->text ("\n");
870 }
871 }
872
873
874 static void
875 tui_refresh_all_command (const char *arg, int from_tty)
876 {
877 /* Make sure the curses mode is enabled. */
878 tui_enable ();
879
880 tui_refresh_all_win ();
881 }
882
883 /* The tab width that should be used by the TUI. */
884
885 unsigned int tui_tab_width = DEFAULT_TAB_LEN;
886
887 /* The tab width as set by the user. */
888
889 static unsigned int internal_tab_width = DEFAULT_TAB_LEN;
890
891 /* After the tab width is set, call this to update the relevant
892 windows. */
893
894 static void
895 update_tab_width ()
896 {
897 for (tui_win_info *win_info : all_tui_windows ())
898 {
899 if (win_info->is_visible ())
900 win_info->update_tab_width ();
901 }
902 }
903
904 /* Callback for "set tui tab-width". */
905
906 static void
907 tui_set_tab_width (const char *ignore,
908 int from_tty, struct cmd_list_element *c)
909 {
910 if (internal_tab_width == 0)
911 {
912 internal_tab_width = tui_tab_width;
913 error (_("Tab width must not be 0"));
914 }
915
916 tui_tab_width = internal_tab_width;
917 update_tab_width ();
918 }
919
920 /* Callback for "show tui tab-width". */
921
922 static void
923 tui_show_tab_width (struct ui_file *file, int from_tty,
924 struct cmd_list_element *c, const char *value)
925 {
926 fprintf_filtered (gdb_stdout, _("TUI tab width is %s spaces.\n"), value);
927
928 }
929
930 /* See tui-win.h. */
931
932 bool compact_source = false;
933
934 /* Callback for "set tui compact-source". */
935
936 static void
937 tui_set_compact_source (const char *ignore, int from_tty,
938 struct cmd_list_element *c)
939 {
940 if (TUI_SRC_WIN != nullptr)
941 TUI_SRC_WIN->refill ();
942 }
943
944 /* Callback for "show tui compact-source". */
945
946 static void
947 tui_show_compact_source (struct ui_file *file, int from_tty,
948 struct cmd_list_element *c, const char *value)
949 {
950 printf_filtered (_("TUI source window compactness is %s.\n"), value);
951 }
952
953 /* Set the tab width of the specified window. */
954 static void
955 tui_set_tab_width_command (const char *arg, int from_tty)
956 {
957 /* Make sure the curses mode is enabled. */
958 tui_enable ();
959 if (arg != NULL)
960 {
961 int ts;
962
963 ts = atoi (arg);
964 if (ts <= 0)
965 warning (_("Tab widths greater than 0 must be specified."));
966 else
967 {
968 internal_tab_width = ts;
969 tui_tab_width = ts;
970
971 update_tab_width ();
972 }
973 }
974 }
975
976
977 /* Set the height of the specified window. */
978 static void
979 tui_set_win_height_command (const char *arg, int from_tty)
980 {
981 /* Make sure the curses mode is enabled. */
982 tui_enable ();
983 if (arg != NULL)
984 {
985 const char *buf = arg;
986 const char *buf_ptr = buf;
987 int new_height;
988 struct tui_win_info *win_info;
989
990 buf_ptr = strchr (buf_ptr, ' ');
991 if (buf_ptr != NULL)
992 {
993 /* Validate the window name. */
994 gdb::string_view wname (buf, buf_ptr - buf);
995 win_info = tui_partial_win_by_name (wname);
996
997 if (win_info == NULL)
998 error (_("Unrecognized window name \"%s\""), arg);
999 if (!win_info->is_visible ())
1000 error (_("Window \"%s\" is not visible"), arg);
1001
1002 /* Process the size. */
1003 buf_ptr = skip_spaces (buf_ptr);
1004
1005 if (*buf_ptr != '\0')
1006 {
1007 bool negate = false;
1008 bool fixed_size = true;
1009 int input_no;;
1010
1011 if (*buf_ptr == '+' || *buf_ptr == '-')
1012 {
1013 if (*buf_ptr == '-')
1014 negate = true;
1015 fixed_size = false;
1016 buf_ptr++;
1017 }
1018 input_no = atoi (buf_ptr);
1019 if (input_no > 0)
1020 {
1021 if (negate)
1022 input_no *= (-1);
1023 if (fixed_size)
1024 new_height = input_no;
1025 else
1026 new_height = win_info->height + input_no;
1027
1028 /* Now change the window's height, and adjust
1029 all other windows around it. */
1030 if (tui_adjust_win_heights (win_info,
1031 new_height) == TUI_FAILURE)
1032 warning (_("Invalid window height specified.\n%s"),
1033 WIN_HEIGHT_USAGE);
1034 else
1035 tui_update_gdb_sizes ();
1036 }
1037 else
1038 warning (_("Invalid window height specified.\n%s"),
1039 WIN_HEIGHT_USAGE);
1040 }
1041 }
1042 else
1043 printf_filtered (WIN_HEIGHT_USAGE);
1044 }
1045 else
1046 printf_filtered (WIN_HEIGHT_USAGE);
1047 }
1048
1049 /* Function to adjust all window heights around the primary. */
1050 static enum tui_status
1051 tui_adjust_win_heights (struct tui_win_info *primary_win_info,
1052 int new_height)
1053 {
1054 enum tui_status status = TUI_FAILURE;
1055
1056 if (new_height_ok (primary_win_info, new_height))
1057 {
1058 status = TUI_SUCCESS;
1059 if (new_height != primary_win_info->height)
1060 {
1061 int diff;
1062 struct tui_win_info *win_info;
1063 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
1064 enum tui_layout_type cur_layout = tui_current_layout ();
1065 int width = tui_term_width ();
1066
1067 diff = (new_height - primary_win_info->height) * (-1);
1068 if (cur_layout == SRC_COMMAND
1069 || cur_layout == DISASSEM_COMMAND)
1070 {
1071 struct tui_win_info *src_win_info;
1072
1073 primary_win_info->resize (new_height, width,
1074 0, primary_win_info->origin.y);
1075 if (primary_win_info->type == CMD_WIN)
1076 {
1077 win_info = *(tui_source_windows ().begin ());
1078 src_win_info = win_info;
1079 }
1080 else
1081 {
1082 win_info = tui_win_list[CMD_WIN];
1083 src_win_info = primary_win_info;
1084 }
1085 win_info->resize (win_info->height + diff, width,
1086 0, win_info->origin.y);
1087 TUI_CMD_WIN->origin.y = locator->origin.y + 1;
1088 if ((src_win_info->type == SRC_WIN
1089 || src_win_info->type == DISASSEM_WIN))
1090 {
1091 tui_source_window_base *src_base
1092 = (tui_source_window_base *) src_win_info;
1093 if (src_base->content.empty ())
1094 src_base->erase_source_content ();
1095 }
1096 }
1097 else
1098 {
1099 struct tui_win_info *first_win;
1100 struct tui_source_window_base *second_win;
1101 tui_source_window_base *src1;
1102
1103 if (cur_layout == SRC_DISASSEM_COMMAND)
1104 {
1105 src1 = TUI_SRC_WIN;
1106 first_win = src1;
1107 second_win = TUI_DISASM_WIN;
1108 }
1109 else
1110 {
1111 src1 = nullptr;
1112 first_win = TUI_DATA_WIN;
1113 second_win = *(tui_source_windows ().begin ());
1114 }
1115 if (primary_win_info == TUI_CMD_WIN)
1116 { /* Split the change in height across the 1st & 2nd
1117 windows, adjusting them as well. */
1118 /* Subtract the locator. */
1119 int first_split_diff = diff / 2;
1120 int second_split_diff = first_split_diff;
1121
1122 if (diff % 2)
1123 {
1124 if (first_win->height >
1125 second_win->height)
1126 if (diff < 0)
1127 first_split_diff--;
1128 else
1129 first_split_diff++;
1130 else
1131 {
1132 if (diff < 0)
1133 second_split_diff--;
1134 else
1135 second_split_diff++;
1136 }
1137 }
1138 /* Make sure that the minimum heights are
1139 honored. */
1140 while ((first_win->height + first_split_diff) < 3)
1141 {
1142 first_split_diff++;
1143 second_split_diff--;
1144 }
1145 while ((second_win->height + second_split_diff) < 3)
1146 {
1147 second_split_diff++;
1148 first_split_diff--;
1149 }
1150 first_win->resize (first_win->height + first_split_diff,
1151 width,
1152 0, first_win->origin.y);
1153 second_win->resize (second_win->height + second_split_diff,
1154 width,
1155 0, first_win->height - 1);
1156 locator->resize (1, width,
1157 0, (second_win->origin.y
1158 + second_win->height + 1));
1159
1160 TUI_CMD_WIN->resize (new_height, width,
1161 0, locator->origin.y + 1);
1162 }
1163 else
1164 {
1165 if ((TUI_CMD_WIN->height + diff) < 1)
1166 { /* If there is no way to increase the command
1167 window take real estate from the 1st or 2nd
1168 window. */
1169 if ((TUI_CMD_WIN->height + diff) < 1)
1170 {
1171 int i;
1172
1173 for (i = TUI_CMD_WIN->height + diff;
1174 (i < 1); i++)
1175 if (primary_win_info == first_win)
1176 second_win->height--;
1177 else
1178 first_win->height--;
1179 }
1180 }
1181 if (primary_win_info == first_win)
1182 first_win->resize (new_height, width, 0, 0);
1183 else
1184 first_win->resize (first_win->height, width, 0, 0);
1185 second_win->origin.y = first_win->height - 1;
1186 if (primary_win_info == second_win)
1187 second_win->resize (new_height, width,
1188 0, first_win->height - 1);
1189 else
1190 second_win->resize (second_win->height, width,
1191 0, first_win->height - 1);
1192 locator->resize (1, width,
1193 0, (second_win->origin.y
1194 + second_win->height + 1));
1195 TUI_CMD_WIN->origin.y = locator->origin.y + 1;
1196 if ((TUI_CMD_WIN->height + diff) < 1)
1197 TUI_CMD_WIN->resize (1, width, 0, locator->origin.y + 1);
1198 else
1199 TUI_CMD_WIN->resize (TUI_CMD_WIN->height + diff, width,
1200 0, locator->origin.y + 1);
1201 }
1202 if (src1 != nullptr && src1->content.empty ())
1203 src1->erase_source_content ();
1204 if (second_win->content.empty ())
1205 second_win->erase_source_content ();
1206 }
1207 }
1208 }
1209
1210 return status;
1211 }
1212
1213 /* See tui-data.h. */
1214
1215 int
1216 tui_win_info::max_height () const
1217 {
1218 return tui_term_height () - 2;
1219 }
1220
1221 static int
1222 new_height_ok (struct tui_win_info *primary_win_info,
1223 int new_height)
1224 {
1225 int ok = (new_height < tui_term_height ());
1226
1227 if (ok)
1228 {
1229 int diff;
1230 enum tui_layout_type cur_layout = tui_current_layout ();
1231
1232 diff = (new_height - primary_win_info->height) * (-1);
1233 if (cur_layout == SRC_COMMAND || cur_layout == DISASSEM_COMMAND)
1234 {
1235 ok = (new_height <= primary_win_info->max_height ()
1236 && new_height >= MIN_CMD_WIN_HEIGHT);
1237 if (ok)
1238 { /* Check the total height. */
1239 struct tui_win_info *win_info;
1240
1241 if (primary_win_info == TUI_CMD_WIN)
1242 win_info = *(tui_source_windows ().begin ());
1243 else
1244 win_info = TUI_CMD_WIN;
1245 ok = ((new_height +
1246 (win_info->height + diff)) <= tui_term_height ());
1247 }
1248 }
1249 else
1250 {
1251 int cur_total_height, total_height, min_height = 0;
1252 struct tui_win_info *first_win;
1253 struct tui_win_info *second_win;
1254
1255 if (cur_layout == SRC_DISASSEM_COMMAND)
1256 {
1257 first_win = TUI_SRC_WIN;
1258 second_win = TUI_DISASM_WIN;
1259 }
1260 else
1261 {
1262 first_win = TUI_DATA_WIN;
1263 second_win = *(tui_source_windows ().begin ());
1264 }
1265 /* We could simply add all the heights to obtain the same
1266 result but below is more explicit since we subtract 1 for
1267 the line that the first and second windows share, and add
1268 one for the locator. */
1269 total_height = cur_total_height =
1270 (first_win->height + second_win->height - 1)
1271 + TUI_CMD_WIN->height + 1; /* Locator. */
1272 if (primary_win_info == TUI_CMD_WIN)
1273 {
1274 /* Locator included since first & second win share a line. */
1275 ok = ((first_win->height +
1276 second_win->height + diff) >=
1277 (MIN_WIN_HEIGHT * 2)
1278 && new_height >= MIN_CMD_WIN_HEIGHT);
1279 if (ok)
1280 {
1281 total_height = new_height +
1282 (first_win->height +
1283 second_win->height + diff);
1284 min_height = MIN_CMD_WIN_HEIGHT;
1285 }
1286 }
1287 else
1288 {
1289 min_height = MIN_WIN_HEIGHT;
1290
1291 /* First see if we can increase/decrease the command
1292 window. And make sure that the command window is at
1293 least 1 line. */
1294 ok = ((TUI_CMD_WIN->height + diff) > 0);
1295 if (!ok)
1296 { /* Looks like we have to increase/decrease one of
1297 the other windows. */
1298 if (primary_win_info == first_win)
1299 ok = (second_win->height + diff) >= min_height;
1300 else
1301 ok = (first_win->height + diff) >= min_height;
1302 }
1303 if (ok)
1304 {
1305 if (primary_win_info == first_win)
1306 total_height = new_height +
1307 second_win->height +
1308 TUI_CMD_WIN->height + diff;
1309 else
1310 total_height = new_height +
1311 first_win->height +
1312 TUI_CMD_WIN->height + diff;
1313 }
1314 }
1315 /* Now make sure that the proposed total height doesn't
1316 exceed the old total height. */
1317 if (ok)
1318 ok = (new_height >= min_height
1319 && total_height <= cur_total_height);
1320 }
1321 }
1322
1323 return ok;
1324 }
1325
1326
1327 static void
1328 parse_scrolling_args (const char *arg,
1329 struct tui_win_info **win_to_scroll,
1330 int *num_to_scroll)
1331 {
1332 if (num_to_scroll)
1333 *num_to_scroll = 0;
1334 *win_to_scroll = tui_win_with_focus ();
1335
1336 /* First set up the default window to scroll, in case there is no
1337 window name arg. */
1338 if (arg != NULL)
1339 {
1340 char *buf_ptr;
1341
1342 /* Process the number of lines to scroll. */
1343 std::string copy = arg;
1344 buf_ptr = &copy[0];
1345 if (isdigit (*buf_ptr))
1346 {
1347 char *num_str;
1348
1349 num_str = buf_ptr;
1350 buf_ptr = strchr (buf_ptr, ' ');
1351 if (buf_ptr != NULL)
1352 {
1353 *buf_ptr = '\0';
1354 if (num_to_scroll)
1355 *num_to_scroll = atoi (num_str);
1356 buf_ptr++;
1357 }
1358 else if (num_to_scroll)
1359 *num_to_scroll = atoi (num_str);
1360 }
1361
1362 /* Process the window name if one is specified. */
1363 if (buf_ptr != NULL)
1364 {
1365 const char *wname;
1366
1367 wname = skip_spaces (buf_ptr);
1368
1369 if (*wname != '\0')
1370 {
1371 *win_to_scroll = tui_partial_win_by_name (wname);
1372
1373 if (*win_to_scroll == NULL)
1374 error (_("Unrecognized window `%s'"), wname);
1375 if (!(*win_to_scroll)->is_visible ())
1376 error (_("Window is not visible"));
1377 else if (*win_to_scroll == TUI_CMD_WIN)
1378 *win_to_scroll = *(tui_source_windows ().begin ());
1379 }
1380 }
1381 }
1382 }
1383
1384 /* Function to initialize gdb commands, for tui window
1385 manipulation. */
1386
1387 void
1388 _initialize_tui_win (void)
1389 {
1390 static struct cmd_list_element *tui_setlist;
1391 static struct cmd_list_element *tui_showlist;
1392 struct cmd_list_element *cmd;
1393
1394 /* Define the classes of commands.
1395 They will appear in the help list in the reverse of this order. */
1396 add_prefix_cmd ("tui", class_tui, set_tui_cmd,
1397 _("TUI configuration variables."),
1398 &tui_setlist, "set tui ",
1399 0 /* allow-unknown */, &setlist);
1400 add_prefix_cmd ("tui", class_tui, show_tui_cmd,
1401 _("TUI configuration variables."),
1402 &tui_showlist, "show tui ",
1403 0 /* allow-unknown */, &showlist);
1404
1405 add_com ("refresh", class_tui, tui_refresh_all_command,
1406 _("Refresh the terminal display."));
1407
1408 cmd = add_com ("tabset", class_tui, tui_set_tab_width_command, _("\
1409 Set the width (in characters) of tab stops.\n\
1410 Usage: tabset N"));
1411 deprecate_cmd (cmd, "set tui tab-width");
1412
1413 cmd = add_com ("winheight", class_tui, tui_set_win_height_command, _("\
1414 Set or modify the height of a specified window.\n"
1415 WIN_HEIGHT_USAGE
1416 "Window names are:\n\
1417 src : the source window\n\
1418 cmd : the command window\n\
1419 asm : the disassembly window\n\
1420 regs : the register display"));
1421 add_com_alias ("wh", "winheight", class_tui, 0);
1422 set_cmd_completer (cmd, winheight_completer);
1423 add_info ("win", tui_all_windows_info,
1424 _("List of all displayed windows."));
1425 cmd = add_com ("focus", class_tui, tui_set_focus_command, _("\
1426 Set focus to named window or next/prev window.\n"
1427 FOCUS_USAGE
1428 "Valid Window names are:\n\
1429 src : the source window\n\
1430 asm : the disassembly window\n\
1431 regs : the register display\n\
1432 cmd : the command window"));
1433 add_com_alias ("fs", "focus", class_tui, 0);
1434 set_cmd_completer (cmd, focus_completer);
1435 add_com ("+", class_tui, tui_scroll_forward_command, _("\
1436 Scroll window forward.\n\
1437 Usage: + [WIN] [N]"));
1438 add_com ("-", class_tui, tui_scroll_backward_command, _("\
1439 Scroll window backward.\n\
1440 Usage: - [WIN] [N]"));
1441 add_com ("<", class_tui, tui_scroll_left_command, _("\
1442 Scroll window text to the left.\n\
1443 Usage: < [WIN] [N]"));
1444 add_com (">", class_tui, tui_scroll_right_command, _("\
1445 Scroll window text to the right.\n\
1446 Usage: > [WIN] [N]"));
1447
1448 /* Define the tui control variables. */
1449 add_setshow_enum_cmd ("border-kind", no_class, tui_border_kind_enums,
1450 &tui_border_kind, _("\
1451 Set the kind of border for TUI windows."), _("\
1452 Show the kind of border for TUI windows."), _("\
1453 This variable controls the border of TUI windows:\n\
1454 space use a white space\n\
1455 ascii use ascii characters + - | for the border\n\
1456 acs use the Alternate Character Set"),
1457 tui_set_var_cmd,
1458 show_tui_border_kind,
1459 &tui_setlist, &tui_showlist);
1460
1461 add_setshow_enum_cmd ("border-mode", no_class, tui_border_mode_enums,
1462 &tui_border_mode, _("\
1463 Set the attribute mode to use for the TUI window borders."), _("\
1464 Show the attribute mode to use for the TUI window borders."), _("\
1465 This variable controls the attributes to use for the window borders:\n\
1466 normal normal display\n\
1467 standout use highlight mode of terminal\n\
1468 reverse use reverse video mode\n\
1469 half use half bright\n\
1470 half-standout use half bright and standout mode\n\
1471 bold use extra bright or bold\n\
1472 bold-standout use extra bright or bold with standout mode"),
1473 tui_set_var_cmd,
1474 show_tui_border_mode,
1475 &tui_setlist, &tui_showlist);
1476
1477 add_setshow_enum_cmd ("active-border-mode", no_class, tui_border_mode_enums,
1478 &tui_active_border_mode, _("\
1479 Set the attribute mode to use for the active TUI window border."), _("\
1480 Show the attribute mode to use for the active TUI window border."), _("\
1481 This variable controls the attributes to use for the active window border:\n\
1482 normal normal display\n\
1483 standout use highlight mode of terminal\n\
1484 reverse use reverse video mode\n\
1485 half use half bright\n\
1486 half-standout use half bright and standout mode\n\
1487 bold use extra bright or bold\n\
1488 bold-standout use extra bright or bold with standout mode"),
1489 tui_set_var_cmd,
1490 show_tui_active_border_mode,
1491 &tui_setlist, &tui_showlist);
1492
1493 add_setshow_zuinteger_cmd ("tab-width", no_class,
1494 &internal_tab_width, _("\
1495 Set the tab width, in characters, for the TUI."), _("\
1496 Show the tab witdh, in characters, for the TUI."), _("\
1497 This variable controls how many spaces are used to display a tab character."),
1498 tui_set_tab_width, tui_show_tab_width,
1499 &tui_setlist, &tui_showlist);
1500
1501 add_setshow_boolean_cmd ("tui-resize-message", class_maintenance,
1502 &resize_message, _("\
1503 Set TUI resize messaging."), _("\
1504 Show TUI resize messaging."), _("\
1505 When enabled GDB will print a message when the terminal is resized."),
1506 nullptr,
1507 show_tui_resize_message,
1508 &maintenance_set_cmdlist,
1509 &maintenance_show_cmdlist);
1510
1511 add_setshow_boolean_cmd ("compact-source", class_tui,
1512 &compact_source, _("\
1513 Set whether the TUI source window is compact."), _("\
1514 Show whether the TUI source window is compact."), _("\
1515 This variable controls whether the TUI source window is shown\n\
1516 in a compact form. The compact form puts the source closer to\n\
1517 the line numbers and uses less horizontal space."),
1518 tui_set_compact_source, tui_show_compact_source,
1519 &tui_setlist, &tui_showlist);
1520 }
This page took 0.095908 seconds and 4 git commands to generate.