GDB (xrefs)
Loading...
Searching...
No Matches
tui-io.c
Go to the documentation of this file.
1/* TUI support I/O functions.
2
3 Copyright (C) 1998-2023 Free Software Foundation, Inc.
4
5 Contributed by Hewlett-Packard Company.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21
22#include "defs.h"
23#include "target.h"
24#include "gdbsupport/event-loop.h"
25#include "event-top.h"
26#include "command.h"
27#include "top.h"
28#include "tui/tui.h"
29#include "tui/tui-data.h"
30#include "tui/tui-io.h"
31#include "tui/tui-command.h"
32#include "tui/tui-win.h"
33#include "tui/tui-wingeneral.h"
34#include "tui/tui-file.h"
35#include "tui/tui-out.h"
36#include "ui-out.h"
37#include "cli-out.h"
38#include <fcntl.h>
39#include <signal.h>
40#ifdef __MINGW32__
41#include <windows.h>
42#endif
43#include "gdbsupport/filestuff.h"
44#include "completer.h"
45#include "gdb_curses.h"
46#include <map>
47#include "pager.h"
48#include "gdbsupport/gdb-checked-static-cast.h"
49
50/* This redefines CTRL if it is not already defined, so it must come
51 after terminal state releated include files like <term.h> and
52 "gdb_curses.h". */
53#include "readline/readline.h"
54
55#ifdef __MINGW32__
56static SHORT ncurses_norm_attr;
57#endif
58
59static int tui_getc (FILE *fp);
60
61static int
63{
64 return (ch == 27);
65}
66
67/* Use definition from readline 4.3. */
68#undef CTRL_CHAR
69#define CTRL_CHAR(c) \
70 ((c) < control_character_threshold && (((c) & 0x80) == 0))
71
72/* This file controls the IO interactions between gdb and curses.
73 When the TUI is enabled, gdb has two modes a curses and a standard
74 mode.
75
76 In curses mode, the gdb outputs are made in a curses command
77 window. For this, the gdb_stdout and gdb_stderr are redirected to
78 the specific ui_file implemented by TUI. The output is handled by
79 tui_puts(). The input is also controlled by curses with
80 tui_getc(). The readline library uses this function to get its
81 input. Several readline hooks are installed to redirect readline
82 output to the TUI (see also the note below).
83
84 In normal mode, the gdb outputs are restored to their origin, that
85 is as if TUI is not used. Readline also uses its original getc()
86 function with stdin.
87
88 Note SCz/2001-07-21: the current readline is not clean in its
89 management of the output. Even if we install a redisplay handler,
90 it sometimes writes on a stdout file. It is important to redirect
91 every output produced by readline, otherwise the curses window will
92 be garbled. This is implemented with a pipe that TUI reads and
93 readline writes to. A gdb input handler is created so that reading
94 the pipe is handled automatically. This will probably not work on
95 non-Unix platforms. The best fix is to make readline clean enough
96 so that is never write on stdout.
97
98 Note SCz/2002-09-01: we now use more readline hooks and it seems
99 that with them we don't need the pipe anymore (verified by creating
100 the pipe and closing its end so that write causes a SIGPIPE). The
101 old pipe code is still there and can be conditionally removed by
102 #undef TUI_USE_PIPE_FOR_READLINE. */
103
104/* For gdb 5.3, prefer to continue the pipe hack as a backup wheel. */
105#ifdef HAVE_PIPE
106#define TUI_USE_PIPE_FOR_READLINE
107#endif
108/* #undef TUI_USE_PIPE_FOR_READLINE */
109
110/* TUI output files. */
111static struct ui_file *tui_stdout;
112static struct ui_file *tui_stderr;
113static struct ui_file *tui_stdlog;
115
116/* GDB output files in non-curses mode. */
117static struct ui_file *tui_old_stdout;
118static struct ui_file *tui_old_stderr;
119static struct ui_file *tui_old_stdlog;
121
122/* Readline previous hooks. */
123static rl_getc_func_t *tui_old_rl_getc_function;
124static rl_voidfunc_t *tui_old_rl_redisplay_function;
125static rl_vintfunc_t *tui_old_rl_prep_terminal;
126static rl_voidfunc_t *tui_old_rl_deprep_terminal;
127static rl_compdisp_func_t *tui_old_rl_display_matches_hook;
129
130/* Readline output stream.
131 Should be removed when readline is clean. */
132static FILE *tui_rl_outstream;
134#ifdef TUI_USE_PIPE_FOR_READLINE
135static int tui_readline_pipe[2];
136#endif
137
138/* Print a character in the curses command window. The output is
139 buffered. It is up to the caller to refresh the screen if
140 necessary. */
141
142static void
143do_tui_putc (WINDOW *w, char c)
144{
145 /* Expand TABs, since ncurses on MS-Windows doesn't. */
146 if (c == '\t')
147 {
148 int col;
149
150 col = getcurx (w);
151 do
152 {
153 waddch (w, ' ');
154 col++;
155 }
156 while ((col % 8) != 0);
157 }
158 else
159 waddch (w, c);
160}
161
162/* Update the cached value of the command window's start line based on
163 the window's current Y coordinate. */
164
165static void
167{
168 TUI_CMD_WIN->start_line = getcury (TUI_CMD_WIN->handle.get ());
169}
170
171/* Print a character in the curses command window. The output is
172 buffered. It is up to the caller to refresh the screen if
173 necessary. */
174
175static void
176tui_putc (char c)
177{
178 do_tui_putc (TUI_CMD_WIN->handle.get (), c);
180}
181
182/* This maps colors to their corresponding color index. */
183
184static std::map<ui_file_style::color, int> color_map;
185
186/* This holds a pair of colors and is used to track the mapping
187 between a color pair index and the actual colors. */
188
190{
191 int fg;
192 int bg;
193
194 bool operator< (const color_pair &o) const
195 {
196 return fg < o.fg || (fg == o.fg && bg < o.bg);
197 }
198};
199
200/* This maps pairs of colors to their corresponding color pair
201 index. */
202
203static std::map<color_pair, int> color_pair_map;
204
205/* This is indexed by ANSI color offset from the base color, and holds
206 the corresponding curses color constant. */
207
208static const int curses_colors[] = {
209 COLOR_BLACK,
210 COLOR_RED,
211 COLOR_GREEN,
212 COLOR_YELLOW,
213 COLOR_BLUE,
214 COLOR_MAGENTA,
215 COLOR_CYAN,
216 COLOR_WHITE
217};
218
219/* Given a color, find its index. */
220
221static bool
222get_color (const ui_file_style::color &color, int *result)
223{
224 if (color.is_none ())
225 *result = -1;
226 else if (color.is_basic ())
227 *result = curses_colors[color.get_value ()];
228 else
229 {
230 auto it = color_map.find (color);
231 if (it == color_map.end ())
232 {
233 /* The first 8 colors are standard. */
234 int next = color_map.size () + 8;
235 if (next >= COLORS)
236 return false;
237 uint8_t rgb[3];
238 color.get_rgb (rgb);
239 /* We store RGB as 0..255, but curses wants 0..1000. */
240 if (init_color (next, rgb[0] * 1000 / 255, rgb[1] * 1000 / 255,
241 rgb[2] * 1000 / 255) == ERR)
242 return false;
243 color_map[color] = next;
244 *result = next;
245 }
246 else
247 *result = it->second;
248 }
249 return true;
250}
251
252/* The most recently emitted color pair. */
253
254static int last_color_pair = -1;
255
256/* The most recently applied style. */
257
259
260/* If true, we're highlighting the current source line in reverse
261 video mode. */
262static bool reverse_mode_p = false;
263
264/* The background/foreground colors before we entered reverse
265 mode. */
268
269/* Given two colors, return their color pair index; making a new one
270 if necessary. */
271
272static int
273get_color_pair (int fg, int bg)
274{
275 color_pair c = { fg, bg };
276 auto it = color_pair_map.find (c);
277 if (it == color_pair_map.end ())
278 {
279 /* Color pair 0 is our default color, so new colors start at
280 1. */
281 int next = color_pair_map.size () + 1;
282 /* Curses has a limited number of available color pairs. Fall
283 back to the default if we've used too many. */
284 if (next >= COLOR_PAIRS)
285 return 0;
286 init_pair (next, fg, bg);
287 color_pair_map[c] = next;
288 return next;
289 }
290 return it->second;
291}
292
293/* Apply STYLE to W. */
294
295void
297{
298 /* Reset. */
299 wattron (w, A_NORMAL);
300 wattroff (w, A_BOLD);
301 wattroff (w, A_DIM);
302 wattroff (w, A_REVERSE);
303 if (last_color_pair != -1)
304 wattroff (w, COLOR_PAIR (last_color_pair));
305 wattron (w, COLOR_PAIR (0));
306
307 const ui_file_style::color &fg = style.get_foreground ();
308 const ui_file_style::color &bg = style.get_background ();
309 if (!fg.is_none () || !bg.is_none ())
310 {
311 int fgi, bgi;
312 if (get_color (fg, &fgi) && get_color (bg, &bgi))
313 {
314#ifdef __MINGW32__
315 /* MS-Windows port of ncurses doesn't support implicit
316 default foreground and background colors, so we must
317 specify them explicitly when needed, using the colors we
318 saw at startup. */
319 if (fgi == -1)
320 fgi = ncurses_norm_attr & 15;
321 if (bgi == -1)
322 bgi = (ncurses_norm_attr >> 4) & 15;
323#endif
324 int pair = get_color_pair (fgi, bgi);
325 if (last_color_pair != -1)
326 wattroff (w, COLOR_PAIR (last_color_pair));
327 wattron (w, COLOR_PAIR (pair));
328 last_color_pair = pair;
329 }
330 }
331
332 switch (style.get_intensity ())
333 {
335 break;
336
338 wattron (w, A_BOLD);
339 break;
340
342 wattron (w, A_DIM);
343 break;
344
345 default:
346 gdb_assert_not_reached ("invalid intensity");
347 }
348
349 if (style.is_reverse ())
350 wattron (w, A_REVERSE);
351
352 last_style = style;
353}
354
355/* Apply an ANSI escape sequence from BUF to W. BUF must start with
356 the ESC character. If BUF does not start with an ANSI escape,
357 return 0. Otherwise, apply the sequence if it is recognized, or
358 simply ignore it if not. In this case, the number of bytes read
359 from BUF is returned. */
360
361static size_t
362apply_ansi_escape (WINDOW *w, const char *buf)
363{
365 size_t n_read;
366
367 if (!style.parse (buf, &n_read))
368 return n_read;
369
370 if (reverse_mode_p)
371 {
373 return n_read;
374
375 /* We want to reverse _only_ the default foreground/background
376 colors. If the foreground color is not the default (because
377 the text was styled), we want to leave it as is. If e.g.,
378 the terminal is fg=BLACK, and bg=WHITE, and the style wants
379 to print text in RED, we want to reverse the background color
380 (print in BLACK), but still print the text in RED. To do
381 that, we enable the A_REVERSE attribute, and re-reverse the
382 parsed-style's fb/bg colors.
383
384 Notes on the approach:
385
386 - there's no portable way to know which colors the default
387 fb/bg colors map to.
388
389 - this approach does the right thing even if you change the
390 terminal colors while GDB is running -- the reversed
391 colors automatically adapt.
392 */
393 if (!style.is_default ())
394 {
395 ui_file_style::color bg = style.get_background ();
396 ui_file_style::color fg = style.get_foreground ();
397 style.set_fg (bg);
398 style.set_bg (fg);
399 }
400
401 /* Enable A_REVERSE. */
402 style.set_reverse (true);
403 }
404
405 tui_apply_style (w, style);
406 return n_read;
407}
408
409/* See tui.io.h. */
410
411void
412tui_set_reverse_mode (WINDOW *w, bool reverse)
413{
415
416 reverse_mode_p = reverse;
417
418 if (reverse)
419 {
420 reverse_save_bg = style.get_background ();
421 reverse_save_fg = style.get_foreground ();
422
424 {
425 /* Switch to default style (reversed) while highlighting the
426 current position. */
427 style = {};
428 }
429 }
430 else
431 {
432 style.set_bg (reverse_save_bg);
433 style.set_fg (reverse_save_fg);
434 }
435
436 style.set_reverse (reverse);
437
438 tui_apply_style (w, style);
439}
440
441/* Print LENGTH characters from the buffer pointed to by BUF to the
442 curses command window. The output is buffered. It is up to the
443 caller to refresh the screen if necessary. */
444
445void
446tui_write (const char *buf, size_t length)
447{
448 /* We need this to be \0-terminated for the regexp matching. */
449 std::string copy (buf, length);
450 tui_puts (copy.c_str ());
451}
452
453/* Print a string in the curses command window. The output is
454 buffered. It is up to the caller to refresh the screen if
455 necessary. */
456
457void
458tui_puts (const char *string, WINDOW *w)
459{
460 if (w == nullptr)
461 w = TUI_CMD_WIN->handle.get ();
462
463 while (true)
464 {
465 const char *next = strpbrk (string, "\n\1\2\033\t");
466
467 /* Print the plain text prefix. */
468 size_t n_chars = next == nullptr ? strlen (string) : next - string;
469 if (n_chars > 0)
470 waddnstr (w, string, n_chars);
471
472 /* We finished. */
473 if (next == nullptr)
474 break;
475
476 char c = *next;
477 switch (c)
478 {
479 case '\1':
480 case '\2':
481 /* Ignore these, they are readline escape-marking
482 sequences. */
483 ++next;
484 break;
485
486 case '\n':
487 case '\t':
488 do_tui_putc (w, c);
489 ++next;
490 break;
491
492 case '\033':
493 {
494 size_t bytes_read = apply_ansi_escape (w, next);
495 if (bytes_read > 0)
496 next += bytes_read;
497 else
498 {
499 /* Just drop the escape. */
500 ++next;
501 }
502 }
503 break;
504
505 default:
506 gdb_assert_not_reached ("missing case in tui_puts");
507 }
508
509 string = next;
510 }
511
512 if (TUI_CMD_WIN != nullptr && w == TUI_CMD_WIN->handle.get ())
514}
515
516static void
517tui_puts_internal (WINDOW *w, const char *string, int *height)
518{
519 char c;
520 int prev_col = 0;
521 bool saw_nl = false;
522
523 while ((c = *string++) != 0)
524 {
525 if (c == '\n')
526 saw_nl = true;
527
528 if (c == '\1' || c == '\2')
529 {
530 /* Ignore these, they are readline escape-marking
531 sequences. */
532 }
533 else
534 {
535 if (c == '\033')
536 {
537 size_t bytes_read = apply_ansi_escape (w, string - 1);
538 if (bytes_read > 0)
539 {
540 string = string + bytes_read - 1;
541 continue;
542 }
543 }
544 do_tui_putc (w, c);
545
546 if (height != nullptr)
547 {
548 int col = getcurx (w);
549 if (col <= prev_col)
550 ++*height;
551 prev_col = col;
552 }
553 }
554 }
555 if (TUI_CMD_WIN != nullptr && w == TUI_CMD_WIN->handle.get ())
557 if (saw_nl)
558 wrefresh (w);
559}
560
561/* Readline callback.
562 Redisplay the command line with its prompt after readline has
563 changed the edited text. */
564void
566{
567 int prev_col;
568 int height;
569 int col;
570 int c_pos;
571 int c_line;
572 int in;
573 WINDOW *w;
574 const char *prompt;
575 int start_line;
576
577 /* Detect when we temporarily left SingleKey and now the readline
578 edit buffer is empty, automatically restore the SingleKey
579 mode. The restore must only be done if the command has finished.
580 The command could call prompt_for_continue and we must not
581 restore SingleKey so that the prompt and normal keymap are used. */
582 if (tui_current_key_mode == TUI_ONE_COMMAND_MODE && rl_end == 0
585
587 prompt = "";
588 else
589 prompt = rl_display_prompt;
590
591 c_pos = -1;
592 c_line = -1;
593 w = TUI_CMD_WIN->handle.get ();
594 start_line = TUI_CMD_WIN->start_line;
595 wmove (w, start_line, 0);
596 prev_col = 0;
597 height = 1;
598 if (prompt != nullptr)
599 tui_puts_internal (w, prompt, &height);
600
601 prev_col = getcurx (w);
602 for (in = 0; in <= rl_end; in++)
603 {
604 unsigned char c;
605
606 if (in == rl_point)
607 {
608 getyx (w, c_line, c_pos);
609 }
610
611 if (in == rl_end)
612 break;
613
614 c = (unsigned char) rl_line_buffer[in];
615 if (CTRL_CHAR (c) || c == RUBOUT)
616 {
617 waddch (w, '^');
618 waddch (w, CTRL_CHAR (c) ? UNCTRL (c) : '?');
619 }
620 else if (c == '\t')
621 {
622 /* Expand TABs, since ncurses on MS-Windows doesn't. */
623 col = getcurx (w);
624 do
625 {
626 waddch (w, ' ');
627 col++;
628 } while ((col % 8) != 0);
629 }
630 else
631 {
632 waddch (w, c);
633 }
634 if (c == '\n')
635 TUI_CMD_WIN->start_line = getcury (w);
636 col = getcurx (w);
637 if (col < prev_col)
638 height++;
639 prev_col = col;
640 }
641 wclrtobot (w);
642 TUI_CMD_WIN->start_line = getcury (w);
643 if (c_line >= 0)
644 wmove (w, c_line, c_pos);
645 TUI_CMD_WIN->start_line -= height - 1;
646
647 wrefresh (w);
648 fflush(stdout);
649}
650
651/* Readline callback to prepare the terminal. It is called once each
652 time we enter readline. Terminal is already setup in curses
653 mode. */
654static void
655tui_prep_terminal (int notused1)
656{
657#ifdef NCURSES_MOUSE_VERSION
658 mousemask (ALL_MOUSE_EVENTS, NULL);
659#endif
660}
661
662/* Readline callback to restore the terminal. It is called once each
663 time we leave readline. There is nothing to do in curses mode. */
664static void
666{
667#ifdef NCURSES_MOUSE_VERSION
668 mousemask (0, NULL);
669#endif
670}
671
672#ifdef TUI_USE_PIPE_FOR_READLINE
673/* Read readline output pipe and feed the command window with it.
674 Should be removed when readline is clean. */
675static void
676tui_readline_output (int error, gdb_client_data data)
677{
678 int size;
679 char buf[256];
680
681 size = read (tui_readline_pipe[0], buf, sizeof (buf) - 1);
682 if (size > 0 && tui_active)
683 {
684 buf[size] = 0;
685 tui_puts (buf);
686 }
687}
688#endif
689
690/* TUI version of displayer.crlf. */
691
692static void
693tui_mld_crlf (const struct match_list_displayer *displayer)
694{
695 tui_putc ('\n');
696}
697
698/* TUI version of displayer.putch. */
699
700static void
701tui_mld_putch (const struct match_list_displayer *displayer, int ch)
702{
703 tui_putc (ch);
704}
705
706/* TUI version of displayer.puts. */
707
708static void
709tui_mld_puts (const struct match_list_displayer *displayer, const char *s)
710{
711 tui_puts (s);
712}
713
714/* TUI version of displayer.flush. */
715
716static void
717tui_mld_flush (const struct match_list_displayer *displayer)
718{
719 wrefresh (TUI_CMD_WIN->handle.get ());
720}
721
722/* TUI version of displayer.erase_entire_line. */
723
724static void
726{
727 WINDOW *w = TUI_CMD_WIN->handle.get ();
728 int cur_y = getcury (w);
729
730 wmove (w, cur_y, 0);
731 wclrtoeol (w);
732 wmove (w, cur_y, 0);
733}
734
735/* TUI version of displayer.beep. */
736
737static void
738tui_mld_beep (const struct match_list_displayer *displayer)
739{
740 beep ();
741}
742
743/* A wrapper for wgetch that enters nonl mode. We We normally want
744 curses' "nl" mode, but when reading from the user, we'd like to
745 differentiate between C-j and C-m, because some users bind these
746 keys differently in their .inputrc. So, put curses into nonl mode
747 just when reading from the user. See PR tui/20819. */
748
749static int
750gdb_wgetch (WINDOW *win)
751{
752 nonl ();
753 int r = wgetch (win);
754 nl ();
755 return r;
756}
757
758/* Helper function for tui_mld_read_key.
759 This temporarily replaces tui_getc for use during tab-completion
760 match list display. */
761
762static int
763tui_mld_getc (FILE *fp)
764{
765 WINDOW *w = TUI_CMD_WIN->handle.get ();
766 int c = gdb_wgetch (w);
767
768 return c;
769}
770
771/* TUI version of displayer.read_key. */
772
773static int
774tui_mld_read_key (const struct match_list_displayer *displayer)
775{
776 rl_getc_func_t *prev = rl_getc_function;
777 int c;
778
779 /* We can't use tui_getc as we need NEWLINE to not get emitted. */
780 rl_getc_function = tui_mld_getc;
781 c = rl_read_key ();
782 rl_getc_function = prev;
783 return c;
784}
785
786/* TUI version of rl_completion_display_matches_hook.
787 See gdb_display_match_list for a description of the arguments. */
788
789static void
790tui_rl_display_match_list (char **matches, int len, int max)
791{
792 struct match_list_displayer displayer;
793
794 rl_get_screen_size (&displayer.height, &displayer.width);
795 displayer.crlf = tui_mld_crlf;
796 displayer.putch = tui_mld_putch;
797 displayer.puts = tui_mld_puts;
798 displayer.flush = tui_mld_flush;
800 displayer.beep = tui_mld_beep;
801 displayer.read_key = tui_mld_read_key;
802
803 gdb_display_match_list (matches, len, max, &displayer);
804}
805
806/* Setup the IO for curses or non-curses mode.
807 - In non-curses mode, readline and gdb use the standard input and
808 standard output/error directly.
809 - In curses mode, the standard output/error is controlled by TUI
810 with the tui_stdout and tui_stderr. The output is redirected in
811 the curses command window. Several readline callbacks are installed
812 so that readline asks for its input to the curses command window
813 with wgetch(). */
814void
815tui_setup_io (int mode)
816{
817 extern int _rl_echoing_p;
818
819 if (mode)
820 {
821 /* Ensure that readline has been initialized before saving any
822 of its variables. */
824
825 /* Redirect readline to TUI. */
826 tui_old_rl_redisplay_function = rl_redisplay_function;
827 tui_old_rl_deprep_terminal = rl_deprep_term_function;
828 tui_old_rl_prep_terminal = rl_prep_term_function;
829 tui_old_rl_getc_function = rl_getc_function;
830 tui_old_rl_display_matches_hook = rl_completion_display_matches_hook;
831 tui_old_rl_outstream = rl_outstream;
832 tui_old_rl_echoing_p = _rl_echoing_p;
833 rl_redisplay_function = tui_redisplay_readline;
834 rl_deprep_term_function = tui_deprep_terminal;
835 rl_prep_term_function = tui_prep_terminal;
836 rl_getc_function = tui_getc;
837 _rl_echoing_p = 0;
838 rl_outstream = tui_rl_outstream;
839 rl_prompt = 0;
840 rl_completion_display_matches_hook = tui_rl_display_match_list;
841 rl_already_prompted = 0;
842
843 /* Keep track of previous gdb output. */
847 tui_old_uiout = gdb::checked_static_cast<cli_ui_out *> (current_uiout);
848
849 /* Reconfigure gdb output. */
856
857 /* Save tty for SIGCONT. */
858 savetty ();
859 }
860 else
861 {
862 /* Restore gdb output. */
869
870 /* Restore readline. */
871 rl_redisplay_function = tui_old_rl_redisplay_function;
872 rl_deprep_term_function = tui_old_rl_deprep_terminal;
873 rl_prep_term_function = tui_old_rl_prep_terminal;
874 rl_getc_function = tui_old_rl_getc_function;
875 rl_completion_display_matches_hook = tui_old_rl_display_matches_hook;
876 rl_outstream = tui_old_rl_outstream;
877 _rl_echoing_p = tui_old_rl_echoing_p;
878 rl_already_prompted = 0;
879
880 /* Save tty for SIGCONT. */
881 savetty ();
882
883 /* Clean up color information. */
884 last_color_pair = -1;
886 color_map.clear ();
887 color_pair_map.clear ();
888 }
889}
890
891#ifdef SIGCONT
892/* Catch SIGCONT to restore the terminal and refresh the screen. */
893static void
894tui_cont_sig (int sig)
895{
896 if (tui_active)
897 {
898 /* Restore the terminal setting because another process (shell)
899 might have changed it. */
900 resetty ();
901
902 /* Force a refresh of the screen. */
904 }
905 signal (sig, tui_cont_sig);
906}
907#endif
908
909/* Initialize the IO for gdb in curses mode. */
910void
912{
913#ifdef SIGCONT
914 signal (SIGCONT, tui_cont_sig);
915#endif
916
917 /* Create tui output streams. */
918 tui_stdout = new pager_file (new tui_file (stdout, true));
919 tui_stderr = new tui_file (stderr, false);
922
923 /* Create the default UI. */
925
926#ifdef TUI_USE_PIPE_FOR_READLINE
927 /* Temporary solution for readline writing to stdout: redirect
928 readline output in a pipe, read that pipe and output the content
929 in the curses command window. */
930 if (gdb_pipe_cloexec (tui_readline_pipe) != 0)
931 error (_("Cannot create pipe for readline"));
932
933 tui_rl_outstream = fdopen (tui_readline_pipe[1], "w");
934 if (tui_rl_outstream == 0)
935 error (_("Cannot redirect readline output"));
936
937 setvbuf (tui_rl_outstream, NULL, _IOLBF, 0);
938
939#ifdef O_NONBLOCK
940 (void) fcntl (tui_readline_pipe[0], F_SETFL, O_NONBLOCK);
941#else
942#ifdef O_NDELAY
943 (void) fcntl (tui_readline_pipe[0], F_SETFL, O_NDELAY);
944#endif
945#endif
946 add_file_handler (tui_readline_pipe[0], tui_readline_output, 0, "tui");
947#else
948 tui_rl_outstream = stdout;
949#endif
950
951#ifdef __MINGW32__
952 /* MS-Windows port of ncurses doesn't support default foreground and
953 background colors, so we must record the default colors at startup. */
954 HANDLE hstdout = (HANDLE)_get_osfhandle (fileno (stdout));
955 DWORD cmode;
956 CONSOLE_SCREEN_BUFFER_INFO csbi;
957
958 if (hstdout != INVALID_HANDLE_VALUE
959 && GetConsoleMode (hstdout, &cmode) != 0
960 && GetConsoleScreenBufferInfo (hstdout, &csbi))
961 ncurses_norm_attr = csbi.wAttributes;
962#endif
963}
964
965/* Dispatch the correct tui function based upon the mouse event. */
966
967#ifdef NCURSES_MOUSE_VERSION
968
969static void
970tui_dispatch_mouse_event ()
971{
972 MEVENT mev;
973 if (getmouse (&mev) != OK)
974 return;
975
976 for (tui_win_info *wi : all_tui_windows ())
977 if (mev.x > wi->x && mev.x < wi->x + wi->width - 1
978 && mev.y > wi->y && mev.y < wi->y + wi->height - 1)
979 {
980 if ((mev.bstate & BUTTON1_CLICKED) != 0
981 || (mev.bstate & BUTTON2_CLICKED) != 0
982 || (mev.bstate & BUTTON3_CLICKED) != 0)
983 {
984 int button = (mev.bstate & BUTTON1_CLICKED) != 0 ? 1
985 : ((mev.bstate & BUTTON2_CLICKED) != 0 ? 2
986 : 3);
987 wi->click (mev.x - wi->x - 1, mev.y - wi->y - 1, button);
988 }
989#ifdef BUTTON5_PRESSED
990 else if ((mev.bstate & BUTTON4_PRESSED) != 0)
991 wi->backward_scroll (3);
992 else if ((mev.bstate & BUTTON5_PRESSED) != 0)
993 wi->forward_scroll (3);
994#endif
995 break;
996 }
997}
998
999#endif
1000
1001/* Dispatch the correct tui function based upon the control
1002 character. */
1003static unsigned int
1004tui_dispatch_ctrl_char (unsigned int ch)
1005{
1006 struct tui_win_info *win_info = tui_win_with_focus ();
1007
1008 /* If no window has the focus, or if the focus window can't scroll,
1009 just pass the character through. */
1010 if (win_info == NULL || !win_info->can_scroll ())
1011 return ch;
1012
1013 switch (ch)
1014 {
1015 case KEY_NPAGE:
1016 win_info->forward_scroll (0);
1017 break;
1018 case KEY_PPAGE:
1019 win_info->backward_scroll (0);
1020 break;
1021 case KEY_DOWN:
1022 case KEY_SF:
1023 win_info->forward_scroll (1);
1024 break;
1025 case KEY_UP:
1026 case KEY_SR:
1027 win_info->backward_scroll (1);
1028 break;
1029 case KEY_RIGHT:
1030 win_info->left_scroll (1);
1031 break;
1032 case KEY_LEFT:
1033 win_info->right_scroll (1);
1034 break;
1035 default:
1036 /* We didn't recognize the character as a control character, so pass it
1037 through. */
1038 return ch;
1039 }
1040
1041 /* We intercepted the control character, so return 0 (which readline
1042 will interpret as a no-op). */
1043 return 0;
1044}
1045
1046/* See tui-io.h. */
1047
1048void
1050{
1051 gdb_assert (tui_active);
1052
1053 WINDOW *w = TUI_CMD_WIN->handle.get ();
1054
1055 /* When hitting return with an empty input, gdb executes the last
1056 command. If we emit a newline, this fills up the command window
1057 with empty lines with gdb prompt at beginning. Instead of that,
1058 stay on the same line but provide a visual effect to show the
1059 user we recognized the command. */
1060 if (rl_end == 0 && !gdb_in_secondary_prompt_p (current_ui))
1061 {
1062 wmove (w, getcury (w), 0);
1063
1064 /* Clear the line. This will blink the gdb prompt since
1065 it will be redrawn at the same line. */
1066 wclrtoeol (w);
1067 wrefresh (w);
1068 napms (20);
1069 }
1070 else
1071 {
1072 /* Move cursor to the end of the command line before emitting the
1073 newline. We need to do so because when ncurses outputs a newline
1074 it truncates any text that appears past the end of the cursor. */
1075 int px, py;
1076 getyx (w, py, px);
1077 px += rl_end - rl_point;
1078 py += px / TUI_CMD_WIN->width;
1079 px %= TUI_CMD_WIN->width;
1080 wmove (w, py, px);
1081 tui_putc ('\n');
1082 }
1083}
1084
1085/* If we're passing an escape sequence to readline, this points to a
1086 string holding the remaining characters of the sequence to pass.
1087 We advance the pointer one character at a time until '\0' is
1088 reached. */
1089static const char *cur_seq = nullptr;
1090
1091/* Set CUR_SEQ to point at the current sequence to pass to readline,
1092 setup to call the input handler again so we complete the sequence
1093 shortly, and return the first character to start the sequence. */
1094
1095static int
1096start_sequence (const char *seq)
1097{
1099 cur_seq = seq + 1;
1100 return seq[0];
1101}
1102
1103/* Main worker for tui_getc. Get a character from the command window.
1104 This is called from the readline package, but wrapped in a
1105 try/catch by tui_getc. */
1106
1107static int
1108tui_getc_1 (FILE *fp)
1109{
1110 int ch;
1111 WINDOW *w;
1112
1113 w = TUI_CMD_WIN->handle.get ();
1114
1115#ifdef TUI_USE_PIPE_FOR_READLINE
1116 /* Flush readline output. */
1117 tui_readline_output (0, 0);
1118#endif
1119
1120 /* We enable keypad mode so that curses's wgetch processes mouse
1121 escape sequences. In keypad mode, wgetch also processes the
1122 escape sequences for keys such as up/down etc. and returns KEY_UP
1123 / KEY_DOWN etc. When we have the focus on the command window
1124 though, we want to pass the raw up/down etc. escape codes to
1125 readline so readline understands them. */
1126 if (cur_seq != nullptr)
1127 {
1128 ch = *cur_seq++;
1129
1130 /* If we've reached the end of the string, we're done with the
1131 sequence. Otherwise, setup to get back here again for
1132 another character. */
1133 if (*cur_seq == '\0')
1134 cur_seq = nullptr;
1135 else
1137 return ch;
1138 }
1139 else
1140 ch = gdb_wgetch (w);
1141
1142 /* Handle prev/next/up/down here. */
1143 ch = tui_dispatch_ctrl_char (ch);
1144
1145#ifdef NCURSES_MOUSE_VERSION
1146 if (ch == KEY_MOUSE)
1147 {
1148 tui_dispatch_mouse_event ();
1149 return 0;
1150 }
1151#endif
1152
1153 /* Translate curses keys back to escape sequences so that readline
1154 can understand them. We do this irrespective of which window has
1155 the focus. If e.g., we're focused on a non-command window, then
1156 the up/down keys will already have been filtered by
1157 tui_dispatch_ctrl_char. Keys that haven't been intercepted will
1158 be passed down to readline. */
1160 {
1161 /* For the standard arrow keys + home/end, hardcode sequences
1162 readline understands. See bind_arrow_keys_internal in
1163 readline/readline.c. */
1164 switch (ch)
1165 {
1166 case KEY_UP:
1167 return start_sequence ("\033[A");
1168 case KEY_DOWN:
1169 return start_sequence ("\033[B");
1170 case KEY_RIGHT:
1171 return start_sequence ("\033[C");
1172 case KEY_LEFT:
1173 return start_sequence ("\033[D");
1174 case KEY_HOME:
1175 return start_sequence ("\033[H");
1176 case KEY_END:
1177 return start_sequence ("\033[F");
1178
1179 /* del and ins are unfortunately not hardcoded in readline for
1180 all systems. */
1181
1182 case KEY_DC: /* del */
1183#ifdef __MINGW32__
1184 return start_sequence ("\340S");
1185#else
1186 return start_sequence ("\033[3~");
1187#endif
1188
1189 case KEY_IC: /* ins */
1190#if defined __MINGW32__
1191 return start_sequence ("\340R");
1192#else
1193 return start_sequence ("\033[2~");
1194#endif
1195 }
1196
1197 /* Keycodes above KEY_MAX are not garanteed to be stable.
1198 Compare keyname instead. */
1199 if (ch >= KEY_MAX)
1200 {
1201 auto name = gdb::string_view (keyname (ch));
1202
1203 /* The following sequences are hardcoded in readline as
1204 well. */
1205
1206 /* ctrl-arrow keys */
1207 if (name == "kLFT5") /* ctrl-left */
1208 return start_sequence ("\033[1;5D");
1209 else if (name == "kRIT5") /* ctrl-right */
1210 return start_sequence ("\033[1;5C");
1211 else if (name == "kDC5") /* ctrl-del */
1212 return start_sequence ("\033[3;5~");
1213
1214 /* alt-arrow keys */
1215 else if (name == "kLFT3") /* alt-left */
1216 return start_sequence ("\033[1;3D");
1217 else if (name == "kRIT3") /* alt-right */
1218 return start_sequence ("\033[1;3C");
1219 }
1220 }
1221
1222 /* Handle the CTRL-L refresh for each window. */
1223 if (ch == '\f')
1224 {
1226 return ch;
1227 }
1228
1229 if (ch == KEY_BACKSPACE)
1230 return '\b';
1231
1233 {
1234 int ch_pending;
1235
1236 nodelay (w, TRUE);
1237 ch_pending = gdb_wgetch (w);
1238 nodelay (w, FALSE);
1239
1240 /* If we have pending input following a start sequence, call the stdin
1241 event handler again because ncurses may have already read and stored
1242 the input into its internal buffer, meaning that we won't get an stdin
1243 event for it. If we don't compensate for this missed stdin event, key
1244 sequences as Alt_F (^[f) will not behave promptly.
1245
1246 (We only compensates for the missed 2nd byte of a key sequence because
1247 2-byte sequences are by far the most commonly used. ncurses may have
1248 buffered a larger, 3+-byte key sequence though it remains to be seen
1249 whether it is useful to compensate for all the bytes of such
1250 sequences.) */
1251 if (ch_pending != ERR)
1252 {
1253 ungetch (ch_pending);
1255 }
1256 }
1257
1258 if (ch > 0xff)
1259 {
1260 /* Readline doesn't understand non-8-bit curses keys, filter
1261 them out. */
1262 return 0;
1263 }
1264
1265 return ch;
1266}
1267
1268/* Get a character from the command window. This is called from the
1269 readline package. */
1270
1271static int
1272tui_getc (FILE *fp)
1273{
1274 try
1275 {
1276 return tui_getc_1 (fp);
1277 }
1278 catch (const gdb_exception &ex)
1279 {
1280 /* Just in case, don't ever let an exception escape to readline.
1281 This shouldn't ever happen, but if it does, print the
1282 exception instead of just crashing GDB. */
1284
1285 /* If we threw an exception, it's because we recognized the
1286 character. */
1287 return 0;
1288 }
1289}
const char *const name
Definition: aarch64-tdep.c:67
#define SHORT
Definition: c-exp.c:320
void get_rgb(uint8_t *rgb) const
Definition: ui-style.c:97
int get_value() const
Definition: ui-style.h:108
bool is_basic() const
Definition: ui-style.h:102
bool is_none() const
Definition: ui-style.h:95
Definition: ui-out.h:160
void gdb_display_match_list(char **matches, int len, int max, const struct match_list_displayer *displayer)
Definition: completer.c:2947
int call_stdin_event_handler_again_p
Definition: event-top.c:99
struct ui * current_ui
Definition: event-top.c:483
void exception_print(struct ui_file *file, const struct gdb_exception &e)
Definition: exceptions.c:105
ssize_t read(int fd, void *buf, size_t count)
Definition: expect-read1.c:26
size_t size
Definition: go32-nat.c:241
struct ui_file * gdb_stdtarg
Definition: main.c:79
struct ui_file * gdb_stdtargerr
Definition: main.c:80
static HANDLE hstdout
Definition: mingw-hdep.c:213
int fg
Definition: tui-io.c:191
int bg
Definition: tui-io.c:192
bool operator<(const color_pair &o) const
Definition: tui-io.c:194
mld_puts_ftype * puts
Definition: completer.h:51
mld_erase_entire_line_ftype * erase_entire_line
Definition: completer.h:58
mld_read_key_ftype * read_key
Definition: completer.h:64
mld_putch_ftype * putch
Definition: completer.h:48
mld_beep_ftype * beep
Definition: completer.h:61
mld_flush_ftype * flush
Definition: completer.h:54
mld_crlf_ftype * crlf
Definition: completer.h:45
void right_scroll(int num_to_scroll)
Definition: tui-win.c:489
virtual bool can_scroll() const
Definition: tui-data.h:135
void left_scroll(int num_to_scroll)
Definition: tui-win.c:479
void backward_scroll(int num_to_scroll)
Definition: tui-win.c:469
void forward_scroll(int num_to_scroll)
Definition: tui-win.c:460
int command_editing
Definition: top.h:88
int gdb_in_secondary_prompt_p(struct ui *ui)
Definition: top.c:1060
struct tui_win_info * tui_win_with_focus(void)
Definition: tui-data.c:57
#define TUI_CMD_WIN
Definition: tui-data.h:189
static std::vector< tui_win_info * > & all_tui_windows()
Definition: tui-data.h:198
static const char * cur_seq
Definition: tui-io.c:1089
static int tui_getc(FILE *fp)
Definition: tui-io.c:1272
static void tui_deprep_terminal(void)
Definition: tui-io.c:665
static int tui_mld_read_key(const struct match_list_displayer *displayer)
Definition: tui-io.c:774
static void tui_prep_terminal(int notused1)
Definition: tui-io.c:655
static int tui_readline_pipe[2]
Definition: tui-io.c:135
static int tui_old_rl_echoing_p
Definition: tui-io.c:128
void tui_apply_style(WINDOW *w, ui_file_style style)
Definition: tui-io.c:296
static void tui_mld_beep(const struct match_list_displayer *displayer)
Definition: tui-io.c:738
static void tui_mld_putch(const struct match_list_displayer *displayer, int ch)
Definition: tui-io.c:701
static FILE * tui_old_rl_outstream
Definition: tui-io.c:133
static void tui_rl_display_match_list(char **matches, int len, int max)
Definition: tui-io.c:790
#define CTRL_CHAR(c)
Definition: tui-io.c:69
static int tui_getc_1(FILE *fp)
Definition: tui-io.c:1108
static void tui_puts_internal(WINDOW *w, const char *string, int *height)
Definition: tui-io.c:517
void tui_initialize_io(void)
Definition: tui-io.c:911
static ui_file_style::color reverse_save_bg(ui_file_style::NONE)
static bool get_color(const ui_file_style::color &color, int *result)
Definition: tui-io.c:222
static int key_is_start_sequence(int ch)
Definition: tui-io.c:62
static int get_color_pair(int fg, int bg)
Definition: tui-io.c:273
void tui_set_reverse_mode(WINDOW *w, bool reverse)
Definition: tui-io.c:412
void tui_setup_io(int mode)
Definition: tui-io.c:815
static std::map< ui_file_style::color, int > color_map
Definition: tui-io.c:184
static struct ui_file * tui_stdout
Definition: tui-io.c:111
static struct ui_file * tui_old_stderr
Definition: tui-io.c:118
struct ui_out * tui_out
Definition: tui-io.c:114
static void tui_putc(char c)
Definition: tui-io.c:176
static size_t apply_ansi_escape(WINDOW *w, const char *buf)
Definition: tui-io.c:362
cli_ui_out * tui_old_uiout
Definition: tui-io.c:120
static rl_voidfunc_t * tui_old_rl_redisplay_function
Definition: tui-io.c:124
static const int curses_colors[]
Definition: tui-io.c:208
static rl_getc_func_t * tui_old_rl_getc_function
Definition: tui-io.c:123
void tui_puts(const char *string, WINDOW *w)
Definition: tui-io.c:458
static int tui_mld_getc(FILE *fp)
Definition: tui-io.c:763
static std::map< color_pair, int > color_pair_map
Definition: tui-io.c:203
static ui_file_style last_style
Definition: tui-io.c:258
static rl_voidfunc_t * tui_old_rl_deprep_terminal
Definition: tui-io.c:126
void tui_write(const char *buf, size_t length)
Definition: tui-io.c:446
static bool reverse_mode_p
Definition: tui-io.c:262
static void update_cmdwin_start_line()
Definition: tui-io.c:166
static struct ui_file * tui_old_stdout
Definition: tui-io.c:117
void tui_inject_newline_into_command_window()
Definition: tui-io.c:1049
static void tui_readline_output(int error, gdb_client_data data)
Definition: tui-io.c:676
static struct ui_file * tui_old_stdlog
Definition: tui-io.c:119
static void tui_mld_puts(const struct match_list_displayer *displayer, const char *s)
Definition: tui-io.c:709
static void tui_mld_erase_entire_line(const struct match_list_displayer *displayer)
Definition: tui-io.c:725
static ui_file_style::color reverse_save_fg(ui_file_style::NONE)
static int start_sequence(const char *seq)
Definition: tui-io.c:1096
static FILE * tui_rl_outstream
Definition: tui-io.c:132
static struct ui_file * tui_stderr
Definition: tui-io.c:112
static void do_tui_putc(WINDOW *w, char c)
Definition: tui-io.c:143
static unsigned int tui_dispatch_ctrl_char(unsigned int ch)
Definition: tui-io.c:1004
static rl_vintfunc_t * tui_old_rl_prep_terminal
Definition: tui-io.c:125
static void tui_mld_flush(const struct match_list_displayer *displayer)
Definition: tui-io.c:717
static int last_color_pair
Definition: tui-io.c:254
static struct ui_file * tui_stdlog
Definition: tui-io.c:113
static void tui_mld_crlf(const struct match_list_displayer *displayer)
Definition: tui-io.c:693
static rl_compdisp_func_t * tui_old_rl_display_matches_hook
Definition: tui-io.c:127
void tui_redisplay_readline(void)
Definition: tui-io.c:565
static int gdb_wgetch(WINDOW *win)
Definition: tui-io.c:750
bool style_tui_current_position
Definition: tui-win.c:223
void tui_refresh_all_win(void)
Definition: tui-win.c:499
void tui_ensure_readline_initialized()
Definition: tui.c:281
enum tui_key_mode tui_current_key_mode
Definition: tui.c:75
bool tui_active
Definition: tui.c:72
void tui_set_key_mode(enum tui_key_mode mode)
Definition: tui.c:270
@ TUI_ONE_COMMAND_MODE
Definition: tui.h:87
@ TUI_SINGLE_KEY_MODE
Definition: tui.h:83
#define current_uiout
Definition: ui-out.h:40
#define gdb_stderr
Definition: utils.h:193
#define gdb_stdlog
Definition: utils.h:196
#define gdb_stdout
Definition: utils.h:188