'thread|frame apply CMD' launches CMD so that CMD output goes to a string_file.
This patch ensures that string_file for such CMD output contains
style escape sequences that 'thread|frame apply' will later on
output on the real terminal, so as to have CMD output properly styled.
The idea is to have the class ui_file having overridable methods
to indicate that the output to this ui_file should be done using
'terminal' behaviour such as styling.
Then these methods are overriden in string_file so that a specially
constructed string_file will get output with style escape sequences.
After this patch, the output of CMD by thread|frame apply CMD is styled
similarly as when CMD is launched directly.
Note that string_file (term_out true) could also support wrapping,
but this is not done (yet?).
Tested on debian/amd64.
gdb/ChangeLog
2019-04-27 Philippe Waroquiers <philippe.waroquiers@skynet.be>
Support style in 'frame|thread apply'
* gdbcmd.h (execute_command_to_string): New term_out parameter.
* record.c (record_start, record_stop): Update callers of
execute_command_to_string with false.
* ui-file.h (class ui_file): New term_out and can_emit_style_escape
methods.
(class string_file): New constructor with term_out parameter.
Override methods term_out and can_emit_style_escape. New member
term_out.
(class stdio_file): Override can_emit_style_escape.
(class tee_file): Override term_out and can_emit_style_escape.
* utils.h (can_emit_style_escape): Remove.
* utils.c (can_emit_style_escape): Likewise.
Update all callers of can_emit_style_escape (SOMESTREAM) to
SOMESTREAM->can_emit_style_escape.
* source-cache.c (source_cache::get_source_lines): Likewise.
* stack.c (frame_apply_command_count): Call execute_command_to_string
passing the term_out characteristic of the current gdb_stdout.
* thread.c (thr_try_catch_cmd): Likewise.
* top.c (execute_command_to_string): pass term_out parameter
to construct the string_file for the command output.
* ui-file.c (term_cli_styling): New function (most code moved
from utils.c can_emit_style_escape).
(string_file::string_file, string_file::can_emit_style_escape,
stdio_file::can_emit_style_escape, tee_file::term_out,
tee_file::can_emit_style_escape): New functions.
extern struct cmd_list_element *save_cmdlist;
extern void execute_command (const char *, int);
-extern std::string execute_command_to_string (const char *p, int from_tty);
+
+/* Execute command P and returns its output. If TERM_OUT,
+ the output is built using terminal output behaviour such
+ as cli_styling. */
+extern std::string execute_command_to_string (const char *p, int from_tty,
+ bool term_out);
extern void print_command_line (struct command_line *, unsigned int,
struct ui_file *);
if (method == NULL)
{
if (format == NULL)
- execute_command_to_string ("record", from_tty);
+ execute_command_to_string ("record", from_tty, false);
else
error (_("Invalid format."));
}
else if (strcmp (method, "full") == 0)
{
if (format == NULL)
- execute_command_to_string ("record full", from_tty);
+ execute_command_to_string ("record full", from_tty, false);
else
error (_("Invalid format."));
}
else if (strcmp (method, "btrace") == 0)
{
if (format == NULL)
- execute_command_to_string ("record btrace", from_tty);
+ execute_command_to_string ("record btrace", from_tty, false);
else if (strcmp (format, "bts") == 0)
- execute_command_to_string ("record btrace bts", from_tty);
+ execute_command_to_string ("record btrace bts", from_tty, false);
else if (strcmp (format, "pt") == 0)
- execute_command_to_string ("record btrace pt", from_tty);
+ execute_command_to_string ("record btrace pt", from_tty, false);
else
error (_("Invalid format."));
}
void
record_stop (int from_tty)
{
- execute_command_to_string ("record stop", from_tty);
+ execute_command_to_string ("record stop", from_tty, false);
}
/* See record.h. */
return false;
#ifdef HAVE_SOURCE_HIGHLIGHT
- if (source_styling && can_emit_style_escape (gdb_stdout))
+ if (source_styling && gdb_stdout->can_emit_style_escape ())
{
const char *fullname = symtab_to_fullname (s);
set to the selected frame. */
scoped_restore_current_thread restore_fi_current_frame;
- cmd_result = execute_command_to_string (cmd, from_tty);
+ cmd_result = execute_command_to_string
+ (cmd, from_tty, gdb_stdout->term_out ());
}
fi = get_selected_frame (_("frame apply "
"unable to get selected frame."));
switch_to_thread (thr);
try
{
- std::string cmd_result = execute_command_to_string (cmd, from_tty);
+ std::string cmd_result = execute_command_to_string
+ (cmd, from_tty, gdb_stdout->term_out ());
if (!flags.silent || cmd_result.length () > 0)
{
if (!flags.quiet)
temporarily set to true. */
std::string
-execute_command_to_string (const char *p, int from_tty)
+execute_command_to_string (const char *p, int from_tty,
+ bool term_out)
{
/* GDB_STDOUT should be better already restored during these
restoration callbacks. */
scoped_restore save_async = make_scoped_restore (¤t_ui->async, 0);
- string_file str_file;
+ string_file str_file (term_out);
{
current_uiout->redirect (&str_file);
return file->isatty ();
}
+/* true if the gdb terminal supports styling, and styling is enabled. */
+
+static bool
+term_cli_styling ()
+{
+ extern int cli_styling;
+
+ if (!cli_styling)
+ return false;
+
+ const char *term = getenv ("TERM");
+ /* Windows doesn't by default define $TERM, but can support styles
+ regardless. */
+#ifndef _WIN32
+ if (term == nullptr || !strcmp (term, "dumb"))
+ return false;
+#else
+ /* But if they do define $TERM, let us behave the same as on Posix
+ platforms, for the benefit of programs which invoke GDB as their
+ back-end. */
+ if (term && !strcmp (term, "dumb"))
+ return false;
+#endif
+ return true;
+}
+
+
void
ui_file_write (struct ui_file *file,
const char *buf,
m_string.append (buf, length_buf);
}
+/* See ui-file.h. */
+
+bool
+string_file::term_out ()
+{
+ return m_term_out;
+}
+
+/* See ui-file.h. */
+
+bool
+string_file::can_emit_style_escape ()
+{
+ return m_term_out && term_cli_styling ();
+}
+
\f
stdio_file::stdio_file (FILE *file, bool close_p)
return ::isatty (m_fd);
}
+/* See ui-file.h. */
+
+bool
+stdio_file::can_emit_style_escape ()
+{
+ return (this == gdb_stdout
+ && this->isatty ()
+ && term_cli_styling ());
+}
+
\f
/* This is the implementation of ui_file method 'write' for stderr.
{
return m_one->isatty ();
}
+
+/* See ui-file.h. */
+
+bool
+tee_file::term_out ()
+{
+ return m_one->term_out ();
+}
+
+/* See ui-file.h. */
+
+bool
+tee_file::can_emit_style_escape ()
+{
+ return (this == gdb_stdout
+ && m_one->term_out ()
+ && term_cli_styling ());
+}
virtual bool isatty ()
{ return false; }
+ /* true indicates terminal output behaviour such as cli_styling.
+ This default implementation indicates to do terminal output
+ behaviour if the UI_FILE is a tty. A derived class can override
+ TERM_OUT to have cli_styling behaviour without being a tty. */
+ virtual bool term_out ()
+ { return isatty (); }
+
+ /* true if ANSI escapes can be used on STREAM. */
+ virtual bool can_emit_style_escape ()
+ { return false; }
+
virtual void flush ()
{}
};
class string_file : public ui_file
{
public:
- string_file () {}
+ /* Construct a string_file to collect 'raw' output, i.e. without
+ 'terminal' behaviour such as cli_styling. */
+ string_file () : m_term_out (false) {};
+ /* If TERM_OUT, construct a string_file with terminal output behaviour
+ such as cli_styling)
+ else collect 'raw' output like the previous constructor. */
+ explicit string_file (bool term_out) : m_term_out (term_out) {};
~string_file () override;
/* Override ui_file methods. */
long read (char *buf, long length_buf) override
{ gdb_assert_not_reached ("a string_file is not readable"); }
+ bool term_out () override;
+ bool can_emit_style_escape () override;
+
/* string_file-specific public API. */
/* Accesses the std::string containing the entire output collected
private:
/* The internal buffer. */
std::string m_string;
+
+ bool m_term_out;
};
/* A ui_file implementation that maps directly onto <stdio.h>'s FILE.
bool isatty () override;
+ bool can_emit_style_escape () override;
+
private:
/* Sets the internal stream to FILE, and saves the FILE's file
descriptor in M_FD. */
void puts (const char *) override;
bool isatty () override;
+ bool term_out () override;
+ bool can_emit_style_escape () override;
void flush () override;
private:
fputs_unfiltered (style.to_ansi ().c_str (), stream);
}
-/* See utils.h. */
-
-bool
-can_emit_style_escape (struct ui_file *stream)
-{
- if (stream != gdb_stdout
- || !cli_styling
- || !ui_file_isatty (stream))
- return false;
- const char *term = getenv ("TERM");
- /* Windows doesn't by default define $TERM, but can support styles
- regardless. */
-#ifndef _WIN32
- if (term == nullptr || !strcmp (term, "dumb"))
- return false;
-#else
- /* But if they do define $TERM, let us behave the same as on Posix
- platforms, for the benefit of programs which invoke GDB as their
- back-end. */
- if (term && !strcmp (term, "dumb"))
- return false;
-#endif
- 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))
+ if (!stream->can_emit_style_escape ())
return;
/* Note that we don't pass STREAM here, because we want to emit to
void
reset_terminal_style (struct ui_file *stream)
{
- if (can_emit_style_escape (stream))
+ if (stream->can_emit_style_escape ())
{
/* Force the setting, regardless of what we think the setting
might already be. */
bool disable_pagination = pagination_disabled_for_command;
/* Clear the current styling. */
- if (can_emit_style_escape (gdb_stdout))
+ if (gdb_stdout->can_emit_style_escape ())
emit_style_escape (ui_file_style (), gdb_stdout);
if (annotation_level > 1)
lines_printed++;
if (wrap_column)
{
- if (can_emit_style_escape (stream))
+ if (stream->can_emit_style_escape ())
emit_style_escape (ui_file_style (), stream);
/* If we aren't actually wrapping, don't output
newline -- if chars_per_line is right, we
if (wrap_column)
{
fputs_unfiltered (wrap_indent, stream);
- if (can_emit_style_escape (stream))
+ if (stream->can_emit_style_escape ())
emit_style_escape (wrap_style, stream);
/* FIXME, this strlen is what prevents wrap_indent from
containing tabs. However, if we recurse to print it
extern void reset_terminal_style (struct ui_file *stream);
-/* Return true if ANSI escapes can be used on STREAM. */
-
-extern bool can_emit_style_escape (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);