[06/16] Reset terminal styles

Message ID 20181128001435.12703-7-tom@tromey.com
State New, archived
Headers

Commit Message

Tom Tromey Nov. 28, 2018, 12:14 a.m. UTC
  This adds a function that can be used to reset terminal styles,
regardless of what style the low-levle output routines currently think
is applied.

This is used to make "echo" and "printf" work properly when emitting
ANSI terminal escapes -- now gdb will reset the style at the end of
the command.

gdb/ChangeLog
2018-11-27  Tom Tromey  <tom@tromey.com>

	* utils.h (reset_terminal_style): Declare.
	* utils.c (can_emit_style_escape): New function.
	(set_output_style): Use it.
	(reset_terminal_style): New function.
	* printcmd.c (printf_command): Call reset_terminal_style.
	* cli/cli-cmds.c (echo_command): Call reset_terminal_style.
---
 gdb/ChangeLog      |  9 +++++++++
 gdb/cli/cli-cmds.c |  2 ++
 gdb/printcmd.c     |  2 ++
 gdb/utils.c        | 37 +++++++++++++++++++++++++++++++------
 gdb/utils.h        |  4 ++++
 5 files changed, 48 insertions(+), 6 deletions(-)
  

Comments

Joel Brobecker Dec. 24, 2018, 4:16 a.m. UTC | #1
Hi Tom,

> This adds a function that can be used to reset terminal styles,
> regardless of what style the low-levle output routines currently think

Typo: levle -> level

> is applied.
> 
> This is used to make "echo" and "printf" work properly when emitting
> ANSI terminal escapes -- now gdb will reset the style at the end of
> the command.
> 
> gdb/ChangeLog
> 2018-11-27  Tom Tromey  <tom@tromey.com>
> 
> 	* utils.h (reset_terminal_style): Declare.
> 	* utils.c (can_emit_style_escape): New function.
> 	(set_output_style): Use it.
> 	(reset_terminal_style): New function.
> 	* printcmd.c (printf_command): Call reset_terminal_style.
> 	* cli/cli-cmds.c (echo_command): Call reset_terminal_style.

OK with me. Just one question below.

> diff --git a/gdb/printcmd.c b/gdb/printcmd.c
> index 8c999188d7..79c3d2d2ff 100644
> --- a/gdb/printcmd.c
> +++ b/gdb/printcmd.c
> @@ -2609,6 +2609,8 @@ static void
>  printf_command (const char *arg, int from_tty)
>  {
>    ui_printf (arg, gdb_stdout);
> +  reset_terminal_style (gdb_stdout);
> +  wrap_here ("");

Can you explain why you added the "wrap_here"?
  
Tom Tromey Dec. 28, 2018, 7:01 p.m. UTC | #2
>>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes:

>> printf_command (const char *arg, int from_tty)
>> {
>> ui_printf (arg, gdb_stdout);
>> +  reset_terminal_style (gdb_stdout);
>> +  wrap_here ("");

Joel> Can you explain why you added the "wrap_here"?

gdb's pager has the unusual property that it introduces another layer of
buffering that isn't accessible to gdb_flush.  So, to properly flush
stdout and I guess stderr, one must first call wrap_here to flush this
buffer.

You can see this most clearly in exceptions.c:print_flush, which is
where this seems to have been documented.

In this particular case, reset_terminal_style might emit an escape
sequence to the wrap buffer.  So, wrap_here is needed to be sure this is
flushed.  We can't flush in reset_terminal_style because it might be
used in cases where flushing is inappropriate, for example in the middle
of a command when paging is still desired.

I think a better design would be to require nothing more than gdb_flush.
However, this requires some thought and experimentation, and seemed
orthogonal to my goal in this series.

Tom
  

Patch

diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 135f550b80..12ac74c7e9 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -689,6 +689,8 @@  echo_command (const char *text, int from_tty)
 	  printf_filtered ("%c", c);
       }
 
+  reset_terminal_style (gdb_stdout);
+
   /* Force this output to appear now.  */
   wrap_here ("");
   gdb_flush (gdb_stdout);
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 8c999188d7..79c3d2d2ff 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -2609,6 +2609,8 @@  static void
 printf_command (const char *arg, int from_tty)
 {
   ui_printf (arg, gdb_stdout);
+  reset_terminal_style (gdb_stdout);
+  wrap_here ("");
   gdb_flush (gdb_stdout);
 }
 
diff --git a/gdb/utils.c b/gdb/utils.c
index 69c9e76576..85b0fb14e3 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -1444,25 +1444,50 @@  emit_style_escape (const ui_file_style &style)
   wrap_buffer.append (style.to_ansi ());
 }
 
-/* Set the current output style.  This will affect future uses of the
-   _filtered output functions.  */
+/* Return true if ANSI escapes can be used on STREAM.  */
 
-static void
-set_output_style (struct ui_file *stream, const ui_file_style &style)
+static bool
+can_emit_style_escape (struct ui_file *stream)
 {
   if (stream != gdb_stdout
       || !cli_styling
-      || style == desired_style
       || !ui_file_isatty (stream))
-    return;
+    return false;
   const char *term = getenv ("TERM");
   if (term == nullptr || !strcmp (term, "dumb"))
+    return false;
+  return true;
+}
+
+/* Set the current output style.  This will affect future uses of the
+   _filtered output functions.  */
+
+static void
+set_output_style (struct ui_file *stream, const ui_file_style &style)
+{
+  if (!can_emit_style_escape (stream)
+      || style == desired_style)
     return;
 
   desired_style = style;
   emit_style_escape (style);
 }
 
+/* See utils.h.  */
+
+void
+reset_terminal_style (struct ui_file *stream)
+{
+  if (can_emit_style_escape (stream))
+    {
+      /* Force the setting, regardless of what we think the setting
+	 might already be.  */
+      desired_style = ui_file_style ();
+      applied_style = desired_style;
+      wrap_buffer.append (desired_style.to_ansi ());
+    }
+}
+
 /* Wait, so the user can read what's on the screen.  Prompt the user
    to continue by pressing RETURN.  'q' is also provided because
    telling users what to do in the prompt is more user-friendly than
diff --git a/gdb/utils.h b/gdb/utils.h
index 9872a15fd7..1f09ec2d47 100644
--- a/gdb/utils.h
+++ b/gdb/utils.h
@@ -439,6 +439,10 @@  extern void fputs_styled (const char *linebuffer,
 			  const ui_file_style &style,
 			  struct ui_file *stream);
 
+/* Reset the terminal style to the default, if needed.  */
+
+extern void reset_terminal_style (struct ui_file *stream);
+
 /* Display the host ADDR on STREAM formatted as ``0x%x''.  */
 extern void gdb_print_host_address_1 (const void *addr, struct ui_file *stream);