Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Tom Tromey <tom@tromey.com>
To: gdb-patches@sourceware.org
Cc: Tom Tromey <tom@tromey.com>
Subject: [PATCH 5/5] Add zebra-striping to CLI table display
Date: Fri, 12 Jun 2026 08:25:25 -0600	[thread overview]
Message-ID: <20260612-submit-zebra-style-v1-5-cfd00b5c984c@tromey.com> (raw)
In-Reply-To: <20260612-submit-zebra-style-v1-0-cfd00b5c984c@tromey.com>

This patch adds two new style settings to gdb.  These can be used to
add "zebra striping" to CLI tables -- that is, change the prevailing
style of alternating lines of a table.

Modifying the CLI ui-out is sufficient for most tables.  However, this
did not work for stack traces, because those aren't ordinary tables.
This patch uses the "phony table" support (added earlier in this
series) to achieve the same effect without otherwise impacting stack
trace display.

By default, styles are only changed if 256 colors are available.  This
way we can choose a relatively innocuous grey background.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32285
---
 gdb/NEWS                               | 10 +++++
 gdb/cli-out.c                          | 24 +++++++++--
 gdb/cli-out.h                          | 10 +++++
 gdb/cli/cli-style.c                    | 43 +++++++++++++++++-
 gdb/cli/cli-style.h                    |  6 ++-
 gdb/doc/gdb.texinfo                    |  8 ++++
 gdb/stack.c                            |  6 +++
 gdb/testsuite/gdb.base/style.exp       |  3 ++
 gdb/testsuite/gdb.base/zebra-style.c   | 32 ++++++++++++++
 gdb/testsuite/gdb.base/zebra-style.exp | 79 ++++++++++++++++++++++++++++++++++
 gdb/testsuite/lib/gdb-utils.exp        | 14 +++---
 gdb/ui-out.c                           |  8 +++-
 gdb/ui-out.h                           |  2 +
 gdb/utils.c                            |  6 +++
 14 files changed, 238 insertions(+), 13 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index d5214a98a57..99f3eccb11a 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -136,6 +136,16 @@ show progress-bars enabled
   content, to be disabled (the set command), or to see if
   progress-bars are currently enabled or not (the show command).
 
+set style even-lines foreground COLOR
+set style even-lines background COLOR
+set style even-lines intensity VALUE
+set style odd-lines foreground COLOR
+set style odd-lines background COLOR
+set style odd-lines intensity VALUE
+  Control the styling of even and odd lines of tables.  These style
+  settings are merged with any other style that would normally be
+  applied when displaying the table.
+
 info proc environ
   Print the initial environment variables of the specified process.
   Supported on Linux.
diff --git a/gdb/cli-out.c b/gdb/cli-out.c
index e1501f5c652..5f0d4bfe0a5 100644
--- a/gdb/cli-out.c
+++ b/gdb/cli-out.c
@@ -42,6 +42,9 @@ cli_ui_out::do_table_begin (int nbrofcols, int nr_rows, const char *tblid)
     /* Only the table suppresses the output and, fortunately, a table
        is not a recursive data structure.  */
     gdb_assert (!m_suppress_output);
+
+  /* Rows start at 1.  */
+  m_row_number = 1;
 }
 
 /* Mark beginning of a table body */
@@ -62,6 +65,7 @@ void
 cli_ui_out::do_table_end (bool phony)
 {
   m_suppress_output = false;
+  m_style = ui_file_style ();
 }
 
 /* Specify table header */
@@ -78,6 +82,18 @@ cli_ui_out::do_table_header (int width, ui_align alignment,
 		   title_style.style ());
 }
 
+/* See ui-out.h.  */
+
+void
+cli_ui_out::do_start_row ()
+{
+  ui_out::do_start_row ();
+  m_style = ((m_row_number % 2 == 0)
+	     ? even_background_style
+	     : odd_background_style).style ();
+  ++m_row_number;
+}
+
 /* Mark beginning of a list */
 
 void
@@ -175,7 +191,7 @@ cli_ui_out::do_field_string (int fldno, int width, ui_align align,
   if (string)
     {
       ui_file *stream = m_streams.back ();
-      stream->emit_style_escape (style);
+      stream->emit_style_escape (m_style.merge (style));
       stream->puts (string);
       stream->emit_style_escape (ui_file_style ());
     }
@@ -208,7 +224,7 @@ cli_ui_out::do_spaces (int numspaces)
   if (m_suppress_output)
     return;
 
-  print_spaces (numspaces, m_streams.back ());
+  fputs_styled (n_spaces (numspaces), m_style, m_streams.back ());
 }
 
 void
@@ -217,7 +233,7 @@ cli_ui_out::do_text (const char *string)
   if (m_suppress_output)
     return;
 
-  gdb_puts (string, m_streams.back ());
+  fputs_styled (string, m_style, m_streams.back ());
 }
 
 void
@@ -458,7 +474,7 @@ cli_ui_out::do_progress_end ()
 void
 cli_ui_out::field_separator ()
 {
-  gdb_putc (' ', m_streams.back ());
+  fputs_styled (" ", m_style, m_streams.back ());
 }
 
 /* Constructor for cli_ui_out.  */
diff --git a/gdb/cli-out.h b/gdb/cli-out.h
index ca138e5ad9a..facb2fa3931 100644
--- a/gdb/cli-out.h
+++ b/gdb/cli-out.h
@@ -48,6 +48,8 @@ class cli_ui_out : public ui_out
   /* This overload is used for "phony" tables.  */
   void do_table_begin () override
   {
+    /* For a phony table, just set the row.  */
+    m_row_number = 1;
   }
 
   virtual void do_table_body () override;
@@ -90,6 +92,8 @@ class cli_ui_out : public ui_out
 				   double, double) override;
   virtual void do_progress_end () override;
 
+  void do_start_row () override;
+
   bool suppress_output ()
   { return m_suppress_output; }
 
@@ -100,6 +104,12 @@ class cli_ui_out : public ui_out
   std::vector<ui_file *> m_streams;
   bool m_suppress_output;
 
+  /* When displaying a table, the current row.  */
+  int m_row_number = 0;
+
+  /* The prevailing background style, used for zebra-striping a table.  */
+  ui_file_style m_style;
+
   /* The state of a recent progress update.  */
   struct cli_progress_info
   {
diff --git a/gdb/cli/cli-style.c b/gdb/cli/cli-style.c
index 03a887232c7..9f727903e72 100644
--- a/gdb/cli/cli-style.c
+++ b/gdb/cli/cli-style.c
@@ -179,6 +179,32 @@ cli_style_option version_style ("version", ui_file_style::MAGENTA,
 
 /* See cli-style.h.  */
 
+cli_style_option even_background_style ("even-lines", ui_file_style::NONE);
+
+/* Helper function to compute the initial value of the odd background
+   style.  */
+
+static ui_file_style::color
+get_initial_odd_color ()
+{
+  const std::vector<color_space> &colors = colorsupport ();
+  auto iter = std::find (colors.begin (), colors.end (),
+			 color_space::RGB_24BIT);
+  /* If 24-bit color is available, use a light grey; otherwise just do
+     nothing.  */
+  if (iter == colors.end ())
+    return ui_file_style::NONE;
+  return ui_file_style::color (0x33, 0x33, 0x33);
+}
+
+/* See cli-style.h.  */
+
+cli_style_option odd_background_style
+     ("odd-lines", ui_file_style::NONE, ui_file_style::NORMAL,
+      get_initial_odd_color ());
+
+/* See cli-style.h.  */
+
 cli_style_option disasm_mnemonic_style ("mnemonic", ui_file_style::GREEN);
 
 /* See cli-style.h.  */
@@ -202,11 +228,12 @@ cli_style_option line_number_style ("line-number", ui_file_style::DIM);
 
 cli_style_option::cli_style_option (const char *name,
 				    ui_file_style::basic_color fg,
-				    ui_file_style::intensity intensity)
+				    ui_file_style::intensity intensity,
+				    ui_file_style::color bg)
   : changed (name),
     m_name (name),
     m_foreground (fg),
-    m_background (ui_file_style::NONE),
+    m_background (bg),
     m_intensity (cli_intensities[intensity])
 {
 }
@@ -705,6 +732,18 @@ coming from your source code."),
 				       &style_set_list, &style_show_list,
 				       false);
 
+  even_background_style.add_setshow_commands (no_class, _("\
+Display styling for even-numbered lines.\n\
+Configure colors used to display even-numbered lines in tables."),
+				      &style_set_list, &style_show_list,
+				      false);
+
+  odd_background_style.add_setshow_commands (no_class, _("\
+Display styling for odd-numbered lines.\n\
+Configure colors used to display odd-numbered lines in tables."),
+				      &style_set_list, &style_show_list,
+				      false);
+
   /* Setup 'disassembler address' style and 'disassembler symbol' style,
      these are aliases for 'address' and 'function' styles respectively.  */
   add_alias_cmd ("address", address_prefix_cmds.set, no_class, 0,
diff --git a/gdb/cli/cli-style.h b/gdb/cli/cli-style.h
index bd4c007228e..cbe7ed1a173 100644
--- a/gdb/cli/cli-style.h
+++ b/gdb/cli/cli-style.h
@@ -31,7 +31,8 @@ class cli_style_option
 
   /* Construct a CLI style option with a foreground color.  */
   cli_style_option (const char *name, ui_file_style::basic_color fg,
-		    ui_file_style::intensity = ui_file_style::NORMAL);
+		    ui_file_style::intensity = ui_file_style::NORMAL,
+		    ui_file_style::color bg = ui_file_style::NONE);
 
   /* Construct a CLI style option with an intensity.  */
   cli_style_option (const char *name, ui_file_style::intensity i);
@@ -151,6 +152,9 @@ extern cli_style_option version_style;
 /* The style for a line number.  */
 extern cli_style_option line_number_style;
 
+extern cli_style_option even_background_style;
+extern cli_style_option odd_background_style;
+
 /* True if source styling is enabled.  */
 extern bool source_styling;
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index a698b2b8451..15dc5253c14 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -28590,6 +28590,14 @@ family of commands.  This style is only used when @value{GDBN} is
 styling using its builtin disassembler library.  By default, this style's
 foreground color is red.
 
+@item even-lines
+@itemx odd-lines
+Control the styling of lines in a table, such as the output of
+@code{info break}.  These styles are used for even- and odd-numbered
+lines, respectively.  Note that, unlike most other styles mentioned
+here, these are merged with any other style that might be applied when
+displaying the table.
+
 @end table
 
 @node Numbers
diff --git a/gdb/stack.c b/gdb/stack.c
index e084976eabf..5667c103616 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -1973,6 +1973,12 @@ backtrace_command_1 (const frame_print_options &fp_opts,
       else
 	trailing = get_current_frame ();
 
+      /* Make a phony table -- we don't want a real table, because we
+	 don't want headers.  But using a table is the easiest way to
+	 get zebra stripes, which we do want.  */
+      ui_out_emit_table phony_table (current_uiout);
+      current_uiout->table_body ();
+
       for (fi = trailing; fi && count--; fi = get_prev_frame (fi))
 	{
 	  QUIT;
diff --git a/gdb/testsuite/gdb.base/style.exp b/gdb/testsuite/gdb.base/style.exp
index eb1cdf46112..02cbd23068d 100644
--- a/gdb/testsuite/gdb.base/style.exp
+++ b/gdb/testsuite/gdb.base/style.exp
@@ -116,6 +116,9 @@ proc run_style_tests { } {
 	    [multi_line \
 		 "#0\\s+$main_expr\\s+\\($arg_expr=$decimal,\\s+$arg_expr=$hex.*\\)\\s+at\\s+$file_expr" \
 		 "$line_expr\\s+.*return.* break here .*"]
+
+	# We don't need to test zebra styling here.
+	gdb_test_no_output "set style odd-lines background none"
 	gdb_test "info breakpoints" \
 	    ".*[limited_style What title].*$main_expr at $file_expr.*"
 
diff --git a/gdb/testsuite/gdb.base/zebra-style.c b/gdb/testsuite/gdb.base/zebra-style.c
new file mode 100644
index 00000000000..9fcc72a244f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/zebra-style.c
@@ -0,0 +1,32 @@
+/* Copyright 2026 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+int
+one (int x)
+{
+  return x + 1;
+}
+
+int
+two (int x)
+{
+  return one (x) + 1;
+}
+
+int
+main (int argc, char **argv)
+{
+  return two (-2);
+}
diff --git a/gdb/testsuite/gdb.base/zebra-style.exp b/gdb/testsuite/gdb.base/zebra-style.exp
new file mode 100644
index 00000000000..2b13f065d5c
--- /dev/null
+++ b/gdb/testsuite/gdb.base/zebra-style.exp
@@ -0,0 +1,79 @@
+# Copyright 2026 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test zebra striping.
+
+standard_testfile
+
+# Style a single line of a "bt".  Only some parts of the text are
+# really checked.  Returns a regexp that can be used to match the
+# line.
+proc style_bt_line {num name filename bg} {
+    # The code lamely emits too many escapes.
+    set result [style "#" reset $bg][style $num reset $bg]
+    append result ".*?"
+    append result [style $name function $bg]
+    append result ".*?"
+    append result [style $filename file $bg]
+    append result ".*?\r\n"
+    return $result
+}
+
+# Style a single line of "info break".  Only some parts of the text
+# are really checked.  Returns a regexp that can be used to match the
+# line.
+proc style_info_line {num name filename bg} {
+    set result [style $num reset $bg]
+    append result ".*?"
+    append result [style $name function $bg]
+    append result ".*?"
+    append result [style $filename file $bg]
+    append result ".*?\r\n"
+    return $result
+}
+
+with_ansi_styling_terminal {
+    if {[prepare_for_testing "failed to prepare" $testfile $srcfile debug]} {
+	return
+    }
+
+    if {![runto one]} {
+	return
+    }
+
+    gdb_test_no_output "set filename-display basename"
+    gdb_test_no_output "set style odd-lines background red"
+    gdb_test_no_output "set style even-lines background black"
+
+    gdb_test_no_output "set style enabled on"
+
+    gdb_test_sequence backtrace "" \
+	[list \
+	     [style_bt_line 0 one zebra-style.c 41] \
+	     [style_bt_line 1 two zebra-style.c 40] \
+	     [style_bt_line 2 main zebra-style.c 41]]
+
+    gdb_breakpoint two
+    gdb_breakpoint main
+
+    gdb_test_sequence "info break" "" \
+	-prompt "$gdb_prompt.*?" \
+	[list \
+	     ".*?Num.*?Address.*What.*?\r\n" \
+	     [style_info_line 1 one zebra-style.c 41] \
+	     [string cat [style "\tbreakpoint" reset 41] ".*?\r\n"] \
+	     [style_info_line 2 two zebra-style.c 40] \
+	     [style_info_line 3 main zebra-style.c 41]]
+}
diff --git a/gdb/testsuite/lib/gdb-utils.exp b/gdb/testsuite/lib/gdb-utils.exp
index cabeb7aa1ed..01d8a1413d6 100644
--- a/gdb/testsuite/lib/gdb-utils.exp
+++ b/gdb/testsuite/lib/gdb-utils.exp
@@ -64,13 +64,16 @@ proc string_list_to_regexp { args } {
 # style to STYLE, and one to reset the style to the default.  The
 # return value is suitable for use as a regular expression.
 
-# STYLE can either be the payload part of an ANSI terminal sequence,
-# or a shorthand for one of the gdb standard styles: "file",
-# "function", "variable", "address", etc.
+# STYLE is a shorthand for one of the gdb standard styles: "file",
+# "function", "variable", "address", etc.  It can also be "none",
+# where STR is returned verbatim, or "reset", where the default style
+# setting (but including the BG parameter) is used.
 
-proc style {str style} {
+# BG is the background color to use.  This option can be useful when
+# testing zebra-striping.
+
+proc style {str style {bg 49}} {
     set fg 39
-    set bg 49
     set intensity 22
     set italic 23
     set underline 24
@@ -86,6 +89,7 @@ proc style {str style} {
 	metadata { set intensity 2 }
 	version { set fg 35; set intensity 1 }
 	line-number { set intensity 2 }
+	reset { }
 	none { return $str }
     }
     return "\033\\\[${fg};${bg};${intensity};${italic};${underline};${reverse}m${str}\033\\\[m"
diff --git a/gdb/ui-out.c b/gdb/ui-out.c
index 1c8ceaa90ee..4add679e7a9 100644
--- a/gdb/ui-out.c
+++ b/gdb/ui-out.c
@@ -414,6 +414,12 @@ ui_out::table_end ()
   m_table_up = nullptr;
 }
 
+void
+ui_out::do_start_row ()
+{
+  m_table_up->start_row ();
+}
+
 void
 ui_out::begin (ui_out_type type, const char *id)
 {
@@ -439,7 +445,7 @@ ui_out::begin (ui_out_type type, const char *id)
   if (m_table_up != nullptr
       && m_table_up->current_state () == ui_out_table::state::BODY
       && m_table_up->entry_level () == level ())
-    m_table_up->start_row ();
+    do_start_row ();
 
   do_begin (type, id);
 }
diff --git a/gdb/ui-out.h b/gdb/ui-out.h
index 12da0084332..7cc299d2cd0 100644
--- a/gdb/ui-out.h
+++ b/gdb/ui-out.h
@@ -397,6 +397,8 @@ class ui_out
   virtual bool do_is_mi_like_p () const
   { return false; }
 
+  virtual void do_start_row ();
+
  private:
 
   /* A table can only be started or ended by ui_out_emit_table.  */
diff --git a/gdb/utils.c b/gdb/utils.c
index 4f99cdb425b..7bbb4a7c59f 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -1833,7 +1833,13 @@ pager_file::puts (const char *linebuffer)
 	  chars_printed = 0;
 	  wrap_here (0); /* Spit out chars, cancel further wraps.  */
 	  lines_printed++;
+	  const ui_file_style save_style = m_applied_style;
+	  const ui_file_style empty_style;
+	  if (save_style != empty_style)
+	    m_stream->emit_style_escape (ui_file_style ());
 	  m_stream->puts ("\n");
+	  if (save_style != empty_style)
+	    m_stream->emit_style_escape (save_style);
 	  linebuffer++;
 	}
     }

-- 
2.49.0


  parent reply	other threads:[~2026-06-12 14:27 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-12 14:25 [PATCH 0/5] Add zebra-striping to CLI tables Tom Tromey
2026-06-12 14:25 ` [PATCH 1/5] Ensure tgetent is called before tgetnum Tom Tromey
2026-06-12 14:25 ` [PATCH 2/5] Make two ui_out methods 'private' Tom Tromey
2026-06-12 14:25 ` [PATCH 3/5] Allow "phony" ui-out tables Tom Tromey
2026-06-12 14:25 ` [PATCH 4/5] Add ui_file_style::merge Tom Tromey
2026-06-12 14:25 ` Tom Tromey [this message]
2026-06-12 15:14   ` [PATCH 5/5] Add zebra-striping to CLI table display Eli Zaretskii
2026-06-13 14:28   ` Matt Rice

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260612-submit-zebra-style-v1-5-cfd00b5c984c@tromey.com \
    --to=tom@tromey.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox