Discussion:
[PATCH 02/16] Add a "context" argument to add_setshow_enum_cmd
Tom Tromey
2018-11-28 00:14:21 UTC
Permalink
This adds a "context" argument to add_setshow_enum_cmd. Now
add_setshow_enum_cmd will call set_cmd_context on both of the new
commands. This is used in a later patch.

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

* command.h (add_setshow_enum_cmd): Add "context" argument.
* cli/cli-decode.c (add_setshow_enum_cmd): Add "context"
argument. Call set_cmd_context.
---
gdb/ChangeLog | 6 ++++++
gdb/cli/cli-decode.c | 10 +++++++---
gdb/command.h | 3 ++-
3 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c
index 5d798e877e..e7b7a110fc 100644
--- a/gdb/cli/cli-decode.c
+++ b/gdb/cli/cli-decode.c
@@ -531,16 +531,20 @@ add_setshow_enum_cmd (const char *name,
cmd_const_sfunc_ftype *set_func,
show_value_ftype *show_func,
struct cmd_list_element **set_list,
- struct cmd_list_element **show_list)
+ struct cmd_list_element **show_list,
+ void *context)
{
- struct cmd_list_element *c;
+ struct cmd_list_element *c, *show;

add_setshow_cmd_full (name, theclass, var_enum, var,
set_doc, show_doc, help_doc,
set_func, show_func,
set_list, show_list,
- &c, NULL);
+ &c, &show);
c->enums = enumlist;
+
+ set_cmd_context (c, context);
+ set_cmd_context (show, context);
}

const char * const auto_boolean_enums[] = { "on", "off", "auto", NULL };
diff --git a/gdb/command.h b/gdb/command.h
index e3d55c2dcb..68514409ec 100644
--- a/gdb/command.h
+++ b/gdb/command.h
@@ -314,7 +314,8 @@ extern void add_setshow_enum_cmd (const char *name,
cmd_const_sfunc_ftype *set_func,
show_value_ftype *show_func,
struct cmd_list_element **set_list,
- struct cmd_list_element **show_list);
+ struct cmd_list_element **show_list,
+ void *context = nullptr);

extern void add_setshow_auto_boolean_cmd (const char *name,
enum command_class theclass,
--
2.17.2
Tom Tromey
2018-11-28 00:14:23 UTC
Permalink
This changes the gdb test suite to set TERM to "dumb" by default.
This setting disables terminal styling, so that the existing tests do
not need to be updated.

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

* lib/gdb.exp (gdb_init): Set the TERM environment variable to
"dumb".
* gdb.base/readline.exp (operate_and_get_next): Save and restore
the TERM environment variable.
---
gdb/testsuite/ChangeLog | 7 +++
gdb/testsuite/gdb.base/readline.exp | 94 +++++++++++++++--------------
gdb/testsuite/lib/gdb.exp | 7 +--
3 files changed, 59 insertions(+), 49 deletions(-)

diff --git a/gdb/testsuite/gdb.base/readline.exp b/gdb/testsuite/gdb.base/readline.exp
index 49bd308197..9f0955c112 100644
--- a/gdb/testsuite/gdb.base/readline.exp
+++ b/gdb/testsuite/gdb.base/readline.exp
@@ -141,57 +141,61 @@ proc operate_and_get_next {name args} {
return 1
}

+save_vars { env(TERM) } {
+ # The arrow key test relies on the standard VT100 bindings, so
+ # make sure that an appropriate terminal is selected. The same
+ # bug doesn't show up if we use ^P / ^N instead.
+ setenv TERM vt100

-gdb_start
-gdb_reinitialize_dir $srcdir/$subdir
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir

-if { ![readline_is_used] } {
- unsupported "readline isn't used."
- return -1
-}
+ if { ![readline_is_used] } {
+ unsupported "readline isn't used."
+ return -1
+ }

-save_vars { timeout env(GDBHISTSIZE) env(GDBHISTFILE) } {
- set timeout 30
-
- # A simple test of operate-and-get-next.
- operate_and_get_next "Simple operate-and-get-next" \
- "p 1" ".* = 1" \
- "p 2" ".* = 2" \
- "p 3" ".* = 3"
-
- # Test operate-and-get-next with a secondary prompt.
- operate_and_get_next "operate-and-get-next with secondary prompt" \
- "if 1 > 0" "" \
- "p 5" "" \
- "end" ".* = 5"
-
- # Verify that arrow keys work in secondary prompts. The control
- # sequence is a hard-coded VT100 up arrow.
- gdb_test "print 42" "\\\$\[0-9\]* = 42"
- set msg "arrow keys with secondary prompt"
- gdb_test_multiple "if 1 > 0\n\033\[A\033\[A\nend" $msg {
- -re ".*\\\$\[0-9\]* = 42\r\n$gdb_prompt $" {
- pass $msg
- }
- -re ".*Undefined command:.*$gdb_prompt $" {
- fail $msg
+ save_vars { timeout env(GDBHISTSIZE) env(GDBHISTFILE) } {
+ set timeout 30
+
+ # A simple test of operate-and-get-next.
+ operate_and_get_next "Simple operate-and-get-next" \
+ "p 1" ".* = 1" \
+ "p 2" ".* = 2" \
+ "p 3" ".* = 3"
+
+ # Test operate-and-get-next with a secondary prompt.
+ operate_and_get_next "operate-and-get-next with secondary prompt" \
+ "if 1 > 0" "" \
+ "p 5" "" \
+ "end" ".* = 5"
+
+ # Verify that arrow keys work in secondary prompts. The control
+ # sequence is a hard-coded VT100 up arrow.
+ gdb_test "print 42" "\\\$\[0-9\]* = 42"
+ set msg "arrow keys with secondary prompt"
+ gdb_test_multiple "if 1 > 0\n\033\[A\033\[A\nend" $msg {
+ -re ".*\\\$\[0-9\]* = 42\r\n$gdb_prompt $" {
+ pass $msg
+ }
+ -re ".*Undefined command:.*$gdb_prompt $" {
+ fail $msg
+ }
}
- }

- # Now repeat the first test with a history file that fills the entire
- # history list.
+ # Now repeat the first test with a history file that fills the entire
+ # history list.

- set env(GDBHISTFILE) "${srcdir}/${subdir}/gdb_history"
- set env(GDBHISTSIZE) "10"
+ set env(GDBHISTFILE) "${srcdir}/${subdir}/gdb_history"
+ set env(GDBHISTSIZE) "10"

- gdb_exit
- gdb_start
- gdb_reinitialize_dir $srcdir/$subdir
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir

- operate_and_get_next "Simple operate-and-get-next" \
- "p 7" ".* = 7" \
- "p 8" ".* = 8" \
- "p 9" ".* = 9"
+ operate_and_get_next "Simple operate-and-get-next" \
+ "p 7" ".* = 7" \
+ "p 8" ".* = 8" \
+ "p 9" ".* = 9"
+ }
}
-
-return 0
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 5a5713b114..7eed7b5190 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -4719,10 +4719,9 @@ proc gdb_init { test_file_name } {
# read from this file.
setenv INPUTRC "/dev/null"

- # The gdb.base/readline.exp arrow key test relies on the standard VT100
- # bindings, so make sure that an appropriate terminal is selected.
- # The same bug doesn't show up if we use ^P / ^N instead.
- setenv TERM "vt100"
+ # This disables style output, which would interfere with many
+ # tests.
+ setenv TERM "dumb"

# Some tests (for example gdb.base/maint.exp) shell out from gdb to use
# grep. Clear GREP_OPTIONS to make the behavior predictable,
--
2.17.2
Tom Tromey
2018-11-28 00:14:25 UTC
Permalink
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 <***@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(-)

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);
--
2.17.2
Tom Tromey
2018-11-28 00:14:28 UTC
Permalink
print_address_symbolic does not use ui-out, so it did not style
function names. This patch changes it to use the low-level style code
directly.

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

* printcmd.c (print_address_symbolic): Style function name.

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

* gdb.base/style.exp: Add test for print_address_symbolic.
---
gdb/ChangeLog | 4 ++++
gdb/printcmd.c | 9 +++++----
gdb/testsuite/ChangeLog | 4 ++++
gdb/testsuite/gdb.base/style.exp | 2 ++
4 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index dd1626455b..c5b6b1a75b 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -50,6 +50,7 @@
#include "format.h"
#include "source.h"
#include "common/byte-vector.h"
+#include "cli/cli-style.h"

/* Last specified output format. */

@@ -535,7 +536,7 @@ print_address_symbolic (struct gdbarch *gdbarch, CORE_ADDR addr,
fputs_filtered ("<*", stream);
else
fputs_filtered ("<", stream);
- fputs_filtered (name.c_str (), stream);
+ fputs_styled (name.c_str (), function_name_style.style (), stream);
if (offset != 0)
fprintf_filtered (stream, "+%u", (unsigned int) offset);

@@ -543,10 +544,10 @@ print_address_symbolic (struct gdbarch *gdbarch, CORE_ADDR addr,
line # of this addr, if we have it; else line # of the nearest symbol. */
if (print_symbol_filename && !filename.empty ())
{
+ fputs_filtered (line == -1 ? " in " : " at ", stream);
+ fputs_styled (filename.c_str (), file_name_style.style (), stream);
if (line != -1)
- fprintf_filtered (stream, " at %s:%d", filename.c_str (), line);
- else
- fprintf_filtered (stream, " in %s", filename.c_str ());
+ fprintf_filtered (stream, ":%d", line);
}
if (unmapped)
fputs_filtered ("*>", stream);
diff --git a/gdb/testsuite/gdb.base/style.exp b/gdb/testsuite/gdb.base/style.exp
index df73e25a16..8b82ae99fa 100644
--- a/gdb/testsuite/gdb.base/style.exp
+++ b/gdb/testsuite/gdb.base/style.exp
@@ -42,4 +42,6 @@ save_vars { env(TERM) } {
gdb_test "info breakpoints" "$main_expr at $file_expr.*"

gdb_test "break main" "file $base_file_expr.*"
+
+ gdb_test "print &main" " = .* <$main_expr>"
}
--
2.17.2
Tom Tromey
2018-11-28 00:14:26 UTC
Permalink
This adds style support for variable names. For the time being, this
is only done in backtraces, not in ptype or print; those places do not
use ui-out and so would need ad hoc changes.

This also adds styling to the names printed for local variables in
"backtrace full". This code does not use ui-out, so the styling is
done using the low-level API.

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

* ui-out.h (enum class ui_out_style_kind) <VARIABLE>: New global.
* stack.c (print_frame_arg): Style name.
* printcmd.c (print_variable_and_value): Style variable name.
* cli/cli-style.h (variable_name_style): Declare.
* cli/cli-style.c (variable_name_style): New global.
(_initialize_cli_style): Update.
* cli-out.c (cli_ui_out::do_field_string): Update.

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

* gdb.base/style.exp: Add test for variable names.
---
gdb/ChangeLog | 10 ++++++++++
gdb/cli-out.c | 3 +++
gdb/cli/cli-style.c | 11 +++++++++++
gdb/cli/cli-style.h | 3 +++
gdb/printcmd.c | 6 +++++-
gdb/stack.c | 2 +-
gdb/testsuite/ChangeLog | 4 ++++
gdb/testsuite/gdb.base/style.exp | 3 ++-
gdb/ui-out.h | 4 +++-
9 files changed, 42 insertions(+), 4 deletions(-)

diff --git a/gdb/cli-out.c b/gdb/cli-out.c
index 4b5fc17390..e1005e1b35 100644
--- a/gdb/cli-out.c
+++ b/gdb/cli-out.c
@@ -173,6 +173,9 @@ cli_ui_out::do_field_string (int fldno, int width, ui_align align,
case ui_out_style_kind::FUNCTION:
fstyle = function_name_style.style ();
break;
+ case ui_out_style_kind::VARIABLE:
+ fstyle = variable_name_style.style ();
+ break;
default:
gdb_assert_not_reached ("missing case");
}
diff --git a/gdb/cli/cli-style.c b/gdb/cli/cli-style.c
index de2866ce75..fd4a4fc477 100644
--- a/gdb/cli/cli-style.c
+++ b/gdb/cli/cli-style.c
@@ -62,6 +62,10 @@ cli_style_option function_name_style (ui_file_style::YELLOW);

/* See cli-style.h. */

+cli_style_option variable_name_style (ui_file_style::CYAN);
+
+/* See cli-style.h. */
+
cli_style_option::cli_style_option (ui_file_style::simple_color fg)
: m_foreground (cli_colors[fg - ui_file_style::NONE]),
m_background (cli_colors[0]),
@@ -254,4 +258,11 @@ Configure function name colors and display intensity"),
"style function",
&style_set_list,
&style_show_list);
+ variable_name_style.add_setshow_commands ("variable", no_class,
+ "style variable",
+ _("\
+Variable name display styling\n\
+Configure variable name colors and display intensity"),
+ &style_set_list,
+ &style_show_list);
}
diff --git a/gdb/cli/cli-style.h b/gdb/cli/cli-style.h
index 36845b2581..3d5142e3de 100644
--- a/gdb/cli/cli-style.h
+++ b/gdb/cli/cli-style.h
@@ -83,6 +83,9 @@ extern cli_style_option file_name_style;
/* The function name style. */
extern cli_style_option function_name_style;

+/* The variable name style. */
+extern cli_style_option variable_name_style;
+
/* True if styling is enabled. */
extern int cli_styling;

diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 79c3d2d2ff..dd1626455b 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -46,6 +46,7 @@
#include "arch-utils.h"
#include "cli/cli-utils.h"
#include "cli/cli-script.h"
+#include "cli/cli-style.h"
#include "format.h"
#include "source.h"
#include "common/byte-vector.h"
@@ -2156,7 +2157,10 @@ print_variable_and_value (const char *name, struct symbol *var,
if (!name)
name = SYMBOL_PRINT_NAME (var);

- fprintf_filtered (stream, "%s%s = ", n_spaces (2 * indent), name);
+ fputs_filtered (n_spaces (2 * indent), stream);
+ fputs_styled (name, variable_name_style.style (), stream);
+ fputs_filtered (" = ", stream);
+
TRY
{
struct value *val;
diff --git a/gdb/stack.c b/gdb/stack.c
index a718bf8901..930d7d0b1e 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -256,7 +256,7 @@ print_frame_arg (const struct frame_arg *arg)
if (arg->entry_kind == print_entry_values_only
|| arg->entry_kind == print_entry_values_compact)
stb.puts ("@entry");
- uiout->field_stream ("name", stb);
+ uiout->field_stream ("name", stb, ui_out_style_kind::VARIABLE);
annotate_arg_name_end ();
uiout->text ("=");

diff --git a/gdb/testsuite/gdb.base/style.exp b/gdb/testsuite/gdb.base/style.exp
index 859e50352f..1ab9d68431 100644
--- a/gdb/testsuite/gdb.base/style.exp
+++ b/gdb/testsuite/gdb.base/style.exp
@@ -34,8 +34,9 @@ save_vars { env(TERM) } {

set main_expr "\033\\\[33mmain\033\\\[m"
set file_expr "\033\\\[32m.*style\\.c\033\\\[m:\[0-9\]"
+ set arg_expr "\033\\\[36marg.\033\\\[m"

gdb_test "frame" \
- "$main_expr.*$file_expr.*"
+ "$main_expr.*$arg_expr.*$arg_expr.*$file_expr.*"
gdb_test "info breakpoints" "$main_expr at $file_expr.*"
}
diff --git a/gdb/ui-out.h b/gdb/ui-out.h
index 8604105c09..93be9a91b2 100644
--- a/gdb/ui-out.h
+++ b/gdb/ui-out.h
@@ -75,7 +75,9 @@ enum class ui_out_style_kind
/* File name. */
FILE,
/* Function name. */
- FUNCTION
+ FUNCTION,
+ /* Variable name. */
+ VARIABLE
};

class ui_out
--
2.17.2
Tom Tromey
2018-11-28 00:14:29 UTC
Permalink
This changes gdb to style the welcome message that is shown by
default. The styling is only done interactively.

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

* top.c (print_gdb_version): Style gdb version number.

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

* gdb.base/style.exp: Add test for version number styling.
---
gdb/ChangeLog | 4 ++++
gdb/testsuite/ChangeLog | 4 ++++
gdb/testsuite/gdb.base/style.exp | 6 ++++++
gdb/top.c | 9 ++++++++-
4 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/gdb/testsuite/gdb.base/style.exp b/gdb/testsuite/gdb.base/style.exp
index 8b82ae99fa..a5bdc2795f 100644
--- a/gdb/testsuite/gdb.base/style.exp
+++ b/gdb/testsuite/gdb.base/style.exp
@@ -44,4 +44,10 @@ save_vars { env(TERM) } {
gdb_test "break main" "file $base_file_expr.*"

gdb_test "print &main" " = .* <$main_expr>"
+
+ gdb_exit
+ gdb_spawn
+
+ gdb_test "" "\033\\\[35;1mGNU gdb.*\033\\\[m.*" \
+ "version is styled"
}
diff --git a/gdb/top.c b/gdb/top.c
index 4a0fedb6a8..50c6cff3d9 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -1281,7 +1281,14 @@ print_gdb_version (struct ui_file *stream, bool interactive)
program to parse, and is just canonical program name and version
number, which starts after last space. */

- fprintf_filtered (stream, "GNU gdb %s%s\n", PKGVERSION, version);
+ ui_file_style style;
+ if (interactive)
+ {
+ ui_file_style nstyle = { ui_file_style::MAGENTA, ui_file_style::NONE,
+ ui_file_style::BOLD };
+ style = nstyle;
+ }
+ fprintf_styled (stream, style, "GNU gdb %s%s\n", PKGVERSION, version);

/* Second line is a copyright notice. */
--
2.17.2
Tom Tromey
2018-11-28 00:14:30 UTC
Permalink
The "Reading symbols" message does not use ui-out (perhaps it
should?), so this styles it using the low-level API.

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

* symfile.c (symbol_file_add_with_addrs): Style file name.

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

* gdb.base/style.exp: Add test for styling of "Reading symbols"
message.
---
gdb/ChangeLog | 4 ++++
gdb/symfile.c | 7 ++++++-
gdb/testsuite/ChangeLog | 5 +++++
gdb/testsuite/gdb.base/style.exp | 4 ++++
4 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/gdb/symfile.c b/gdb/symfile.c
index 8ab6a25de7..b5d888ee2b 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -58,6 +58,7 @@
#include "cli/cli-utils.h"
#include "common/byte-vector.h"
#include "selftest.h"
+#include "cli/cli-style.h"

#include <sys/types.h>
#include <fcntl.h>
@@ -1110,7 +1111,11 @@ symbol_file_add_with_addrs (bfd *abfd, const char *name,
if (deprecated_pre_add_symbol_hook)
deprecated_pre_add_symbol_hook (name);
else
- printf_filtered (_("Reading symbols from %s...\n"), name);
+ {
+ puts_filtered (_("Reading symbols from "));
+ fputs_styled (name, file_name_style.style (), gdb_stdout);
+ puts_filtered ("...\n");
+ }
}
syms_from_objfile (objfile, addrs, add_flags);

diff --git a/gdb/testsuite/gdb.base/style.exp b/gdb/testsuite/gdb.base/style.exp
index a5bdc2795f..a44d78f236 100644
--- a/gdb/testsuite/gdb.base/style.exp
+++ b/gdb/testsuite/gdb.base/style.exp
@@ -50,4 +50,8 @@ save_vars { env(TERM) } {

gdb_test "" "\033\\\[35;1mGNU gdb.*\033\\\[m.*" \
"version is styled"
+
+ set quoted [string_to_regexp $binfile]
+ gdb_test "file $binfile" \
+ "Reading symbols from \033\\\[32m${quoted}\033\\\[m..." \
}
--
2.17.2
Tom Tromey
2018-11-28 00:14:33 UTC
Permalink
This changes tui_show_source_line to use wclrtoeol rather than
manually emitting a sequence of spaces.

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

* tui/tui-winsource.c (tui_show_source_line): Use wclrtoeol.
---
gdb/ChangeLog | 4 ++++
gdb/tui/tui-winsource.c | 8 +-------
2 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/gdb/tui/tui-winsource.c b/gdb/tui/tui-winsource.c
index 49eb4ce6fc..0bf74383b1 100644
--- a/gdb/tui/tui-winsource.c
+++ b/gdb/tui/tui-winsource.c
@@ -272,7 +272,6 @@ static void
tui_show_source_line (struct tui_win_info *win_info, int lineno)
{
struct tui_win_element *line;
- int x;

line = win_info->generic.content[lineno - 1];
if (line->which_element.source.is_exec_point)
@@ -284,12 +283,7 @@ tui_show_source_line (struct tui_win_info *win_info, int lineno)
wattroff (win_info->generic.handle, A_STANDOUT);

/* Clear to end of line but stop before the border. */
- x = getcurx (win_info->generic.handle);
- while (x + 1 < win_info->generic.width)
- {
- waddch (win_info->generic.handle, ' ');
- x = getcurx (win_info->generic.handle);
- }
+ wclrtoeol (win_info->generic.handle);
}

void
--
2.17.2
Tom Tromey
2018-11-28 00:14:22 UTC
Permalink
This introduces the new ui_file_style class and various helpers. This
class represents a terminal style and provides methods for parsing and
emitting the corresponding ANSI terminal escape sequences.

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

* unittests/style-selftests.c: New file.
* ui-style.c: New file.
* ui-style.h: New file.
* ui-file.h: Include ui-style.h.
* Makefile.in (COMMON_SFILES): Add ui-style.c.
(HFILES_NO_SRCDIR): Add ui-style.h.
(SUBDIR_UNITTESTS_SRCS): Add style-selftests.c.
---
gdb/ChangeLog | 10 +
gdb/Makefile.in | 3 +
gdb/ui-file.h | 1 +
gdb/ui-style.c | 412 ++++++++++++++++++++++++++++++++
gdb/ui-style.h | 215 +++++++++++++++++
gdb/unittests/style-selftests.c | 109 +++++++++
6 files changed, 750 insertions(+)
create mode 100644 gdb/ui-style.c
create mode 100644 gdb/ui-style.h
create mode 100644 gdb/unittests/style-selftests.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 3be058f052..ce0d799b7d 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -426,6 +426,7 @@ SUBDIR_UNITTESTS_SRCS = \
unittests/scoped_mmap-selftests.c \
unittests/scoped_restore-selftests.c \
unittests/string_view-selftests.c \
+ unittests/style-selftests.c \
unittests/tracepoint-selftests.c \
unittests/unpack-selftests.c \
unittests/utils-selftests.c \
@@ -1124,6 +1125,7 @@ COMMON_SFILES = \
typeprint.c \
ui-file.c \
ui-out.c \
+ ui-style.c \
user-regs.c \
utils.c \
valarith.c \
@@ -1397,6 +1399,7 @@ HFILES_NO_SRCDIR = \
typeprint.h \
ui-file.h \
ui-out.h \
+ ui-style.h \
user-regs.h \
utils.h \
valprint.h \
diff --git a/gdb/ui-file.h b/gdb/ui-file.h
index 2cf5f83d47..b780dff4d5 100644
--- a/gdb/ui-file.h
+++ b/gdb/ui-file.h
@@ -20,6 +20,7 @@
#define UI_FILE_H

#include <string>
+#include "ui-style.h"

/* The abstract ui_file base class. */

diff --git a/gdb/ui-style.c b/gdb/ui-style.c
new file mode 100644
index 0000000000..a6e102e7b2
--- /dev/null
+++ b/gdb/ui-style.c
@@ -0,0 +1,412 @@
+/* Styling for ui_file
+ Copyright (C) 2018 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "defs.h"
+#include "ui-style.h"
+
+/* A regular expression that is used for matching ANSI terminal escape
+ sequences. */
+
+static const char *ansi_regex_text =
+ /* Introduction. */
+ "^\033\\["
+#define DATA_SUBEXP 1
+ /* Capture parameter and intermediate bytes. */
+ "("
+ /* Parameter bytes. */
+ "[\x30-\x3f]*"
+ /* Intermediate bytes. */
+ "[\x20-\x2f]*"
+ /* End the first capture. */
+ ")"
+ /* The final byte. */
+#define FINAL_SUBEXP 2
+ "([\x40-\x7e])";
+
+/* The number of subexpressions to allocate space for, including the
+ "0th" whole match subexpression. */
+#define NUM_SUBEXPRESSIONS 3
+
+/* The compiled form of ansi_regex_text. */
+
+static regex_t ansi_regex;
+
+/* This maps bright colors to RGB triples. The index is the bright
+ color index, starting with bright black. The values come from
+ xterm. */
+
+static const uint8_t bright_colors[][3] = {
+ { 127, 127, 127 }, /* Black. */
+ { 255, 0, 0 }, /* Red. */
+ { 0, 255, 0 }, /* Green. */
+ { 255, 255, 0 }, /* Yellow. */
+ { 92, 92, 255 }, /* Blue. */
+ { 255, 0, 255 }, /* Magenta. */
+ { 0, 255, 255 }, /* Cyan. */
+ { 255, 255, 255 } /* White. */
+};
+
+/* See ui-style.h. */
+
+bool
+ui_file_style::color::append_ansi (bool is_fg, std::string *str) const
+{
+ if (m_simple)
+ {
+ if (m_value >= BLACK && m_value <= WHITE)
+ str->append (std::to_string (m_value + (is_fg ? 30 : 40)));
+ else if (m_value > WHITE && m_value <= WHITE + 8)
+ str->append (std::to_string (m_value - WHITE + (is_fg ? 90 : 100)));
+ else if (m_value != -1)
+ {
+ str->append (is_fg ? "38;5;" : "48;5;");
+ str->append (std::to_string (m_value));
+ }
+ else
+ return false;
+ }
+ else
+ {
+ str->append (is_fg ? "38;2;" : "48;2;");
+ str->append (std::to_string (m_red)
+ + ";" + std::to_string (m_green)
+ + ";" + std::to_string (m_blue));
+ }
+ return true;
+}
+
+/* See ui-style.h. */
+
+void
+ui_file_style::color::get_rgb (uint8_t *rgb) const
+{
+ if (m_simple)
+ {
+ /* Can't call this for a basic color. */
+ if (m_value >= 8 && m_value <= 15)
+ memcpy (rgb, bright_colors[m_value - 8], 3 * sizeof (uint8_t));
+ else if (m_value >= 16 && m_value <= 231)
+ {
+ int value = m_value;
+ value -= 16;
+ /* This obscure formula seems to be what terminals actually
+ do. */
+ int component = value / 36;
+ rgb[0] = component == 0 ? 0 : (55 + component * 40);
+ value %= 36;
+ component = value / 6;
+ rgb[1] = component == 0 ? 0 : (55 + component * 40);
+ value %= 6;
+ rgb[2] = value == 0 ? 0 : (55 + value * 40);
+ }
+ else if (m_value >= 232)
+ {
+ uint8_t v = (m_value - 232) * 10 + 8;
+ rgb[0] = v;
+ rgb[1] = v;
+ rgb[2] = v;
+ }
+ else
+ gdb_assert_not_reached ("get_rgb called on invalid color");
+ }
+ else
+ {
+ rgb[0] = m_red;
+ rgb[1] = m_green;
+ rgb[2] = m_blue;
+ }
+}
+
+/* See ui-style.h. */
+
+std::string
+ui_file_style::to_ansi () const
+{
+ std::string result ("\033[");
+ bool need_semi = m_foreground.append_ansi (true, &result);
+ if (!m_background.is_none ())
+ {
+ if (need_semi)
+ result.push_back (';');
+ m_background.append_ansi (false, &result);
+ need_semi = true;
+ }
+ if (m_intensity != NORMAL)
+ {
+ if (need_semi)
+ result.push_back (';');
+ result.append (std::to_string (m_intensity));
+ need_semi = true;
+ }
+ if (m_reverse)
+ {
+ if (need_semi)
+ result.push_back (';');
+ result.push_back ('7');
+ }
+ result.push_back ('m');
+ return result;
+}
+
+/* Read a ";" and a number from STRING. Return the number of
+ characters read and put the number into *NUM. */
+
+static bool
+read_semi_number (const char *string, int *idx, long *num)
+{
+ if (string[*idx] != ';')
+ return false;
+ ++*idx;
+ if (string[*idx] < '0' || string[*idx] > '9')
+ return false;
+ char *tail;
+ *num = strtol (string + *idx, &tail, 10);
+ *idx = tail - string;
+ return true;
+}
+
+/* A helper for ui_file_style::parse that reads an extended color
+ sequence; that is, and 8- or 24- bit color. */
+
+static bool
+extended_color (const char *str, int *idx, ui_file_style::color *color)
+{
+ long value;
+
+ if (!read_semi_number (str, idx, &value))
+ return false;
+
+ if (value == 5)
+ {
+ /* 8-bit color. */
+ if (!read_semi_number (str, idx, &value))
+ return false;
+
+ if (value >= 0 && value <= 255)
+ *color = ui_file_style::color (value);
+ else
+ return false;
+ }
+ else if (value == 2)
+ {
+ /* 24-bit color. */
+ long r, g, b;
+ if (!read_semi_number (str, idx, &r)
+ || r > 255
+ || !read_semi_number (str, idx, &g)
+ || g > 255
+ || !read_semi_number (str, idx, &b)
+ || b > 255)
+ return false;
+ *color = ui_file_style::color (r, g, b);
+ }
+ else
+ {
+ /* Unrecognized sequence. */
+ return false;
+ }
+
+ return true;
+}
+
+/* See ui-style.h. */
+
+bool
+ui_file_style::parse (const char *buf, size_t *n_read)
+{
+ regmatch_t subexps[NUM_SUBEXPRESSIONS];
+
+ int match = regexec (&ansi_regex, buf, ARRAY_SIZE (subexps), subexps, 0);
+ if (match == REG_NOMATCH)
+ {
+ *n_read = 0;
+ return false;
+ }
+ /* Other failures mean the regexp is broken. */
+ gdb_assert (match == 0);
+ /* The regexp is anchored. */
+ gdb_assert (subexps[0].rm_so == 0);
+ /* The final character exists. */
+ gdb_assert (subexps[FINAL_SUBEXP].rm_eo - subexps[FINAL_SUBEXP].rm_so == 1);
+
+ if (buf[subexps[FINAL_SUBEXP].rm_so] != 'm')
+ {
+ /* We don't handle this sequence, so just drop it. */
+ *n_read = subexps[0].rm_eo;
+ return false;
+ }
+
+ /* Examine each setting in the match and apply it to the result.
+ See the Select Graphic Rendition section of
+ https://en.wikipedia.org/wiki/ANSI_escape_code. In essence each
+ code is just a number, separated by ";"; there are some more
+ wrinkles but we don't support them all.. */
+
+ /* "\033[m" means the same thing as "\033[0m", so handle that
+ specially here. */
+ if (subexps[DATA_SUBEXP].rm_so == subexps[DATA_SUBEXP].rm_eo)
+ *this = ui_file_style ();
+
+ for (regoff_t i = subexps[DATA_SUBEXP].rm_so;
+ i < subexps[DATA_SUBEXP].rm_eo;
+ ++i)
+ {
+ if (buf[i] == ';')
+ {
+ /* Skip. */
+ }
+ else if (buf[i] >= '0' && buf[i] <= '9')
+ {
+ char *tail;
+ long value = strtol (buf + i, &tail, 10);
+ i = tail - buf;
+
+ switch (value)
+ {
+ case 0:
+ /* Reset. */
+ *this = ui_file_style ();
+ break;
+ case 1:
+ /* Bold. */
+ m_intensity = BOLD;
+ break;
+ case 2:
+ /* Dim. */
+ m_intensity = DIM;
+ break;
+ case 7:
+ /* Reverse. */
+ m_reverse = true;
+ break;
+ case 21:
+ m_intensity = NORMAL;
+ break;
+ case 22:
+ /* Normal. */
+ m_intensity = NORMAL;
+ break;
+ case 27:
+ /* Inverse off. */
+ m_reverse = false;
+ break;
+
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ /* Note: not 38. */
+ case 39:
+ m_foreground = color (value - 30);
+ break;
+
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ /* Note: not 48. */
+ case 49:
+ m_background = color (value - 40);
+ break;
+
+ case 90:
+ case 91:
+ case 92:
+ case 93:
+ case 94:
+ case 95:
+ case 96:
+ case 97:
+ m_foreground = color (value - 90 + 8);
+ break;
+
+ case 100:
+ case 101:
+ case 102:
+ case 103:
+ case 104:
+ case 105:
+ case 106:
+ case 107:
+ m_background = color (value - 100 + 8);
+ break;
+
+ case 38:
+ /* If we can't parse the extended color, fail. */
+ if (!extended_color (buf, &i, &m_foreground))
+ {
+ *n_read = subexps[0].rm_eo;
+ return false;
+ }
+ break;
+
+ case 48:
+ /* If we can't parse the extended color, fail. */
+ if (!extended_color (buf, &i, &m_background))
+ {
+ *n_read = subexps[0].rm_eo;
+ return false;
+ }
+ break;
+
+ default:
+ /* Ignore everything else. */
+ break;
+ }
+ }
+ else
+ {
+ /* Unknown, let's just ignore. */
+ }
+ }
+
+ *n_read = subexps[0].rm_eo;
+ return true;
+}
+
+/* See ui-style.h. */
+
+bool
+skip_ansi_escape (const char *buf, int *bytes)
+{
+ regmatch_t subexps[NUM_SUBEXPRESSIONS];
+
+ int match = regexec (&ansi_regex, buf, ARRAY_SIZE (subexps), subexps, 0);
+ if (match == REG_NOMATCH || buf[subexps[FINAL_SUBEXP].rm_so] != 'm')
+ return false;
+
+ *bytes = subexps[FINAL_SUBEXP].rm_eo;
+ return true;
+}
+
+void
+_initialize_ui_style ()
+{
+ int code = regcomp (&ansi_regex, ansi_regex_text, REG_EXTENDED);
+ /* If the regular expression was incorrect, it was a programming
+ error. */
+ gdb_assert (code == 0);
+}
diff --git a/gdb/ui-style.h b/gdb/ui-style.h
new file mode 100644
index 0000000000..d08139cef2
--- /dev/null
+++ b/gdb/ui-style.h
@@ -0,0 +1,215 @@
+/* Styling for ui_file
+ Copyright (C) 2018 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#ifndef UI_STYLE_H
+#define UI_STYLE_H
+
+/* Styles that can be applied to a ui_file. */
+struct ui_file_style
+{
+ /* One of the simple colors that can be handled by ANSI
+ terminals. */
+ enum simple_color
+ {
+ NONE = -1,
+ BLACK,
+ RED,
+ GREEN,
+ YELLOW,
+ BLUE,
+ MAGENTA,
+ CYAN,
+ WHITE
+ };
+
+ /* Representation of a terminal color. */
+ class color
+ {
+ public:
+
+ color (simple_color c)
+ : m_simple (true),
+ m_value (c)
+ {
+ }
+
+ color (int c)
+ : m_simple (true),
+ m_value (c)
+ {
+ gdb_assert (c >= -1 && c <= 255);
+ }
+
+ color (uint8_t r, uint8_t g, uint8_t b)
+ : m_simple (false),
+ m_red (r),
+ m_green (g),
+ m_blue (b)
+ {
+ }
+
+ bool operator== (const color &other) const
+ {
+ if (m_simple != other.m_simple)
+ return false;
+ if (m_simple)
+ return m_value == other.m_value;
+ return (m_red == other.m_red && m_green == other.m_green
+ && m_blue == other.m_blue);
+ }
+
+ bool operator< (const color &other) const
+ {
+ if (m_simple != other.m_simple)
+ return m_simple < other.m_simple;
+ if (m_simple)
+ return m_value < other.m_value;
+ if (m_red < other.m_red)
+ return true;
+ if (m_red == other.m_red)
+ {
+ if (m_green < other.m_green)
+ return true;
+ if (m_green == other.m_green)
+ return m_blue < other.m_blue;
+ }
+ return false;
+ }
+
+ /* Return true if this is the "NONE" color, false otherwise. */
+ bool is_none () const
+ {
+ return m_simple && m_value == NONE;
+ }
+
+ /* Return true if this is one of the basic colors, false
+ otherwise. */
+ bool is_basic () const
+ {
+ return m_simple && m_value >= BLACK && m_value <= WHITE;
+ }
+
+ /* Return the value of a basic color. */
+ int get_value () const
+ {
+ gdb_assert (is_basic ());
+ return m_value;
+ }
+
+ /* Fill in RGB with the red/green/blue values for this color.
+ This may not be called for simple colors or for the "NONE"
+ color. */
+ void get_rgb (uint8_t *rgb) const;
+
+ /* Append the ANSI terminal escape sequence for this color to STR.
+ IS_FG indicates whether this is a foreground or background
+ color. Returns true if any characters were written; returns
+ false otherwise (which can only happen for the "NONE"
+ color). */
+ bool append_ansi (bool is_fg, std::string *str) const;
+
+ private:
+
+ bool m_simple;
+ int m_value;
+ uint8_t m_red, m_green, m_blue;
+ };
+
+ /* Intensity settings that are available. */
+ enum intensity
+ {
+ NORMAL = 0,
+ BOLD,
+ DIM
+ };
+
+ ui_file_style ()
+ {
+ }
+
+ ui_file_style (color f, color b, intensity i = NORMAL)
+ : m_foreground (f),
+ m_background (b),
+ m_intensity (i)
+ {
+ }
+
+ bool operator== (const ui_file_style &other) const
+ {
+ return (m_foreground == other.m_foreground
+ && m_background == other.m_background
+ && m_intensity == other.m_intensity
+ && m_reverse == other.m_reverse);
+ }
+
+ bool operator!= (const ui_file_style &other) const
+ {
+ return !(*this == other);
+ }
+
+ /* Return the ANSI escape sequence for this style. */
+ std::string to_ansi () const;
+
+ /* Return true if this style specified reverse display; false
+ otherwise. */
+ bool is_reverse () const
+ {
+ return m_reverse;
+ }
+
+ /* Return the foreground color of this style. */
+ const color &get_foreground () const
+ {
+ return m_foreground;
+ }
+
+ /* Return the background color of this style. */
+ const color &get_background () const
+ {
+ return m_background;
+ }
+
+ /* Return the intensity of this style. */
+ intensity get_intensity () const
+ {
+ return m_intensity;
+ }
+
+ /* Parse an ANSI escape sequence in BUF, modifying this style. BUF
+ must begin with an ESC character. Return true if an escape
+ sequence was successfully parsed; false otherwise. In either
+ case, N_READ is updated to reflect the number of chars read from
+ BUF. */
+ bool parse (const char *buf, size_t *n_read);
+
+private:
+
+ color m_foreground = NONE;
+ color m_background = NONE;
+ intensity m_intensity = NORMAL;
+ bool m_reverse = false;
+};
+
+/* Skip an ANSI escape sequence in BUF. BUF must begin with an ESC
+ character. Return true if an escape sequence was successfully
+ skipped; false otherwise. In either case, N_READ is updated to
+ reflect the number of chars read from BUF. */
+
+extern bool skip_ansi_escape (const char *buf, int *bytes);
+
+#endif /* UI_STYLE_H */
diff --git a/gdb/unittests/style-selftests.c b/gdb/unittests/style-selftests.c
new file mode 100644
index 0000000000..108ed6ccd2
--- /dev/null
+++ b/gdb/unittests/style-selftests.c
@@ -0,0 +1,109 @@
+/* Self tests for ui_file_style
+
+ Copyright (C) 2018 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "defs.h"
+#include "selftest.h"
+#include "ui-style.h"
+
+namespace selftests {
+namespace style {
+
+#define CHECK_RGB(R, G, B) \
+ SELF_CHECK (rgb[0] == (R) && rgb[1] == (G) && rgb[2] == (B))
+
+static void
+run_tests ()
+{
+ ui_file_style style;
+ size_t n_read;
+ uint8_t rgb[3];
+
+ SELF_CHECK (style.parse ("\033[m", &n_read));
+ SELF_CHECK (n_read == 3);
+ SELF_CHECK (style.get_foreground ().is_none ());
+ SELF_CHECK (style.get_background ().is_none ());
+ SELF_CHECK (style.get_intensity () == ui_file_style::NORMAL);
+ SELF_CHECK (!style.is_reverse ());
+ SELF_CHECK (style.to_ansi () == "\033[m");
+
+ style = ui_file_style ();
+ SELF_CHECK (style.parse ("\033[0m", &n_read));
+ SELF_CHECK (n_read == 4);
+ SELF_CHECK (style.get_foreground ().is_none ());
+ SELF_CHECK (style.get_background ().is_none ());
+ SELF_CHECK (style.get_intensity () == ui_file_style::NORMAL);
+ SELF_CHECK (!style.is_reverse ());
+ /* This particular case does not round-trip identically, but the
+ difference is unimportant. */
+ SELF_CHECK (style.to_ansi () == "\033[m");
+
+ SELF_CHECK (style.parse ("\033[7m", &n_read));
+ SELF_CHECK (n_read == 4);
+ SELF_CHECK (style.get_foreground ().is_none ());
+ SELF_CHECK (style.get_background ().is_none ());
+ SELF_CHECK (style.get_intensity () == ui_file_style::NORMAL);
+ SELF_CHECK (style.is_reverse ());
+ SELF_CHECK (style.to_ansi () == "\033[7m");
+
+ style = ui_file_style ();
+ SELF_CHECK (style.parse ("\033[32;1m", &n_read));
+ SELF_CHECK (n_read == 7);
+ SELF_CHECK (style.get_foreground ().is_basic ());
+ SELF_CHECK (style.get_foreground ().get_value () == ui_file_style::GREEN);
+ SELF_CHECK (style.get_background ().is_none ());
+ SELF_CHECK (style.get_intensity () == ui_file_style::BOLD);
+ SELF_CHECK (!style.is_reverse ());
+ SELF_CHECK (style.to_ansi () == "\033[32;1m");
+
+ style = ui_file_style ();
+ SELF_CHECK (style.parse ("\033[38;5;112;48;5;249m", &n_read));
+ SELF_CHECK (n_read == 20);
+ SELF_CHECK (!style.get_foreground ().is_basic ());
+ style.get_foreground ().get_rgb (rgb);
+ CHECK_RGB (0x87, 0xd7, 0);
+ SELF_CHECK (!style.get_background ().is_basic ());
+ style.get_background ().get_rgb (rgb);
+ CHECK_RGB (0xb2, 0xb2, 0xb2);
+ SELF_CHECK (style.get_intensity () == ui_file_style::NORMAL);
+ SELF_CHECK (!style.is_reverse ());
+ SELF_CHECK (style.to_ansi () == "\033[38;5;112;48;5;249m");
+
+ style = ui_file_style ();
+ SELF_CHECK (style.parse ("\033[38;2;83;84;85;48;2;0;1;254;2;7m", &n_read));
+ SELF_CHECK (n_read == 33);
+ SELF_CHECK (!style.get_foreground ().is_basic ());
+ style.get_foreground ().get_rgb (rgb);
+ CHECK_RGB (83, 84, 85);
+ SELF_CHECK (!style.get_background ().is_basic ());
+ style.get_background ().get_rgb (rgb);
+ CHECK_RGB (0, 1, 254);
+ SELF_CHECK (style.get_intensity () == ui_file_style::DIM);
+ SELF_CHECK (style.is_reverse ());
+ SELF_CHECK (style.to_ansi () == "\033[38;2;83;84;85;48;2;0;1;254;2;7m");
+}
+
+} /* namespace style */
+} /* namespace selftests */
+
+void
+_initialize_style_selftest ()
+{
+ selftests::register_test ("style",
+ selftests::style::run_tests);
+}
--
2.17.2
Tom Tromey
2018-11-28 00:14:31 UTC
Permalink
This changes gdb to style addresses.

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

* ui-out.h (enum class ui_out_style_kind) <ADDRESS>: New
constant.
* ui-out.c (ui_out::field_core_addr): Add styling.
* stack.c (print_frame): Add styling.
* printcmd.c (print_address): Add styling.
(print_address_demangle, info_address_command): Likewise.
* cli/cli-style.h (address_style): Declare.
* cli/cli-style.c (address_style): New global.
(_initialize_cli_style): Register new commands.
* cli-out.c (cli_ui_out::do_field_string): Update.

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

* gdb.base/style.exp: Update test to check for address styling.
---
gdb/ChangeLog | 13 ++++++++++++
gdb/cli-out.c | 3 +++
gdb/cli/cli-style.c | 11 ++++++++++
gdb/cli/cli-style.h | 3 +++
gdb/printcmd.c | 36 +++++++++++++++++++++-----------
gdb/stack.c | 3 ++-
gdb/testsuite/ChangeLog | 4 ++++
gdb/testsuite/gdb.base/style.exp | 2 +-
gdb/ui-out.c | 3 ++-
gdb/ui-out.h | 4 +++-
10 files changed, 66 insertions(+), 16 deletions(-)

diff --git a/gdb/cli-out.c b/gdb/cli-out.c
index e1005e1b35..691f993bad 100644
--- a/gdb/cli-out.c
+++ b/gdb/cli-out.c
@@ -176,6 +176,9 @@ cli_ui_out::do_field_string (int fldno, int width, ui_align align,
case ui_out_style_kind::VARIABLE:
fstyle = variable_name_style.style ();
break;
+ case ui_out_style_kind::ADDRESS:
+ fstyle = address_style.style ();
+ break;
default:
gdb_assert_not_reached ("missing case");
}
diff --git a/gdb/cli/cli-style.c b/gdb/cli/cli-style.c
index fd4a4fc477..74e3958eb8 100644
--- a/gdb/cli/cli-style.c
+++ b/gdb/cli/cli-style.c
@@ -66,6 +66,10 @@ cli_style_option variable_name_style (ui_file_style::CYAN);

/* See cli-style.h. */

+cli_style_option address_style (ui_file_style::BLUE);
+
+/* See cli-style.h. */
+
cli_style_option::cli_style_option (ui_file_style::simple_color fg)
: m_foreground (cli_colors[fg - ui_file_style::NONE]),
m_background (cli_colors[0]),
@@ -265,4 +269,11 @@ Variable name display styling\n\
Configure variable name colors and display intensity"),
&style_set_list,
&style_show_list);
+ address_style.add_setshow_commands ("address", no_class,
+ "style address",
+ _("\
+Address display styling\n\
+Configure address colors and display intensity"),
+ &style_set_list,
+ &style_show_list);
}
diff --git a/gdb/cli/cli-style.h b/gdb/cli/cli-style.h
index 3d5142e3de..b1e9e09d45 100644
--- a/gdb/cli/cli-style.h
+++ b/gdb/cli/cli-style.h
@@ -86,6 +86,9 @@ extern cli_style_option function_name_style;
/* The variable name style. */
extern cli_style_option variable_name_style;

+/* The address style. */
+extern cli_style_option address_style;
+
/* True if styling is enabled. */
extern int cli_styling;

diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index c5b6b1a75b..98f5b23ce5 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -693,7 +693,7 @@ void
print_address (struct gdbarch *gdbarch,
CORE_ADDR addr, struct ui_file *stream)
{
- fputs_filtered (paddress (gdbarch, addr), stream);
+ fputs_styled (paddress (gdbarch, addr), address_style.style (), stream);
print_address_symbolic (gdbarch, addr, stream, asm_demangle, " ");
}

@@ -726,7 +726,7 @@ print_address_demangle (const struct value_print_options *opts,
{
if (opts->addressprint)
{
- fputs_filtered (paddress (gdbarch, addr), stream);
+ fputs_styled (paddress (gdbarch, addr), address_style.style (), stream);
print_address_symbolic (gdbarch, addr, stream, do_demangle, " ");
}
else
@@ -1404,14 +1404,17 @@ info_address_command (const char *exp, int from_tty)
fprintf_symbol_filtered (gdb_stdout, exp,
current_language->la_language, DMGL_ANSI);
printf_filtered ("\" is at ");
- fputs_filtered (paddress (gdbarch, load_addr), gdb_stdout);
+ fputs_styled (paddress (gdbarch, load_addr), address_style.style (),
+ gdb_stdout);
printf_filtered (" in a file compiled without debugging");
section = MSYMBOL_OBJ_SECTION (objfile, msymbol.minsym);
if (section_is_overlay (section))
{
load_addr = overlay_unmapped_address (load_addr, section);
printf_filtered (",\n -- loaded at ");
- fputs_filtered (paddress (gdbarch, load_addr), gdb_stdout);
+ fputs_styled (paddress (gdbarch, load_addr),
+ address_style.style (),
+ gdb_stdout);
printf_filtered (" in overlay section %s",
section->the_bfd_section->name);
}
@@ -1451,12 +1454,14 @@ info_address_command (const char *exp, int from_tty)
case LOC_LABEL:
printf_filtered ("a label at address ");
load_addr = SYMBOL_VALUE_ADDRESS (sym);
- fputs_filtered (paddress (gdbarch, load_addr), gdb_stdout);
+ fputs_styled (paddress (gdbarch, load_addr), address_style.style (),
+ gdb_stdout);
if (section_is_overlay (section))
{
load_addr = overlay_unmapped_address (load_addr, section);
printf_filtered (",\n -- loaded at ");
- fputs_filtered (paddress (gdbarch, load_addr), gdb_stdout);
+ fputs_styled (paddress (gdbarch, load_addr), address_style.style (),
+ gdb_stdout);
printf_filtered (" in overlay section %s",
section->the_bfd_section->name);
}
@@ -1485,12 +1490,14 @@ info_address_command (const char *exp, int from_tty)
case LOC_STATIC:
printf_filtered (_("static storage at address "));
load_addr = SYMBOL_VALUE_ADDRESS (sym);
- fputs_filtered (paddress (gdbarch, load_addr), gdb_stdout);
+ fputs_styled (paddress (gdbarch, load_addr), address_style.style (),
+ gdb_stdout);
if (section_is_overlay (section))
{
load_addr = overlay_unmapped_address (load_addr, section);
printf_filtered (_(",\n -- loaded at "));
- fputs_filtered (paddress (gdbarch, load_addr), gdb_stdout);
+ fputs_styled (paddress (gdbarch, load_addr), address_style.style (),
+ gdb_stdout);
printf_filtered (_(" in overlay section %s"),
section->the_bfd_section->name);
}
@@ -1522,12 +1529,14 @@ info_address_command (const char *exp, int from_tty)
case LOC_BLOCK:
printf_filtered (_("a function at address "));
load_addr = BLOCK_ENTRY_PC (SYMBOL_BLOCK_VALUE (sym));
- fputs_filtered (paddress (gdbarch, load_addr), gdb_stdout);
+ fputs_styled (paddress (gdbarch, load_addr), address_style.style (),
+ gdb_stdout);
if (section_is_overlay (section))
{
load_addr = overlay_unmapped_address (load_addr, section);
printf_filtered (_(",\n -- loaded at "));
- fputs_filtered (paddress (gdbarch, load_addr), gdb_stdout);
+ fputs_styled (paddress (gdbarch, load_addr), address_style.style (),
+ gdb_stdout);
printf_filtered (_(" in overlay section %s"),
section->the_bfd_section->name);
}
@@ -1557,12 +1566,15 @@ info_address_command (const char *exp, int from_tty)
{
load_addr = BMSYMBOL_VALUE_ADDRESS (msym);
printf_filtered (_("static storage at address "));
- fputs_filtered (paddress (gdbarch, load_addr), gdb_stdout);
+ fputs_styled (paddress (gdbarch, load_addr),
+ address_style.style (), gdb_stdout);
if (section_is_overlay (section))
{
load_addr = overlay_unmapped_address (load_addr, section);
printf_filtered (_(",\n -- loaded at "));
- fputs_filtered (paddress (gdbarch, load_addr), gdb_stdout);
+ fputs_styled (paddress (gdbarch, load_addr),
+ address_style.style (),
+ gdb_stdout);
printf_filtered (_(" in overlay section %s"),
section->the_bfd_section->name);
}
diff --git a/gdb/stack.c b/gdb/stack.c
index 930d7d0b1e..819bb616f0 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -1176,7 +1176,8 @@ print_frame (struct frame_info *frame, int print_level,
if (pc_p)
uiout->field_core_addr ("addr", gdbarch, pc);
else
- uiout->field_string ("addr", "<unavailable>");
+ uiout->field_string ("addr", "<unavailable>",
+ ui_out_style_kind::ADDRESS);
annotate_frame_address_end ();
uiout->text (" in ");
}
diff --git a/gdb/testsuite/gdb.base/style.exp b/gdb/testsuite/gdb.base/style.exp
index a44d78f236..b633340afe 100644
--- a/gdb/testsuite/gdb.base/style.exp
+++ b/gdb/testsuite/gdb.base/style.exp
@@ -43,7 +43,7 @@ save_vars { env(TERM) } {

gdb_test "break main" "file $base_file_expr.*"

- gdb_test "print &main" " = .* <$main_expr>"
+ gdb_test "print &main" " = .* \033\\\[34m$hex\033\\\[m <$main_expr>"

gdb_exit
gdb_spawn
diff --git a/gdb/ui-out.c b/gdb/ui-out.c
index 761d6c0745..49f04dd936 100644
--- a/gdb/ui-out.c
+++ b/gdb/ui-out.c
@@ -469,7 +469,8 @@ void
ui_out::field_core_addr (const char *fldname, struct gdbarch *gdbarch,
CORE_ADDR address)
{
- field_string (fldname, print_core_address (gdbarch, address));
+ field_string (fldname, print_core_address (gdbarch, address),
+ ui_out_style_kind::ADDRESS);
}

void
diff --git a/gdb/ui-out.h b/gdb/ui-out.h
index 93be9a91b2..96466d8023 100644
--- a/gdb/ui-out.h
+++ b/gdb/ui-out.h
@@ -77,7 +77,9 @@ enum class ui_out_style_kind
/* Function name. */
FUNCTION,
/* Variable name. */
- VARIABLE
+ VARIABLE,
+ /* Address. */
+ ADDRESS
};

class ui_out
--
2.17.2
Tom Tromey
2018-11-28 00:14:24 UTC
Permalink
This adds some output styling to the CLI.

A style is currently a foreground color, a background color, and an
intensity (dim or bold). (This list could be expanded depending on
terminal capabilities.)

A style can be applied while printing. For ui-out, this is done by
passing the style constant as an argument. For low-level cases,
fprintf_styled and fputs_styled are provided.

Users can control the style via a number of new set/show commands. In
the interest of not typing many nearly-identical documentation
strings, I automated this. On the down side, this is not very
i18n-friendly.

I've chose some default colors to use. I think it would be good to
enable this by default, so that when users start the new gdb, they
will see the new feature.

Stylizing is done if TERM is set and is not "dumb". This could be
improved when the TUI is available by using the curses has_colors
call. That is, the lowest layer could call this without committing to
using curses everywhere; see my other patch for TUI colorizing.

I considered adding a new "set_style" method to ui_file. However,
because the implementation had to interact with the pager code, I
didn't take this approach. But, one idea might be to put the isatty
check there and then have it defer to the lower layers.

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

* utils.h (set_output_style, fprintf_styled)
(fputs_styled): Declare.
* utils.c (applied_style, desired_style): New globals.
(emit_style_escape, set_output_style): New function.
(prompt_for_continue): Emit style escapes.
(fputs_maybe_filtered): Likewise.
(fputs_styled, fprintf_styled): New functions.
* ui-out.h (enum class ui_out_style_kind): New.
(class ui_out) <field_string, field_stream, do_field_string>: Add
style parameter.
* ui-out.c (ui_out::field_stream, ui_out::field_string): Add style
parameter.
* tui/tui-out.h (class tui_ui_out) <do_field_string>: Add style
parameter.
* tui/tui-out.c (tui_ui_out::do_field_string): Add style
parameter.
(tui_ui_out::do_field_string): Update.
* tracepoint.c (print_one_static_tracepoint_marker): Style
output.
* stack.c (print_frame_info, print_frame): Style output.
* source.c (print_source_lines_base): Style output.
* skip.c (info_skip_command): Style output.
* record-btrace.c (btrace_call_history_src_line): Style output.
(btrace_call_history): Likewise.
* python/py-framefilter.c (py_print_frame): Style output.
* mi/mi-out.h (class mi_ui_out) <do_field_string>: Add style
parameter.
* mi/mi-out.c (mi_ui_out::do_table_header)
(mi_ui_out::do_field_int): Update.
(mi_ui_out::do_field_string): Update.
* disasm.c (gdb_pretty_print_disassembler::pretty_print_insn):
Style output.
* cli/cli-style.h: New file.
* cli/cli-style.c: New file.
* cli-out.h (class cli_ui_out) <do_field_string>: Add style
parameter.
* cli-out.c (cli_ui_out::do_table_header)
(cli_ui_out::do_field_int, cli_ui_out::do_field_skip): Update.
(cli_ui_out::do_field_string): Add style parameter. Style the
output.
* breakpoint.c (print_breakpoint_location): Style output.
(update_static_tracepoint): Likewise.
* Makefile.in (SUBDIR_CLI_SRCS): Add cli-style.c.
(HFILES_NO_SRCDIR): Add cli-style.h.

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

* gdb.base/style.exp: New file.
* gdb.base/style.c: New file.
---
gdb/ChangeLog | 47 ++++++
gdb/Makefile.in | 2 +
gdb/breakpoint.c | 12 +-
gdb/cli-out.c | 36 ++++-
gdb/cli-out.h | 3 +-
gdb/cli/cli-style.c | 257 +++++++++++++++++++++++++++++++
gdb/cli/cli-style.h | 89 +++++++++++
gdb/disasm.c | 3 +-
gdb/mi/mi-out.c | 12 +-
gdb/mi/mi-out.h | 3 +-
gdb/python/py-framefilter.c | 5 +-
gdb/record-btrace.c | 12 +-
gdb/skip.c | 6 +-
gdb/source.c | 3 +-
gdb/stack.c | 13 +-
gdb/testsuite/ChangeLog | 5 +
gdb/testsuite/gdb.base/style.c | 22 +++
gdb/testsuite/gdb.base/style.exp | 41 +++++
gdb/tracepoint.c | 7 +-
gdb/tui/tui-out.c | 5 +-
gdb/tui/tui-out.h | 2 +-
gdb/ui-out.c | 10 +-
gdb/ui-out.h | 21 ++-
gdb/utils.c | 80 +++++++++-
gdb/utils.h | 16 ++
25 files changed, 667 insertions(+), 45 deletions(-)
create mode 100644 gdb/cli/cli-style.c
create mode 100644 gdb/cli/cli-style.h
create mode 100644 gdb/testsuite/gdb.base/style.c
create mode 100644 gdb/testsuite/gdb.base/style.exp

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index ce0d799b7d..54baf96ea3 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -239,6 +239,7 @@ SUBDIR_CLI_SRCS = \
cli/cli-logging.c \
cli/cli-script.c \
cli/cli-setshow.c \
+ cli/cli-style.c \
cli/cli-utils.c

SUBDIR_CLI_OBS = $(patsubst %.c,%.o,$(SUBDIR_CLI_SRCS))
@@ -1428,6 +1429,7 @@ HFILES_NO_SRCDIR = \
cli/cli-decode.h \
cli/cli-script.h \
cli/cli-setshow.h \
+ cli/cli-style.h \
cli/cli-utils.h \
common/buffer.h \
common/cleanups.h \
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 8af3d54a77..53763e0254 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -5860,13 +5860,15 @@ print_breakpoint_location (struct breakpoint *b,
if (sym)
{
uiout->text ("in ");
- uiout->field_string ("func", SYMBOL_PRINT_NAME (sym));
+ uiout->field_string ("func", SYMBOL_PRINT_NAME (sym),
+ ui_out_style_kind::FUNCTION);
uiout->text (" ");
uiout->wrap_hint (wrap_indent_at_field (uiout, "what"));
uiout->text ("at ");
}
uiout->field_string ("file",
- symtab_to_filename_for_display (loc->symtab));
+ symtab_to_filename_for_display (loc->symtab),
+ ui_out_style_kind::FILE);
uiout->text (":");

if (uiout->is_mi_like_p ())
@@ -13427,11 +13429,13 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
uiout->text ("Now in ");
if (sym)
{
- uiout->field_string ("func", SYMBOL_PRINT_NAME (sym));
+ uiout->field_string ("func", SYMBOL_PRINT_NAME (sym),
+ ui_out_style_kind::FUNCTION);
uiout->text (" at ");
}
uiout->field_string ("file",
- symtab_to_filename_for_display (sal2.symtab));
+ symtab_to_filename_for_display (sal2.symtab),
+ ui_out_style_kind::FILE);
uiout->text (":");

if (uiout->is_mi_like_p ())
diff --git a/gdb/cli-out.c b/gdb/cli-out.c
index 7e3ee3e54c..4b5fc17390 100644
--- a/gdb/cli-out.c
+++ b/gdb/cli-out.c
@@ -25,6 +25,7 @@
#include "cli-out.h"
#include "completer.h"
#include "readline/readline.h"
+#include "cli/cli-style.h"

/* These are the CLI output functions */

@@ -71,7 +72,8 @@ cli_ui_out::do_table_header (int width, ui_align alignment,
if (m_suppress_output)
return;

- do_field_string (0, width, alignment, 0, col_hdr.c_str ());
+ do_field_string (0, width, alignment, 0, col_hdr.c_str (),
+ ui_out_style_kind::DEFAULT);
}

/* Mark beginning of a list */
@@ -99,7 +101,8 @@ cli_ui_out::do_field_int (int fldno, int width, ui_align alignment,

std::string str = string_printf ("%d", value);

- do_field_string (fldno, width, alignment, fldname, str.c_str ());
+ do_field_string (fldno, width, alignment, fldname, str.c_str (),
+ ui_out_style_kind::DEFAULT);
}

/* used to omit a field */
@@ -111,7 +114,8 @@ cli_ui_out::do_field_skip (int fldno, int width, ui_align alignment,
if (m_suppress_output)
return;

- do_field_string (fldno, width, alignment, fldname, "");
+ do_field_string (fldno, width, alignment, fldname, "",
+ ui_out_style_kind::DEFAULT);
}

/* other specific cli_field_* end up here so alignment and field
@@ -119,7 +123,8 @@ cli_ui_out::do_field_skip (int fldno, int width, ui_align alignment,

void
cli_ui_out::do_field_string (int fldno, int width, ui_align align,
- const char *fldname, const char *string)
+ const char *fldname, const char *string,
+ ui_out_style_kind style)
{
int before = 0;
int after = 0;
@@ -154,7 +159,25 @@ cli_ui_out::do_field_string (int fldno, int width, ui_align align,
spaces (before);

if (string)
- fputs_filtered (string, m_streams.back ());
+ {
+ ui_file_style fstyle;
+ switch (style)
+ {
+ case ui_out_style_kind::DEFAULT:
+ /* Nothing. */
+ break;
+ case ui_out_style_kind::FILE:
+ /* Nothing. */
+ fstyle = file_name_style.style ();
+ break;
+ case ui_out_style_kind::FUNCTION:
+ fstyle = function_name_style.style ();
+ break;
+ default:
+ gdb_assert_not_reached ("missing case");
+ }
+ fputs_styled (string, fstyle, m_streams.back ());
+ }

if (after)
spaces (after);
@@ -175,7 +198,8 @@ cli_ui_out::do_field_fmt (int fldno, int width, ui_align align,

std::string str = string_vprintf (format, args);

- do_field_string (fldno, width, align, fldname, str.c_str ());
+ do_field_string (fldno, width, align, fldname, str.c_str (),
+ ui_out_style_kind::DEFAULT);
}

void
diff --git a/gdb/cli-out.h b/gdb/cli-out.h
index f701da7bf3..4fe10a40a2 100644
--- a/gdb/cli-out.h
+++ b/gdb/cli-out.h
@@ -51,7 +51,8 @@ protected:
const char *fldname) override;
virtual void do_field_string (int fldno, int width, ui_align align,
const char *fldname,
- const char *string) override;
+ const char *string,
+ ui_out_style_kind style) override;
virtual void do_field_fmt (int fldno, int width, ui_align align,
const char *fldname, const char *format,
va_list args)
diff --git a/gdb/cli/cli-style.c b/gdb/cli/cli-style.c
new file mode 100644
index 0000000000..de2866ce75
--- /dev/null
+++ b/gdb/cli/cli-style.c
@@ -0,0 +1,257 @@
+/* CLI colorizing
+
+ Copyright (C) 2018 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "defs.h"
+#include "cli/cli-cmds.h"
+#include "cli/cli-style.h"
+
+/* True if styling is enabled. */
+
+#if defined(_WIN32) || defined (__CYGWIN__)
+int cli_styling = 0;
+#else
+int cli_styling = 1;
+#endif
+
+/* Name of colors; must correspond to ui_file_style::simple_color. */
+static const char * const cli_colors[] = {
+ "none",
+ "black",
+ "red",
+ "green",
+ "yellow",
+ "blue",
+ "magenta",
+ "cyan",
+ "white",
+ nullptr
+};
+
+/* Names of intensities; must correspond to
+ ui_file_style::intensity. */
+static const char * const cli_intensities[] = {
+ "normal",
+ "bold",
+ "dim",
+ nullptr
+};
+
+/* See cli-style.h. */
+
+cli_style_option file_name_style (ui_file_style::GREEN);
+
+/* See cli-style.h. */
+
+cli_style_option function_name_style (ui_file_style::YELLOW);
+
+/* See cli-style.h. */
+
+cli_style_option::cli_style_option (ui_file_style::simple_color fg)
+ : m_foreground (cli_colors[fg - ui_file_style::NONE]),
+ m_background (cli_colors[0]),
+ m_intensity (cli_intensities[ui_file_style::NORMAL])
+{
+}
+
+/* Return the color number corresponding to COLOR. */
+
+static int
+color_number (const char *color)
+{
+ for (int i = 0; i < ARRAY_SIZE (cli_colors); ++i)
+ {
+ if (color == cli_colors[i])
+ return i - 1;
+ }
+ gdb_assert_not_reached ("color not found");
+}
+
+/* See cli-style.h. */
+
+ui_file_style
+cli_style_option::style () const
+{
+ int fg = color_number (m_foreground);
+ int bg = color_number (m_background);
+ ui_file_style::intensity intensity = ui_file_style::NORMAL;
+
+ for (int i = 0; i < ARRAY_SIZE (cli_intensities); ++i)
+ {
+ if (m_intensity == cli_intensities[i])
+ {
+ intensity = (ui_file_style::intensity) i;
+ break;
+ }
+ }
+
+ return ui_file_style (fg, bg, intensity);
+}
+
+/* See cli-style.h. */
+
+void
+cli_style_option::do_set (const char *args, int from_tty)
+{
+}
+
+/* See cli-style.h. */
+
+void
+cli_style_option::do_show (const char *args, int from_tty)
+{
+}
+
+/* See cli-style.h. */
+
+void
+cli_style_option::do_show_foreground (struct ui_file *file, int from_tty,
+ struct cmd_list_element *cmd,
+ const char *value)
+{
+ const char *name = (const char *) get_cmd_context (cmd);
+ fprintf_filtered (file, _("The \"%s\" foreground color is: %s\n"),
+ name, value);
+}
+
+/* See cli-style.h. */
+
+void
+cli_style_option::do_show_background (struct ui_file *file, int from_tty,
+ struct cmd_list_element *cmd,
+ const char *value)
+{
+ const char *name = (const char *) get_cmd_context (cmd);
+ fprintf_filtered (file, _("The \"%s\" background color is: %s\n"),
+ name, value);
+}
+
+/* See cli-style.h. */
+
+void
+cli_style_option::do_show_intensity (struct ui_file *file, int from_tty,
+ struct cmd_list_element *cmd,
+ const char *value)
+{
+ const char *name = (const char *) get_cmd_context (cmd);
+ fprintf_filtered (file, _("The \"%s\" display intensity is: %s\n"),
+ name, value);
+}
+
+/* See cli-style.h. */
+
+void
+cli_style_option::add_setshow_commands (const char *name,
+ enum command_class theclass,
+ const char *prefix_doc,
+ const char *prefixname,
+ struct cmd_list_element **set_list,
+ struct cmd_list_element **show_list)
+{
+ m_show_prefix = std::string ("set ") + prefixname + " ";
+ m_show_prefix = std::string ("show ") + prefixname + " ";
+
+ add_prefix_cmd (name, no_class, do_set, prefix_doc, &m_set_list,
+ m_show_prefix.c_str (), 0, set_list);
+ add_prefix_cmd (name, no_class, do_show, prefix_doc, &m_show_list,
+ m_set_prefix.c_str (), 0, show_list);
+
+ add_setshow_enum_cmd ("foreground", theclass, cli_colors,
+ &m_foreground,
+ _("Set the foreground color for this property"),
+ _("Show the foreground color for this property"),
+ nullptr,
+ nullptr,
+ do_show_foreground,
+ &m_set_list, &m_show_list, (void *) name);
+ add_setshow_enum_cmd ("background", theclass, cli_colors,
+ &m_background,
+ _("Set the background color for this property"),
+ _("Show the background color for this property"),
+ nullptr,
+ nullptr,
+ do_show_background,
+ &m_set_list, &m_show_list, (void *) name);
+ add_setshow_enum_cmd ("intensity", theclass, cli_intensities,
+ &m_intensity,
+ _("Set the display intensity color for this property"),
+ _("\
+Show the display intensity color for this property"),
+ nullptr,
+ nullptr,
+ do_show_intensity,
+ &m_set_list, &m_show_list, (void *) name);
+}
+
+static void
+set_style (const char *arg, int from_tty)
+{
+}
+
+static void
+show_style (const char *arg, int from_tty)
+{
+}
+
+static void
+show_style_enabled (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ if (cli_styling)
+ fprintf_filtered (file, _("CLI output styling is enabled.\n"));
+ else
+ fprintf_filtered (file, _("CLI output styling is disabled.\n"));
+}
+
+void
+_initialize_cli_style ()
+{
+ static cmd_list_element *style_set_list;
+ static cmd_list_element *style_show_list;
+
+ add_prefix_cmd ("style", no_class, set_style, _("\
+Style-specific settings\n\
+Configure various style-related variables, such as colors"),
+ &style_set_list, "set style ", 0, &setlist);
+ add_prefix_cmd ("style", no_class, show_style, _("\
+Style-specific settings\n\
+Configure various style-related variables, such as colors"),
+ &style_show_list, "show style ", 0, &showlist);
+
+ add_setshow_boolean_cmd ("enabled", no_class, &cli_styling, _("\
+Set whether CLI styling is enabled."), _("\
+Show whether CLI is enabled."), _("\
+If enabled, output to the terminal is styled."),
+ NULL, show_style_enabled,
+ &style_set_list, &style_show_list);
+
+ file_name_style.add_setshow_commands ("filename", no_class,
+ _("\
+Filename display styling\n\
+Configure filename colors and display intensity."),
+ "style filename",
+ &style_set_list,
+ &style_show_list);
+ function_name_style.add_setshow_commands ("function", no_class,
+ _("\
+Function name display styling\n\
+Configure function name colors and display intensity"),
+ "style function",
+ &style_set_list,
+ &style_show_list);
+}
diff --git a/gdb/cli/cli-style.h b/gdb/cli/cli-style.h
new file mode 100644
index 0000000000..36845b2581
--- /dev/null
+++ b/gdb/cli/cli-style.h
@@ -0,0 +1,89 @@
+/* CLI stylizing
+
+ Copyright (C) 2018 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#ifndef CLI_STYLE_H
+#define CLI_STYLE_H
+
+#include "ui-file.h"
+
+/* A single CLI style option. */
+class cli_style_option
+{
+public:
+
+ /* Construct a CLI style option with a foreground color. */
+ cli_style_option (ui_file_style::simple_color fg);
+
+ /* Return a ui_file_style corresponding to the settings in this CLI
+ style. */
+ ui_file_style style () const;
+
+ /* Call once to register this CLI style with the CLI engine. */
+ void add_setshow_commands (const char *name,
+ enum command_class theclass,
+ const char *prefix_doc,
+ const char *prefixname,
+ struct cmd_list_element **set_list,
+ struct cmd_list_element **show_list);
+
+private:
+
+ /* The foreground. */
+ const char *m_foreground;
+ /* The background. */
+ const char *m_background;
+ /* The intensity. */
+ const char *m_intensity;
+
+ /* Storage for prefixes needed when registering the commands. */
+ std::string m_show_prefix;
+ std::string m_set_prefix;
+ /* Storage for command lists needed when registering
+ subcommands. */
+ struct cmd_list_element *m_set_list = nullptr;
+ struct cmd_list_element *m_show_list = nullptr;
+
+ /* Callback to set a value. */
+ static void do_set (const char *args, int from_tty);
+ /* Callback to show a value. */
+ static void do_show (const char *args, int from_tty);
+ /* Callback to show the foreground. */
+ static void do_show_foreground (struct ui_file *file, int from_tty,
+ struct cmd_list_element *cmd,
+ const char *value);
+ /* Callback to show the background. */
+ static void do_show_background (struct ui_file *file, int from_tty,
+ struct cmd_list_element *cmd,
+ const char *value);
+ /* Callback to show the intensity. */
+ static void do_show_intensity (struct ui_file *file, int from_tty,
+ struct cmd_list_element *cmd,
+ const char *value);
+};
+
+/* The file name style. */
+extern cli_style_option file_name_style;
+
+/* The function name style. */
+extern cli_style_option function_name_style;
+
+/* True if styling is enabled. */
+extern int cli_styling;
+
+#endif /* CLI_STYLE_H */
diff --git a/gdb/disasm.c b/gdb/disasm.c
index 128c3abfde..5e016be79f 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -244,7 +244,8 @@ gdb_pretty_print_disassembler::pretty_print_insn (struct ui_out *uiout,
the future. */
uiout->text (" <");
if ((flags & DISASSEMBLY_OMIT_FNAME) == 0)
- uiout->field_string ("func-name", name.c_str ());
+ uiout->field_string ("func-name", name.c_str (),
+ ui_out_style_kind::FUNCTION);
uiout->text ("+");
uiout->field_int ("offset", offset);
uiout->text (">:\t");
diff --git a/gdb/mi/mi-out.c b/gdb/mi/mi-out.c
index 39b18b03a0..4aa4a5c601 100644
--- a/gdb/mi/mi-out.c
+++ b/gdb/mi/mi-out.c
@@ -65,8 +65,10 @@ mi_ui_out::do_table_header (int width, ui_align alignment,
open (NULL, ui_out_type_tuple);
do_field_int (0, 0, ui_center, "width", width);
do_field_int (0, 0, ui_center, "alignment", alignment);
- do_field_string (0, 0, ui_center, "col_name", col_name.c_str ());
- do_field_string (0, width, alignment, "colhdr", col_hdr.c_str ());
+ do_field_string (0, 0, ui_center, "col_name", col_name.c_str (),
+ ui_out_style_kind::DEFAULT);
+ do_field_string (0, width, alignment, "colhdr", col_hdr.c_str (),
+ ui_out_style_kind::DEFAULT);
close (ui_out_type_tuple);
}

@@ -95,7 +97,8 @@ mi_ui_out::do_field_int (int fldno, int width, ui_align alignment,
char buffer[20]; /* FIXME: how many chars long a %d can become? */

xsnprintf (buffer, sizeof (buffer), "%d", value);
- do_field_string (fldno, width, alignment, fldname, buffer);
+ do_field_string (fldno, width, alignment, fldname, buffer,
+ ui_out_style_kind::DEFAULT);
}

/* Used to omit a field. */
@@ -111,7 +114,8 @@ mi_ui_out::do_field_skip (int fldno, int width, ui_align alignment,

void
mi_ui_out::do_field_string (int fldno, int width, ui_align align,
- const char *fldname, const char *string)
+ const char *fldname, const char *string,
+ ui_out_style_kind style)
{
ui_file *stream = m_streams.back ();
field_separator ();
diff --git a/gdb/mi/mi-out.h b/gdb/mi/mi-out.h
index 89ff88cd32..b576263d2b 100644
--- a/gdb/mi/mi-out.h
+++ b/gdb/mi/mi-out.h
@@ -57,7 +57,8 @@ protected:
virtual void do_field_skip (int fldno, int width, ui_align align,
const char *fldname) override;
virtual void do_field_string (int fldno, int width, ui_align align,
- const char *fldname, const char *string) override;
+ const char *fldname, const char *string,
+ ui_out_style_kind style) override;
virtual void do_field_fmt (int fldno, int width, ui_align align,
const char *fldname, const char *format, va_list args)
override ATTRIBUTE_PRINTF (6,0);
diff --git a/gdb/python/py-framefilter.c b/gdb/python/py-framefilter.c
index fe17b70f53..53ff5c822e 100644
--- a/gdb/python/py-framefilter.c
+++ b/gdb/python/py-framefilter.c
@@ -898,7 +898,7 @@ py_print_frame (PyObject *filter, frame_filter_flags flags,
if (function == NULL)
out->field_skip ("func");
else
- out->field_string ("func", function);
+ out->field_string ("func", function, ui_out_style_kind::FUNCTION);
}
}

@@ -934,7 +934,8 @@ py_print_frame (PyObject *filter, frame_filter_flags flags,
out->wrap_hint (" ");
out->text (" at ");
annotate_frame_source_file ();
- out->field_string ("file", filename.get ());
+ out->field_string ("file", filename.get (),
+ ui_out_style_kind::FILE);
annotate_frame_source_file_end ();
}
}
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 814f080941..8e8ef15284 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -1091,7 +1091,8 @@ btrace_call_history_src_line (struct ui_out *uiout,
return;

uiout->field_string ("file",
- symtab_to_filename_for_display (symbol_symtab (sym)));
+ symtab_to_filename_for_display (symbol_symtab (sym)),
+ ui_out_style_kind::FILE);

btrace_compute_src_line_range (bfun, &begin, &end);
if (end < begin)
@@ -1182,11 +1183,14 @@ btrace_call_history (struct ui_out *uiout,
}

if (sym != NULL)
- uiout->field_string ("function", SYMBOL_PRINT_NAME (sym));
+ uiout->field_string ("function", SYMBOL_PRINT_NAME (sym),
+ ui_out_style_kind::FUNCTION);
else if (msym != NULL)
- uiout->field_string ("function", MSYMBOL_PRINT_NAME (msym));
+ uiout->field_string ("function", MSYMBOL_PRINT_NAME (msym),
+ ui_out_style_kind::FUNCTION);
else if (!uiout->is_mi_like_p ())
- uiout->field_string ("function", "??");
+ uiout->field_string ("function", "??",
+ ui_out_style_kind::FUNCTION);

if ((flags & RECORD_PRINT_INSN_RANGE) != 0)
{
diff --git a/gdb/skip.c b/gdb/skip.c
index 77373e85e6..a8f8ee1962 100644
--- a/gdb/skip.c
+++ b/gdb/skip.c
@@ -413,7 +413,8 @@ info_skip_command (const char *arg, int from_tty)

current_uiout->field_string ("file",
e.file ().empty () ? "<none>"
- : e.file ().c_str ()); /* 4 */
+ : e.file ().c_str (),
+ ui_out_style_kind::FILE); /* 4 */
if (e.function_is_regexp ())
current_uiout->field_string ("regexp", "y"); /* 5 */
else
@@ -421,7 +422,8 @@ info_skip_command (const char *arg, int from_tty)

current_uiout->field_string ("function",
e.function ().empty () ? "<none>"
- : e.function ().c_str ()); /* 6 */
+ : e.function ().c_str (),
+ ui_out_style_kind::FUNCTION); /* 6 */

current_uiout->text ("\n");
}
diff --git a/gdb/source.c b/gdb/source.c
index e295fbf49e..7552496f78 100644
--- a/gdb/source.c
+++ b/gdb/source.c
@@ -1320,7 +1320,8 @@ print_source_lines_base (struct symtab *s, int line, int stopline,
MI expects both fields. ui_source_list is set only for CLI,
not for TUI. */
if (uiout->is_mi_like_p () || uiout->test_flags (ui_source_list))
- uiout->field_string ("file", symtab_to_filename_for_display (s));
+ uiout->field_string ("file", symtab_to_filename_for_display (s),
+ ui_out_style_kind::FILE);
if (uiout->is_mi_like_p () || !uiout->test_flags (ui_source_list))
{
const char *s_fullname = symtab_to_fullname (s);
diff --git a/gdb/stack.c b/gdb/stack.c
index f34d7b2a17..a718bf8901 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -824,16 +824,19 @@ print_frame_info (struct frame_info *frame, int print_level,
if (get_frame_type (frame) == DUMMY_FRAME)
{
annotate_function_call ();
- uiout->field_string ("func", "<function called from gdb>");
+ uiout->field_string ("func", "<function called from gdb>",
+ ui_out_style_kind::FUNCTION);
}
else if (get_frame_type (frame) == SIGTRAMP_FRAME)
{
annotate_signal_handler_caller ();
- uiout->field_string ("func", "<signal handler called>");
+ uiout->field_string ("func", "<signal handler called>",
+ ui_out_style_kind::FUNCTION);
}
else if (get_frame_type (frame) == ARCH_FRAME)
{
- uiout->field_string ("func", "<cross-architecture call>");
+ uiout->field_string ("func", "<cross-architecture call>",
+ ui_out_style_kind::FUNCTION);
}
uiout->text ("\n");
annotate_frame_end ();
@@ -1182,7 +1185,7 @@ print_frame (struct frame_info *frame, int print_level,
string_file stb;
fprintf_symbol_filtered (&stb, funname ? funname.get () : "??",
funlang, DMGL_ANSI);
- uiout->field_stream ("func", stb);
+ uiout->field_stream ("func", stb, ui_out_style_kind::FUNCTION);
uiout->wrap_hint (" ");
annotate_frame_args ();

@@ -1225,7 +1228,7 @@ print_frame (struct frame_info *frame, int print_level,
uiout->wrap_hint (" ");
uiout->text (" at ");
annotate_frame_source_file ();
- uiout->field_string ("file", filename_display);
+ uiout->field_string ("file", filename_display, ui_out_style_kind::FILE);
if (uiout->is_mi_like_p ())
{
const char *fullname = symtab_to_fullname (sal.symtab);
diff --git a/gdb/testsuite/gdb.base/style.c b/gdb/testsuite/gdb.base/style.c
new file mode 100644
index 0000000000..a7820831fd
--- /dev/null
+++ b/gdb/testsuite/gdb.base/style.c
@@ -0,0 +1,22 @@
+/* Copyright 2018 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/>. */
+
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+ return 0; /* break here */
+}
diff --git a/gdb/testsuite/gdb.base/style.exp b/gdb/testsuite/gdb.base/style.exp
new file mode 100644
index 0000000000..859e50352f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/style.exp
@@ -0,0 +1,41 @@
+# Copyright 2018 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/>.
+
+# Test CLI output styling.
+
+standard_testfile
+
+save_vars { env(TERM) } {
+ # We need an ANSI-capable terminal to get the output.
+ setenv TERM ansi
+
+ if {[prepare_for_testing "failed to prepare" $testfile $srcfile]} {
+ return -1
+ }
+
+ if {![runto_main]} {
+ fail "style tests failed"
+ return
+ }
+
+ gdb_test_no_output "set style enabled on"
+
+ set main_expr "\033\\\[33mmain\033\\\[m"
+ set file_expr "\033\\\[32m.*style\\.c\033\\\[m:\[0-9\]"
+
+ gdb_test "frame" \
+ "$main_expr.*$file_expr.*"
+ gdb_test "info breakpoints" "$main_expr at $file_expr.*"
+}
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 8cd53374f9..5c1111297c 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -3684,8 +3684,8 @@ print_one_static_tracepoint_marker (int count,
if (sym)
{
uiout->text ("in ");
- uiout->field_string ("func",
- SYMBOL_PRINT_NAME (sym));
+ uiout->field_string ("func", SYMBOL_PRINT_NAME (sym),
+ ui_out_style_kind::FUNCTION);
uiout->wrap_hint (wrap_indent);
uiout->text (" at ");
}
@@ -3695,7 +3695,8 @@ print_one_static_tracepoint_marker (int count,
if (sal.symtab != NULL)
{
uiout->field_string ("file",
- symtab_to_filename_for_display (sal.symtab));
+ symtab_to_filename_for_display (sal.symtab),
+ ui_out_style_kind::FILE);
uiout->text (":");

if (uiout->is_mi_like_p ())
diff --git a/gdb/tui/tui-out.c b/gdb/tui/tui-out.c
index 6d4e2363f3..29d7bfa84b 100644
--- a/gdb/tui/tui-out.c
+++ b/gdb/tui/tui-out.c
@@ -51,7 +51,8 @@ tui_ui_out::do_field_int (int fldno, int width, ui_align alignment,

void
tui_ui_out::do_field_string (int fldno, int width, ui_align align,
- const char *fldname, const char *string)
+ const char *fldname, const char *string,
+ ui_out_style_kind style)
{
if (suppress_output ())
return;
@@ -68,7 +69,7 @@ tui_ui_out::do_field_string (int fldno, int width, ui_align align,

m_start_of_line++;

- cli_ui_out::do_field_string (fldno, width, align, fldname, string);
+ cli_ui_out::do_field_string (fldno, width, align, fldname, string, style);
}

void
diff --git a/gdb/tui/tui-out.h b/gdb/tui/tui-out.h
index d191c65810..a4903eef61 100644
--- a/gdb/tui/tui-out.h
+++ b/gdb/tui/tui-out.h
@@ -31,7 +31,7 @@ protected:
void do_field_int (int fldno, int width, ui_align align, const char *fldname,
int value) override;
void do_field_string (int fldno, int width, ui_align align, const char *fldname,
- const char *string) override;
+ const char *string, ui_out_style_kind style) override;
void do_field_fmt (int fldno, int width, ui_align align, const char *fldname,
const char *format, va_list args) override
ATTRIBUTE_PRINTF (6,0);
diff --git a/gdb/ui-out.c b/gdb/ui-out.c
index 3d74f78543..761d6c0745 100644
--- a/gdb/ui-out.c
+++ b/gdb/ui-out.c
@@ -473,10 +473,11 @@ ui_out::field_core_addr (const char *fldname, struct gdbarch *gdbarch,
}

void
-ui_out::field_stream (const char *fldname, string_file &stream)
+ui_out::field_stream (const char *fldname, string_file &stream,
+ ui_out_style_kind style)
{
if (!stream.empty ())
- field_string (fldname, stream.c_str ());
+ field_string (fldname, stream.c_str (), style);
else
field_skip (fldname);
stream.clear ();
@@ -497,7 +498,8 @@ ui_out::field_skip (const char *fldname)
}

void
-ui_out::field_string (const char *fldname, const char *string)
+ui_out::field_string (const char *fldname, const char *string,
+ ui_out_style_kind style)
{
int fldno;
int width;
@@ -505,7 +507,7 @@ ui_out::field_string (const char *fldname, const char *string)

verify_field (&fldno, &width, &align);

- do_field_string (fldno, width, align, fldname, string);
+ do_field_string (fldno, width, align, fldname, string, style);
}

void
diff --git a/gdb/ui-out.h b/gdb/ui-out.h
index 81e2e0b20d..8604105c09 100644
--- a/gdb/ui-out.h
+++ b/gdb/ui-out.h
@@ -66,6 +66,18 @@ enum ui_out_type
ui_out_type_list
};

+/* Possible kinds of styling. */
+
+enum class ui_out_style_kind
+{
+ /* The default (plain) style. */
+ DEFAULT,
+ /* File name. */
+ FILE,
+ /* Function name. */
+ FUNCTION
+};
+
class ui_out
{
public:
@@ -95,9 +107,11 @@ class ui_out
int value);
void field_core_addr (const char *fldname, struct gdbarch *gdbarch,
CORE_ADDR address);
- void field_string (const char *fldname, const char *string);
+ void field_string (const char *fldname, const char *string,
+ ui_out_style_kind style = ui_out_style_kind::DEFAULT);
void field_string (const char *fldname, const std::string &string);
- void field_stream (const char *fldname, string_file &stream);
+ void field_stream (const char *fldname, string_file &stream,
+ ui_out_style_kind style = ui_out_style_kind::DEFAULT);
void field_skip (const char *fldname);
void field_fmt (const char *fldname, const char *format, ...)
ATTRIBUTE_PRINTF (3, 4);
@@ -141,7 +155,8 @@ class ui_out
virtual void do_field_skip (int fldno, int width, ui_align align,
const char *fldname) = 0;
virtual void do_field_string (int fldno, int width, ui_align align,
- const char *fldname, const char *string) = 0;
+ const char *fldname, const char *string,
+ ui_out_style_kind style) = 0;
virtual void do_field_fmt (int fldno, int width, ui_align align,
const char *fldname, const char *format,
va_list args)
diff --git a/gdb/utils.c b/gdb/utils.c
index 0f1953a66d..69c9e76576 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -71,6 +71,7 @@
#include "cp-support.h"
#include <algorithm>
#include "common/pathstuff.h"
+#include "cli/cli-style.h"

void (*deprecated_error_begin_hook) (void);

@@ -1422,6 +1423,46 @@ set_screen_width_and_height (int width, int height)
set_width ();
}

+/* The currently applied style. */
+
+static ui_file_style applied_style;
+
+/* The currently desired style. This can differ from the applied
+ style when showing the pagination prompt. */
+
+static ui_file_style desired_style;
+
+/* Emit an ANSI style escape for STYLE to the wrap buffer. */
+
+static void
+emit_style_escape (const ui_file_style &style)
+{
+ if (applied_style == style)
+ return;
+ applied_style = style;
+
+ wrap_buffer.append (style.to_ansi ());
+}
+
+/* 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 (stream != gdb_stdout
+ || !cli_styling
+ || style == desired_style
+ || !ui_file_isatty (stream))
+ return;
+ const char *term = getenv ("TERM");
+ if (term == nullptr || !strcmp (term, "dumb"))
+ return;
+
+ desired_style = style;
+ emit_style_escape (style);
+}
+
/* 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
@@ -1437,6 +1478,9 @@ prompt_for_continue (void)
steady_clock::time_point prompt_started = steady_clock::now ();
bool disable_pagination = pagination_disabled_for_command;

+ /* Clear the current styling. */
+ emit_style_escape (ui_file_style ());
+
if (annotation_level > 1)
printf_unfiltered (("\n\032\032pre-prompt-for-continue\n"));

@@ -1481,6 +1525,9 @@ prompt_for_continue (void)
reinitialize_more_filter ();
pagination_disabled_for_command = disable_pagination;

+ /* Restore the current styling. */
+ emit_style_escape (desired_style);
+
dont_repeat (); /* Forget prev cmd -- CR won't repeat it. */
}

@@ -1714,7 +1761,11 @@ fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream,
if chars_per_line is right, we probably just overflowed
anyway; if it's wrong, let us keep going. */
if (wrap_column)
- fputc_unfiltered ('\n', stream);
+ {
+ emit_style_escape (ui_file_style ());
+ flush_wrap_buffer (stream);
+ fputc_unfiltered ('\n', stream);
+ }

/* Possible new page. Note that
PAGINATION_DISABLED_FOR_COMMAND might be set during
@@ -1727,6 +1778,7 @@ fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream,
if (wrap_column)
{
fputs_unfiltered (wrap_indent, stream);
+ emit_style_escape (desired_style);
flush_wrap_buffer (stream);
/* FIXME, this strlen is what prevents wrap_indent from
containing tabs. However, if we recurse to print it
@@ -1759,6 +1811,17 @@ fputs_filtered (const char *linebuffer, struct ui_file *stream)
fputs_maybe_filtered (linebuffer, stream, 1);
}

+/* See utils.h. */
+
+void
+fputs_styled (const char *linebuffer, const ui_file_style &style,
+ struct ui_file *stream)
+{
+ set_output_style (stream, style);
+ fputs_maybe_filtered (linebuffer, stream, 1);
+ set_output_style (stream, ui_file_style ());
+}
+
int
putchar_unfiltered (int c)
{
@@ -1986,6 +2049,21 @@ fprintfi_filtered (int spaces, struct ui_file *stream, const char *format,
va_end (args);
}

+/* See utils.h. */
+
+void
+fprintf_styled (struct ui_file *stream, const ui_file_style &style,
+ const char *format, ...)
+{
+ va_list args;
+
+ set_output_style (stream, style);
+ va_start (args, format);
+ vfprintf_filtered (stream, format, args);
+ va_end (args);
+ set_output_style (stream, ui_file_style ());
+}
+

void
printf_filtered (const char *format, ...)
diff --git a/gdb/utils.h b/gdb/utils.h
index 08a29af1dc..9872a15fd7 100644
--- a/gdb/utils.h
+++ b/gdb/utils.h
@@ -423,6 +423,22 @@ extern void fputstrn_unfiltered (const char *str, int n, int quotr,
/* Return nonzero if filtered printing is initialized. */
extern int filtered_printing_initialized (void);

+/* Like fprintf_filtered, but styles the output according to STYLE,
+ when appropriate. */
+
+extern void fprintf_styled (struct ui_file *stream,
+ const ui_file_style &style,
+ const char *fmt,
+ ...)
+ ATTRIBUTE_PRINTF (3, 4);
+
+/* Like fputs_filtered, but styles the output according to STYLE, when
+ appropriate. */
+
+extern void fputs_styled (const char *linebuffer,
+ const ui_file_style &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);
--
2.17.2
Tom Tromey
2018-11-28 00:14:35 UTC
Permalink
This documents the new "set style" commands.

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

* NEWS: Mention terminal styling.

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

* gdb.texinfo (Output Styling): New node.
---
gdb/ChangeLog | 4 +++
gdb/NEWS | 30 +++++++++++++++++++
gdb/doc/ChangeLog | 4 +++
gdb/doc/gdb.texinfo | 72 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 110 insertions(+)

diff --git a/gdb/NEWS b/gdb/NEWS
index 9ecbb83d99..a5e677bc84 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -40,6 +40,11 @@

* The RISC-V target now supports target descriptions.

+* Terminal styling is now available for the CLI and the TUI. GNU
+ Source Highlight can additionally be used to provide styling of
+ source code snippets. See the "set style" commands, below, for more
+ information.
+
* New targets

NXP S12Z s12z-*-elf
@@ -116,6 +121,31 @@ set tui tab-width NCHARS
show tui tab-width NCHARS
"set tui tab-width" replaces the "tabset" command, which has been deprecated.

+set style enabled [on|off]
+show style enabled
+ Enable or disable terminal styling. Styling is enabled by default
+ on most hosts.
+
+set style filename foreground COLOR
+set style filename background COLOR
+set style filename intensity VALUE
+ Control the styling of file names.
+
+set style function foreground COLOR
+set style function background COLOR
+set style function intensity VALUE
+ Control the styling of function names.
+
+set style variable foreground COLOR
+set style variable background COLOR
+set style variable intensity VALUE
+ Control the styling of variable names.
+
+set style address foreground COLOR
+set style address background COLOR
+set style address intensity VALUE
+ Control the styling of addresses.
+
* MI changes

** The '-data-disassemble' MI command now accepts an '-a' option to
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 7350d94573..4d7b085f35 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -24196,6 +24196,7 @@ described here.
* Editing:: Command editing
* Command History:: Command history
* Screen Size:: Screen size
+* Output Styling:: Output styling
* Numbers:: Numbers
* ABI:: Configuring the current ABI
* Auto-loading:: Automatically loading associated files
@@ -24503,6 +24504,77 @@ Options, -batch}) also automatically disables pagination.
Show the current pagination mode.
@end table

+@node Output Styling
+@section Output Styling
+@cindex styling
+@cindex colors
+
+@value{GDBN} can style its output on a capable terminal. This is
+enabled by default on most systems. Various style settings are
+available; and styles can also be disabled entirely.
+
+@table @code
+@kindex set style enabled
+@item set style enabled @samp{on|off}
+Enable or disable all styling. The default is host-dependent, with
+most hosts defaulting to @samp{on}.
+
+@kindex show style enabled
+@item show style enabled
+Show the current state of styling.
+@end table
+
+Subcommands of @code{set style} control specific forms of styling.
+These subcommands all follow the same pattern: each style-able object
+can be styled with a foreground color, a background color, and an
+intensity.
+
+For example, the style of file names can be controlled using the
+@code{set style filename} group of commands:
+
+@table @code
+@kindex set style filename background
+@item set style filename background @var{color}
+Set the background to @var{color}. Valid colors are @samp{none}
+(meaning the terminal's default color), @samp{black}, @samp{red},
+@samp{green}, @samp{yellow}, @samp{vlue}, @samp{magenta}, @samp{cyan},
+***@samp{white}.
+
+@kindex set style filename foreground
+@item set style filename foreground @var{color}
+Set the foreground to @var{color}. Valid colors are @samp{none}
+(meaning the terminal's default color), @samp{black}, @samp{red},
+@samp{green}, @samp{yellow}, @samp{vlue}, @samp{magenta}, @samp{cyan},
+***@samp{white}.
+
+@kindex set style filename intensity
+@item set style filename intensity @var{value}
+Set the intensity to @var{value}. Valid intensities are @samp{normal}
+(the default), @samp{bold}, and @samp{dim}.
+@end table
+
+The style-able objects are:
+@table @code
+@kindex set style filename
+@item filename
+Control the styling of file names.
+
+@kindex set style function
+@item function
+Control the styling of function names. These are managed with the
+@code{set style function} family of commands.
+
+@kindex set style variable
+@item variable
+Control the styling of variable names. These are managed with the
+@code{set style variable} family of commands.
+
+@kindex set style address
+@item address
+Control the styling of addresses. These are managed with the
+@code{set style address} family of commands.
+@end table
+
@node Numbers
@section Numbers
@cindex number representation
--
2.17.2
Eli Zaretskii
2018-11-28 06:51:57 UTC
Permalink
Date: Tue, 27 Nov 2018 17:14:35 -0700
+For example, the style of file names can be controlled using the
+
+
+
+
+Control the styling of file names.
+
+Control the styling of function names. These are managed with the
+
+Control the styling of variable names. These are managed with the
+
+Control the styling of addresses. These are managed with the
The text is OK, but you have numerous "set style" index entries that
all start with the same substring and will point to almost the same
page. This is not useful, IME. I suggest just a single index entry
about "set style" instead.

Thanks.
Tom Tromey
2018-11-28 00:14:32 UTC
Permalink
PR tui/14126 notes that ANSI terminal escape sequences don't affect
the colors shown in the TUI. A simple way to see this is to try the
extended-prompt example from the gdb manual.

Curses does not pass escape sequences through to the terminal.
Instead, it replaces non-printable characters with a visible
representation, for example "^[" for the ESC character.

This patch fixes the problem by adding a simple ANSI terminal sequence
parser to gdb. These sequences are decoded and those that are
recognized are turned into the appropriate curses calls.

The curses approach to color handling is unusual and so there are some
oddities in the implementation.

Standard curses has no notion of the default colors of the terminal.
So, if you set the foreground color, it is not possible to reset it --
you have to pick some other color. ncurses provides an extension to
handle this, so this patch updates configure and uses it when
available.

Second, in curses, colors always come in pairs: you cannot set just
the foreground. This patch handles this by tracking actually-used
pairs of colors and keeping a table of these for reuse.

Third, there are a limited number of such pairs available. In this
patch, if you try to use too many color combinations, gdb will just
ignore some color changes.

Finally, in addition to limiting the number of color pairs, curses
also limits the number of colors. This means that, when using
extended 8- or 24-bit color sequences, it may be possible to exhaust
the curses color table.

I am very sour on the curses design now.

I do not know how to write a test for this, so I did not.

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

PR tui/14126:
* tui/tui.c (tui_enable): Call start_color and
use_default_colors.
* tui/tui-io.c (struct color_pair): New.
(color_pair_map, last_color_pair, last_style): New globals.
(tui_setup_io): Clean up color map when shutting down.
(curses_colors): New constant.
(get_color_pair, apply_ansi_escape): New functions.
(tui_write): Rewrite.
(tui_puts_internal): New function, from tui_puts. Add "height"
parameter.
(tui_puts): Use tui_puts_internal.
(tui_redisplay_readline): Use tui_puts_internal.
(_initialize_tui_io): New function.
(color_map): New globals.
(get_color): New function.
* configure.ac: Check for use_default_colors.
* config.in, configure: Rebuild.
---
gdb/ChangeLog | 21 +++++
gdb/config.in | 3 +
gdb/configure | 2 +-
gdb/configure.ac | 2 +-
gdb/tui/tui-io.c | 232 +++++++++++++++++++++++++++++++++++++++++++----
gdb/tui/tui.c | 9 ++
6 files changed, 251 insertions(+), 18 deletions(-)

diff --git a/gdb/config.in b/gdb/config.in
index deb9d4a996..760db6b320 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -543,6 +543,9 @@
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H

+/* Define to 1 if you have the `use_default_colors' function. */
+#undef HAVE_USE_DEFAULT_COLORS
+
/* Define to 1 if you have the `vfork' function. */
#undef HAVE_VFORK

diff --git a/gdb/configure b/gdb/configure
index 7665ba6531..44df6ebcfb 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -13320,7 +13320,7 @@ for ac_func in getauxval getrusage getuid getgid \
sigaction sigprocmask sigsetmask socketpair \
ttrace wborder wresize setlocale iconvlist libiconvlist btowc \
setrlimit getrlimit posix_madvise waitpid \
- ptrace64 sigaltstack setns
+ ptrace64 sigaltstack setns use_default_colors
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
diff --git a/gdb/configure.ac b/gdb/configure.ac
index e1ea60660b..56cd0927bb 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -1359,7 +1359,7 @@ AC_CHECK_FUNCS([getauxval getrusage getuid getgid \
sigaction sigprocmask sigsetmask socketpair \
ttrace wborder wresize setlocale iconvlist libiconvlist btowc \
setrlimit getrlimit posix_madvise waitpid \
- ptrace64 sigaltstack setns])
+ ptrace64 sigaltstack setns use_default_colors])
AM_LANGINFO_CODESET
GDB_AC_COMMON

diff --git a/gdb/tui/tui-io.c b/gdb/tui/tui-io.c
index 7823688522..b1099246dd 100644
--- a/gdb/tui/tui-io.c
+++ b/gdb/tui/tui-io.c
@@ -40,6 +40,7 @@
#include "filestuff.h"
#include "completer.h"
#include "gdb_curses.h"
+#include <map>

/* This redefines CTRL if it is not already defined, so it must come
after terminal state releated include files like <term.h> and
@@ -188,17 +189,219 @@ tui_putc (char c)
update_cmdwin_start_line ();
}

+/* This maps colors to their corresponding color index. */
+
+static std::map<ui_file_style::color, int> color_map;
+
+/* This holds a pair of colors and is used to track the mapping
+ between a color pair index and the actual colors. */
+
+struct color_pair
+{
+ int fg;
+ int bg;
+
+ bool operator< (const color_pair &o) const
+ {
+ return fg < o.fg || (fg == o.fg && bg < o.bg);
+ }
+};
+
+/* This maps pairs of colors to their corresponding color pair
+ index. */
+
+static std::map<color_pair, int> color_pair_map;
+
+/* This is indexed by ANSI color offset from the base color, and holds
+ the corresponding curses color constant. */
+
+static const int curses_colors[] = {
+ COLOR_BLACK,
+ COLOR_RED,
+ COLOR_GREEN,
+ COLOR_YELLOW,
+ COLOR_BLUE,
+ COLOR_MAGENTA,
+ COLOR_CYAN,
+ COLOR_WHITE
+};
+
+/* Given a color, find its index. */
+
+static bool
+get_color (const ui_file_style::color &color, int *result)
+{
+ if (color.is_none ())
+ *result = 1;
+ else if (color.is_basic ())
+ *result = curses_colors[color.get_value ()];
+ else
+ {
+ auto it = color_map.find (color);
+ if (it == color_map.end ())
+ {
+ /* The first 8 colors are standard. */
+ int next = color_map.size () + 8;
+ if (next >= COLORS)
+ return false;
+ uint8_t rgb[3];
+ color.get_rgb (rgb);
+ /* We store RGB as 0..255, but curses wants 0..1000. */
+ if (init_color (next, rgb[0] * 1000 / 255, rgb[1] * 1000 / 255,
+ rgb[2] * 1000 / 255) == ERR)
+ return false;
+ color_map[color] = next;
+ *result = next;
+ }
+ else
+ *result = it->second;
+ }
+ return true;
+}
+
+/* The most recently emitted color pair. */
+
+static int last_color_pair = -1;
+
+/* The most recently applied style. */
+
+static ui_file_style last_style;
+
+/* Given two colors, return their color pair index; making a new one
+ if necessary. */
+
+static int
+get_color_pair (int fg, int bg)
+{
+ color_pair c = { fg, bg };
+ auto it = color_pair_map.find (c);
+ if (it == color_pair_map.end ())
+ {
+ /* Color pair 0 is our default color, so new colors start at
+ 1. */
+ int next = color_pair_map.size () + 1;
+ /* Curses has a limited number of available color pairs. Fall
+ back to the default if we've used too many. */
+ if (next >= COLOR_PAIRS)
+ return 0;
+ init_pair (next, fg, bg);
+ color_pair_map[c] = next;
+ return next;
+ }
+ return it->second;
+}
+
+/* Apply an ANSI escape sequence from BUF to W. BUF must start with
+ the ESC character. If BUF does not start with an ANSI escape,
+ return 0. Otherwise, apply the sequence if it is recognized, or
+ simply ignore it if not. In this case, the number of bytes read
+ from BUF is returned. */
+
+static size_t
+apply_ansi_escape (WINDOW *w, const char *buf)
+{
+ ui_file_style style = last_style;
+ size_t n_read;
+
+ if (!style.parse (buf, &n_read))
+ return n_read;
+
+ /* Reset. */
+ wattron (w, A_NORMAL);
+ wattroff (w, A_BOLD);
+ wattroff (w, A_DIM);
+ wattroff (w, A_REVERSE);
+ if (last_color_pair != -1)
+ wattroff (w, COLOR_PAIR (last_color_pair));
+ wattron (w, COLOR_PAIR (0));
+
+ const ui_file_style::color &fg = style.get_foreground ();
+ const ui_file_style::color &bg = style.get_background ();
+ if (!fg.is_none () || !bg.is_none ())
+ {
+ int fgi, bgi;
+ if (get_color (fg, &fgi) && get_color (bg, &bgi))
+ {
+ int pair = get_color_pair (fgi, bgi);
+ if (last_color_pair != -1)
+ wattroff (w, COLOR_PAIR (last_color_pair));
+ wattron (w, COLOR_PAIR (pair));
+ last_color_pair = pair;
+ }
+ }
+
+ switch (style.get_intensity ())
+ {
+ case ui_file_style::NORMAL:
+ break;
+
+ case ui_file_style::BOLD:
+ wattron (w, A_BOLD);
+ break;
+
+ case ui_file_style::DIM:
+ wattron (w, A_DIM);
+ break;
+
+ default:
+ gdb_assert_not_reached ("invalid intensity");
+ }
+
+ if (style.is_reverse ())
+ wattron (w, A_REVERSE);
+
+ last_style = style;
+ return n_read;
+}
+
/* Print LENGTH characters from the buffer pointed to by BUF to the
curses command window. The output is buffered. It is up to the
caller to refresh the screen if necessary. */

void
tui_write (const char *buf, size_t length)
+{
+ /* We need this to be \0-terminated for the regexp matching. */
+ std::string copy (buf, length);
+ tui_puts (copy.c_str ());
+}
+
+static void
+tui_puts_internal (const char *string, int *height)
{
WINDOW *w = TUI_CMD_WIN->generic.handle;
+ char c;
+ int prev_col = 0;

- for (size_t i = 0; i < length; i++)
- do_tui_putc (w, buf[i]);
+ while ((c = *string++) != 0)
+ {
+ if (c == '\1' || c == '\2')
+ {
+ /* Ignore these, they are readline escape-marking
+ sequences. */
+ }
+ else
+ {
+ if (c == '\033')
+ {
+ size_t bytes_read = apply_ansi_escape (w, string - 1);
+ if (bytes_read > 0)
+ {
+ string = string + bytes_read - 1;
+ continue;
+ }
+ }
+ do_tui_putc (w, c);
+
+ if (height != nullptr)
+ {
+ int col = getcurx (w);
+ if (col <= prev_col)
+ ++*height;
+ prev_col = col;
+ }
+ }
+ }
update_cmdwin_start_line ();
}

@@ -209,12 +412,7 @@ tui_write (const char *buf, size_t length)
void
tui_puts (const char *string)
{
- WINDOW *w = TUI_CMD_WIN->generic.handle;
- char c;
-
- while ((c = *string++) != 0)
- do_tui_putc (w, c);
- update_cmdwin_start_line ();
+ tui_puts_internal (string, nullptr);
}

/* Readline callback.
@@ -254,14 +452,10 @@ tui_redisplay_readline (void)
wmove (w, start_line, 0);
prev_col = 0;
height = 1;
- for (in = 0; prompt && prompt[in]; in++)
- {
- waddch (w, prompt[in]);
- col = getcurx (w);
- if (col <= prev_col)
- height++;
- prev_col = col;
- }
+ if (prompt != nullptr)
+ tui_puts_internal (prompt, &height);
+
+ prev_col = getcurx (w);
for (in = 0; in <= rl_end; in++)
{
unsigned char c;
@@ -537,6 +731,12 @@ tui_setup_io (int mode)

/* Save tty for SIGCONT. */
savetty ();
+
+ /* Clean up color information. */
+ last_color_pair = -1;
+ last_style = ui_file_style ();
+ color_map.clear ();
+ color_pair_map.clear ();
}
}

diff --git a/gdb/tui/tui.c b/gdb/tui/tui.c
index 50cad22f16..2299824d97 100644
--- a/gdb/tui/tui.c
+++ b/gdb/tui/tui.c
@@ -437,6 +437,15 @@ tui_enable (void)
gdb_getenv_term ());
}
w = stdscr;
+ if (has_colors ())
+ {
+#ifdef HAVE_USE_DEFAULT_COLORS
+ /* Ncurses extension to help with resetting to the default
+ color. */
+ use_default_colors ();
+#endif
+ start_color ();
+ }

/* Check required terminal capabilities. The MinGW port of
ncurses does have them, but doesn't expose them through "cup". */
--
2.17.2
Tom Tromey
2018-11-28 00:14:27 UTC
Permalink
say_where does not use ui-out, so function and file names printed by
it were not styled. This patch changes say_where to use the low-level
style code directly.

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

* breakpoint.c (say_where): Style file name.

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

* gdb.base/style.exp: Add test for breakpoint setting.
---
gdb/ChangeLog | 4 ++++
gdb/breakpoint.c | 12 +++++++++---
gdb/testsuite/ChangeLog | 4 ++++
gdb/testsuite/gdb.base/style.exp | 5 ++++-
4 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 53763e0254..b99b0fb27c 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -68,6 +68,7 @@
#include "format.h"
#include "thread-fsm.h"
#include "tid-parse.h"
+#include "cli/cli-style.h"

/* readline include files */
#include "readline/readline.h"
@@ -12195,9 +12196,14 @@ say_where (struct breakpoint *b)
/* If there is a single location, we can print the location
more nicely. */
if (b->loc->next == NULL)
- printf_filtered (": file %s, line %d.",
- symtab_to_filename_for_display (b->loc->symtab),
- b->loc->line_number);
+ {
+ puts_filtered (": file ");
+ fputs_styled (symtab_to_filename_for_display (b->loc->symtab),
+ file_name_style.style (),
+ gdb_stdout);
+ printf_filtered (", line %d.",
+ b->loc->line_number);
+ }
else
/* This is not ideal, but each location may have a
different file name, and this at least reflects the
diff --git a/gdb/testsuite/gdb.base/style.exp b/gdb/testsuite/gdb.base/style.exp
index 1ab9d68431..df73e25a16 100644
--- a/gdb/testsuite/gdb.base/style.exp
+++ b/gdb/testsuite/gdb.base/style.exp
@@ -33,10 +33,13 @@ save_vars { env(TERM) } {
gdb_test_no_output "set style enabled on"

set main_expr "\033\\\[33mmain\033\\\[m"
- set file_expr "\033\\\[32m.*style\\.c\033\\\[m:\[0-9\]"
+ set base_file_expr "\033\\\[32m.*style\\.c\033\\\[m"
+ set file_expr "$base_file_expr:\[0-9\]"
set arg_expr "\033\\\[36marg.\033\\\[m"

gdb_test "frame" \
"$main_expr.*$arg_expr.*$arg_expr.*$file_expr.*"
gdb_test "info breakpoints" "$main_expr at $file_expr.*"
+
+ gdb_test "break main" "file $base_file_expr.*"
}
--
2.17.2
Tom Tromey
2018-11-28 00:14:34 UTC
Permalink
This changes gdb to highlight source using GNU Source Highlight, if it
is available.

This affects the output of the "list" command and also the TUI source
window.

No new test because I didn't see a way to make it work when Source
Highlight is not found.

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

* utils.h (can_emit_style_escape): Declare.
* utils.c (can_emit_style_escape): No longer static.
* cli/cli-style.c (set_style_enabled): New function.
(_initialize_cli_style): Use it.
* tui/tui-winsource.c (tui_show_source_line): Use tui_puts.
(tui_alloc_source_buffer): Change how source lines are allocated.
* tui/tui-source.c (copy_source_line): New function.
(tui_set_source_content): Use source cache.
* tui/tui-io.h (tui_puts): Update.
* tui/tui-io.c (tui_puts_internal): Add window parameter.
(tui_puts): Likewise.
(tui_redisplay_readline): Update.
* tui/tui-data.c (free_content_elements): Change how source window
contents are freed.
* source.c (forget_cached_source_info): Clear the source cache.
(print_source_lines_base): Use the source cache.
* source-cache.h: New file.
* source-cache.c: New file.
* configure.ac: Check for GNU Source Highlight library.
* configure: Update.
* config.in: Update.
* Makefile.in (SRCHIGH_LIBS, SRCHIGH_CFLAGS): New variables.
(INTERNAL_CFLAGS_BASE): Add SRCHIGH_CFLAGS.
(CLIBS): Add SRCHIGH_LIBS.
(COMMON_SFILES): Add source-cache.c.
(HFILES_NO_SRCDIR): Add source-cache.h.
---
gdb/ChangeLog | 29 ++++
gdb/Makefile.in | 12 +-
gdb/cli/cli-style.c | 9 +-
gdb/config.in | 3 +
gdb/configure | 30 ++++
gdb/configure.ac | 23 +++
gdb/source-cache.c | 209 +++++++++++++++++++++++++++
gdb/source-cache.h | 79 +++++++++++
gdb/source.c | 38 ++---
gdb/tui/tui-data.c | 5 +-
gdb/tui/tui-io.c | 11 +-
gdb/tui/tui-io.h | 4 +-
gdb/tui/tui-source.c | 302 +++++++++++++++++++---------------------
gdb/tui/tui-winsource.c | 17 +--
gdb/utils.c | 4 +-
gdb/utils.h | 4 +
16 files changed, 576 insertions(+), 203 deletions(-)
create mode 100644 gdb/source-cache.c
create mode 100644 gdb/source-cache.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 54baf96ea3..50d429d792 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -194,6 +194,10 @@ LIBIPT = @LIBIPT@
# Where is libmpfr? This will be empty if libmpfr was not available.
LIBMPFR = @LIBMPFR@

+# GNU source highlight library.
+SRCHIGH_LIBS = @SRCHIGH_LIBS@
+SRCHIGH_CFLAGS = @SRCHIGH_CFLAGS@
+
WARN_CFLAGS = @WARN_CFLAGS@
WERROR_CFLAGS = @WERROR_CFLAGS@
GDB_WARN_CFLAGS = $(WARN_CFLAGS)
@@ -565,7 +569,8 @@ INTERNAL_CFLAGS_BASE = \
$(CXXFLAGS) $(GLOBAL_CFLAGS) $(PROFILE_CFLAGS) \
$(GDB_CFLAGS) $(OPCODES_CFLAGS) $(READLINE_CFLAGS) $(ZLIBINC) \
$(BFD_CFLAGS) $(INCLUDE_CFLAGS) $(LIBDECNUMBER_CFLAGS) \
- $(INTL_CFLAGS) $(INCGNU) $(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS)
+ $(INTL_CFLAGS) $(INCGNU) $(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS) \
+ $(SRCHIGH_CFLAGS)
INTERNAL_WARN_CFLAGS = $(INTERNAL_CFLAGS_BASE) $(GDB_WARN_CFLAGS)
INTERNAL_CFLAGS = $(INTERNAL_WARN_CFLAGS) $(GDB_WERROR_CFLAGS)

@@ -591,7 +596,8 @@ CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(ZLIB) $(INTL) $(LIBIBERTY) $(LIBD
$(XM_CLIBS) $(GDBTKLIBS) \
@LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \
$(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) $(LIBIPT) \
- $(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) $(LIBICONV) $(LIBMPFR)
+ $(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) $(LIBICONV) $(LIBMPFR) \
+ $(SRCHIGH_LIBS)
CDEPS = $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \
$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU)

@@ -1101,6 +1107,7 @@ COMMON_SFILES = \
solib.c \
solib-target.c \
source.c \
+ source-cache.c \
stabsread.c \
stack.c \
std-regs.c \
@@ -1376,6 +1383,7 @@ HFILES_NO_SRCDIR = \
solib-target.h \
solist.h \
source.h \
+ source-cache.h \
sparc-nat.h \
sparc-ravenscar-thread.h \
sparc-tdep.h \
diff --git a/gdb/cli/cli-style.c b/gdb/cli/cli-style.c
index 74e3958eb8..16415e0f88 100644
--- a/gdb/cli/cli-style.c
+++ b/gdb/cli/cli-style.c
@@ -20,6 +20,7 @@
#include "defs.h"
#include "cli/cli-cmds.h"
#include "cli/cli-style.h"
+#include "source-cache.h"

/* True if styling is enabled. */

@@ -216,6 +217,12 @@ show_style (const char *arg, int from_tty)
{
}

+static void
+set_style_enabled (const char *args, int from_tty, struct cmd_list_element *c)
+{
+ g_source_cache.clear ();
+}
+
static void
show_style_enabled (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
@@ -245,7 +252,7 @@ Configure various style-related variables, such as colors"),
Set whether CLI styling is enabled."), _("\
Show whether CLI is enabled."), _("\
If enabled, output to the terminal is styled."),
- NULL, show_style_enabled,
+ set_style_enabled, show_style_enabled,
&style_set_list, &style_show_list);

file_name_style.add_setshow_commands ("filename", no_class,
diff --git a/gdb/config.in b/gdb/config.in
index 760db6b320..ea907d2b56 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -426,6 +426,9 @@
/* Define to 1 if the system has the type `socklen_t'. */
#undef HAVE_SOCKLEN_T

+/* Define to 1 if the source-highlight library is available */
+#undef HAVE_SOURCE_HIGHLIGHT
+
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H

diff --git a/gdb/configure b/gdb/configure
index 44df6ebcfb..811664ed40 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -701,6 +701,8 @@ ALLOCA
LTLIBIPT
LIBIPT
HAVE_LIBIPT
+SRCHIGH_CFLAGS
+SRCHIGH_LIBS
HAVE_GUILE_FALSE
HAVE_GUILE_TRUE
GUILE_LIBS
@@ -11469,6 +11471,34 @@ else
fi


+# ---------------------------- #
+# Check for source highlight. #
+# ---------------------------- #
+
+SRCHIGH_LIBS=
+SRCHIGH_CFLAGS=
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for source highlight" >&5
+$as_echo_n "checking for source highlight... " >&6; }
+if test "${pkg_config_prog_path}" = "missing"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no - pkg-config not found" >&5
+$as_echo "no - pkg-config not found" >&6; }
+else
+ if ${pkg_config_prog_path} --exists source-highlight; then
+ SRCHIGH_CFLAGS=`${pkg_config_prog_path} --cflags source-highlight`
+ SRCHIGH_LIBS=`${pkg_config_prog_path} --libs source-highlight`
+
+$as_echo "#define HAVE_SOURCE_HIGHLIGHT 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+fi
+
+
+
# --------------------- #
# Check for libmcheck. #
# --------------------- #
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 56cd0927bb..7d2d39b710 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -1226,6 +1226,29 @@ AC_SUBST(GUILE_CPPFLAGS)
AC_SUBST(GUILE_LIBS)
AM_CONDITIONAL(HAVE_GUILE, test "${have_libguile}" != no)

+# ---------------------------- #
+# Check for source highlight. #
+# ---------------------------- #
+
+SRCHIGH_LIBS=
+SRCHIGH_CFLAGS=
+AC_MSG_CHECKING([for the source-highlight library])
+if test "${pkg_config_prog_path}" = "missing"; then
+ AC_MSG_RESULT([no - pkg-config not found])
+else
+ if ${pkg_config_prog_path} --exists source-highlight; then
+ SRCHIGH_CFLAGS=`${pkg_config_prog_path} --cflags source-highlight`
+ SRCHIGH_LIBS=`${pkg_config_prog_path} --libs source-highlight`
+ AC_DEFINE([HAVE_SOURCE_HIGHLIGHT], 1,
+ [Define to 1 if the source-highlight library is available])
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ fi
+fi
+AC_SUBST(SRCHIGH_LIBS)
+AC_SUBST(SRCHIGH_CFLAGS)
+
# --------------------- #
# Check for libmcheck. #
# --------------------- #
diff --git a/gdb/source-cache.c b/gdb/source-cache.c
new file mode 100644
index 0000000000..56851806e4
--- /dev/null
+++ b/gdb/source-cache.c
@@ -0,0 +1,209 @@
+/* Cache of styled source file text
+ Copyright (C) 2018 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#include "defs.h"
+#include "source-cache.h"
+#include "common/scoped_fd.h"
+#include "source.h"
+#include "cli/cli-style.h"
+
+#ifdef HAVE_SOURCE_HIGHLIGHT
+#include <fstream>
+#include <sstream>
+#include <srchilite/sourcehighlight.h>
+#include <srchilite/langmap.h>
+#endif
+
+/* The number of source files we'll cache. */
+
+#define MAX_ENTRIES 5
+
+/* See source-cache.h. */
+
+source_cache g_source_cache;
+
+/* See source-cache.h. */
+
+bool
+source_cache::get_plain_source_lines (struct symtab *s, int first_line,
+ int last_line, std::string *lines)
+{
+ scoped_fd desc (open_source_file (s));
+ if (desc.get () < 0)
+ return false;
+
+ if (s->line_charpos == 0)
+ find_source_lines (s, desc.get ());
+
+ if (first_line < 1 || first_line > s->nlines || last_line < 1)
+ return false;
+
+ if (lseek (desc.get (), s->line_charpos[first_line - 1], SEEK_SET) < 0)
+ perror_with_name (symtab_to_filename_for_display (s));
+
+ int last_charpos;
+ if (last_line >= s->nlines)
+ {
+ struct stat st;
+
+ if (fstat (desc.get (), &st) < 0)
+ perror_with_name (symtab_to_filename_for_display (s));
+ /* We could cache this in line_charpos... */
+ last_charpos = st.st_size;
+ }
+ else
+ last_charpos = s->line_charpos[last_line];
+
+ lines->resize (last_charpos - s->line_charpos[first_line - 1]);
+ if (myread (desc.get (), &(*lines)[0], lines->size ()) < 0)
+ perror_with_name (symtab_to_filename_for_display (s));
+
+ return true;
+}
+
+/* See source-cache.h. */
+
+bool
+source_cache::extract_lines (const struct source_text &text, int first_line,
+ int last_line, std::string *lines)
+{
+ int lineno = 1;
+ std::string::size_type pos = 0;
+ std::string::size_type first_pos = std::string::npos;
+
+ while (pos != std::string::npos && lineno <= last_line)
+ {
+ std::string::size_type new_pos = text.contents.find ('\n', pos);
+
+ if (lineno == first_line)
+ first_pos = pos;
+
+ pos = new_pos;
+ if (lineno == last_line || pos == std::string::npos)
+ {
+ if (pos == std::string::npos)
+ pos = text.contents.size ();
+ *lines = text.contents.substr (first_pos, pos - first_pos);
+ return true;
+ }
+ ++lineno;
+ ++pos;
+ }
+
+ return false;
+}
+
+/* Return the Source Highlight language name, given a gdb language
+ LANG. Returns NULL if the language is not known. */
+
+static const char *
+get_language_name (enum language lang)
+{
+ switch (lang)
+ {
+ case language_c:
+ case language_objc:
+ return "c.lang";
+
+ case language_cplus:
+ return "cpp.lang";
+
+ case language_d:
+ return "d.lang";
+
+ case language_go:
+ return "go.lang";
+
+ case language_fortran:
+ return "fortran.lang";
+
+ case language_m2:
+ /* Not handled by Source Highlight. */
+ break;
+
+ case language_asm:
+ return "asm.lang";
+
+ case language_pascal:
+ return "pascal.lang";
+
+ case language_opencl:
+ /* Not handled by Source Highlight. */
+ break;
+
+ case language_rust:
+ /* Not handled by Source Highlight. */
+ break;
+
+ case language_ada:
+ return "ada.lang";
+
+ default:
+ break;
+ }
+
+ return nullptr;
+}
+
+/* See source-cache.h. */
+
+bool
+source_cache::get_source_lines (struct symtab *s, int first_line,
+ int last_line, std::string *lines)
+{
+ if (first_line < 1 || last_line < 1 || first_line > last_line)
+ return false;
+
+#ifdef HAVE_SOURCE_HIGHLIGHT
+ if (can_emit_style_escape (gdb_stdout))
+ {
+ const char *fullname = symtab_to_fullname (s);
+
+ for (const auto &item : m_source_map)
+ {
+ if (item.fullname == fullname)
+ return extract_lines (item, first_line, last_line, lines);
+ }
+
+ const char *lang_name = get_language_name (SYMTAB_LANGUAGE (s));
+ if (lang_name != nullptr)
+ {
+ std::ifstream input (fullname);
+ if (input.is_open ())
+ {
+ srchilite::SourceHighlight highlighter ("esc.outlang");
+ highlighter.setStyleFile("esc.style");
+
+ std::ostringstream output;
+ highlighter.highlight (input, output, lang_name, fullname);
+
+ source_text result = { fullname, output.str () };
+ m_source_map.push_back (std::move (result));
+
+ if (m_source_map.size () > MAX_ENTRIES)
+ m_source_map.erase (m_source_map.begin ());
+
+ return extract_lines (m_source_map.back (), first_line,
+ last_line, lines);
+ }
+ }
+ }
+#endif /* HAVE_SOURCE_HIGHLIGHT */
+
+ return get_plain_source_lines (s, first_line, last_line, lines);
+}
diff --git a/gdb/source-cache.h b/gdb/source-cache.h
new file mode 100644
index 0000000000..2236d38846
--- /dev/null
+++ b/gdb/source-cache.h
@@ -0,0 +1,79 @@
+/* Cache of styled source file text
+ Copyright (C) 2018 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#ifndef SOURCE_CACHE_H
+#define SOURCE_CACHE_H
+
+/* This caches highlighted source text, keyed by the source file's
+ full name. A size-limited LRU cache is used.
+
+ Highlighting depends on the GNU Source Highlight library. When not
+ available, this cache will fall back on reading plain text from the
+ appropriate file. */
+class source_cache
+{
+public:
+
+ source_cache ()
+ {
+ }
+
+ /* Get the source text for the source file in symtab S. FIRST_LINE
+ and LAST_LINE are the first and last lines to return; line
+ numbers are 1-based. If the file cannot be read, false is
+ returned. Otherwise, LINES is set to the desired text. The
+ returned text may include ANSI terminal escapes. */
+ bool get_source_lines (struct symtab *s, int first_line,
+ int last_line, std::string *lines);
+
+ /* Remove all the items from the source cache. */
+ void clear ()
+ {
+ m_source_map.clear ();
+ }
+
+private:
+
+ /* One element in the cache. */
+ struct source_text
+ {
+ /* The full name of the file. */
+ std::string fullname;
+ /* The contents of the file. */
+ std::string contents;
+ };
+
+ /* A helper function for get_source_lines that is used when the
+ source lines are not highlighted. The arguments and return value
+ are as for get_source_lines. */
+ bool get_plain_source_lines (struct symtab *s, int first_line,
+ int last_line, std::string *lines);
+ /* A helper function for get_plain_source_lines that extracts the
+ desired source lines from TEXT, putting them into LINES. The
+ arguments and return value are as for get_source_lines. */
+ bool extract_lines (const struct source_text &text, int first_line,
+ int last_line, std::string *lines);
+
+ /* The contents of the cache. */
+ std::vector<source_text> m_source_map;
+};
+
+/* The global source cache. */
+extern source_cache g_source_cache;
+
+#endif /* SOURCE_CACHE_H */
diff --git a/gdb/source.c b/gdb/source.c
index 7552496f78..aa7eb8a6d4 100644
--- a/gdb/source.c
+++ b/gdb/source.c
@@ -45,6 +45,7 @@
#include "common/scoped_fd.h"
#include <algorithm>
#include "common/pathstuff.h"
+#include "source-cache.h"

#define OPEN_MODE (O_RDONLY | O_BINARY)
#define FDOPEN_MODE FOPEN_RB
@@ -393,6 +394,7 @@ forget_cached_source_info (void)
forget_cached_source_info_for_objfile (objfile);
}

+ g_source_cache.clear ();
last_source_visited = NULL;
}

@@ -1344,25 +1346,18 @@ print_source_lines_base (struct symtab *s, int line, int stopline,

last_source_error = 0;

- if (s->line_charpos == 0)
- find_source_lines (s, desc.get ());
-
- if (line < 1 || line > s->nlines)
+ std::string lines;
+ if (!g_source_cache.get_source_lines (s, line, stopline - 1, &lines))
error (_("Line number %d out of range; %s has %d lines."),
line, symtab_to_filename_for_display (s), s->nlines);

- if (lseek (desc.get (), s->line_charpos[line - 1], 0) < 0)
- perror_with_name (symtab_to_filename_for_display (s));
-
- gdb_file_up stream = desc.to_file (FDOPEN_MODE);
- clearerr (stream.get ());
-
+ const char *iter = lines.c_str ();
while (nlines-- > 0)
{
char buf[20];

- c = fgetc (stream.get ());
- if (c == EOF)
+ c = *iter++;
+ if (c == '\0')
break;
last_line_listed = current_source_line;
if (flags & PRINT_SOURCE_LINES_FILENAME)
@@ -1374,7 +1369,7 @@ print_source_lines_base (struct symtab *s, int line, int stopline,
uiout->text (buf);
do
{
- if (c < 040 && c != '\t' && c != '\n' && c != '\r')
+ if (c < 040 && c != '\t' && c != '\n' && c != '\r' && c != '\033')
{
xsnprintf (buf, sizeof (buf), "^%c", c + 0100);
uiout->text (buf);
@@ -1384,12 +1379,13 @@ print_source_lines_base (struct symtab *s, int line, int stopline,
else if (c == '\r')
{
/* Skip a \r character, but only before a \n. */
- int c1 = fgetc (stream.get ());
-
- if (c1 != '\n')
+ if (iter[1] == '\n')
+ {
+ ++iter;
+ c = '\n';
+ }
+ else
printf_filtered ("^%c", c + 0100);
- if (c1 != EOF)
- ungetc (c1, stream.get ());
}
else
{
@@ -1397,8 +1393,12 @@ print_source_lines_base (struct symtab *s, int line, int stopline,
uiout->text (buf);
}
}
- while (c != '\n' && (c = fgetc (stream.get ())) >= 0);
+ while (c != '\n' && (c = *iter++) != '\0');
+ if (c == '\0')
+ break;
}
+ if (lines.back () != '\n')
+ uiout->text ("\n");
}

/* Show source lines from the file of symtab S, starting with line
diff --git a/gdb/tui/tui-data.c b/gdb/tui/tui-data.c
index 4391f0d100..2b95f197fd 100644
--- a/gdb/tui/tui-data.c
+++ b/gdb/tui/tui-data.c
@@ -838,7 +838,7 @@ free_content_elements (tui_win_content content,
{
int i;

- if (type == SRC_WIN || type == DISASSEM_WIN)
+ if (type == DISASSEM_WIN)
{
/* Free whole source block. */
xfree (content[0]->which_element.source.line);
@@ -854,6 +854,9 @@ free_content_elements (tui_win_content content,
{
switch (type)
{
+ case SRC_WIN:
+ xfree (element->which_element.source.line);
+ break;
case DATA_WIN:
xfree (element);
break;
diff --git a/gdb/tui/tui-io.c b/gdb/tui/tui-io.c
index b1099246dd..0c7b88f1c7 100644
--- a/gdb/tui/tui-io.c
+++ b/gdb/tui/tui-io.c
@@ -367,9 +367,8 @@ tui_write (const char *buf, size_t length)
}

static void
-tui_puts_internal (const char *string, int *height)
+tui_puts_internal (WINDOW *w, const char *string, int *height)
{
- WINDOW *w = TUI_CMD_WIN->generic.handle;
char c;
int prev_col = 0;

@@ -410,9 +409,11 @@ tui_puts_internal (const char *string, int *height)
necessary. */

void
-tui_puts (const char *string)
+tui_puts (const char *string, WINDOW *w)
{
- tui_puts_internal (string, nullptr);
+ if (w == nullptr)
+ w = TUI_CMD_WIN->generic.handle;
+ tui_puts_internal (w, string, nullptr);
}

/* Readline callback.
@@ -453,7 +454,7 @@ tui_redisplay_readline (void)
prev_col = 0;
height = 1;
if (prompt != nullptr)
- tui_puts_internal (prompt, &height);
+ tui_puts_internal (TUI_CMD_WIN->generic.handle, prompt, &height);

prev_col = getcurx (w);
for (in = 0; in <= rl_end; in++)
diff --git a/gdb/tui/tui-io.h b/gdb/tui/tui-io.h
index 11752d0845..95887639ec 100644
--- a/gdb/tui/tui-io.h
+++ b/gdb/tui/tui-io.h
@@ -22,11 +22,13 @@
#ifndef TUI_IO_H
#define TUI_IO_H

+#include "gdb_curses.h"
+
struct ui_out;
class cli_ui_out;

/* Print the string in the curses command window. */
-extern void tui_puts (const char *);
+extern void tui_puts (const char *, WINDOW * = nullptr);

/* Print LENGTH characters from the buffer pointed to by BUF to the
curses command window. */
diff --git a/gdb/tui/tui-source.c b/gdb/tui/tui-source.c
index 3c4f06b01a..260b274297 100644
--- a/gdb/tui/tui-source.c
+++ b/gdb/tui/tui-source.c
@@ -28,14 +28,90 @@
#include "symtab.h"
#include "objfiles.h"
#include "filenames.h"
+#include "source-cache.h"

#include "tui/tui.h"
#include "tui/tui-data.h"
+#include "tui/tui-io.h"
#include "tui/tui-stack.h"
#include "tui/tui-winsource.h"
#include "tui/tui-source.h"
#include "gdb_curses.h"

+/* A helper function for tui_set_source_content that extracts some
+ source text from PTR. LINE_NO is the line number; FIRST_COL is the
+ first column to extract, and LINE_WIDTH is the number of characters
+ to display. Returns a string holding the desired text. */
+
+static std::string
+copy_source_line (const char **ptr, int line_no, int first_col,
+ int line_width)
+{
+ const char *lineptr = *ptr;
+
+ /* Init the line with the line number. */
+ std::string result = string_printf ("%-6d", line_no);
+ int len = result.size ();
+ len = len - ((len / tui_tab_width) * tui_tab_width);
+ result.append (len, ' ');
+
+ int column = 0;
+ char c;
+ do
+ {
+ int skip_bytes;
+
+ c = *lineptr;
+ if (c == '\033' && skip_ansi_escape (lineptr, &skip_bytes))
+ {
+ /* We always have to preserve escapes. */
+ result.append (lineptr, lineptr + skip_bytes);
+ lineptr += skip_bytes;
+ continue;
+ }
+
+ ++lineptr;
+ ++column;
+ /* We have to process all the text in order to pick up all the
+ escapes. */
+ if (column < first_col || column > first_col + line_width)
+ continue;
+
+ if (c == '\n' || c == '\r' || c == '\0')
+ {
+ /* Nothing. */
+ }
+ else if (c < 040 && c != '\t')
+ {
+ result.push_back ('^');
+ result.push_back (c + 0100);
+ }
+ else if (c == 0177)
+ {
+ result.push_back ('^');
+ result.push_back ('?');
+ }
+ else if (c == '\t')
+ {
+ int j, max_tab_len = tui_tab_width;
+
+ for (j = column - ((column / max_tab_len) * max_tab_len);
+ j < max_tab_len && column < first_col + line_width;
+ column++, j++)
+ result.push_back (' ');
+ }
+ else
+ result.push_back (c);
+ }
+ while (c != '\0' && c != '\n' && c != '\r');
+
+ if (c == '\r' && *lineptr == '\n')
+ ++lineptr;
+ *ptr = lineptr;
+
+ return result;
+}
+
/* Function to display source in the source window. */
enum tui_status
tui_set_source_content (struct symtab *s,
@@ -46,8 +122,7 @@ tui_set_source_content (struct symtab *s,

if (s != (struct symtab *) NULL)
{
- int i, c, line_width, nlines;
- char *src_line = 0;
+ int line_width, nlines;

if ((ret = tui_alloc_source_buffer (TUI_SRC_WIN)) == TUI_SUCCESS)
{
@@ -55,8 +130,10 @@ tui_set_source_content (struct symtab *s,
/* Take hilite (window border) into account, when
calculating the number of lines. */
nlines = (line_no + (TUI_SRC_WIN->generic.height - 2)) - line_no;
- scoped_fd desc = open_source_file (s);
- if (desc.get () < 0)
+
+ std::string srclines;
+ if (!g_source_cache.get_source_lines (s, line_no, line_no + nlines,
+ &srclines))
{
if (!noerror)
{
@@ -70,165 +147,68 @@ tui_set_source_content (struct symtab *s,
}
else
{
- if (s->line_charpos == 0)
- find_source_lines (s, desc.get ());
-
- if (line_no < 1 || line_no > s->nlines)
- printf_unfiltered ("Line number %d out of range; "
- "%s has %d lines.\n",
- line_no,
- symtab_to_filename_for_display (s),
- s->nlines);
- else if (lseek (desc.get (), s->line_charpos[line_no - 1], 0)
- < 0)
- perror_with_name (symtab_to_filename_for_display (s));
- else
+ int cur_line_no, cur_line;
+ struct tui_gen_win_info *locator
+ = tui_locator_win_info_ptr ();
+ struct tui_source_info *src
+ = &TUI_SRC_WIN->detail.source_info;
+ const char *s_filename = symtab_to_filename_for_display (s);
+
+ if (TUI_SRC_WIN->generic.title)
+ xfree (TUI_SRC_WIN->generic.title);
+ TUI_SRC_WIN->generic.title = xstrdup (s_filename);
+
+ xfree (src->fullname);
+ src->fullname = xstrdup (symtab_to_fullname (s));
+
+ cur_line = 0;
+ src->gdbarch = get_objfile_arch (SYMTAB_OBJFILE (s));
+ src->start_line_or_addr.loa = LOA_LINE;
+ cur_line_no = src->start_line_or_addr.u.line_no = line_no;
+
+ const char *iter = srclines.c_str ();
+ while (cur_line < nlines)
{
- int offset, cur_line_no, cur_line, cur_len, threshold;
- struct tui_gen_win_info *locator
- = tui_locator_win_info_ptr ();
- struct tui_source_info *src
- = &TUI_SRC_WIN->detail.source_info;
- const char *s_filename = symtab_to_filename_for_display (s);
-
- if (TUI_SRC_WIN->generic.title)
- xfree (TUI_SRC_WIN->generic.title);
- TUI_SRC_WIN->generic.title = xstrdup (s_filename);
-
- xfree (src->fullname);
- src->fullname = xstrdup (symtab_to_fullname (s));
-
- /* Determine the threshold for the length of the
- line and the offset to start the display. */
- offset = src->horizontal_offset;
- threshold = (line_width - 1) + offset;
- gdb_file_up stream = desc.to_file (FOPEN_RT);
- clearerr (stream.get ());
- cur_line = 0;
- src->gdbarch = get_objfile_arch (SYMTAB_OBJFILE (s));
- src->start_line_or_addr.loa = LOA_LINE;
- cur_line_no = src->start_line_or_addr.u.line_no = line_no;
- if (offset > 0)
- src_line = (char *) xmalloc (
- (threshold + 1) * sizeof (char));
- while (cur_line < nlines)
- {
- struct tui_win_element *element
- = TUI_SRC_WIN->generic.content[cur_line];
-
- /* Get the first character in the line. */
- c = fgetc (stream.get ());
-
- if (offset == 0)
- src_line = TUI_SRC_WIN->generic.content[cur_line]
- ->which_element.source.line;
- /* Init the line with the line number. */
- sprintf (src_line, "%-6d", cur_line_no);
- cur_len = strlen (src_line);
- i = cur_len - ((cur_len / tui_tab_width)
- * tui_tab_width);
- while (i < tui_tab_width)
- {
- src_line[cur_len] = ' ';
- i++;
- cur_len++;
- }
- src_line[cur_len] = (char) 0;
-
- /* Set whether element is the execution point
- and whether there is a break point on it. */
- element->which_element.source.line_or_addr.loa =
- LOA_LINE;
- element->which_element.source.line_or_addr.u.line_no =
- cur_line_no;
- element->which_element.source.is_exec_point =
- (filename_cmp (locator->content[0]
- ->which_element.locator.full_name,
- symtab_to_fullname (s)) == 0
- && cur_line_no
- == locator->content[0]
- ->which_element.locator.line_no);
- if (c != EOF)
- {
- i = strlen (src_line) - 1;
- do
- {
- if ((c != '\n') && (c != '\r')
- && (++i < threshold))
- {
- if (c < 040 && c != '\t')
- {
- src_line[i++] = '^';
- src_line[i] = c + 0100;
- }
- else if (c == 0177)
- {
- src_line[i++] = '^';
- src_line[i] = '?';
- }
- else
- { /* Store the charcter in the
- line buffer. If it is a tab,
- then translate to the correct
- number of chars so we don't
- overwrite our buffer. */
- if (c == '\t')
- {
- int j, max_tab_len
- = tui_tab_width;
-
- for (j = i - ((i / max_tab_len)
- * max_tab_len);
- j < max_tab_len
- && i < threshold;
- i++, j++)
- src_line[i] = ' ';
- i--;
- }
- else
- src_line[i] = c;
- }
- src_line[i + 1] = 0;
- }
- else
- { /* If we have not reached EOL, then
- eat chars until we do. */
- while (c != EOF && c != '\n' && c != '\r')
- c = fgetc (stream.get ());
- /* Handle non-'\n' end-of-line. */
- if (c == '\r'
- && (c = fgetc (stream.get ())) != '\n'
- && c != EOF)
- {
- ungetc (c, stream.get ());
- c = '\r';
- }
-
- }
- }
- while (c != EOF && c != '\n' && c != '\r'
- && i < threshold
- && (c = fgetc (stream.get ())));
- }
- /* Now copy the line taking the offset into
- account. */
- if (offset == 0)
- ;
- else if (strlen (src_line) > offset)
- strcpy (TUI_SRC_WIN->generic.content[cur_line]
- ->which_element.source.line,
- &src_line[offset]);
- else
- TUI_SRC_WIN->generic.content[cur_line]
- ->which_element.source.line[0] = (char) 0;
- cur_line++;
- cur_line_no++;
- }
- if (offset > 0)
- xfree (src_line);
- TUI_SRC_WIN->generic.content_size = nlines;
- ret = TUI_SUCCESS;
+ struct tui_win_element *element
+ = TUI_SRC_WIN->generic.content[cur_line];
+
+ std::string text;
+ if (*iter != '\0')
+ text = copy_source_line (&iter, cur_line_no,
+ src->horizontal_offset,
+ line_width);
+
+ /* Set whether element is the execution point
+ and whether there is a break point on it. */
+ element->which_element.source.line_or_addr.loa =
+ LOA_LINE;
+ element->which_element.source.line_or_addr.u.line_no =
+ cur_line_no;
+ element->which_element.source.is_exec_point =
+ (filename_cmp (locator->content[0]
+ ->which_element.locator.full_name,
+ symtab_to_fullname (s)) == 0
+ && cur_line_no
+ == locator->content[0]
+ ->which_element.locator.line_no);
+
+ xfree (TUI_SRC_WIN->generic.content[cur_line]
+ ->which_element.source.line);
+ int alloc_len = text.size ();
+ if (alloc_len < line_width)
+ alloc_len = line_width + 1;
+ TUI_SRC_WIN->generic.content[cur_line]
+ ->which_element.source.line
+ = (char *) xmalloc (alloc_len);
+ strcpy (TUI_SRC_WIN->generic.content[cur_line]
+ ->which_element.source.line,
+ text.c_str ());
+
+ cur_line++;
+ cur_line_no++;
}
+ TUI_SRC_WIN->generic.content_size = nlines;
+ ret = TUI_SUCCESS;
}
}
}
diff --git a/gdb/tui/tui-winsource.c b/gdb/tui/tui-winsource.c
index 0bf74383b1..00b4b9e4fa 100644
--- a/gdb/tui/tui-winsource.c
+++ b/gdb/tui/tui-winsource.c
@@ -31,6 +31,7 @@

#include "tui/tui.h"
#include "tui/tui-data.h"
+#include "tui/tui-io.h"
#include "tui/tui-stack.h"
#include "tui/tui-win.h"
#include "tui/tui-wingeneral.h"
@@ -277,8 +278,9 @@ tui_show_source_line (struct tui_win_info *win_info, int lineno)
if (line->which_element.source.is_exec_point)
wattron (win_info->generic.handle, A_STANDOUT);

- mvwaddstr (win_info->generic.handle, lineno, 1,
- line->which_element.source.line);
+ wmove (win_info->generic.handle, lineno, 1);
+ tui_puts (line->which_element.source.line,
+ win_info->generic.handle);
if (line->which_element.source.is_exec_point)
wattroff (win_info->generic.handle, A_STANDOUT);

@@ -595,7 +597,6 @@ tui_update_exec_info (struct tui_win_info *win_info)
enum tui_status
tui_alloc_source_buffer (struct tui_win_info *win_info)
{
- char *src_line_buf;
int i, line_width, max_lines;

/* The window width/height includes the highlight box. Determine actual
@@ -603,20 +604,14 @@ tui_alloc_source_buffer (struct tui_win_info *win_info)
max_lines = win_info->generic.height - 2;
line_width = win_info->generic.width - 2 + 1;

- /*
- * Allocate the buffer for the source lines. Do this only once
- * since they will be re-used for all source displays. The only
- * other time this will be done is when a window's size changes.
- */
+ /* Allocate the buffer for the source lines. */
if (win_info->generic.content == NULL)
{
- src_line_buf = (char *)
- xmalloc ((max_lines * line_width) * sizeof (char));
/* Allocate the content list. */
win_info->generic.content = tui_alloc_content (max_lines, SRC_WIN);
for (i = 0; i < max_lines; i++)
win_info->generic.content[i]->which_element.source.line
- = src_line_buf + (line_width * i);
+ = (char *) xmalloc (line_width);
}

return TUI_SUCCESS;
diff --git a/gdb/utils.c b/gdb/utils.c
index 85b0fb14e3..00f524c52e 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -1444,9 +1444,9 @@ emit_style_escape (const ui_file_style &style)
wrap_buffer.append (style.to_ansi ());
}

-/* Return true if ANSI escapes can be used on STREAM. */
+/* See utils.h. */

-static bool
+bool
can_emit_style_escape (struct ui_file *stream)
{
if (stream != gdb_stdout
diff --git a/gdb/utils.h b/gdb/utils.h
index 1f09ec2d47..16ee9fbd33 100644
--- a/gdb/utils.h
+++ b/gdb/utils.h
@@ -443,6 +443,10 @@ extern void fputs_styled (const char *linebuffer,

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);
--
2.17.2
Tom Tromey
2018-11-28 00:14:20 UTC
Permalink
Currently wrap buffering is implemented by allocating a string that is
the same width as the window, and then writing characters into it.
However, if gdb emits terminal escapes, then these could possibly
overflow the buffer.

To prevent this, change the wrap buffer to be a std::string and update
the various uses.

This also changes utils.c to always emit characters to the wrap
buffer. This simplifies future patches which emit terminal escape
sequences, and also makes it possible for the "echo" and "printf"
commands to be used to emit terminal escapes and have these work in
the TUI.

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

* utils.c (filter_initalized): New global.
(wrap_buffer): Now a std::string.
(wrap_pointer): Remove.
(flush_wrap_buffer): New function.
(filtered_printing_initialized, set_width, wrap_here)
(fputs_maybe_filtered): Update.
---
gdb/ChangeLog | 9 ++++++++
gdb/utils.c | 63 +++++++++++++++++++++------------------------------
2 files changed, 35 insertions(+), 37 deletions(-)

diff --git a/gdb/utils.c b/gdb/utils.c
index 0577e64ea8..0f1953a66d 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -1268,13 +1268,11 @@ static bool pagination_disabled_for_command;
the end of the line, we spit out a newline, the indent, and then
the buffered output. */

-/* Malloc'd buffer with chars_per_line+2 bytes. Contains characters which
- are waiting to be output (they have already been counted in chars_printed).
- When wrap_buffer[0] is null, the buffer is empty. */
-static char *wrap_buffer;
+static bool filter_initalized = false;

-/* Pointer in wrap_buffer to the next character to fill. */
-static char *wrap_pointer;
+/* Contains characters which are waiting to be output (they have
+ already been counted in chars_printed). */
+static std::string wrap_buffer;

/* String to indent by if the wrap occurs. Must not be NULL if wrap_column
is non-zero. */
@@ -1347,7 +1345,7 @@ init_page_info (void)
int
filtered_printing_initialized (void)
{
- return wrap_buffer != NULL;
+ return filter_initalized;
}

set_batch_flag_and_restore_page_info::set_batch_flag_and_restore_page_info ()
@@ -1387,8 +1385,7 @@ set_screen_size (void)
rl_set_screen_size (rows, cols);
}

-/* Reinitialize WRAP_BUFFER according to the current value of
- CHARS_PER_LINE. */
+/* Reinitialize WRAP_BUFFER. */

static void
set_width (void)
@@ -1396,14 +1393,8 @@ set_width (void)
if (chars_per_line == 0)
init_page_info ();

- if (!wrap_buffer)
- {
- wrap_buffer = (char *) xmalloc (chars_per_line + 2);
- wrap_buffer[0] = '\0';
- }
- else
- wrap_buffer = (char *) xrealloc (wrap_buffer, chars_per_line + 2);
- wrap_pointer = wrap_buffer; /* Start it at the beginning. */
+ wrap_buffer.clear ();
+ filter_initalized = true;
}

static void
@@ -1521,6 +1512,18 @@ reinitialize_more_filter (void)
pagination_disabled_for_command = false;
}

+/* Flush the wrap buffer to STREAM, if necessary. */
+
+static void
+flush_wrap_buffer (struct ui_file *stream)
+{
+ if (!wrap_buffer.empty ())
+ {
+ fputs_unfiltered (wrap_buffer.c_str (), stream);
+ wrap_buffer.clear ();
+ }
+}
+
/* Indicate that if the next sequence of characters overflows the line,
a newline should be inserted here rather than when it hits the end.
If INDENT is non-null, it is a string to be printed to indent the
@@ -1546,17 +1549,11 @@ void
wrap_here (const char *indent)
{
/* This should have been allocated, but be paranoid anyway. */
- if (!wrap_buffer)
+ if (!filter_initalized)
internal_error (__FILE__, __LINE__,
_("failed internal consistency check"));

- if (wrap_buffer[0])
- {
- *wrap_pointer = '\0';
- fputs_unfiltered (wrap_buffer, gdb_stdout);
- }
- wrap_pointer = wrap_buffer;
- wrap_buffer[0] = '\0';
+ flush_wrap_buffer (gdb_stdout);
if (chars_per_line == UINT_MAX) /* No line overflow checking. */
{
wrap_column = 0;
@@ -1669,6 +1666,7 @@ fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream,
|| top_level_interpreter () == NULL
|| top_level_interpreter ()->interp_ui_out ()->is_mi_like_p ())
{
+ flush_wrap_buffer (stream);
fputs_unfiltered (linebuffer, stream);
return;
}
@@ -1692,10 +1690,7 @@ fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream,
/* Print a single line. */
if (*lineptr == '\t')
{
- if (wrap_column)
- *wrap_pointer++ = '\t';
- else
- fputc_unfiltered ('\t', stream);
+ wrap_buffer.push_back ('\t');
/* Shifting right by 3 produces the number of tab stops
we have already passed, and then adding one and
shifting left 3 advances to the next tab stop. */
@@ -1704,10 +1699,7 @@ fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream,
}
else
{
- if (wrap_column)
- *wrap_pointer++ = *lineptr;
- else
- fputc_unfiltered (*lineptr, stream);
+ wrap_buffer.push_back (*lineptr);
chars_printed++;
lineptr++;
}
@@ -1735,8 +1727,7 @@ fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream,
if (wrap_column)
{
fputs_unfiltered (wrap_indent, stream);
- *wrap_pointer = '\0'; /* Null-terminate saved stuff, */
- fputs_unfiltered (wrap_buffer, stream); /* and eject it. */
+ flush_wrap_buffer (stream);
/* FIXME, this strlen is what prevents wrap_indent from
containing tabs. However, if we recurse to print it
and count its chars, we risk trouble if wrap_indent is
@@ -1745,8 +1736,6 @@ fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream,
if we are printing a long string. */
chars_printed = strlen (wrap_indent)
+ (save_chars - wrap_column);
- wrap_pointer = wrap_buffer; /* Reset buffer */
- wrap_buffer[0] = '\0';
wrap_column = 0; /* And disable fancy wrap */
}
}
--
2.17.2
Eli Zaretskii
2018-11-28 07:02:15 UTC
Permalink
Date: Tue, 27 Nov 2018 17:14:19 -0700
This series doesn't support the Windows console. I don't know
anything about it. So, it defaults to disabling styling on Windows
filter escape sequences from the output and apply them by some other
means.
Will the Windows TUI build support styling out of the box? It uses
ncurses.

And I don't think I understand what you mean by "filter escape
sequences from the output". Where (on what level) would such filter
be installed, given that output is written directly to the console?

I see that you introduced the emit_style_escape function that switches
styles. What I don't think I understand is whether it will work to
have a Windows implementation of that that calls a function which
causes the text output after that to use given colors? It seems it
will, because the code calls emit_style_escape before and after each
string, but I cannot be sure.

Thanks.
Tom Tromey
2018-11-29 22:43:59 UTC
Permalink
Eli> Will the Windows TUI build support styling out of the box? It uses
Eli> ncurses.

I think it should work, but you'd have to "set style enabled on" first.

Eli> And I don't think I understand what you mean by "filter escape
Eli> sequences from the output". Where (on what level) would such filter
Eli> be installed, given that output is written directly to the console?

I think either utils.c would have to be modified to change where it
sends output, or stdio_file::puts would have to be modified. The idea
there would be to call a host-specific function; and then on Windows do
the filtering+styling if the output is going to the terminal.

Eli> I see that you introduced the emit_style_escape function that switches
Eli> styles. What I don't think I understand is whether it will work to
Eli> have a Windows implementation of that that calls a function which
Eli> causes the text output after that to use given colors? It seems it
Eli> will, because the code calls emit_style_escape before and after each
Eli> string, but I cannot be sure.

Doing it that way can't work due to buffering. Also, this approach
would be undesirable anyway, because GNU Source Highlight emits escape
codes -- that's why I abandoned my earlier plan of implementing styling
as objects in the utils.c buffer. Instead, I think filtering the escape
sequences is really the only way.

Tom
Eli Zaretskii
2018-11-30 07:03:01 UTC
Permalink
Date: Thu, 29 Nov 2018 15:43:59 -0700
Eli> Will the Windows TUI build support styling out of the box? It uses
Eli> ncurses.
I think it should work, but you'd have to "set style enabled on" first.
Maybe a TUI invocation should "set style enabled on" on all platforms?
Or at least on those that use ncurses?
Eli> And I don't think I understand what you mean by "filter escape
Eli> sequences from the output". Where (on what level) would such filter
Eli> be installed, given that output is written directly to the console?
I think either utils.c would have to be modified to change where it
sends output, or stdio_file::puts would have to be modified. The idea
there would be to call a host-specific function; and then on Windows do
the filtering+styling if the output is going to the terminal.
Ouch! I hoped we could avoid such kludges. Although it could, of
course, be done, I did that at some point for Gnu Grep. One problem
with this approach is that it needs to fix the escape sequences for
the relevant attributes, whereas AFAIU your code simply uses the
terminfo that happens to be in effect, is that right?
Eli> I see that you introduced the emit_style_escape function that switches
Eli> styles. What I don't think I understand is whether it will work to
Eli> have a Windows implementation of that that calls a function which
Eli> causes the text output after that to use given colors? It seems it
Eli> will, because the code calls emit_style_escape before and after each
Eli> string, but I cannot be sure.
Doing it that way can't work due to buffering.
Not sure I understand. Console output is generally line-buffered, and
there's fflush to force writing any buffered output before applying
text attributes. Am I missing something?
Also, this approach would be undesirable anyway, because GNU Source
Highlight emits escape codes -- that's why I abandoned my earlier
plan of implementing styling as objects in the utils.c buffer.
What is GNU Source Highlight, and what is its relevance to the issue
at hand?
Instead, I think filtering the escape sequences is really the only
way.
The problem with that is that it hard-codes the SGR sequences concepts
right into the design, and the escape sequences are unknown in advance
on systems where there's no terminfo.

Thanks.
Tom Tromey
2018-11-30 16:17:36 UTC
Permalink
Tom> I think it should work, but you'd have to "set style enabled on" first.

Eli> Maybe a TUI invocation should "set style enabled on" on all platforms?
Eli> Or at least on those that use ncurses?

That would possibly override the user's setting. It's probably better
to simply implement the console support for Windows. Or, change how the
disabling is done on Windows -- right now it is done by changing the
default for this setting, but perhaps it could be done some other way.

Is it possible to ssh in to a Windows machine and then use gdb? That's
one scenario where you may want to keep the ANSI terminal escape
sequences in the output. It also may affect how calls to the Windows
API are handled.

Eli> One problem with this approach is that it needs to fix the escape
Eli> sequences for the relevant attributes, whereas AFAIU your code
Eli> simply uses the terminfo that happens to be in effect, is that
Eli> right?

This patch series uses ANSI escape sequences for the styling; and the
TUI decodes these and turns them into curses calls.

Tom> Doing it that way can't work due to buffering.

Eli> Not sure I understand. Console output is generally line-buffered, and
Eli> there's fflush to force writing any buffered output before applying
Eli> text attributes. Am I missing something?

utils.c implements its own buffering. Previous to this series this was
only done when "wrap_column > 0", but patch #1 changes this code to
always buffer.

This is a problem for other approaches because styles are emitted inline
with other text; and then flushed as a unit.

Tom> Also, this approach would be undesirable anyway, because GNU Source
Tom> Highlight emits escape codes -- that's why I abandoned my earlier
Tom> plan of implementing styling as objects in the utils.c buffer.

Eli> What is GNU Source Highlight, and what is its relevance to the issue
Eli> at hand?

GNU Source Highlight is used to style source text.

https://www.gnu.org/software/src-highlite/

Support for using it is added to gdb in patch #15.

Tom> Instead, I think filtering the escape sequences is really the only
Tom> way.

Eli> The problem with that is that it hard-codes the SGR sequences concepts
Eli> right into the design, and the escape sequences are unknown in advance
Eli> on systems where there's no terminfo.

Only terminals using the ANSI sequences are supported by this series, at
least for the CLI. The TUI can support more in theory, though I have no
way to test that.

Tom

Loading...