| /* Python interface to ui_file_style objects. | |
| Copyright (C) 2025 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 "python-internal.h" | |
| #include "ui-style.h" | |
| #include "py-color.h" | |
| #include "cli/cli-decode.h" | |
| #include "cli/cli-style.h" | |
| #include "top.h" | |
| /* Intensity constants and their values. */ | |
| static struct { | |
| const char *name; | |
| ui_file_style::intensity value; | |
| } intensity_constants[] = | |
| { | |
| { "INTENSITY_NORMAL", ui_file_style::NORMAL }, | |
| { "INTENSITY_DIM", ui_file_style::DIM }, | |
| { "INTENSITY_BOLD", ui_file_style::BOLD } | |
| }; | |
| /* A style. */ | |
| struct style_object | |
| { | |
| PyObject_HEAD | |
| /* Underlying style, only valid when STYLE_NAME is NULL. */ | |
| ui_file_style style; | |
| /* The name of the style. Can be NULL, in which case STYLE holds the | |
| style value. */ | |
| char *style_name; | |
| }; | |
| extern PyTypeObject style_object_type; | |
| /* Initialize the 'style' module. */ | |
| static int | |
| gdbpy_initialize_style () | |
| { | |
| for (auto &pair : intensity_constants) | |
| if (PyModule_AddIntConstant (gdb_module, pair.name, | |
| static_cast<long> (pair.value)) < 0) | |
| return -1; | |
| return gdbpy_type_ready (&style_object_type, gdb_module); | |
| } | |
| /* Free any resources help by SELF, and reset points to NULL. */ | |
| static void | |
| stylepy_free_resources (PyObject *self) | |
| { | |
| style_object *style = (style_object *) self; | |
| xfree (style->style_name); | |
| style->style_name = nullptr; | |
| } | |
| /* gdb.Style deallocation method. */ | |
| static void | |
| stylepy_dealloc (PyObject *self) | |
| { | |
| stylepy_free_resources (self); | |
| Py_TYPE (self)->tp_free (self); | |
| } | |
| /* Find style NAME and return it. If NAME cannot be found then an empty | |
| optional is returned, and a Python error will be set. | |
| If HAS_INTENSITY_PTR is not NULL, then, if NAME is found, | |
| *HAS_INTENSITY_PTR will be set true if NAME has an "intensity" | |
| sub-command, and set false otherwise. If NAME is not found then | |
| *HAS_INTENSITY_PTR is left unchanged. | |
| If FOUND_CMD_PTR is not NULL, then, if NAME is found, *FOUND_CMD_PTR is | |
| set to point to the prefix command matching NAME. If NAME is a | |
| multi-word style name (e.g. 'disassembler comment') then *FOUND_CMD_PTR | |
| will point to the prefix command for the last word (e.g. 'comment'). */ | |
| static std::optional<ui_file_style> | |
| stylepy_style_from_name (const char *name, bool *has_intensity_ptr = nullptr, | |
| const cmd_list_element **found_cmd_ptr = nullptr) | |
| { | |
| std::string cmd_str = std::string ("show style ") + name; | |
| struct cmd_list_element *cmd = nullptr; | |
| struct cmd_list_element *alias = nullptr; | |
| int found; | |
| try | |
| { | |
| struct cmd_list_element *prefix; | |
| found = lookup_cmd_composition (cmd_str.c_str (), &alias, &prefix, &cmd); | |
| } | |
| catch (const gdb_exception &ex) | |
| { | |
| PyErr_Format (PyExc_RuntimeError, | |
| _("style '%s' cannot be found."), name); | |
| return {}; | |
| } | |
| gdb_assert (!found || cmd != nullptr); | |
| if (!found || cmd == CMD_LIST_AMBIGUOUS || !cmd->is_prefix ()) | |
| { | |
| PyErr_Format (PyExc_RuntimeError, | |
| _("style '%s' cannot be found."), name); | |
| return {}; | |
| } | |
| ui_file_style style; | |
| bool has_fg = false; | |
| bool has_bg = false; | |
| bool has_intensity = false; | |
| for (cmd_list_element *sub = *cmd->subcommands; | |
| sub != nullptr; | |
| sub = sub->next) | |
| { | |
| if (!sub->var.has_value ()) | |
| continue; | |
| if (strcmp (sub->name, "foreground") == 0) | |
| { | |
| const ui_file_style::color &color | |
| = sub->var->get<ui_file_style::color> (); | |
| style.set_fg (color); | |
| has_fg = true; | |
| } | |
| else if (strcmp (sub->name, "background") == 0) | |
| { | |
| const ui_file_style::color &color | |
| = sub->var->get<ui_file_style::color> (); | |
| style.set_bg (color); | |
| has_bg = true; | |
| } | |
| else if (strcmp (sub->name, "intensity") == 0 | |
| && sub->var->type () == var_enum) | |
| { | |
| const char *intensity_str = sub->var->get<const char *> (); | |
| ui_file_style::intensity intensity = ui_file_style::NORMAL; | |
| if (strcmp (intensity_str, "bold") == 0) | |
| intensity = ui_file_style::BOLD; | |
| else if (strcmp (intensity_str, "dim") == 0) | |
| intensity = ui_file_style::DIM; | |
| style.set_intensity (intensity); | |
| has_intensity = true; | |
| } | |
| } | |
| /* All styles should have a foreground and background, but the intensity | |
| is optional. */ | |
| if (!has_fg || !has_bg) | |
| { | |
| PyErr_Format (PyExc_RuntimeError, | |
| _("style '%s' missing '%s' component."), name, | |
| (has_fg ? "background" : "foreground")); | |
| return {}; | |
| } | |
| if (has_intensity_ptr != nullptr) | |
| *has_intensity_ptr = has_intensity; | |
| /* If NAME identified an alias then use that instead of CMD, this means | |
| the style's cached name will better match the string the user used to | |
| initialise the style. */ | |
| if (found_cmd_ptr != nullptr) | |
| *found_cmd_ptr = alias != nullptr ? alias : cmd; | |
| return style; | |
| } | |
| /* Initialise a gdb.Style object from a named style. We only store the | |
| style name within SELF, each time the style is used, we look up its | |
| current value, this allows the style to change if the user adjusts the | |
| settings. */ | |
| static int | |
| stylepy_init_from_style_name (PyObject *self, const char *style_name) | |
| { | |
| style_object *style = (style_object *) self; | |
| gdb_assert (style->style_name == nullptr); | |
| gdb_assert (style_name != nullptr); | |
| const cmd_list_element *cmd = nullptr; | |
| std::optional<ui_file_style> maybe_style | |
| = stylepy_style_from_name (style_name, nullptr, &cmd); | |
| if (!maybe_style.has_value ()) | |
| return -1; | |
| /* If we found a style then we must have found a prefix command. */ | |
| gdb_assert (cmd != nullptr); | |
| gdb_assert (cmd->is_prefix ()); | |
| /* Get the components of this command. */ | |
| std::vector<std::string> components = cmd->command_components (); | |
| gdb_assert (components.size () > 2); | |
| gdb_assert (components[0] == "show"); | |
| gdb_assert (components[1] == "style"); | |
| /* And build the components into a string, but without the 'show style' | |
| part at the start. */ | |
| std::string expanded_style_name (components[2]); | |
| for (int i = 3; i < components.size (); ++i) | |
| expanded_style_name += " " + components[i]; | |
| style->style_name = xstrdup (expanded_style_name.c_str ()); | |
| return 0; | |
| } | |
| /* Convert INTENSITY_VALUE to a valid intensity enum value, if possible, | |
| and return the enum value. If INTENSITY_VALUE is not a valid intensity | |
| value then set a Python error, and return an empty optional. */ | |
| static std::optional<ui_file_style::intensity> | |
| stylepy_long_to_intensity (long intensity_value) | |
| { | |
| switch (intensity_value) | |
| { | |
| case ui_file_style::NORMAL: | |
| case ui_file_style::DIM: | |
| case ui_file_style::BOLD: | |
| return static_cast<ui_file_style::intensity> (intensity_value); | |
| default: | |
| PyErr_Format | |
| (PyExc_ValueError, _("invalid 'intensity' value %d."), | |
| intensity_value); | |
| return {}; | |
| } | |
| } | |
| /* Initialise a gdb.Style object from a foreground and background | |
| gdb.Color object, and an intensity. */ | |
| static int | |
| stylepy_init_from_parts (PyObject *self, PyObject *fg, PyObject *bg, | |
| int intensity_value) | |
| { | |
| style_object *style = (style_object *) self; | |
| gdb_assert (style->style_name == nullptr); | |
| if (fg == Py_None) | |
| fg = nullptr; | |
| if (bg == Py_None) | |
| bg = nullptr; | |
| if (fg != nullptr && !gdbpy_is_color (fg)) | |
| { | |
| PyErr_Format | |
| (PyExc_TypeError, | |
| _("'foreground' argument must be gdb.Color or None, not %s."), | |
| Py_TYPE (fg)->tp_name); | |
| return -1; | |
| } | |
| if (bg != nullptr && !gdbpy_is_color (bg)) | |
| { | |
| PyErr_Format | |
| (PyExc_TypeError, | |
| _("'background' argument must be gdb.Color or None, not %s."), | |
| Py_TYPE (bg)->tp_name); | |
| return -1; | |
| } | |
| if (fg != nullptr) | |
| style->style.set_fg (gdbpy_get_color (fg)); | |
| else | |
| style->style.set_fg (ui_file_style::color (ui_file_style::NONE)); | |
| if (bg != nullptr) | |
| style->style.set_bg (gdbpy_get_color (bg)); | |
| else | |
| style->style.set_bg (ui_file_style::color (ui_file_style::NONE)); | |
| /* Convert INTENSITY_VALUE into the enum. */ | |
| std::optional<ui_file_style::intensity> intensity | |
| = stylepy_long_to_intensity (intensity_value); | |
| if (!intensity.has_value ()) | |
| return -1; | |
| style->style.set_intensity (intensity.value ()); | |
| return 0; | |
| } | |
| /* gdb.Style object initializer. Either: | |
| gdb.Style.__init__("style name") | |
| gdb.Style.__init__(fg, bg, intensity) | |
| This init function supports two possible sets of arguments. Both | |
| options are different enough that we can distinguish the two by the | |
| argument types. Dispatch to one of the two stylepy_init_from_* | |
| functions above. */ | |
| static int | |
| stylepy_init (PyObject *self, PyObject *args, PyObject *kwargs) | |
| { | |
| /* If this object was previously initialised, then clear it out now. */ | |
| stylepy_free_resources (self); | |
| /* Try to parse the incoming arguments as a string, this is a style | |
| name. */ | |
| const char *style_name = nullptr; | |
| static const char *keywords_style[] = { "style", nullptr }; | |
| if (gdb_PyArg_ParseTupleAndKeywords (args, kwargs, "s", keywords_style, | |
| &style_name)) | |
| return stylepy_init_from_style_name (self, style_name); | |
| /* That didn't work, discard any errors. */ | |
| PyErr_Clear (); | |
| /* Try to parse the incoming arguments as a list of parts, this is an | |
| unnamed style. */ | |
| PyObject *foreground_color = nullptr; | |
| PyObject *background_color = nullptr; | |
| int intensity_value = static_cast<int> (ui_file_style::NORMAL); | |
| static const char *keywords_parts[] | |
| = { "foreground", "background", "intensity", nullptr }; | |
| if (gdb_PyArg_ParseTupleAndKeywords (args, kwargs, "|OOi", keywords_parts, | |
| &foreground_color, | |
| &background_color, | |
| &intensity_value)) | |
| return stylepy_init_from_parts (self, foreground_color, | |
| background_color, intensity_value); | |
| /* Return the error gdb_PyArg_ParseTupleAndKeywords set. */ | |
| return -1; | |
| } | |
| /* See python-internal.h. */ | |
| bool | |
| gdbpy_is_style (PyObject *obj) | |
| { | |
| gdb_assert (obj != nullptr); | |
| return PyObject_TypeCheck (obj, &style_object_type); | |
| } | |
| /* Return the ui_file_style for STYLEPY. If the style cannot be found, | |
| then return an empty optional, and set a Python error. */ | |
| static std::optional<ui_file_style> | |
| stylepy_to_style (style_object *stylepy) | |
| { | |
| std::optional<ui_file_style> style; | |
| if (stylepy->style_name != nullptr) | |
| style = stylepy_style_from_name (stylepy->style_name); | |
| else | |
| style.emplace (stylepy->style); | |
| return style; | |
| } | |
| /* See python-internal.h. */ | |
| std::optional<ui_file_style> | |
| gdbpy_style_object_to_ui_file_style (PyObject *obj) | |
| { | |
| gdb_assert (obj != nullptr); | |
| gdb_assert (gdbpy_is_style (obj)); | |
| style_object *style_obj = (style_object *) obj; | |
| return stylepy_to_style (style_obj); | |
| } | |
| /* Implementation of gdb.Style.escape_sequence(). Return the escape | |
| sequence to apply Style. If styling is turned off, then this returns | |
| the empty string. Can raise an exception if a named style can no longer | |
| be read. */ | |
| static PyObject * | |
| stylepy_escape_sequence (PyObject *self, PyObject *args) | |
| { | |
| style_object *style_obj = (style_object *) self; | |
| std::optional<ui_file_style> style = stylepy_to_style (style_obj); | |
| if (!style.has_value ()) | |
| return nullptr; | |
| std::string style_str; | |
| if (term_cli_styling ()) | |
| style_str = style->to_ansi (); | |
| return host_string_to_python_string (style_str.c_str ()).release (); | |
| } | |
| /* Implement gdb.Style.apply(STR). Return a new string which is STR with | |
| escape sequences added so that STR is formatted in this style. A | |
| trailing escape sequence is added to restore the default style. | |
| If styling is currently disabled ('set style enabled off'), then no | |
| escape sequences are added, but all the checks for the validity of the | |
| current style are still performed, and a new string, a copy of the | |
| input string is returned. | |
| Can raise a Python exception and return NULL if the argument types are | |
| wrong, or if a named style can no longer be read. */ | |
| static PyObject * | |
| stylepy_apply (PyObject *self, PyObject *args, PyObject *kw) | |
| { | |
| style_object *style_obj = (style_object *) self; | |
| static const char *keywords[] = { "string", nullptr }; | |
| PyObject *input_obj; | |
| /* Grab the incoming string as a Python object. In the case where | |
| styling is not being applied we can just return this object with the | |
| reference count incremented. */ | |
| if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "O!", keywords, | |
| &PyUnicode_Type, &input_obj)) | |
| return nullptr; | |
| std::optional<ui_file_style> style = stylepy_to_style (style_obj); | |
| if (!style.has_value ()) | |
| return nullptr; | |
| if (gdb_stdout->can_emit_style_escape ()) | |
| { | |
| gdb_assert (gdbpy_is_string (input_obj)); | |
| gdb::unique_xmalloc_ptr<char> | |
| input (python_string_to_host_string (input_obj)); | |
| std::string output | |
| = style->to_ansi () + input.get () + ui_file_style ().to_ansi (); | |
| return host_string_to_python_string (output.c_str ()).release (); | |
| } | |
| else | |
| { | |
| /* Return an unmodified "copy" of INPUT_OBJ by just incrementing the | |
| reference count. */ | |
| Py_INCREF (input_obj); | |
| return input_obj; | |
| } | |
| } | |
| /* Implement reading the gdb.Style.foreground attribute. */ | |
| static PyObject * | |
| stylepy_get_foreground (PyObject *self, void *closure) | |
| { | |
| style_object *style_obj = (style_object *) self; | |
| std::optional<ui_file_style> style = stylepy_to_style (style_obj); | |
| if (!style.has_value ()) | |
| return nullptr; | |
| gdbpy_ref<> color = create_color_object (style->get_foreground ()); | |
| if (color == nullptr) | |
| return nullptr; | |
| return color.release (); | |
| } | |
| /* Implement writing the gdb.Style.foreground attribute. */ | |
| static int | |
| stylepy_set_foreground (PyObject *self, PyObject *newvalue, void *closure) | |
| { | |
| if (!gdbpy_is_color (newvalue)) | |
| { | |
| PyErr_Format (PyExc_TypeError, _("value must be gdb.Color, not %s"), | |
| Py_TYPE (newvalue)->tp_name); | |
| return -1; | |
| } | |
| style_object *style_obj = (style_object *) self; | |
| /* Handle unnamed styles. This is easy, just update the embedded style | |
| object. */ | |
| if (style_obj->style_name == nullptr) | |
| { | |
| style_obj->style.set_fg (gdbpy_get_color (newvalue)); | |
| return 0; | |
| } | |
| /* Handle named styles. This is harder, we need to write to the actual | |
| parameter. */ | |
| std::string cmd_string | |
| = string_printf ("set style %s foreground %s", | |
| style_obj->style_name, | |
| gdbpy_get_color (newvalue).to_string ().c_str ()); | |
| try | |
| { | |
| execute_command (cmd_string.c_str (), 0); | |
| } | |
| catch (const gdb_exception &except) | |
| { | |
| return gdbpy_handle_gdb_exception (-1, except); | |
| } | |
| return 0; | |
| } | |
| /* Implement reading the gdb.Style.background attribute. */ | |
| static PyObject * | |
| stylepy_get_background (PyObject *self, void *closure) | |
| { | |
| style_object *style_obj = (style_object *) self; | |
| std::optional<ui_file_style> style = stylepy_to_style (style_obj); | |
| if (!style.has_value ()) | |
| return nullptr; | |
| gdbpy_ref<> color = create_color_object (style->get_background ()); | |
| if (color == nullptr) | |
| return nullptr; | |
| return color.release (); | |
| } | |
| /* Implement writing the gdb.Style.background attribute. */ | |
| static int | |
| stylepy_set_background (PyObject *self, PyObject *newvalue, void *closure) | |
| { | |
| if (!gdbpy_is_color (newvalue)) | |
| { | |
| PyErr_Format (PyExc_TypeError, _("value must be gdb.Color, not %s"), | |
| Py_TYPE (newvalue)->tp_name); | |
| return -1; | |
| } | |
| style_object *style_obj = (style_object *) self; | |
| /* Handle unnamed styles. This is easy, just update the embedded style | |
| object. */ | |
| if (style_obj->style_name == nullptr) | |
| { | |
| style_obj->style.set_bg (gdbpy_get_color (newvalue)); | |
| return 0; | |
| } | |
| /* Handle named styles. This is harder, we need to write to the actual | |
| parameter. */ | |
| std::string cmd_string | |
| = string_printf ("set style %s background %s", | |
| style_obj->style_name, | |
| gdbpy_get_color (newvalue).to_string ().c_str ()); | |
| try | |
| { | |
| execute_command (cmd_string.c_str (), 0); | |
| } | |
| catch (const gdb_exception &except) | |
| { | |
| return gdbpy_handle_gdb_exception (-1, except); | |
| } | |
| return 0; | |
| } | |
| /* Implement reading the gdb.Style.intensity attribute. */ | |
| static PyObject * | |
| stylepy_get_intensity (PyObject *self, void *closure) | |
| { | |
| style_object *style_obj = (style_object *) self; | |
| std::optional<ui_file_style> style = stylepy_to_style (style_obj); | |
| if (!style.has_value ()) | |
| return nullptr; | |
| ui_file_style::intensity intensity = style->get_intensity (); | |
| return PyLong_FromLong (static_cast<long> (intensity)); | |
| } | |
| /* Return a string representing INTENSITY. */ | |
| static const char * | |
| stylepy_intensity_to_string (ui_file_style::intensity intensity) | |
| { | |
| const char *intensity_str = nullptr; | |
| switch (intensity) | |
| { | |
| case ui_file_style::NORMAL: | |
| intensity_str = "normal"; | |
| break; | |
| case ui_file_style::BOLD: | |
| intensity_str = "bold"; | |
| break; | |
| case ui_file_style::DIM: | |
| intensity_str = "dim"; | |
| break; | |
| } | |
| gdb_assert (intensity_str != nullptr); | |
| return intensity_str; | |
| } | |
| /* Implement writing the gdb.Style.intensity attribute. */ | |
| static int | |
| stylepy_set_intensity (PyObject *self, PyObject *newvalue, void *closure) | |
| { | |
| style_object *style_obj = (style_object *) self; | |
| if (!PyLong_Check (newvalue)) | |
| { | |
| PyErr_Format | |
| (PyExc_TypeError, | |
| _("value must be a Long (a gdb.INTENSITY constant), not %s"), | |
| Py_TYPE (newvalue)->tp_name); | |
| return -1; | |
| } | |
| /* Convert the Python object to a value we can use. */ | |
| long intensity_value; | |
| if (!gdb_py_int_as_long (newvalue, &intensity_value)) | |
| return -1; | |
| std::optional<ui_file_style::intensity> intensity | |
| = stylepy_long_to_intensity (intensity_value); | |
| if (!intensity.has_value ()) | |
| return -1; | |
| /* Handle unnamed styles. This is easy, just update the embedded style | |
| object. */ | |
| if (style_obj->style_name == nullptr) | |
| { | |
| style_obj->style.set_intensity (intensity.value ()); | |
| return 0; | |
| } | |
| /* Handle named styles. This is harder, we need to write to the actual | |
| parameter. First though, look up the named style to see if it has an | |
| intensity. HAS_INTENSITY will be set true only if the style exists, | |
| and has an 'intensity' setting. */ | |
| bool has_intensity = false; | |
| std::optional<ui_file_style> style | |
| = stylepy_style_from_name (style_obj->style_name, &has_intensity); | |
| if (!style.has_value ()) | |
| return -1; | |
| if (!has_intensity) | |
| { | |
| PyErr_Format | |
| (PyExc_ValueError, "the intensity of style '%s' is not writable.", | |
| style_obj->style_name); | |
| return -1; | |
| } | |
| const char *intensity_str = stylepy_intensity_to_string (intensity.value ()); | |
| gdb_assert (intensity_str != nullptr); | |
| std::string cmd_string | |
| = string_printf ("set style %s intensity %s", | |
| style_obj->style_name, intensity_str); | |
| try | |
| { | |
| execute_command (cmd_string.c_str (), 0); | |
| } | |
| catch (const gdb_exception &except) | |
| { | |
| return gdbpy_handle_gdb_exception (-1, except); | |
| } | |
| return 0; | |
| } | |
| /* Call FETCH_ATTR, passing in SELF, to get a PyObject*, then convert it to | |
| a Python string, and finally into a C++ managed string. Will return | |
| nullptr and set a Python error if something goes wrong. | |
| The FETCH_ATTR function will be a function that returns an attribute | |
| from SELF. */ | |
| static gdb::unique_xmalloc_ptr<char> | |
| stylepy_attribute_to_string | |
| (PyObject *self, | |
| gdb::function_view<PyObject * (PyObject *, void *)> fetch_attr) | |
| { | |
| PyObject *attr_obj = fetch_attr (self, nullptr); | |
| if (attr_obj == nullptr) | |
| return nullptr; | |
| PyObject *str_obj = PyObject_Str (attr_obj); | |
| if (str_obj == nullptr) | |
| return nullptr; | |
| return python_string_to_host_string (str_obj); | |
| } | |
| /* __repr__ implementation for gdb.Style. */ | |
| static PyObject * | |
| stylepy_repr (PyObject *self) | |
| { | |
| style_object *style_obj = (style_object *) self; | |
| gdb::unique_xmalloc_ptr<char> fg_str | |
| (stylepy_attribute_to_string (self, stylepy_get_foreground)); | |
| gdb::unique_xmalloc_ptr<char> bg_str | |
| (stylepy_attribute_to_string (self, stylepy_get_background)); | |
| PyObject *intensity_obj = stylepy_get_intensity (self, nullptr); | |
| if (intensity_obj == nullptr) | |
| return nullptr; | |
| gdb_assert (PyLong_Check (intensity_obj)); | |
| long intensity_value; | |
| if (!gdb_py_int_as_long (intensity_obj, &intensity_value)) | |
| return nullptr; | |
| std::optional<ui_file_style::intensity> intensity | |
| = stylepy_long_to_intensity (intensity_value); | |
| if (!intensity.has_value ()) | |
| return nullptr; | |
| const char *intensity_str = stylepy_intensity_to_string (intensity.value ()); | |
| gdb_assert (intensity_str != nullptr); | |
| if (style_obj->style_name == nullptr) | |
| return PyUnicode_FromFormat ("<%s fg=%s, bg=%s, intensity=%s>", | |
| Py_TYPE (self)->tp_name, | |
| fg_str.get (), bg_str.get (), | |
| intensity_str); | |
| else | |
| return PyUnicode_FromFormat ("<%s name='%s', fg=%s, bg=%s, intensity=%s>", | |
| Py_TYPE (self)->tp_name, | |
| style_obj->style_name, fg_str.get (), | |
| bg_str.get (), intensity_str); | |
| } | |
| /* Style methods. */ | |
| static PyMethodDef stylepy_methods[] = | |
| { | |
| { "escape_sequence", stylepy_escape_sequence, METH_NOARGS, | |
| "escape_sequence () -> str.\n\ | |
| Return the ANSI escape sequence for this style."}, | |
| { "apply", (PyCFunction) stylepy_apply, METH_VARARGS | METH_KEYWORDS, | |
| "apply(String) -> String.\n\ | |
| Apply this style to the input string. Return an updated string."}, | |
| {nullptr} | |
| }; | |
| /* Attribute get/set Python definitions. */ | |
| static gdb_PyGetSetDef style_object_getset[] = { | |
| { "foreground", stylepy_get_foreground, stylepy_set_foreground, | |
| "The gdb.Color for the foreground of this style.", NULL }, | |
| { "background", stylepy_get_background, stylepy_set_background, | |
| "The gdb.Color for the background of this style.", NULL }, | |
| { "intensity", stylepy_get_intensity, stylepy_set_intensity, | |
| "The Str for the intensity of this style.", NULL }, | |
| { nullptr } /* Sentinel. */ | |
| }; | |
| PyTypeObject style_object_type = | |
| { | |
| PyVarObject_HEAD_INIT (nullptr, 0) | |
| "gdb.Style", /*tp_name*/ | |
| sizeof (style_object), /*tp_basicsize*/ | |
| 0, /*tp_itemsize*/ | |
| stylepy_dealloc, /*tp_dealloc*/ | |
| 0, /*tp_print*/ | |
| 0, /*tp_getattr*/ | |
| 0, /*tp_setattr*/ | |
| 0, /*tp_compare*/ | |
| stylepy_repr, /*tp_repr*/ | |
| 0, /*tp_as_number*/ | |
| 0, /*tp_as_sequence*/ | |
| 0, /*tp_as_mapping*/ | |
| 0, /*tp_hash */ | |
| 0, /*tp_call*/ | |
| 0, /*tp_str*/ | |
| 0, /*tp_getattro*/ | |
| 0, /*tp_setattro*/ | |
| 0, /*tp_as_buffer*/ | |
| Py_TPFLAGS_DEFAULT, /*tp_flags*/ | |
| "GDB style object", /* tp_doc */ | |
| 0, /* tp_traverse */ | |
| 0, /* tp_clear */ | |
| 0, /* tp_richcompare */ | |
| 0, /* tp_weaklistoffset */ | |
| 0, /* tp_iter */ | |
| 0, /* tp_iternext */ | |
| stylepy_methods, /* tp_methods */ | |
| 0, /* tp_members */ | |
| style_object_getset, /* tp_getset */ | |
| 0, /* tp_base */ | |
| 0, /* tp_dict */ | |
| 0, /* tp_descr_get */ | |
| 0, /* tp_descr_set */ | |
| 0, /* tp_dictoffset */ | |
| stylepy_init, /* tp_init */ | |
| 0, /* tp_alloc */ | |
| PyType_GenericNew /* tp_new */ | |
| }; | |
| GDBPY_INITIALIZE_FILE (gdbpy_initialize_style); |