From 9e820dec13ec153f5843a30afe6d1c5037405278 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Sun, 27 Sep 2020 20:30:30 -0600 Subject: [PATCH] Use a curses pad for source and disassembly windows This changes the TUI source and disassembly windows to use a curses pad for their text. This is an important step toward properly handling non-ASCII characters, because it makes it easy to scroll horizontally without needing gdb to also understand multi-byte character boundaries -- this can be wholly delegated to curses. Horizontal scrolling is probably also faster now, because no re-rendering is required. gdb/ChangeLog 2020-09-27 Tom Tromey * unittests/tui-selftests.c: Update. * tui/tui-winsource.h (struct tui_source_window_base) : New methods. : New members. (tui_copy_source_line): Update. * tui/tui-winsource.c (tui_copy_source_line): Remove line_no, first_col, line_width, ndigits parameters. Add length. (tui_source_window_base::show_source_line): Write to pad. Line number now 0-based. (tui_source_window_base::refresh_pad): New method. (tui_source_window_base::show_source_content): Write to pad. Call refresh_pad. (tui_source_window_base::do_scroll_horizontal): Call refresh_pad, not refill. (tui_source_window_base::update_exec_info): Call show_line_number. * tui/tui-source.h (struct tui_source_window) : New method. : New member. * tui/tui-source.c (tui_source_window::set_contents): Set m_digits and m_max_length. (tui_source_window::show_line_number): New method. * tui/tui-io.h (tui_puts): Fix comment. * tui/tui-disasm.c (tui_disasm_window::set_contents): Set m_max_length. --- gdb/ChangeLog | 28 ++++++++++++ gdb/tui/tui-disasm.c | 9 ++-- gdb/tui/tui-io.h | 3 +- gdb/tui/tui-source.c | 29 ++++++++---- gdb/tui/tui-source.h | 11 +++++ gdb/tui/tui-winsource.c | 84 +++++++++++++++++------------------ gdb/tui/tui-winsource.h | 41 ++++++++++++----- gdb/unittests/tui-selftests.c | 6 +-- 8 files changed, 140 insertions(+), 71 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index c835fdb14ad..38b9fa6b353 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,31 @@ +2020-09-27 Tom Tromey + + * unittests/tui-selftests.c: Update. + * tui/tui-winsource.h (struct tui_source_window_base) + : New methods. + : New members. + (tui_copy_source_line): Update. + * tui/tui-winsource.c (tui_copy_source_line): Remove line_no, + first_col, line_width, ndigits parameters. Add length. + (tui_source_window_base::show_source_line): Write to pad. Line + number now 0-based. + (tui_source_window_base::refresh_pad): New method. + (tui_source_window_base::show_source_content): Write to pad. Call + refresh_pad. + (tui_source_window_base::do_scroll_horizontal): Call refresh_pad, + not refill. + (tui_source_window_base::update_exec_info): Call + show_line_number. + * tui/tui-source.h (struct tui_source_window) : New + method. + : New member. + * tui/tui-source.c (tui_source_window::set_contents): Set m_digits + and m_max_length. + (tui_source_window::show_line_number): New method. + * tui/tui-io.h (tui_puts): Fix comment. + * tui/tui-disasm.c (tui_disasm_window::set_contents): Set + m_max_length. + 2020-09-27 Tom Tromey * tui/tui-winsource.c diff --git a/gdb/tui/tui-disasm.c b/gdb/tui/tui-disasm.c index d684b02fd12..0b7980ee80b 100644 --- a/gdb/tui/tui-disasm.c +++ b/gdb/tui/tui-disasm.c @@ -318,8 +318,7 @@ tui_disasm_window::set_contents (struct gdbarch *arch, const struct symtab_and_line &sal) { int i; - int offset = m_horizontal_offset; - int max_lines, line_width; + int max_lines; CORE_ADDR cur_pc; struct tui_locator_window *locator = tui_locator_win_info_ptr (); int tab_len = tui_tab_width; @@ -336,7 +335,6 @@ tui_disasm_window::set_contents (struct gdbarch *arch, /* Window size, excluding highlight box. */ max_lines = height - 2; - line_width = width - TUI_EXECINFO_SIZE - 2; /* Get temporary table that will hold all strings (addr & insn). */ std::vector asm_lines; @@ -348,6 +346,7 @@ tui_disasm_window::set_contents (struct gdbarch *arch, /* Now construct each line. */ m_content.resize (max_lines); + m_max_length = -1; for (i = 0; i < max_lines; i++) { tui_source_element *src = &m_content[i]; @@ -370,7 +369,9 @@ tui_disasm_window::set_contents (struct gdbarch *arch, } const char *ptr = line.c_str (); - src->line = tui_copy_source_line (&ptr, -1, offset, line_width, 0); + int line_len; + src->line = tui_copy_source_line (&ptr, &line_len); + m_max_length = std::max (m_max_length, line_len); src->line_or_addr.loa = LOA_ADDRESS; src->line_or_addr.u.addr = addr; diff --git a/gdb/tui/tui-io.h b/gdb/tui/tui-io.h index 2cc47ba4beb..5e21bb7811d 100644 --- a/gdb/tui/tui-io.h +++ b/gdb/tui/tui-io.h @@ -27,7 +27,8 @@ struct ui_out; class cli_ui_out; -/* Print the string in the curses command window. */ +/* Print the string in the given curses window. If no window is + provided, the command window is used. */ extern void tui_puts (const char *, WINDOW * = nullptr); /* Print LENGTH characters from the buffer pointed to by BUF to the diff --git a/gdb/tui/tui-source.c b/gdb/tui/tui-source.c index fd5bd7dd960..cc6680406d9 100644 --- a/gdb/tui/tui-source.c +++ b/gdb/tui/tui-source.c @@ -50,12 +50,9 @@ tui_source_window::set_contents (struct gdbarch *arch, if (s == NULL) return false; - int line_width, nlines; - - line_width = width - TUI_EXECINFO_SIZE - 1; /* Take hilite (window border) into account, when calculating the number of lines. */ - nlines = height - 2; + int nlines = height - 2; std::string srclines; const std::vector *offsets; @@ -78,15 +75,16 @@ tui_source_window::set_contents (struct gdbarch *arch, m_start_line_or_addr.loa = LOA_LINE; cur_line_no = m_start_line_or_addr.u.line_no = line_no; - int digits = 0; + m_digits = 7; if (compact_source) { /* Solaris 11+gcc 5.5 has ambiguous overloads of log10, so we cast to double to get the right one. */ double l = log10 ((double) offsets->size ()); - digits = 1 + (int) l; + m_digits = 1 + (int) l; } + m_max_length = -1; const char *iter = srclines.c_str (); m_content.resize (nlines); while (cur_line < nlines) @@ -95,9 +93,11 @@ tui_source_window::set_contents (struct gdbarch *arch, std::string text; if (*iter != '\0') - text = tui_copy_source_line (&iter, cur_line_no, - m_horizontal_offset, - line_width, digits); + { + int line_len; + text = tui_copy_source_line (&iter, &line_len); + m_max_length = std::max (m_max_length, line_len); + } /* Set whether element is the execution point and whether there is a break point on it. */ @@ -225,3 +225,14 @@ tui_source_window::display_start_addr (struct gdbarch **gdbarch_p, *gdbarch_p = m_gdbarch; find_line_pc (cursal.symtab, m_start_line_or_addr.u.line_no, addr_p); } + +/* See tui-winsource.h. */ + +void +tui_source_window::show_line_number (int offset) const +{ + int lineno = m_content[0].line_or_addr.u.line_no + offset; + char text[20]; + xsnprintf (text, sizeof (text), "%*d ", m_digits - 1, lineno); + waddstr (handle.get (), text); +} diff --git a/gdb/tui/tui-source.h b/gdb/tui/tui-source.h index 1df84cf304c..020f710c237 100644 --- a/gdb/tui/tui-source.h +++ b/gdb/tui/tui-source.h @@ -63,12 +63,23 @@ protected: bool set_contents (struct gdbarch *gdbarch, const struct symtab_and_line &sal) override; + int extra_margin () const override + { + return m_digits; + } + + void show_line_number (int lineno) const override; + private: /* Answer whether a particular line number or address is displayed in the current source window. */ bool line_is_displayed (int line) const; + /* How many digits to use when formatting the line number. This + includes the trailing space. */ + int m_digits; + /* It is the resolved form as returned by symtab_to_fullname. */ gdb::unique_xmalloc_ptr m_fullname; }; diff --git a/gdb/tui/tui-winsource.c b/gdb/tui/tui-winsource.c index 6723bad82cc..2300b9ab1e9 100644 --- a/gdb/tui/tui-winsource.c +++ b/gdb/tui/tui-winsource.c @@ -65,27 +65,13 @@ tui_display_main () /* See tui-winsource.h. */ std::string -tui_copy_source_line (const char **ptr, int line_no, int first_col, - int line_width, int ndigits) +tui_copy_source_line (const char **ptr, int *length) { const char *lineptr = *ptr; /* Init the line with the line number. */ std::string result; - if (line_no > 0) - { - if (ndigits > 0) - result = string_printf ("%*d ", ndigits, line_no); - else - { - result = string_printf ("%-6d", line_no); - int len = result.size (); - len = len - ((len / tui_tab_width) * tui_tab_width); - result.append (len, ' '); - } - } - int column = 0; char c; do @@ -112,21 +98,11 @@ tui_copy_source_line (const char **ptr, int line_no, int first_col, --column; for (int j = column % max_tab_len; - j < max_tab_len && column < first_col + line_width; + j < max_tab_len; column++, j++) - if (column >= first_col) - result.push_back (' '); + result.push_back (' '); }; - /* We have to process all the text in order to pick up all the - escapes. */ - if (column <= first_col || column > first_col + line_width) - { - if (c == '\t') - process_tab (); - continue; - } - if (c == '\n' || c == '\r' || c == '\0') { /* Nothing. */ @@ -135,11 +111,13 @@ tui_copy_source_line (const char **ptr, int line_no, int first_col, { result.push_back ('^'); result.push_back (c + 0100); + ++column; } else if (c == 0177) { result.push_back ('^'); result.push_back ('?'); + ++column; } else if (c == '\t') process_tab (); @@ -152,6 +130,9 @@ tui_copy_source_line (const char **ptr, int line_no, int first_col, ++lineptr; *ptr = lineptr; + if (length != nullptr) + *length = column; + return result; } @@ -254,24 +235,31 @@ void tui_source_window_base::show_source_line (int lineno) { struct tui_source_element *line; - int x; - line = &m_content[lineno - 1]; + line = &m_content[lineno]; if (line->is_exec_point) - tui_set_reverse_mode (handle.get (), true); + tui_set_reverse_mode (m_pad.get (), true); - wmove (handle.get (), lineno, TUI_EXECINFO_SIZE); - tui_puts (line->line.c_str (), handle.get ()); + wmove (m_pad.get (), lineno, 0); + tui_puts (line->line.c_str (), m_pad.get ()); if (line->is_exec_point) - tui_set_reverse_mode (handle.get (), false); + tui_set_reverse_mode (m_pad.get (), false); +} - /* Clear to end of line but stop before the border. */ - x = getcurx (handle.get ()); - while (x + 1 < width) - { - waddch (handle.get (), ' '); - x = getcurx (handle.get ()); - } +/* See tui-winsource.h. */ + +void +tui_source_window_base::refresh_pad () +{ + int pad_width = std::max (m_max_length, width); + int left_margin = 1 + TUI_EXECINFO_SIZE + extra_margin (); + int view_width = width - left_margin - 1; + int pad_x = std::min (pad_width - view_width, m_horizontal_offset); + /* Ensure that an equal number of scrolls will work if the user + scrolled beyond where we clip. */ + m_horizontal_offset = pad_x; + prefresh (m_pad.get (), 0, pad_x, y + 1, x + left_margin, + y + 1 + m_content.size (), x + left_margin + view_width - 1); } void @@ -279,10 +267,18 @@ tui_source_window_base::show_source_content () { gdb_assert (!m_content.empty ()); - for (int lineno = 1; lineno <= m_content.size (); lineno++) + check_and_display_highlight_if_needed (); + + int pad_width = std::max (m_max_length, width); + if (m_pad == nullptr || pad_width > getmaxx (m_pad.get ())) + m_pad.reset (newpad (m_content.size (), pad_width)); + + werase (m_pad.get ()); + for (int lineno = 0; lineno < m_content.size (); lineno++) show_source_line (lineno); - check_and_display_highlight_if_needed (); + refresh_pad (); + refresh_window (); } @@ -380,7 +376,7 @@ tui_source_window_base::do_scroll_horizontal (int num_to_scroll) if (offset < 0) offset = 0; m_horizontal_offset = offset; - refill (); + refresh_pad (); } } @@ -519,6 +515,8 @@ tui_source_window_base::update_exec_info () element[TUI_EXEC_POS] = '>'; mvwaddstr (handle.get (), i + 1, 1, element); + + show_line_number (i); } refresh_window (); } diff --git a/gdb/tui/tui-winsource.h b/gdb/tui/tui-winsource.h index ba9c0fd505e..5fc6a6d8126 100644 --- a/gdb/tui/tui-winsource.h +++ b/gdb/tui/tui-winsource.h @@ -107,6 +107,20 @@ protected: virtual bool set_contents (struct gdbarch *gdbarch, const struct symtab_and_line &sal) = 0; + /* Return the number of extra margin characters needed by this + instance. */ + virtual int extra_margin () const + { + return 0; + } + + /* Display the line number in the window margin. OFFSET indicates + which line to display; it is 0-based, with 0 meaning the line at + the top of the window. */ + virtual void show_line_number (int offset) const + { + } + /* Redraw the complete line of a source or disassembly window. */ void show_source_line (int lineno); @@ -119,6 +133,9 @@ protected: std::vector m_content; + /* Length of longest line to be displayed. */ + int m_max_length; + public: /* Refill the source window's source cache and update it. If this @@ -162,11 +179,17 @@ private: void show_source_content (); + /* Re-display the pad in the window. */ + void refresh_pad (); + /* Called when the user "set style enabled" setting is changed. */ void style_changed (); /* A token used to register and unregister an observer. */ gdb::observers::token m_observable; + + /* Pad used to display fixme mumble */ + std::unique_ptr m_pad; }; @@ -264,19 +287,15 @@ extern void tui_display_main (void); extern void tui_update_source_windows_with_addr (struct gdbarch *, CORE_ADDR); extern void tui_update_source_windows_with_line (struct symtab_and_line sal); -/* Extract some source text from PTR. LINE_NO is the line number. If - it is positive, it is printed at the start of the line. FIRST_COL - is the first column to extract, and LINE_WIDTH is the number of - characters to display. NDIGITS is used to format the line number - (if it is positive). If NDIGITS is greater than 0, then that many - digits are used; otherwise the line number is formatted with 6 - digits and the text is aligned to the next tab stop. Returns a - string holding the desired text. PTR is updated to point to the - start of the next line. */ +/* Extract some source text from PTR. Returns a string holding the + desired text. PTR is updated to point to the start of the next + line. If LENGTH is non-NULL, then the length of the line is stored + there. Escape sequences are not counted against the length. + Actually an approximation is used -- each byte of a multi-byte + sequence counts as a character here. */ extern std::string tui_copy_source_line (const char **ptr, - int line_no, int first_col, - int line_width, int ndigits); + int *length = nullptr); /* Constant definitions. */ #define SCROLL_THRESHOLD 2 /* Threshold for lazy scroll. */ diff --git a/gdb/unittests/tui-selftests.c b/gdb/unittests/tui-selftests.c index 6144e23f394..7ab2a634b61 100644 --- a/gdb/unittests/tui-selftests.c +++ b/gdb/unittests/tui-selftests.c @@ -31,13 +31,13 @@ static void run_tests () { const char *text = "hello"; - std::string result = tui_copy_source_line (&text, 0, 0, 50, 0); + std::string result = tui_copy_source_line (&text); SELF_CHECK (result == "hello"); SELF_CHECK (*text == '\0'); text = "hello\n"; - result = tui_copy_source_line (&text, 0, 0, 3, 0); - SELF_CHECK (result == "hel"); + result = tui_copy_source_line (&text); + SELF_CHECK (result == "hello"); SELF_CHECK (*text == '\0'); } -- 2.30.2