[v3,gdb/cli] Fix wrapping for TERM=ansi

Message ID 20230505132008.32133-1-tdevries@suse.de
State Committed
Headers
Series [v3,gdb/cli] Fix wrapping for TERM=ansi |

Commit Message

Tom de Vries May 5, 2023, 1:20 p.m. UTC
  I. Auto-detected width (xterm vs. ansi)

Say we have a terminal with a width of 40 chars:
...
$ echo $COLUMNS
40
...

With TERM=xterm, we report a width of 40 chars:
...
$ TERM=xterm gdb
(gdb) show width
Number of characters gdb thinks are in a line is 40.
...

And with TERM=ansi, a width of 39 chars:
...
$ TERM=ansi gdb
(gdb) show width
Number of characters gdb thinks are in a line is 39.
...

Gdb uses readline to auto-detect screen size, and readline decides in the
TERM=ansi case that the terminal does not have reliable auto-wrap, and
consequently decides to hide the last terminal column from the readline user
(in other words GDB), hence we get 39 instead of 40.

II. Types of wrapping

Looking a bit more in detail inside gdb, it seems there are two types of
wrapping:
- readline wrapping (in other words, prompt edit wrapping), and
- gdb output wrapping (can be observed by issuing "info sources").
  This type of wrapping attempts to wrap some of the gdb output earlier
  than the indicated width, to not break lines in inconvenient places.

III. Readline wrapping, auto-detected screen size

Alright, so then how do we fare with the auto-detected screen widths?

First, let's try readline wrapping.

[ COLUMNS == 40, TERM=xterm reporting width 40 and TERM=ansi reporting width
39. ]

Let's try with xterm:
...
$ TERM=xterm gdb
(gdb) 7890123456789012345678901234567890
123
...
That looks as expected, wrapping occurs after 40 chars.

Now, let's try with ansi:
...
$ TERM=ansi gdb
(gdb) 78901234567890123456789012345678
90123
...
It looks like wrapping occurred after 38, while readline should be capable of
wrapping after 39 chars.

This is caused by readline hiding the last column, twice.

In more detail:
- readline detects the screen width: 40,
- readline hides the last column, setting the readline screen width to 39,
- readline reports 39 to gdb as screen width,
- gdb sets its width setting to 39,
- gdb sets readline screen width to 39,
- readline hides the last column, again, setting the readline screen width to
  38.

This is reported as PR cli/30346.

IV. gdb output wrapping, auto-detected screen size

Say we set the terminal width to 56. With TERM=xterm, we have:
...
/home/abuild/rpmbuild/BUILD/glibc-2.31/csu/elf-init.c,
/data/vries/hello.c,
...
but with TERM=ansi:
...
/home/abuild/rpmbuild/BUILD/glibc-2.31/csu/elf-init.c, /
data/vries/hello.c,
...

So what happened here?  With TERM=ansi, the width setting is auto-detected to
55, and gdb assumes the terminal inserts a line break there, which it doesn't
because the terminal width is 56.

This is reported as PR cli/30411.

V. Fix PRs

Fix both mentioned PRs by taking into account the hidden column when readline
reports the screen width in init_page_info, and updating chars_per_line
accordingly.

Note that now we report the same width for both TERM=xterm and TERM=ansi,
which is much clearer.

The point where readline respectively expects or ensures wrapping is still
indicated by "maint info screen", for xterm:
...
Number of characters readline reports are in a line is 40.
...
and ansi:
...
Number of characters readline reports are in a line is 39.
...

VI. Testing

PR cli/30346 is covered by existing regression tests gdb.base/wrap-line.exp
and gdb.tui/wrap-line.exp, so remove the KFAILs there.

I didn't manage to come up with a regression test for PR cli/30411.  Perhaps
that would be easier if we had a maintenance command that echoes its arguments
while applying gdb output wrapping.

Tested on x86_64-linux.

PR cli/30346
PR cli/30411
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30346
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30411
---
 gdb/testsuite/gdb.base/wrap-line.exp | 6 ------
 gdb/testsuite/gdb.tui/wrap-line.exp  | 6 ------
 gdb/utils.c                          | 2 +-
 3 files changed, 1 insertion(+), 13 deletions(-)


base-commit: 4891c459927d9a9c0f516c35e2d9d4ce212dd06e
  

Patch

diff --git a/gdb/testsuite/gdb.base/wrap-line.exp b/gdb/testsuite/gdb.base/wrap-line.exp
index 938b5c44099..03d94720c9c 100644
--- a/gdb/testsuite/gdb.base/wrap-line.exp
+++ b/gdb/testsuite/gdb.base/wrap-line.exp
@@ -86,12 +86,6 @@  proc test_wrap { width_auto_detected } {
 	gdb_assert { $gdb_width == [expr $readline_width + 1] }
     }
 
-    if { $width_auto_detected && $::term == "ansi" } {
-	if { $gdb_width == [expr $env_width - 1] || $gdb_width == $env_width } {
-	    # Generate KFAIL or KPASS.
-	    setup_kfail "cli/30346" "*-*-*"
-	}
-    }
     gdb_assert { $gdb_width == $env_width } "width"
 
     # New prompt, but avoid emitting a pass in order to avoid ending the line
diff --git a/gdb/testsuite/gdb.tui/wrap-line.exp b/gdb/testsuite/gdb.tui/wrap-line.exp
index b28170808b8..f1e07a7decd 100644
--- a/gdb/testsuite/gdb.tui/wrap-line.exp
+++ b/gdb/testsuite/gdb.tui/wrap-line.exp
@@ -92,12 +92,6 @@  proc test_wrap_cli_tui { auto_detected_width } {
 	}
     }
 
-    if { $auto_detected_width } {
-	if { $gdb_width == [expr $::cols - 1] || $gdb_width == $::cols } {
-	    # Generate KFAIL or KPASS.
-	    setup_kfail "cli/30346" "*-*-*"
-	}
-    }
     gdb_assert { $gdb_width == $::cols } "width"
 
     # TERM=ansi, so readline hides the last column.
diff --git a/gdb/utils.c b/gdb/utils.c
index 3af54ec5179..e3857592fc5 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -1161,7 +1161,7 @@  init_page_info (void)
       readline_hidden_cols = _rl_term_autowrap ? 0 : 1;
 
       lines_per_page = rows;
-      chars_per_line = cols;
+      chars_per_line = cols + readline_hidden_cols;
 
       /* Readline should have fetched the termcap entry for us.
 	 Only try to use tgetnum function if rl_get_screen_size