From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id PfsXBWxqnGiTVQIAWB0awg (envelope-from ) for ; Wed, 13 Aug 2025 06:35:24 -0400 Authentication-Results: simark.ca; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=Re05ddhJ; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 03CD71E0B3; Wed, 13 Aug 2025 06:35:24 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=ham autolearn_force=no version=4.0.1 Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id EF8A71E04C for ; Wed, 13 Aug 2025 06:35:21 -0400 (EDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 7887E3858C2C for ; Wed, 13 Aug 2025 10:35:21 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7887E3858C2C Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=Re05ddhJ Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id 6FF213858D20 for ; Wed, 13 Aug 2025 10:34:37 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 6FF213858D20 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 6FF213858D20 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1755081277; cv=none; b=rY36K6NBTOjFXlI3UZU876AHLNPFm04jng28+86XadTX9parxky/1cOp/+Zlx7VSGNAWhIlzmesUQFuQ/aSySb4mM9SAa2bVRaVrQs1W5lhnb+PXzqecph87Pxvd16628R/JX12US6ItXe0pn5CzbpjW92hLJzVueHynx2USWRQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1755081277; c=relaxed/simple; bh=eYQutVU/dj4K3lIx5eTFcCfVje0F3Qb6F7PKXwnA0/Y=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=x4NITXUIaxuDL5QHV7EZKYI1pOPLcIo5ccb5Y1IXGFz6SR+l/ifhbXrxpK3USWnwNUyrGHItfpIZfeYlkAm9p2WHZ4QR8rdKRofCFDEoTYFgTNNUvNim0qrJYp9xgZUkQA8qzREAXtVqywSwQAXVNGcjC4xyWw14NB5j2MCKJ7A= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6FF213858D20 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1755081277; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=LsK4CcM6+dUGvCQgveBfF2fqO5CDgkgUxHXYjAambjw=; b=Re05ddhJnKG92LYw9v47BH/UKKK1yyIbh9xNNpCRjV6QAFRwq16R7M+lGqYR9ILhQ0HcoC JqmG0YMNXs407wBVBGUJBEvoEJvE49fQ/9sH9XYAA2+LL4f2s9cw6Ndc/VovPdkwuhbYfB hf4SbkP5Px2csX4JObmfYGyKAv7gK9E= Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-339-qvJO-7XPMcCPeeBr_6LVfQ-1; Wed, 13 Aug 2025 06:34:35 -0400 X-MC-Unique: qvJO-7XPMcCPeeBr_6LVfQ-1 X-Mimecast-MFC-AGG-ID: qvJO-7XPMcCPeeBr_6LVfQ_1755081275 Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-459d3abb2b5so24697895e9.3 for ; Wed, 13 Aug 2025 03:34:35 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1755081274; x=1755686074; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=LsK4CcM6+dUGvCQgveBfF2fqO5CDgkgUxHXYjAambjw=; b=CPoG1cK/NtuwGemfl2ermiAKtQdcyvwNEiUqRD+/hEHpJS7gxiGP47FaeVl8skolbH 6C7pSAoxxumpfNxrA8ao6yIJh4R62xngMBp6cZ+rQrGZNPOjdxjvirzvnNzp9CFlzFi5 sXmn21AgBVb2PN8cNNYKllsU5cE9kPfjnwAgfDpt0hAiCtkP9VfDcjgIG4fyEeHISQUz 9hj3UfesPXp9FtVq3Z3qxEwQ4ysc85KyI3CIhWFnSwrGcpbGociabr3Is3lUV4k2q/5I VDNj7EdJLXOgkT2B4cAhjbj4P0gvAKMHe5Rw5Ff/1J3N0gRA6om7cN7JmvinbO6CvTQU 6lKg== X-Gm-Message-State: AOJu0Yw4MhLcRg8pM9pkCTmyP5ci3hGwSHUTROLlcMtMUz2NiHoy+zL5 HFFIA3m/Rky/SGEz3kJngalSKAIvGUsIB42xSqBQX9xaBM1ugpTg+687aFWTuC6MgFYUsgnZKpT omg8QkVe3v3QaO3L/xALulnlQyGNBWej4LhdpPxMG0lHIos/RAsanu7tyy2uCzv1kt05r/igjZ7 6QyW4PhxnGozaOHhBt/UtKi2CNEe+iV8+tazG52jr/fcPn8uY= X-Gm-Gg: ASbGncu2P9BJGA+uDIcblbBy1Y12lwJ17ZNLqOE+VCEBs0i33ZxFhGEznxiyZFPDZn1 GC1e47WsQvyvmUm4ZJMjRFSgB7mI7dLGLEiTqVQF+rsfcGsNOpdpqpG8Sk3RhMER6jIjevEPUKi X3WSjuIqjcr0Or+6GTq8Ya6cWm1+hWS7tqf9NNiSoZ31MGyI9nYIFiTJZ3es/U2Gl3Vmc6FRIDh Q1G9gsBjWuTQu1YaUqIq07AUwy7ESnl0xcwzfzABonSeAzGGYXBkfXYOeMvXUKFKMqlnchpIxNV 6R76LJ43g4jRp2PANH4Va1Oe8RzH9pRLcKg9VVyNfevPd2vmQqh2bWRS8Ek= X-Received: by 2002:a05:600c:1ca8:b0:459:d6a6:77c with SMTP id 5b1f17b1804b1-45a170bd0bbmr13285085e9.33.1755081273636; Wed, 13 Aug 2025 03:34:33 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEELEudHTWCDI9BaWwvbtQ0csqpCiqcohZPiSK0ly7y9oHpzj048L2vB1ffXFmTXExCK7eJHA== X-Received: by 2002:a05:600c:1ca8:b0:459:d6a6:77c with SMTP id 5b1f17b1804b1-45a170bd0bbmr13284495e9.33.1755081272593; Wed, 13 Aug 2025 03:34:32 -0700 (PDT) Received: from localhost (13.81.93.209.dyn.plus.net. [209.93.81.13]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45a16de7665sm24998115e9.16.2025.08.13.03.34.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 13 Aug 2025 03:34:32 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv7 3/4] gdb/python: new class gdb.StyleParameterSet Date: Wed, 13 Aug 2025 11:34:30 +0100 Message-ID: <76fa89c16d227269ea23273b6039b9cc3afcdb1f.1755080429.git.aburgess@redhat.com> X-Mailer: git-send-email 2.47.1 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: n_sLV-uwn4-ct_Qu05Ujs5C0cLGH2sZHexCCbGpSi4c_1755081275 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit content-type: text/plain; charset="US-ASCII"; x-default=true X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org Add a new helper class gdb.StyleParameterSet. This new class can be used to simplify creation of new style parameter sets. A style parameter set is the 'foreground', 'background', and (optionally), the 'intensity' settings, all grouped under a single prefix command. And example usage is: (gdb) python s = gdb.StyleParameterSet("my-style") (gdb) show style my-style style my-style background: The "my-style" style background color is: none style my-style foreground: The "my-style" style foreground color is: none style my-style intensity: The "my-style" style display intensity is: normal (gdb) Having created a gdb.StyleParameterSet, the object itself can be used to access a named style corresponding to the setting group, like this: (gdb) python print(s.style) (gdb) Of course, having access to the gdb.Style makes it easy to change the settings, or the settings can be adjusted via the normal CLI 'set' commands. As gdb.StyleParameterSet manages a set of parameters, and the gdb.Parameter class uses Parameter.value as the attribute to read the parameter's value, there is also StyleParameterSet.value, but this is just an alias for StyleParameterSet.style, that is, it allows the gdb.Style object to be read and written too. It is worth noting that this class only creates a single level of prefix command. As an example GDB has style 'disassembler mnemonic', where the 'disassembler' part is a group of related styles. If a user wanted to create: style my-style-group style-1 style-2 style-3 Where each of 'style-1', 'style-2', and 'style-3' will have the full set of 'foreground', 'background', and 'intensity', then the gdb.StyleParameterSet can be used to create the 'style-N' part, but the user will have to create the 'my-style-group' prefix themselves, possibly using gdb.ParameterPrefix, e.g.: gdb.ParameterPrefix("style my-style-group", gdb.COMMAND_NONE) gdb.StyleParameterSet("my-style-group style-1") gdb.StyleParameterSet("my-style-group style-2") gdb.StyleParameterSet("my-style-group style-3") --- gdb/NEWS | 4 + gdb/doc/python.texi | 115 +++++- gdb/python/lib/gdb/__init__.py | 209 ++++++++++ .../gdb.python/py-style-parameter-set.exp | 366 ++++++++++++++++++ 4 files changed, 693 insertions(+), 1 deletion(-) create mode 100644 gdb/testsuite/gdb.python/py-style-parameter-set.exp diff --git a/gdb/NEWS b/gdb/NEWS index 303374377ba..6ae6710e877 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -144,6 +144,10 @@ info threads [-gid] [-stopped] [-running] [ID]... gdb.INTENSITY_DIM for use with gdb.Style when representing intensities. + ** New gdb.StyleParameterSet for creating custom style settings. + Use gdb.StyleParameterSet(NAME) to create 'set style NAME ...' + and 'show style NAME ...' parameters. + ** The memory_source argument (the second argument) has been removed from gdb.disassembler.builtin_disassemble. This argument was never used by GDB, and was added by mistake. The unused argument diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi index 0b4ed9d6a1c..486f0a8f750 100644 --- a/gdb/doc/python.texi +++ b/gdb/doc/python.texi @@ -5293,6 +5293,7 @@ Parameters In Python feature-2}, then the @kbd{plugin-name} would need to be a prefix command (@pxref{CLI Commands In Python}). +@anchor{gdb.ParameterPrefix} However, when creating parameters, you will almost always need to create two prefix commands, one as a @kbd{set} sub-command, and one as a @kbd{show} sub-command. @value{GDBN} provides the @@ -5379,6 +5380,117 @@ Parameters In Python ExampleParam("plugin-name feature-2") @end smallexample +@anchor{Creating Style Parameters} +The helper class @code{gdb.StyleParameterSet} exists to make it easier +to create new styles. @value{GDBN} places style settings under +@samp{show style @dots{}} and @samp{set style @dots{}}, an example of a style +is @samp{filename}. Each style is really a prefix command (@pxref{CLI +Commands In Python}), with sub-commands @samp{foreground}, +@samp{background}, and optionally, @samp{intensity}. + +It is simple enough to create a new style using two @code{gdb.Command} +objects for the prefix commands (one for @samp{set}, and one for +@samp{show}), and three @code{gdb.Parameter} objects, one each for the +@samp{foreground}, @samp{background}, and @samp{intensity}. You would +also want to take care to craft the help text so that the new style +behaves the same as the existing styles. + +Or, you can use the @code{gdb.StyleParameterSet} class, which takes +care of all this, as the following example shows: + +@smallexample +@group +(@value{GDBP}) python s = gdb.StyleParameterSet("my-style") +(@value{GDBP}) show style my-style +style my-style background: The "my-style" style background color is: none +style my-style foreground: The "my-style" style foreground color is: none +style my-style intensity: The "my-style" style display intensity is: normal +(@value{GDBP}) +@end group +@end smallexample + +You might also want to group a number of styles within a new prefix, +similar to how @value{GDBN} groups disassembler related styles within +the @samp{style disassembler} prefix. This can be done using +@code{gdb.ParameterPrefix} (@pxref{gdb.ParameterPrefix}), as in this +example: + +@smallexample +@group +(@value{GDBP}) python gdb.ParameterPrefix("style my-group", gdb.COMMAND_NONE) +(@value{GDBP}) python s_a = gdb.StyleParameterSet("my-group aaa") +(@value{GDBP}) python s_b = gdb.StyleParameterSet("my-group bbb") +(@value{GDBP}) show style my-group +style my-group aaa background: The "my-group aaa" style background color is: none +style my-group aaa foreground: The "my-group aaa" style foreground color is: none +style my-group aaa intensity: The "my-group aaa" style display intensity is: normal +style my-group bbb background: The "my-group bbb" style background color is: none +style my-group bbb foreground: The "my-group bbb" style foreground color is: none +style my-group bbb intensity: The "my-group bbb" style display intensity is: normal +(@value{GDBP}) +@end group +@end smallexample + +The @code{gdb.StyleParameterSet} class has the following methods and +attributes: + +@defun StyleParameterSet.__init__(name, @w{add_intensity=@code{True}}, @w{doc=@code{None}}) +Create a new style group based on @var{name}, which is a string. For +example if @var{name} is @samp{my-style}, then @value{GDBN} will +create the prefix commands @samp{set style my-style} and @samp{show +style my-style}. Within these prefix commands will be +@samp{foreground}, @samp{background}, and @samp{intensity} parameters +with the appropriate types. + +It is also possible for @var{name} to consist of multiple words, so +long as each prefix command (except the last one) already exists. For +example, it is valid to use a @var{name} value of @samp{disassembler +my-style}, as the @samp{disassembler} prefix command already exists. +@value{GDBN} would then create @samp{set style disassembler my-style} +and @samp{show style disassembler my-style}, and within the +@samp{my-style} prefixes will be the @samp{foreground}, +@samp{background}, and @samp{intensity} parameters with the +appropriate types. + +Every style requires a @samp{foreground} and @samp{background}, but +not every style needs an @samp{intensity}. If @var{add_intensity} is +@code{True} (the default), then the @samp{intensity} parameter will be +created. If @var{add_intensity} is @code{False}, then the +@samp{intensity} parameter will not be created. + +If the @samp{intensity} parameter is not created, then the +@code{gdb.Style} (@pxref{Styles In Python}) created from this +@code{gdb.StyleParameterSet} will have @code{gdb.INTENSITY_NORMAL}. + +The @var{doc} should be a string which will be used as the help text +for the @var{name} prefix command. This text is used as the +@code{Command.__doc__} value for the @code{gdb.Command} object that is +the prefix command object (@pxref{CLI Commands In Python}). If +@var{doc} is @code{None} (the default) then a basic default help text +is used. +@end defun + +@defun StyleParameterSet.apply(string) +Equivalent to @code{StyleParameterSet.style.apply(string)}. Returns a +copy of @var{string} with escape sequences added to the start and end. +The escape sequence at the start applies this style, and the escape +sequence at the end restores the terminal default. + +If styling is disabled (i.e.@: @samp{set style enabled off}), then no +escape sequences are added and this method returns a copy of +@var{string}. +@end defun + +@defvar StyleParameterSet.style +This read/write attribute holds a @code{gdb.Style} object +(@pxref{Styles In Python}), that is a named style associated with this +style parameter group. +@end defvar + +@defvar StyleParameterSet.value +This is an alias for @code{StyleParameterSet.style}, see above. +@end defvar + @node Functions In Python @subsubsection Writing new convenience functions @@ -7275,7 +7387,8 @@ Styles In Python @value{GDBN} has many styles builtin (@pxref{Output Styling}), and style objects can be created that apply these builtin styles to Python -output. +output. It is also possible to create new styles which can be used to +style Python output (@pxref{Creating Style Parameters}). The style class is called @code{gdb.Style}, and has the following methods and attributes: diff --git a/gdb/python/lib/gdb/__init__.py b/gdb/python/lib/gdb/__init__.py index cedd897ab0f..f2f57280007 100644 --- a/gdb/python/lib/gdb/__init__.py +++ b/gdb/python/lib/gdb/__init__.py @@ -515,3 +515,212 @@ class ParameterPrefix: def dont_repeat(self): if self.active_prefix is not None: self.active_prefix.dont_repeat() + + +class StyleParameterSet: + """Create new style parameters. + + A style parameter is a set of parameters that start with 'set style ...' + and 'show style ...'. For example 'filename' is a style parameter, and + 'disassembler symbol' is another style parameter. + + The name of the style parameter is really a prefix command. Under this + we must have two commands 'foreground' and 'background', which are color + parameters. A third, optional command 'intensity', is an enum with + values 'normal', 'bold', and 'dim'. + + A StyleParameterSet is initialised with a name, e.g. 'filename' or + 'disassembler symbol'. The StyleParameterSet creates the prefix + commands in the 'set style' and 'show style' name space, and then adds + the 'foreground', 'background', and optionally, the 'intensity' + commands. + + If you want a whole new style group, similar to 'disassembler', + then you need to add this yourself first, then StyleParameterSet + can be used to create styles within the new prefix group. + + The 'value' attribute on this object can be used to get and set a + gdb.Style object which controls all aspects of this style. + + For readability, the alias 'style' is the same as 'value'. + """ + + def __init__(self, name, add_intensity=True, doc=None): + # The STYLE_NAME is something like 'filename' is 'set style + # filename ...', and PARAM_NAME is one of 'foreground', + # 'background', or 'intensity'. The DESC_TEXT is the long + # form used in help text, like 'foreground color' or 'display + # intensity'. The DEFAULT_VALUE is used to set the SELF.value + # attribute. And PARAM_TYPE is a gdb.PARAM_* constant. The + # ARGS is used for gdb.PARAM_ENUM, which ARGS should be the + # enum value list. + class style_parameter(Parameter): + def __init__( + self, + style_name, + parent_obj, + param_name, + desc_text, + default_value, + param_type, + *args + ): + # Setup documentation must be done before calling + # parent's __init__ method, as the __init__ reads (and + # copies) these values. + self.show_doc = "Show the " + desc_text + " for this property." + self.set_doc = "Set the " + desc_text + " for this property." + self.__doc__ = "" + + # Call the parent's __init__ method to actually create + # the parameter. + super().__init__( + "style " + style_name + " " + param_name, + COMMAND_NONE, + param_type, + *args + ) + + # Store information we need in other methods. + self._style_name = style_name + self._desc_text = desc_text + self._parent = parent_obj + + # Finally, setup the default value. + self.value = default_value + + # Return the 'show style ' string, + # which has styling applied. + def get_show_string(self, value): + s = self._parent.style + return ( + "The " + + s.apply('"' + self._style_name + '" style') + + " " + + self._desc_text + + " is: " + + value + ) + + class style_foreground_parameter(style_parameter): + def __init__(self, name, parent): + super().__init__( + name, + parent, + "foreground", + "foreground color", + Color(), + PARAM_COLOR, + ) + + class style_background_parameter(style_parameter): + def __init__(self, name, parent): + super().__init__( + name, + parent, + "background", + "background color", + Color(), + PARAM_COLOR, + ) + + class style_intensity_parameter(style_parameter): + def __init__(self, name, parent): + super().__init__( + name, + parent, + "intensity", + "display intensity", + "normal", + PARAM_ENUM, + ["normal", "bold", "dim"], + ) + + if doc is None: + doc = ( + "The " + + name + + " display styling.\nConfigure " + + name + + " colors and display intensity." + ) + + ParameterPrefix("style " + name, COMMAND_NONE, doc) + self._foreground = style_foreground_parameter(name, self) + self._background = style_background_parameter(name, self) + if add_intensity: + self._intensity = style_intensity_parameter(name, self) + self._name = name + self._style = None + + @property + def value(self): + """Return the gdb.Style object for this parameter set.""" + if self._style is None: + self._style = Style(self._name) + return self._style + + @property + def style(self): + """Return the gdb.Style object for this parameter set. + + This is an alias for self.value.""" + return self.value + + @value.setter + def value(self, new_value): + """Set this parameter set to NEW_VALUE, a gdb.Style object. + + The attributes of NEW_VALUE are used to update the current settings + of this parameter set. If this parameter set was created without + an intensity setting, then the intensity of NEW_VALUE is ignored.""" + if not isinstance(new_value, Style): + raise TypeError("value must be gdb.Style, not %s" % type(new_value)) + self._foreground.value = new_value.foreground + self._background.value = new_value.background + if hasattr(self, "_intensity"): + intensity_value = new_value.intensity + if intensity_value == INTENSITY_BOLD: + intensity_string = "bold" + elif intensity_value == INTENSITY_DIM: + intensity_string = "dim" + elif intensity_value == INTENSITY_NORMAL: + intensity_string = "normal" + else: + raise ValueError( + "unknown intensity value %d from Style" % intensity_value + ) + + self._intensity.value = intensity_string + + @style.setter + def style(self, new_value): + """Set this parameter set to NEW_VALUE, a gdb.Style object. + + This is an alias for self.value.""" + self.value = new_value + + def apply(self, *args, **kwargs): + """Apply this style to the arguments. + + Forwards all arguments to self.style.apply(). The arguments should be a string, + to which this style is applied. This function returns the same string with + escape sequences added to apply this style. + + If styling is globally disabled ('set style enabled off') then no escape sequences + will be addedded, the input string is returned.""" + return self.style.apply(*args, **kwargs) + + def __repr__(self): + """A string representation of SELF.""" + + def full_typename(obj): + module = type(obj).__module__ + qualname = type(obj).__qualname__ + + if module is None or module == "builtins": + return qualname + else: + return module + "." + qualname + + return "<" + full_typename(self) + " name='" + self._name + "'>" diff --git a/gdb/testsuite/gdb.python/py-style-parameter-set.exp b/gdb/testsuite/gdb.python/py-style-parameter-set.exp new file mode 100644 index 00000000000..73d94d1bb51 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-style-parameter-set.exp @@ -0,0 +1,366 @@ +# Copyright (C) 2025 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 . + +# This file is part of the GDB testsuite. It tests gdb.StyleParameterSet. + +load_lib gdb-python.exp + +require allow_python_tests + +# Create a regexp that can be used to match the output of a 'show style +# NAME' command. HAS_INTENSITY is a boolean and indicates if style NAME has +# an intensity attribute. +proc gen_show_style_re { name has_intensity } { + set output \ + [list \ + "style ${name} background: The \"${name}\" style background color is: none" \ + "style ${name} foreground: The \"${name}\" style foreground color is: none"] + + if { $has_intensity } { + lappend output \ + "style ${name} intensity: The \"${name}\" style display intensity is: normal" + } + + return [multi_line {*}$output] +} + +# Create a regexp to match against the output of a 'set style NAME' command, +# that is, a 'set' command that doesn't actually set an attribute of a +# style, in this case GDB will print some useful help text. HAS_INTENSITY is +# a boolean and indicates if style NAME has an intensity attribute or not. +proc gen_set_style_re { name has_intensity } { + set output \ + [list \ + "List of \"set style $name\" subcommands:" \ + "" \ + "set style $name background -- Set the background color for this property\\." \ + "set style $name foreground -- Set the foreground color for this property\\."] + + if { $has_intensity } { + lappend output \ + "set style $name intensity -- Set the display intensity for this property\\." + } + + lappend output \ + "" \ + "Type \"help set style $name\" followed by subcommand name for full documentation\\." \ + "Type \"apropos word\" to search for commands related to \"word\"\\." \ + "Type \"apropos -v word\" for full documentation of commands related to \"word\"\\." \ + "Command name abbreviations are allowed if unambiguous\\." + + return [multi_line {*}$output] +} + +# Create a regexp to match against the output of a 'help show style NAME' +# command. HAS_INTENSITY is a boolean and indicates if style NAME has an +# intensity attribute or not. DOC is a regexp that matches the doc string +# for style NAME. +proc gen_help_show_style_re { name has_intensity doc } { + set output \ + [list \ + $doc \ + "" \ + "List of \"show style ${name}\" subcommands:" \ + "" \ + "show style $name background -- Show the background color for this property\\." \ + "show style $name foreground -- Show the foreground color for this property\\."] + if { $has_intensity } { + lappend output \ + "show style $name intensity -- Show the display intensity for this property\\." + } + + lappend output \ + "" \ + "Type \"help show style $name\" followed by subcommand name for full documentation\\." \ + "Type \"apropos word\" to search for commands related to \"word\"\\." \ + "Type \"apropos -v word\" for full documentation of commands related to \"word\"\\." \ + "Command name abbreviations are allowed if unambiguous\\." + + return [multi_line {*}$output] +} + +# Create a regexp to match against the output of a 'help set style NAME' +# command. HAS_INTENSITY is a boolean and indicates if style NAME has an +# intensity attribute or not. DOC is a regexp that matches the doc string +# for style NAME. +proc gen_help_set_style_re { name has_intensity doc } { + return \ + [multi_line \ + $doc \ + "" \ + [gen_set_style_re $name $has_intensity]] +} + +# Create styles with and without intensity. Use named and unnamed +# argument passing, and vary the argument passing order. Create +# styles with and without documentation. +# +# Confirm that the styles contain the expected sub-commands, and that +# the documentation is as expected. +proc_with_prefix test_basic_usage {} { + gdb_test_no_output \ + "python style_1 = gdb.StyleParameterSet(\"style-1\")" \ + "create style-1" + + gdb_test_no_output \ + "python style_2 = gdb.StyleParameterSet(add_intensity=True, name=\"style-2\")" \ + "create style-2" + + gdb_test_no_output \ + "python style_3 = gdb.StyleParameterSet(name=\"style-3\", doc=\"Style-3 display styling.\\nThis is a multi-line documentation\\nstring describing style-3.\")" \ + "create style-3" + + gdb_test_no_output \ + "python style_4 = gdb.StyleParameterSet(\"style-4\", add_intensity=False)" \ + "create style-4" + + foreach style { style-1 style-2 style-3 } { + gdb_test "show style $style" \ + [gen_show_style_re $style true] + gdb_test "set style $style" \ + [gen_set_style_re $style true] + } + + gdb_test "show style style-4" \ + [gen_show_style_re "style-4" false] + + foreach style { style-1 style-2 } { + gdb_test "help show style $style" \ + [gen_help_show_style_re $style true \ + [multi_line \ + "The $style display styling\\." \ + "Configure $style colors and display intensity\\."]] + + + set out [gen_help_set_style_re $style true \ + [multi_line \ + "The $style display styling\\." \ + "Configure $style colors and display intensity\\."]] + + gdb_test "help set style $style" \ + [gen_help_set_style_re $style true \ + [multi_line \ + "The $style display styling\\." \ + "Configure $style colors and display intensity\\."]] + } + + gdb_test "help show style style-3" \ + [gen_help_show_style_re "style-3" true \ + [multi_line \ + "Style-3 display styling\\." \ + "This is a multi-line documentation" \ + "string describing style-3\\."]] + + gdb_test "help show style style-4" \ + [gen_help_show_style_re "style-4" false \ + [multi_line \ + "The style-4 display styling\\." \ + "Configure style-4 colors and display intensity\\."]] + + for { set i 1 } { $i < 5 } { incr i } { + gdb_test "python print(style_$i)" \ + "" \ + "print repr of style_$i" + } + + # There is no 'style-4 intensity' property. + gdb_test "show style style-4 foreground" \ + "The \"style-4\" style foreground color is: none" + gdb_test "show style style-4 background" \ + "The \"style-4\" style background color is: none" + gdb_test "show style style-4 intensity" \ + "Undefined show style style-4 command: \"intensity\"\\. Try \"help show style style-4\"\\." + + # There is a 'style-1 intensity' property. + gdb_test "show style style-1 foreground" \ + "The \"style-1\" style foreground color is: none" \ + "show style-1 foreground before changes" + gdb_test "show style style-1 background" \ + "The \"style-1\" style background color is: none" \ + "show style-1 background before changes" + gdb_test "show style style-1 intensity" \ + "The \"style-1\" style display intensity is: normal" \ + "show style-1 intensity before changes" + + # Grab the gdb.Style objects from 'style-1'. + gdb_test_no_output "python s1 = style_1.style" + gdb_test_no_output "python s2 = style_1.value" + + # Check both represent the same style. + gdb_test "python print(s1)" \ + "" \ + "print s1 style before changes" + gdb_test "python print(s2)" \ + "" \ + "print s2 style before changes" + + gdb_test_no_output \ + "python s1.foreground=gdb.Color('red')" "set foreground" + gdb_test_no_output \ + "python s1.background=gdb.Color('blue')" "set background" + gdb_test_no_output \ + "python s1.intensity=gdb.INTENSITY_DIM" "set intensity" + + gdb_test "python print(s1)" \ + "" \ + "print s1 style after first set of changes" + gdb_test "python print(s2)" \ + "" \ + "print s2 style after first set of changes" + + # Check the style properties have updated. + gdb_test "show style style-1 foreground" \ + "The \"style-1\" style foreground color is: red" \ + "show style-1 foreground after first set of changes" + gdb_test "show style style-1 background" \ + "The \"style-1\" style background color is: blue" \ + "show style-1 background after first set of changes" + gdb_test "show style style-1 intensity" \ + "The \"style-1\" style display intensity is: dim" \ + "show style-1 intensity after first set of changes" + + # Change the style properties, check gdb.Style objects update. + gdb_test_no_output "set style style-1 foreground yellow" + gdb_test_no_output "set style style-1 background cyan" + gdb_test_no_output "set style style-1 intensity bold" + + gdb_test "python print(s1)" \ + "" \ + "print s1 style after second set of changes" + gdb_test "python print(s2)" \ + "" \ + "print s2 style after second set of changes" + + # Assign a gdb.Style to set 'style-1'. First create some unnamed + # style objects that can be used. + gdb_test_no_output \ + "python uns1 = gdb.Style(foreground=gdb.Color('white'), background=gdb.Color('black'), intensity=gdb.INTENSITY_BOLD)" \ + "create uns1" + gdb_test_no_output \ + "python uns2 = gdb.Style(foreground=gdb.Color('black'), background=gdb.Color('white'), intensity=gdb.INTENSITY_DIM)" \ + "create uns2" + + gdb_test_no_output "python style_1.value = uns1" + gdb_test "show style style-1 foreground" \ + "The \"style-1\" style foreground color is: white" \ + "show style-1 foreground after assigning uns1" + gdb_test "show style style-1 background" \ + "The \"style-1\" style background color is: black" \ + "show style-1 background after assigning uns1" + gdb_test "show style style-1 intensity" \ + "The \"style-1\" style display intensity is: bold" \ + "show style-1 intensity after assigning uns1" + + gdb_test_no_output "python style_1.style = uns2" + gdb_test "show style style-1 foreground" \ + "The \"style-1\" style foreground color is: black" \ + "show style-1 foreground after assigning uns2" + gdb_test "show style style-1 background" \ + "The \"style-1\" style background color is: white" \ + "show style-1 background after assigning uns2" + gdb_test "show style style-1 intensity" \ + "The \"style-1\" style display intensity is: dim" \ + "show style-1 intensity after assigning uns2" + + # Assign a style with an intensity that is not 'NORMAL' to a + # StyleParameterSet that doesn't have an intensity. The new + # intensity setting should be ignored. + gdb_test_no_output "python style_4.style = uns1" + gdb_test "show style style-4 foreground" \ + "The \"style-4\" style foreground color is: white" \ + "show style-4 foreground after assigning uns1" + gdb_test "show style style-4 background" \ + "The \"style-4\" style background color is: black" \ + "show style-4 background after assigning uns1" + gdb_test "show style style-4 intensity" \ + "Undefined show style style-4 command: \"intensity\"\\. Try \"help show style style-4\"\\." \ + "show style-4 intensity after assigning uns1" + + gdb_test "python print(style_4.style)" \ + "" \ + "print string repr of style_4's style" +} + +# Test creating a style prefix with gdb.ParameterPrefix, then adding +# some styles within the new prefix. Change the style through the CLI +# and confirm that the associated Python object updated as expected. +proc_with_prefix test_style_prefix {} { + gdb_test_no_output \ + "python gdb.ParameterPrefix(\"style my-style-group\", gdb.COMMAND_NONE)" + gdb_test_no_output \ + "python style_1 = gdb.StyleParameterSet(\"my-style-group style-1\")" \ + "create style-1" + gdb_test_no_output \ + "python style_2 = gdb.StyleParameterSet(\"my-style-group style-2\")" \ + "create style-2" + + gdb_test "python print(style_1.style)" \ + "" \ + "print 'my-style-group style-1' style before changes" + gdb_test "python print(style_2.style)" \ + "" \ + "print 'my-style-group style-2' style before changes" + + gdb_test_no_output "set style my-style-group style-1 foreground red" + gdb_test_no_output "set style my-style-group style-1 background yellow" + gdb_test_no_output "set style my-style-group style-1 intensity bold" + gdb_test_no_output "set style my-style-group style-2 foreground black" + gdb_test_no_output "set style my-style-group style-2 background blue" + gdb_test_no_output "set style my-style-group style-2 intensity dim" + + gdb_test "python print(style_1.style)" \ + "" \ + "print 'my-style-group style-1' style after changes" + gdb_test "python print(style_2.style)" \ + "" \ + "print 'my-style-group style-2' style after changes" +} + +# Test that gdb.StyleParameterSet.apply() works as expected. +proc_with_prefix test_applying {} { + # Create a new StyleParameterSet, and adjust its settings. + gdb_test_no_output \ + "python style_1 = gdb.StyleParameterSet(\"style-1\")" \ + "create style-1" + gdb_test_no_output \ + "python uns1 = gdb.Style(foreground=gdb.Color('red'), background=gdb.Color('blue'), intensity=gdb.INTENSITY_BOLD)" \ + "create uns1" + gdb_test_no_output "python style_1 = uns1" + + # When styling is off (which it currently is), no escape sequences + # should be added. + gdb_test \ + "python print(style_1.apply('xxx'))" "^xxx" \ + "apply StyleParameterSet to a string when styling is off" + + # When styling is on, we should see an escape sequence added. + gdb_test "with style enabled on -- python print(style_1.apply('xxx'))" \ + "\033\\\[31;44;1;23;24;27mxxx\033\\\[m" \ + "apply a style when styling is on" +} + +# Start GDB. +with_ansi_styling_terminal { + clean_restart +} + +# Turn styling off so that the output of 'show style ...' isn't styled, this +# makes it easier to match the output. +gdb_test_no_output "set style enabled off" + +# Run the tests. +test_basic_usage +test_style_prefix +test_applying -- 2.47.1