Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Andrew Burgess <aburgess@redhat.com>
To: gdb-patches@sourceware.org
Cc: Andrew Burgess <aburgess@redhat.com>,
	Patryk Sondej <patryk.sondej@gmail.com>
Subject: [PATCH] gdb: fix handling of raw ANSI escape sequences printed from Python
Date: Thu, 15 Jan 2026 11:06:48 +0000	[thread overview]
Message-ID: <2b96eaf47bcb84cf955f4e59ec34c8582b5ceb81.1768475197.git.aburgess@redhat.com> (raw)

Bug PR gdb/33748 reports a regression with print styled output from
Python when using ANSI escape sequences to apply the styling.  This
regression was introduced by commit:

  commit 3825c972a636852600b47c242826313f4b9963b8
  Date:   Wed Jun 18 15:02:29 2025 +0100

      gdb: allow gdb.Color to work correctly with pagination

Prior to this commit GDB would always forward any ANSI escape
sequences directly to the output stream, but this meant that GDB
didn't know which style was currently in effect.

The above commit changed GDB so that we would parse the ANSI escape
sequence, and then apply it to the output stream, this allowed GDB to
track which style was in use, which in turn meant that GDB could
correctly suspend the style and reapply it when the pager was
activated.

The problem though is that ANSI escape sequences can be built up in
parts.  For example, a user can emit the sequence to change the
foreground blue, and then later emit the sequence to change the text
to bold.  The result is output that is both blue and bold.

In the above commit, when parsing an incoming ANSI sequence, GDB was
always starting from the default styling state.  The result of parsing
the ANSI sequence was then being applied.  In our above example, this
meant that when parsing the sequence for bold text we would "forget"
that the current style had a blue foreground color.

This can be easily fixed by starting from the current style, rather
than the default style.

This fix was suggested by Patryk Sondej who originally reported the
bug.

Co-Authored-By: Patryk Sondej <patryk.sondej@gmail.com>
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33748
---
 .../gdb.python/py-color-via-ansi-esc.exp      | 70 +++++++++++++++++++
 gdb/utils.c                                   |  5 +-
 2 files changed, 74 insertions(+), 1 deletion(-)
 create mode 100644 gdb/testsuite/gdb.python/py-color-via-ansi-esc.exp

diff --git a/gdb/testsuite/gdb.python/py-color-via-ansi-esc.exp b/gdb/testsuite/gdb.python/py-color-via-ansi-esc.exp
new file mode 100644
index 00000000000..9aac552fe1a
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-color-via-ansi-esc.exp
@@ -0,0 +1,70 @@
+# Copyright (C) 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/>.
+
+# This file is part of the GDB testsuite.  It tests styled output from
+# Python via raw ANSI escape sequences.
+
+load_lib gdb-python.exp
+
+require allow_python_tests
+require {!is_remote host}
+
+# Start with a fresh GDB, but enable color support.
+with_ansi_styling_terminal {
+    clean_restart
+}
+
+# Create two variables in the parent scope called ${NAME} and
+# ${NAME}_re.  The variable ${NAME} will be the string for the ANSI
+# escape sequence containing VALUE, and ${NAME}_re will be the regular
+# expression to match that same sequence.
+proc setup_ansi { name value } {
+    upvar 1 $name var
+    upvar 1 ${name}_re var_re
+
+    set var "\\033\[${value}m"
+    set var_re "\033\\\[${value}m"
+}
+
+# Different colors.
+setup_ansi red 31
+setup_ansi green 32
+setup_ansi blue 34
+
+# Different intensities.
+setup_ansi normal 22
+setup_ansi bold 1
+setup_ansi dim 2
+
+# Italic.
+setup_ansi italic 3
+setup_ansi no_italic 23
+
+# Underline.
+setup_ansi underline 4
+setup_ansi no_underline 24
+
+# Restore all settings to default.
+setup_ansi default 0
+
+gdb_test_no_output "python flag=\"OUTPUT=\""
+
+gdb_test "python print('%s${blue}blue ${bold}blue+bold ${green}green+bold ${normal}green ${red}red${default}' % (flag))" \
+    "OUTPUT=${blue_re}blue ${bold_re}blue\\+bold ${green_re}green\\+bold ${normal_re}green ${red_re}red${default_re}" \
+    "foreground colors and bold"
+
+gdb_test "python print('%snormal ${italic}italic ${underline}italic+underline ${no_underline}italic ${no_italic}normal' % (flag))" \
+    "OUTPUT=normal ${italic_re}italic ${underline_re}italic\\+underline ${no_underline_re}italic ${no_italic_re}normal" \
+    "italic and underline"
diff --git a/gdb/utils.c b/gdb/utils.c
index 876aad1c448..8c5f34b9687 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -1703,8 +1703,11 @@ pager_file::puts (const char *linebuffer)
 	      /* We don't consider escape sequences as characters, so we
 		 don't increment chars_printed here.  */
 
+	      /* This style sequence might not set every style attribute,
+		 so start with the currently applied style, and update
+		 that.  */
 	      size_t style_len;
-	      ui_file_style style;
+	      ui_file_style style = m_applied_style;
 	      if (style.parse (linebuffer, &style_len)
 		  && style_len <= skip_bytes)
 		{

base-commit: 141f3b0ce1a4141ec0bbd19f1c5713999113a7de
-- 
2.47.1


             reply	other threads:[~2026-01-15 11:07 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-15 11:06 Andrew Burgess [this message]
2026-01-15 16:00 ` Tom Tromey
2026-01-15 16:51   ` Andrew Burgess
2026-01-15 17:17     ` Tom Tromey

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=2b96eaf47bcb84cf955f4e59ec34c8582b5ceb81.1768475197.git.aburgess@redhat.com \
    --to=aburgess@redhat.com \
    --cc=gdb-patches@sourceware.org \
    --cc=patryk.sondej@gmail.com \
    /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