}
}
+# Run an 'apropos' command. Each line of output starts with a
+# non-default style (command style). Ensure that pagination triggers
+# during the 'apropos' output such that, at the point pagination kicks
+# in, a non-default style is in effect.
+#
+# Then, at the pagination prompt, quit the command.
+#
+# Next, run a command which switches to a different style, and then
+# back to the current style.
+#
+# At one point, a bug in the pagination code would leave the
+# non-default style from the 'apropos' command recorded as the current
+# style, such that the second command would switch back to the earlier
+# style.
+proc test_pagination_cmd_after_quit_styling {} {
+ with_ansi_styling_terminal {
+ clean_restart
+ }
+
+ # We're going to use 'apropos time'. Check that with a height of
+ # 12 lines, each line starts with a non-default style, and that we
+ # do see the pagination prompt. This means that there are more
+ # than 12 lines for this command.
+ with_test_prefix "validate apropos output" {
+ gdb_test_no_output "set height 12"
+
+ set saw_pagination_prompt false
+ gdb_test_multiple "apropos time" "" {
+ -re "^apropos time\r\n" {
+ exp_continue
+ }
+ -re "^\033\\\[39;49;1;27m\[^\r\n\]+\r\n" {
+ exp_continue
+ }
+ -re "^$::pagination_prompt$" {
+ set saw_pagination_prompt true
+ send_gdb "q\n"
+ exp_continue
+ }
+ -re "^q\r\n" {
+ exp_continue
+ }
+ -re "^Quit\r\n" {
+ exp_continue
+ }
+ -re "^$::gdb_prompt $" {
+ gdb_assert { $saw_pagination_prompt } $gdb_test_name
+ }
+ -re "^\[^\r\n\]+\r\n" {
+ exp_continue
+ }
+ }
+ }
+
+ # Now reduce the height to 10 and re-run 'apropos time'. Based on
+ # the previous check, we know that this is going to present the
+ # pagination prompt when a non-default style is in use.
+ gdb_test_no_output "set height 10"
+
+ set saw_pagination_prompt false
+ gdb_test_multiple "apropos time" "" {
+ -re "$::pagination_prompt" {
+ set saw_pagination_prompt true
+ send_gdb "q\n"
+ exp_continue
+ }
+ -re "\r\n$::gdb_prompt $" {
+ gdb_assert { $saw_pagination_prompt } $gdb_test_name
+ }
+ }
+
+ # The help output for this maintenance command switches to a
+ # different style, and then back to the default. If the
+ # pagination bug still exists, then this would switch back to the
+ # non-default style that was in use when pagination kicked in
+ # above.
+ gdb_test "maintenance time" \
+ "^\"\033\\\[39;49;1;27mmaintenance time\033\\\[m\" takes a numeric argument\\."
+}
+
+# Helper for test_pagination_prompt_styling. Return false if STR, a
+# line that appears immediately before a pagination prompt, matches
+# the pattern for needing a style reset at the end, but does not have
+# the style reset.
+#
+# In all other cases, return true. So lines that don't match the
+# known pattern for neededing a style reset will always return true,
+# as will lines that match the pattern, and do have the style reset.
+proc previous_line_is_ok { str } {
+
+ # Create a copy of STR with all the '\033' characters removed.
+ # Then compare string lengths to get a count of the '\033'
+ # charactes present in STR.
+ regsub -all "\033" $str {} stripped
+ set count [expr [string length $str] - [string length $stripped]]
+
+ # If STR switched styles, then it _must_ switch back again,
+ # otherwise the pagination prompt will be in the wrong style.
+ # This means that there _must_ be an even number of '\033'
+ # characters in STR. If there is not then we switched style, but
+ # failed to switch back.
+ if { [expr $count % 2] != 0 } {
+ return false
+ }
+
+ # For lines that don't match this pattern, we cannot comment on
+ # where the style reset should occur, so lets just claim the line
+ # is fine.
+ if { ![regexp "\\s+$::hex - $::hex is \[^\r\n\]+ in " $str] } {
+ return true
+ }
+
+ # This line did match the above pattern, so we know that a style
+ # reset _must_ occur at the end of the line. If it doesn't then
+ # this line is not OK.
+ if { ![regexp "\033\\\[m$" $str] } {
+ return false
+ }
+
+ # All tests passed, this line looks OK.
+ return true
+}
+
+# Test that the pagination prompt is displayed unstyled. This is done
+# by looking at the 'info files' output and selecting a width that
+# will mean we should get a pagination prompt part way through a
+# styled filename.
+#
+# Then, re-run 'info files' and check that for every pagination
+# prompt, the previous line disables styling as expected.
+proc test_pagination_prompt_styling {} {
+ with_ansi_styling_terminal {
+ clean_restart $::binfile
+ }
+
+ if {![runto_main]} {
+ return
+ }
+
+ # Set height so we actually get a pagination prompt.
+ gdb_test_no_output "set height 3"
+
+ # Scan the 'info files' output and set DESIRED_WIDTH such that it
+ # will trigger pagination part-way through a styled filename.
+ set desired_width 0
+ gdb_test_multiple "info files" "find good test width" {
+ -re "^info files\r\n" {
+ exp_continue
+ }
+
+ -re "^$::pagination_prompt$" {
+ send_gdb "\n"
+ exp_continue
+ }
+
+ -re "^$::gdb_prompt $" {
+ }
+
+ -re "^((\\s+$::hex - $::hex is \[^\r\n\]+ in )\[^\r\n\]+)\r\n" {
+ if { $desired_width == 0 } {
+ set full_line $expect_out(1,string)
+ set inner_line $expect_out(2,string)
+ set desired_width [expr [string length $inner_line] + ([string length $full_line] - [string length $inner_line]) / 2]
+ }
+ exp_continue
+ }
+
+ -re "^\[^\r\n\]*\r\n" {
+ exp_continue
+ }
+ }
+
+ # Now setup the screen width.
+ gdb_test_no_output "set width $desired_width"
+
+ # Re-run 'info files'. Check that the content before any
+ # pagination prompt correctly disables styling.
+ set saw_bad_line false
+ set prev_line ""
+ gdb_test_multiple "info files" "check pagination prompt styling" {
+ -re "^info files\r\n" {
+ exp_continue
+ }
+
+ -re "^$::pagination_prompt$" {
+ if { ![previous_line_is_ok $prev_line] } {
+ set saw_bad_line true
+ }
+ send_gdb "\n"
+ exp_continue
+ }
+
+ -re "^(\[^\r\n\]+)$::pagination_prompt$" {
+ set prev_line $expect_out(1,string)
+ if { ![previous_line_is_ok $prev_line] } {
+ set saw_bad_line true
+ }
+ send_gdb "\n"
+ exp_continue
+ }
+
+ -re "^$::gdb_prompt $" {
+ gdb_assert { !$saw_bad_line } $gdb_test_name
+ }
+
+ -re "^(\[^\r\n\]*)\r\n" {
+ set prev_line $expect_out(1,string)
+ exp_continue
+ }
+ }
+}
+
+# Test that GDB can correctly restore the current style after a
+# pagination prompt.
+#
+# Set the logging file to a garbage string based on LENGTH (is
+# actually 2x LENGTH), then 'show logging file'. Press return at the
+# pagination prompt, and check that the reset of the filename is
+# styled correctly, and that GDB correctly switches back to the
+# default style once the logging file has finished.
+proc test_pagination_continue_styling_1 { length } {
+ with_ansi_styling_terminal {
+ clean_restart $::binfile
+ }
+
+ set filename [string repeat "ax" $length]
+
+ gdb_test_no_output "set logging file $filename"
+
+ gdb_test_no_output "set height 3"
+ gdb_test_no_output "set width 80"
+
+ set saw_bad_styling false
+ gdb_test_multiple "show logging file" "" {
+ -re "^show logging file\r\n" {
+ exp_continue
+ }
+
+ -re "^The current logfile is \"\033\\\[32;49;22;27m(?:ax)+\033\\\[m" {
+ exp_continue
+ }
+
+ -re "^\r\n\033\\\[32;49;22;27m(?:ax)+\033\\\[m(?=--)" {
+ exp_continue
+ }
+
+ -re "^\r\n\033\\\[32;49;22;27m(?:ax)+(?=--)" {
+ set saw_bad_styling true
+ exp_continue
+ }
+
+ -re "^\r\n\033\\\[32;49;22;27m(?:ax)+\033\\\[m\"\\.\r\n" {
+ exp_continue
+ }
+
+ -re "^$::gdb_prompt $" {
+ gdb_assert { !$saw_bad_styling } $gdb_test_name
+ }
+
+ -re "^$::pagination_prompt$$" {
+ send_gdb "\n"
+ exp_continue
+ }
+ }
+}
+
+# Wrapper around test_pagination_continue_styling_1, calls that
+# function with different lengths.
+proc test_pagination_continue_styling { } {
+ foreach_with_prefix length { 80 160 } {
+ test_pagination_continue_styling_1 $length
+ }
+}
+
# Check to see if the Python styling of disassembler output is
# expected or not, this styling requires Python support in GDB, and
# the Python pygments module to be available.
test_colorsupport_truecolor_only
test_enable_styling_warning
+test_pagination_cmd_after_quit_styling
+test_pagination_prompt_styling
+test_pagination_continue_styling
{
m_applied_style = style;
if (m_paging)
- m_stream->emit_style_escape (style);
+ {
+ /* Previous style changes will have been sent to m_stream via
+ escape sequences encoded in the m_wrap_buffer. As a result,
+ the m_stream->m_applied_style will not have been updated.
+
+ If we now use m_stream->emit_style_escape, then the required
+ style might not actually be emitted as the requested style
+ might happen to match the out of date value in
+ m_stream->m_applied_style.
+
+ Instead, send the style change directly using m_stream->puts.
+
+ However, we track what style is currently applied to the
+ underlying stream in m_stream_style, this is updated whenever
+ m_wrap_buffer is flushed to the underlying stream. And so, if
+ the style we are applying matches what we know is currently
+ applied to the underlying stream, then we can skip sending
+ this style to the stream. */
+ if (m_stream_style != m_applied_style)
+ {
+ m_stream->puts (style.to_ansi ().c_str ());
+ m_stream_style = m_applied_style;
+ }
+ }
else
m_wrap_buffer.append (style.to_ansi ());
}
scoped_restore save_paging = make_scoped_restore (&m_paging, true);
- /* Clear the current styling. */
- m_stream->emit_style_escape (ui_file_style ());
+ /* Clear the current styling on ourselves and the managed stream. */
+ this->emit_style_escape (ui_file_style ());
if (annotation_level > 1)
m_stream->puts (("\n\032\032pre-prompt-for-continue\n"));
if (!m_paging && !m_wrap_buffer.empty ())
{
m_stream->puts (m_wrap_buffer.c_str ());
+ m_stream_style = m_applied_style;
m_wrap_buffer.clear ();
}
}
m_wrap_column = 0; /* And disable fancy wrap */
}
else if (did_paginate)
- m_stream->emit_style_escape (save_style);
+ this->emit_style_escape (save_style);
}
}