Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Tom de Vries <tdevries@suse.de>
To: Andrew Burgess <aburgess@redhat.com>, gdb-patches@sourceware.org
Subject: Re: [PATCHv7 1/4] gdb: allow gdb.Color to work correctly with pagination
Date: Mon, 25 Aug 2025 12:21:38 +0200	[thread overview]
Message-ID: <7af123b1-ded2-40bb-b6af-7c5d4bb6f17a@suse.de> (raw)
In-Reply-To: <87y0r866lq.fsf@redhat.com>

On 8/24/25 18:13, Andrew Burgess wrote:
> Andrew Burgess <aburgess@redhat.com> writes:
> 
>> This commit allows gdb.Color objects to be used to style output from
>> GDB commands written in Python, and the styled output should work
>> correctly with pagination.
> 
> I've gone ahead and pushed this fix.
> 

The new test-case fails for me on aarch64-linux.  I've filed a PR ( 
https://sourceware.org/bugzilla/show_bug.cgi?id=33321 ) to track this.

Thanks,
- Tom

> I believe that the change I've made here is inline with how the same
> problem is handled in the TUI, parsing the escape sequence and then
> using the resulting ui_file_style object.  And the second part of the
> fix, changing gdb_printf to gdb_puts falls out from making the first
> change.
> 
> Given that the gdb.Color API was added since GDB 16, it seems sensible
> to get this bug fixed before GDB 17 branches.
> 
> The other patches in this series I've not pushed, pending review.
> 
> Thanks,
> Andrew
> 
> 
> 
>>
>> There are two parts to fixing this:
>>
>> First, GDB needs to be able to track the currently applied style
>> within the page_file class.  This means that style changes need to be
>> achieved with calls to pager_file::emit_style_escape.
>>
>> Now usually, GDB does this by calling something like fprintf_styled,
>> which takes care to apply the style for us.  However, that's not
>> really an option here as a gdb.Color isn't a full style, and as the
>> gdb.Color object is designed to be converted directly into escape
>> sequences that can then be printed, we really need a solution that
>> works with this approach.
>>
>> However pager_file::puts already has code in place to handle escape
>> sequences.  Right now all this code does is spot the escape sequence
>> and append it to the m_wrap_buffer.  But in this commit I propose that
>> we go one step further, parse the escape sequence back into a
>> ui_file_style object in pager_file::puts, and then we can call
>> pager_file::emit_style_escape.
>>
>> If the parsing doesn't work then we can just add the escape sequence
>> to m_wrap_buffer as we did before.
>>
>> But wait, how can this work if a gdb.Color isn't a full style?  Turns
>> out that's not a problem.  We only ever emit the escape sequence for
>> those parts of a style that need changing, so a full style that sets
>> the foreground color will emit the same escape sequence as a gdb.Color
>> for the foreground.  When we convert the escape sequence back into a
>> ui_file_style, then we get a style with everything set to default,
>> except the foreground color.
>>
>> I had hoped that this would be all that was needed.  But unfortunately
>> this doesn't work because of the second problem...
>>
>> ... the implementation of the Python function gdb.write() calls
>> gdb_printf(), which calls gdb_vprintf(), which calls ui_file::vprintf,
>> which calls ui_out::vmessage, which calls ui_out::call_do_message, and
>> finally we reach cli_ui_out::do_message.  This final do_message
>> function does this:
>>
>>    ui_file *stream = m_streams.back ();
>>    stream->emit_style_escape (style);
>>    stream->puts (str.c_str ());
>>    stream->emit_style_escape (ui_file_style ());
>>
>> If we imagine the case where we are emitting a style, triggered from
>> Python like this:
>>
>>    gdb.write(gdb.Color('red').escape_sequence(True))
>>
>> the STYLE in this case will be the default ui_file_style(), and STR
>> will hold the escape sequence we are writing.
>>
>> After the first change, where pager_file::puts now calls
>> pager_file::emit_style_escape, the current style of STREAM will have
>> been updated.  But this means that the final emit_style_escape will
>> now restore the default style.
>>
>> The fix for this is to avoid using the high level gdb_printf from
>> gdb.write(), and instead use gdb_puts instead.  The gdb_puts function
>> doesn't restore the default style, which means our style modification
>> survives.
>>
>> There's a new test included.  This test includes what appears like a
>> pointless extra loop (looping over a single value), but later commits
>> in this series will add more values to this list.
>> ---
>>   gdb/python/python.c                           |  18 +--
>>   .../gdb.python/py-color-pagination.exp        | 122 ++++++++++++++++++
>>   .../gdb.python/py-color-pagination.py         |  46 +++++++
>>   gdb/utils.c                                   |  21 ++-
>>   4 files changed, 195 insertions(+), 12 deletions(-)
>>   create mode 100644 gdb/testsuite/gdb.python/py-color-pagination.exp
>>   create mode 100644 gdb/testsuite/gdb.python/py-color-pagination.py
>>
>> diff --git a/gdb/python/python.c b/gdb/python/python.c
>> index cb0d642a67d..1af7896eb08 100644
>> --- a/gdb/python/python.c
>> +++ b/gdb/python/python.c
>> @@ -1570,21 +1570,21 @@ gdbpy_write (PyObject *self, PyObject *args, PyObject *kw)
>>   
>>     try
>>       {
>> +      ui_file *stream;
>>         switch (stream_type)
>>   	{
>>   	case 1:
>> -	  {
>> -	    gdb_printf (gdb_stderr, "%s", arg);
>> -	    break;
>> -	  }
>> +	  stream = gdb_stderr;
>> +	  break;
>>   	case 2:
>> -	  {
>> -	    gdb_printf (gdb_stdlog, "%s", arg);
>> -	    break;
>> -	  }
>> +	  stream = gdb_stdlog;
>> +	  break;
>>   	default:
>> -	  gdb_printf (gdb_stdout, "%s", arg);
>> +	  stream = gdb_stdout;
>> +	  break;
>>   	}
>> +
>> +      gdb_puts (arg, stream);
>>       }
>>     catch (const gdb_exception &except)
>>       {
>> diff --git a/gdb/testsuite/gdb.python/py-color-pagination.exp b/gdb/testsuite/gdb.python/py-color-pagination.exp
>> new file mode 100644
>> index 00000000000..3235fffe5cc
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.python/py-color-pagination.exp
>> @@ -0,0 +1,122 @@
>> +# Copyright (C) 2025 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 gdb.Color and how this
>> +# interacts with GDB's pagination system.
>> +
>> +load_lib gdb-python.exp
>> +
>> +require allow_python_tests
>> +
>> +standard_testfile
>> +
>> +set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py]
>> +
>> +set str "<[string repeat - 78]>"
>> +
>> +# These define all the default attributes for a style: background
>> +# color, intensity, italics, and underlined.
>> +set other_attr ";49;22;23;24;27"
>> +
>> +# These colors set the foreground color only.  Everything else is the
>> +# default.
>> +set black "(?:\033\\\[30${other_attr}m)"
>> +set red "(?:\033\\\[31${other_attr}m)"
>> +set green "(?:\033\\\[32${other_attr}m)"
>> +set yellow "(?:\033\\\[33${other_attr}m)"
>> +set blue "(?:\033\\\[34${other_attr}m)"
>> +set magenta "(?:\033\\\[35${other_attr}m)"
>> +set cyan "(?:\033\\\[36${other_attr}m)"
>> +set white "(?:\033\\\[37${other_attr}m)"
>> +
>> +set any_color "(?:${black}|${red}|${green}|${yellow}|${blue}|${magenta}|${cyan}|${white})"
>> +
>> +# Run the command 'TYPE-fill MODE' which fills the screen with output and
>> +# triggers the pagination prompt.  Check that styling is applied correctly
>> +# to the output.
>> +proc test_pagination { type mode } {
>> +
>> +    # Start with a fresh GDB, but enable color support.
>> +    with_ansi_styling_terminal {
>> +	clean_restart
>> +    }
>> +
>> +    gdb_test_no_output "source $::pyfile" "source the script"
>> +
>> +    gdb_test_no_output "set width 80"
>> +    gdb_test_no_output "set height 15"
>> +
>> +    set saw_bad_color_handling false
>> +    set expected_restore_color ""
>> +    set last_color ""
>> +    gdb_test_multiple "$type-fill $mode" "" {
>> +	-re "^$type-fill $mode\r\n" {
>> +	    exp_continue
>> +	}
>> +
>> +	-re "^(${::any_color}?)(${::any_color})$::str" {
>> +	    # After a continuation prompt GDB will restore the previous
>> +	    # color, and then we immediately switch to a new color.
>> +	    set restored_color $expect_out(1,string)
>> +	    if { $restored_color ne ""
>> +		 && $restored_color ne $expected_restore_color } {
>> +		set saw_bad_color_handling true
>> +	    }
>> +	    set last_color $expect_out(2,string)
>> +	    exp_continue
>> +	}
>> +
>> +	-re "^\033\\\[${::decimal}m$::str" {
>> +	    # This catches the case where the color's escape sequence has
>> +	    # not been converted back into a full style.  This indicates
>> +	    # something went wrong in the pager_file::puts function.
>> +	    set saw_bad_color_handling true
>> +	    exp_continue
>> +	}
>> +
>> +	-re "^((?:\033\\\[m)?)$::pagination_prompt$" {
>> +	    # After a pagination prompt we expect GDB to restore the last
>> +	    # color.
>> +	    set expected_restore_color $last_color
>> +
>> +	    # If we didn't see a color reset sequence then the pagination
>> +	    # prompt will have been printed in the wrong color, this is a
>> +	    # GDB bug.
>> +	    set color_reset $expect_out(1,string)
>> +	    if { $color_reset eq "" } {
>> +		set saw_bad_color_handling true
>> +	    }
>> +
>> +	    # Send '\n' to view more output.
>> +	    send_gdb "\n"
>> +	    exp_continue
>> +	}
>> +
>> +	-re "^\r\n" {
>> +	    # The matches the newline sent to the continuation prompt.
>> +	    exp_continue
>> +	}
>> +
>> +	-re "^\033\\\[m\r\n$::gdb_prompt $" {
>> +	    gdb_assert { !$saw_bad_color_handling } $gdb_test_name
>> +	}
>> +    }
>> +}
>> +
>> +foreach_with_prefix type { color } {
>> +    foreach_with_prefix mode { write print } {
>> +	test_pagination $type $mode
>> +    }
>> +}
>> diff --git a/gdb/testsuite/gdb.python/py-color-pagination.py b/gdb/testsuite/gdb.python/py-color-pagination.py
>> new file mode 100644
>> index 00000000000..efd501eedf5
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.python/py-color-pagination.py
>> @@ -0,0 +1,46 @@
>> +# Copyright (C) 2025 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/>.
>> +
>> +import gdb
>> +
>> +basic_colors = ["black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"]
>> +
>> +
>> +def write(mode, text):
>> +    if mode == "write":
>> +        gdb.write(text)
>> +    else:
>> +        print(text, end="")
>> +
>> +
>> +class ColorTester(gdb.Command):
>> +    def __init__(self):
>> +        super().__init__("color-fill", gdb.COMMAND_USER)
>> +
>> +    def invoke(self, args, from_tty):
>> +        mode = args
>> +        str = "<" + "-" * 78 + ">"
>> +        for i in range(0, 20):
>> +            for color_name in basic_colors:
>> +                c = gdb.Color(color_name)
>> +                write(mode, c.escape_sequence(True))
>> +                write(mode, str)
>> +
>> +        default = gdb.Color("none")
>> +        write(mode, default.escape_sequence(True))
>> +        write(mode, "\n")
>> +
>> +
>> +ColorTester()
>> diff --git a/gdb/utils.c b/gdb/utils.c
>> index 10d3d51e481..92e626a9c75 100644
>> --- a/gdb/utils.c
>> +++ b/gdb/utils.c
>> @@ -1702,10 +1702,25 @@ pager_file::puts (const char *linebuffer)
>>   	  else if (*linebuffer == '\033'
>>   		   && skip_ansi_escape (linebuffer, &skip_bytes))
>>   	    {
>> -	      m_wrap_buffer.append (linebuffer, skip_bytes);
>> -	      /* Note that we don't consider this a character, so we
>> +	      /* We don't consider escape sequences as characters, so we
>>   		 don't increment chars_printed here.  */
>> -	      linebuffer += skip_bytes;
>> +
>> +	      size_t style_len;
>> +	      ui_file_style style;
>> +	      if (style.parse (linebuffer, &style_len)
>> +		  && style_len <= skip_bytes)
>> +		{
>> +		  this->emit_style_escape (style);
>> +
>> +		  linebuffer += style_len;
>> +		  skip_bytes -= style_len;
>> +		}
>> +
>> +	      if (skip_bytes > 0)
>> +		{
>> +		  m_wrap_buffer.append (linebuffer, skip_bytes);
>> +		  linebuffer += skip_bytes;
>> +		}
>>   	    }
>>   	  else if (*linebuffer == '\r')
>>   	    {
>> -- 
>> 2.47.1
> 


  reply	other threads:[~2025-08-25 10:22 UTC|newest]

Thread overview: 61+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-06-04  9:39 [PATCH 0/2] Python Style API Andrew Burgess
2025-06-04  9:39 ` [PATCH 1/2] gdb/python: add gdb.Style class Andrew Burgess
2025-06-04  9:39 ` [PATCH 2/2] gdb/python: new class gdb.StyleParameterSet Andrew Burgess
2025-06-06 13:38 ` [PATCHv2 0/2] Python Style API Andrew Burgess
2025-06-06 13:38   ` [PATCHv2 1/2] gdb/python: add gdb.Style class Andrew Burgess
2025-06-06 14:21     ` Eli Zaretskii
2025-06-06 13:38   ` [PATCHv2 2/2] gdb/python: new class gdb.StyleParameterSet Andrew Burgess
2025-06-07 10:44   ` [PATCHv3 0/2] Python Style API Andrew Burgess
2025-06-07 10:44     ` [PATCHv3 1/2] gdb/python: add gdb.Style class Andrew Burgess
2025-06-07 10:44     ` [PATCHv3 2/2] gdb/python: new class gdb.StyleParameterSet Andrew Burgess
2025-06-09 15:54     ` [PATCHv3 0/2] Python Style API Andrew Burgess
2025-06-18 19:30     ` [PATCHv4 0/4] " Andrew Burgess
2025-06-18 19:30       ` [PATCHv4 1/4] gdb: allow gdb.Color to work correctly with pagination Andrew Burgess
2025-06-18 19:30       ` [PATCHv4 2/4] gdb/python: add gdb.Style class Andrew Burgess
2025-06-18 19:30       ` [PATCHv4 3/4] gdb/python: new class gdb.StyleParameterSet Andrew Burgess
2025-06-18 19:30       ` [PATCHv4 4/4] gdb: extend gdb.write to support styled output Andrew Burgess
2025-06-25 14:42       ` [PATCHv5 0/4] Python Style API Andrew Burgess
2025-06-25 14:42         ` [PATCHv5 1/4] gdb: allow gdb.Color to work correctly with pagination Andrew Burgess
2025-06-25 14:42         ` [PATCHv5 2/4] gdb/python: add gdb.Style class Andrew Burgess
2025-06-25 14:42         ` [PATCHv5 3/4] gdb/python: new class gdb.StyleParameterSet Andrew Burgess
2025-06-25 14:42         ` [PATCHv5 4/4] gdb/python: extend gdb.write to support styled output Andrew Burgess
2025-07-07 14:43         ` [PATCHv6 0/4] Python Style API Andrew Burgess
2025-07-07 14:43           ` [PATCHv6 1/4] gdb: allow gdb.Color to work correctly with pagination Andrew Burgess
2025-07-07 14:43           ` [PATCHv6 2/4] gdb/python: add gdb.Style class Andrew Burgess
2025-07-07 14:43           ` [PATCHv6 3/4] gdb/python: new class gdb.StyleParameterSet Andrew Burgess
2025-07-07 14:43           ` [PATCHv6 4/4] gdb/python: extend gdb.write to support styled output Andrew Burgess
2025-08-13 10:25           ` [PATCHv7 0/4] Fix for gdb.Color + pagination AND new gdb.Style API Andrew Burgess
2025-08-13 10:25             ` [PATCHv7 1/4] gdb: allow gdb.Color to work correctly with pagination Andrew Burgess
2025-08-24 16:13               ` Andrew Burgess
2025-08-25 10:21                 ` Tom de Vries [this message]
2025-08-26 14:35                   ` [PATCH] gdb/testsuite: work around empty substring bug in expect Andrew Burgess
2025-08-27  6:24                     ` Tom de Vries
2025-08-13 10:29             ` [PATCHv7 2/4] gdb/python: add gdb.Style class Andrew Burgess
2025-08-13 10:30             ` [PATCHv7 4/4] gdb/python: extend gdb.write to support styled output Andrew Burgess
2025-08-13 12:37               ` Eli Zaretskii
2025-08-13 10:34             ` [PATCHv7 3/4] gdb/python: new class gdb.StyleParameterSet Andrew Burgess
2025-08-13 13:05               ` Eli Zaretskii
2025-08-13 13:05               ` Eli Zaretskii
2025-08-27 11:34             ` [PATCHv8 0/3] new gdb.Style API Andrew Burgess
2025-08-27 11:34               ` [PATCHv8 1/3] gdb/python: add gdb.Style class Andrew Burgess
2025-09-16 16:47                 ` Tom Tromey
2025-09-23 16:59                   ` Andrew Burgess
2025-08-27 11:34               ` [PATCHv8 2/3] gdb/python: new class gdb.StyleParameterSet Andrew Burgess
2025-09-16 16:50                 ` Tom Tromey
2025-08-27 11:34               ` [PATCHv8 3/3] gdb/python: extend gdb.write to support styled output Andrew Burgess
2025-09-16 16:56                 ` Tom Tromey
2025-09-23 17:05                   ` Andrew Burgess
2025-09-23 18:38                     ` Tom Tromey
2025-09-23 16:54               ` [PATCHv9 0/3] new gdb.Style API Andrew Burgess
2025-09-23 16:54                 ` [PATCHv9 1/3] gdb/python: add gdb.Style class Andrew Burgess
2025-09-23 16:54                 ` [PATCHv9 2/3] gdb/python: new class gdb.StyleParameterSet Andrew Burgess
2025-09-23 16:54                 ` [PATCHv9 3/3] gdb/python: extend gdb.write to support styled output Andrew Burgess
2025-10-03 19:27                 ` [PATCHv9 0/3] new gdb.Style API Tom Tromey
2025-10-05 12:51                   ` Andrew Burgess
2025-10-05 15:16                     ` Tom de Vries
2025-10-05 17:59                       ` Tom Tromey
2025-10-06  9:01                         ` Andrew Burgess
2025-10-05 18:03                       ` Andrew Burgess
2025-10-05 18:41                         ` Tom de Vries
2025-10-06  9:01                           ` Andrew Burgess
2025-10-06 12:29                             ` Tom de Vries

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=7af123b1-ded2-40bb-b6af-7c5d4bb6f17a@suse.de \
    --to=tdevries@suse.de \
    --cc=aburgess@redhat.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