From: Tom Tromey <tom@tromey.com>
To: Andrei Pikas <gdb@mail.api.win>
Cc: tom@tromey.com, gdb-patches@sourceware.org
Subject: Re: [PATCH v7] Add an option with a color type.
Date: Fri, 04 Oct 2024 11:55:15 -0600 [thread overview]
Message-ID: <87r08vhhx8.fsf@tromey.com> (raw)
In-Reply-To: <20240914190452.423367-1-gdb@mail.api.win> (Andrei Pikas's message of "Sat, 14 Sep 2024 22:04:52 +0300")
>>>>> "Andrei" == Andrei Pikas <gdb@mail.api.win> writes:
Andrei> Colors can be specified as "none" for terminal's default color, as a name of
Andrei> one of the eight standard colors of ISO/IEC 6429 "black", "red", "green", etc.,
Andrei> as an RGB hexadecimal tripplet #RRGGBB for 24-bit TrueColor, or as an
Andrei> integer from 0 to 255. Integers 0 to 7 are the synonyms for the standard
Andrei> colors. Integers 8-15 are used for the so-called bright colors from the
Andrei> aixterm extended 16-color palette. Integers 16-255 are the indexes into xterm
Andrei> extended 256-color palette (usually 6x6x6 cube plus gray ramp). In
Andrei> general, 256-color palette is terminal dependent and sometimes can be
Andrei> changed with OSC 4 sequences, e.g. "\033]4;1;rgb:00/FF/00\033\\".
Thank you for the patch. I'm sorry about the long delays on this; gdb
has an ongoing review bandwidth problem. Anyway, I like this a lot and
I would like to see it get in.
I have a fair number of notes here but nothing really major.
Andrei> + case var_color:
Andrei> + {
Andrei> + std::string s = var.get<ui_file_style::color> ().to_string ();
Andrei> + return value_cstring (s.c_str (), s.size (),
Andrei> + builtin_type (gdbarch)->builtin_char);
Other code in this function uses:
return current_language->value_string (gdbarch, value, len);
Andrei> + if (*text == '\0')
Andrei> + {
Andrei> + /* Convenience to let the user know what the option
Andrei> + can accept. Note there's no common prefix between
Andrei> + the strings on purpose, so that complete_on_enum doesn't do
Andrei> + a partial match. */
Andrei> + tracker.add_completion (make_unique_xstrdup ("NUMBER"));
Andrei> + tracker.add_completion (make_unique_xstrdup ("#RRGGBB"));
Andrei> + }
This is a clever idea and I somewhat wish readline had a more robust
completion API to show this kind of info "inline".
Andrei> +ui_file_style::color
Andrei> +parse_cli_var_color (const char **args)
Andrei> +{
Andrei> + /* Do a "set" command. ARG is nullptr if no argument, or the
Andrei> + text of the argument. */
Andrei> +
Andrei> + if (args == nullptr || *args == nullptr || **args == '\0')
Andrei> + {
Andrei> + std::string msg;
Andrei> +
Andrei> + for (size_t i = 0; ui_file_style::basic_color_enums[i]; ++i)
Andrei> + {
Andrei> + msg.append ("\"");
Andrei> + msg.append (ui_file_style::basic_color_enums[i]);
Andrei> + msg.append ("\", ");
I think this ends up appending an extra comma. Perhaps the
comma-addition should be done at the star of the loop, if "i > 0".
Andrei> diff --git a/gdb/cli/cli-option.c b/gdb/cli/cli-option.c
Andrei> index 05539285c80..3a165ef6d2c 100644
Andrei> --- a/gdb/cli/cli-option.c
Andrei> +++ b/gdb/cli/cli-option.c
Andrei> @@ -45,6 +45,9 @@ union option_value
Andrei> /* For var_string options. This is malloc-allocated. */
Andrei> std::string *string;
Andrei> +
Andrei> + /* For var_color options. */
Andrei> + ui_file_style::color color = ui_file_style::NONE;
I didn't even know inline initializers were possible in a union.
Anyway I think it's probably better to leave this off.
Andrei> +@node Colors In Python
Andrei> +@subsection Python representation of colors
This new node doesn't seem to be referenced from a menu anywhere. I
think it has to be added to the appropriate spot in the menu in the
"Python API" node.
Andrei> diff --git a/gdb/python/py-color.c b/gdb/python/py-color.c
Andrei> new file mode 100644
Andrei> index 00000000000..1d72cc3e7d1
Andrei> --- /dev/null
Andrei> +++ b/gdb/python/py-color.c
Andrei> @@ -0,0 +1,347 @@
Andrei> +/* Python interface to ui_file_style::color objects.
Andrei> +
Andrei> + Copyright (C) 2008-2022 Free Software Foundation, Inc.
I suspect this should just be 2024.
Andrei> +/* See py-color.h. */
Andrei> +bool
Andrei> +gdbpy_is_color (PyObject *obj)
Andrei> +{
Andrei> + return PyObject_IsInstance (obj, (PyObject *)&colorpy_object_type);
gdb style is a space after the closing paren of a cast.
Andrei> +static PyObject *
Andrei> +colorpy_escape_sequence (PyObject *self, PyObject *is_fg_obj)
Andrei> +{
...
Andrei> + bool is_fg = PyObject_IsTrue (is_fg_obj);
In theory, this can fail, returning -1.
In practice, the code already calls PyBool_Check, so I think just a
direct comparison against Py_True would be fine.
Andrei> +static int
Andrei> +colorpy_init (PyObject *self, PyObject *args, PyObject *kwds)
...
Andrei> + if (colorspace_obj)
Andrei> + {
Andrei> + if (PyLong_Check (colorspace_obj))
Andrei> + {
Andrei> + long colorspace_id = -1;
Andrei> + if (! gdb_py_int_as_long (colorspace_obj, &colorspace_id))
Andrei> + return -1;
Andrei> + if (colorspace_id < INT_MIN || colorspace_id > INT_MAX)
Andrei> + error (_("colorspace %ld is out of range."), colorspace_id);
It seems like the range check here should use the colorspace enum values.
Andrei> + Py_ssize_t tuple_size = PyTuple_Size (value_obj);
Andrei> + if (tuple_size != 3)
Andrei> + error (_("Tuple value with RGB must be of size 3."));
If PyTuple_Size returns -1, this should early-return.
Andrei> + if (!str)
Andrei> + return -1;
gdb uses comparisons like 'str == nullptr' here.
Andrei> + if (colorspace_obj != nullptr
Andrei> + && colorspace != obj->color.colorspace ())
Andrei> + error (_("colorspace doesn't match to value."));
I would s/to/the in this error message.
Andrei> + catch (const gdb_exception &except)
Andrei> + {
Andrei> + gdbpy_convert_exception (except);
Andrei> + return -1;
Andrei> + }
A newish change landed and now this is written
return gdbpy_handle_exception (-1, except);
Andrei> +/* Deallocate function for a gdb.Color. */
Andrei> +
Andrei> +static void
Andrei> +colorpy_dealloc (PyObject *)
Andrei> +{
Andrei> +}
I wonder if this is necessary.
If so maybe a comment explaining why would be good.
Andrei> +/* Initialize the 'color' module. */
Andrei> +static int
Andrei> +gdbpy_initialize_color (void)
Andrei> +{
Andrei> + colorpy_object_type.tp_new = PyType_GenericNew;
Andrei> + if (PyType_Ready (&colorpy_object_type) < 0)
Andrei> + return -1;
A recent change means that this should now call gdbpy_type_ready
instead. This also removes the need to call gdb_pymodule_addobject, so
this call can be lowered to the end of this function.
Andrei> diff --git a/gdb/python/py-color.h b/gdb/python/py-color.h
...
Andrei> +/* Extracts value from OBJ object of gdb.Color type. */
Andrei> +extern const ui_file_style::color & gdbpy_get_color (PyObject *obj);
No space after the "&".
Andrei> - memset (&obj->value, 0, sizeof (obj->value));
Andrei> + obj->value = {}; /* zeros initialization */
Was this needed?
Andrei> diff --git a/gdb/testsuite/gdb.guile/scm-color.exp b/gdb/testsuite/gdb.guile/scm-color.exp
Andrei> new file mode 100644
Andrei> index 00000000000..e5773650f2f
Andrei> --- /dev/null
Andrei> +++ b/gdb/testsuite/gdb.guile/scm-color.exp
Andrei> @@ -0,0 +1,110 @@
Andrei> +# Copyright (C) 2010-2022 Free Software Foundation, Inc.
Another date to change. I'd suggest looking at all of them.
Andrei> diff --git a/gdb/testsuite/gdb.python/py-parameter.exp b/gdb/testsuite/gdb.python/py-parameter.exp
Andrei> index de524f49ad6..6e6a6007198 100644
Andrei> --- a/gdb/testsuite/gdb.python/py-parameter.exp
Andrei> +++ b/gdb/testsuite/gdb.python/py-parameter.exp
Andrei> @@ -185,6 +185,58 @@ proc_with_prefix test_enum_parameter { } {
Andrei> "Undefined item: \"three\".*" "set invalid enum parameter"
Andrei> }
Andrei> +# Test an color parameter.
Andrei> +proc_with_prefix test_color_parameter { } {
Andrei> + global env
Andrei> + save_vars { env(TERM) env(COLORTERM) } {
This should probably use with_ansi_styling_terminal to avoid having
NO_COLOR set?
Andrei> +static void
Andrei> +init_colorsupport_var (void)
You should use "()" instead of "(void)". The latter is a leftover
C-ism.
Andrei> +{
Andrei> + const std::vector<color_space>& cs = colorsupport ();
Also move the "&" after the space.
Andrei> +/* See ui-style.h. */
Andrei> +/* Must correspond to ui_file_style::basic_color. */
Andrei> +const std::vector<const char *> ui_file_style::basic_color_enums = {
Andrei> + "none",
Andrei> + "black",
Andrei> + "red",
Andrei> + "green",
Andrei> + "yellow",
Andrei> + "blue",
Andrei> + "magenta",
Andrei> + "cyan",
Andrei> + "white",
Andrei> + nullptr
Andrei> +};
I guess the nullptr is needed since although it is a vector now, it's
still passed to some null-expecting API? Like maybe completion?
I wonder if a vector can be constexpr.
Andrei> bool
Andrei> ui_file_style::color::append_ansi (bool is_fg, std::string *str) const
Andrei> {
...
Andrei> + else
Andrei> + return false;
I wonder when this can happen and if it could somehow be made
impossible.
Andrei> +const std::vector<color_space> &
Andrei> +colorsupport ()
Andrei> +{
Andrei> + static const std::vector<color_space> value = []
I didn't realize you could omit the '()' from a lambda.
Andrei> + {
Andrei> + std::vector<color_space> result = {color_space::MONOCHROME};
Andrei> +
Andrei> + int colors = tgetnum ((char *)"Co");
Is the cast really needed?
Andrei> + const char *colorterm = getenv ("COLORTERM");
Andrei> + if (colorterm && (!strcmp (colorterm, "truecolor")
'colorterm != nullptr'
Andrei> +const char *
Andrei> +color_space_name (color_space c)
Andrei> +{
Andrei> + switch (c)
Andrei> + {
Andrei> + case color_space::MONOCHROME: return "monochrome";
Andrei> + case color_space::ANSI_8COLOR: return "ansi_8color";
Andrei> + case color_space::AIXTERM_16COLOR: return "aixterm_16color";
Andrei> + case color_space::XTERM_256COLOR: return "xterm_256color";
Andrei> + case color_space::RGB_24BIT: return "rgb_24bit";
Andrei> + }
Andrei> + error (_("Color space %d has no name."), static_cast<int> (c));
Probably an assert-not-reached is more appropriate here?
Andrei> +}
Andrei> diff --git a/gdb/ui-style.h b/gdb/ui-style.h
Andrei> index 1b7b5fafb9d..a13618dfce5 100644
Andrei> --- a/gdb/ui-style.h
Andrei> +++ b/gdb/ui-style.h
Andrei> @@ -19,6 +19,26 @@
Andrei> #ifndef UI_STYLE_H
Andrei> #define UI_STYLE_H
Andrei> +/* One of the color spaces that usually supported by terminals. */
Andrei> +enum class color_space
Andrei> +{
Andrei> + MONOCHROME, // one default terminal color
Andrei> + ANSI_8COLOR, // foreground colors \e[30m ... \e[37m,
Andrei> + // background colors \e[40m ... \e[47m
Andrei> + AIXTERM_16COLOR, // foreground colors \e[30m ... \e[37m, \e[90m ... \e[97m
Andrei> + // background colors \e[40m ... \e[47m, \e[100m ... \e107m
Andrei> + XTERM_256COLOR, // foreground colors \e[38;5;0m ... \e[38;5;255m
Andrei> + // background colors \e[48;5;0m ... \e[48;5;255m
Andrei> + RGB_24BIT // foreground colors \e[38;2;0;0;0m ... \e[38;2;255;255;255m
Andrei> + // background colors \e[48;2;0;0;0m ... \e[48;2;255;255;255m
gdb doesn't use "//" comments. Also normally gdb doesn't use trailing
comments on the line; instead I'd put them before each constant they
describe.
Tom
next prev parent reply other threads:[~2024-10-04 17:55 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-10-16 11:40 [PATCH v4] " Andrei Pikas
2022-10-16 13:45 ` Eli Zaretskii via Gdb-patches
2022-10-16 16:03 ` [PATCH v5] " Andrei Pikas
2022-10-16 16:22 ` Eli Zaretskii via Gdb-patches
2022-10-16 16:28 ` [PATCH v6] " Andrei Pikas
2022-10-16 16:45 ` Eli Zaretskii via Gdb-patches
2024-04-19 19:33 ` Tom Tromey
2024-04-19 19:52 ` Andrei Pikas
2024-04-19 20:19 ` Tom Tromey
2024-04-20 18:24 ` Tom Tromey
2024-04-20 18:32 ` Andrei Pikas
2024-05-11 15:17 ` Andrei Pikas
2024-05-13 19:02 ` Tom Tromey
2024-05-21 9:00 ` Andrei Pikas
2024-09-13 20:16 ` Tom Tromey
2024-09-14 18:06 ` Andrei Pikas
2024-09-14 19:38 ` Tom Tromey
2024-09-14 19:43 ` Andrei Pikas
2024-09-14 19:04 ` [PATCH v7] " Andrei Pikas
2024-09-15 5:37 ` Eli Zaretskii
2024-10-05 19:11 ` Andrei Pikas
2024-10-05 19:40 ` Eli Zaretskii
2024-10-04 17:55 ` Tom Tromey [this message]
2024-10-05 17:55 ` Andrei Pikas
2024-10-05 19:27 ` [PATCH v8] " Andrei Pikas
2024-10-06 5:40 ` Eli Zaretskii
2024-12-13 21:01 ` Tom Tromey
2024-12-13 21:23 ` Andrei Pikas
2024-12-14 7:59 ` Eli Zaretskii
2025-01-12 20:34 ` Tom Tromey
2025-02-03 16:23 ` Tom de Vries
2025-02-04 0:24 ` Tom Tromey
2025-02-04 14:24 ` Tom de Vries
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87r08vhhx8.fsf@tromey.com \
--to=tom@tromey.com \
--cc=gdb-patches@sourceware.org \
--cc=gdb@mail.api.win \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox