From f48b840cfa478d6bfeb6e16f24fd5b650c70e4f2 Mon Sep 17 00:00:00 2001 From: kotontrion Date: Wed, 20 Nov 2024 10:41:56 +0100 Subject: [PATCH 01/29] compile: fix flag values gtk builder does not support combining interger values with | in flags properties, so the short names are used instead. --- blueprintcompiler/language/values.py | 2 +- tests/samples/flags.ui | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/blueprintcompiler/language/values.py b/blueprintcompiler/language/values.py index 63cf4fc..e060b65 100644 --- a/blueprintcompiler/language/values.py +++ b/blueprintcompiler/language/values.py @@ -216,7 +216,7 @@ class Flag(AstNode): if not isinstance(type, Enumeration): return None elif member := type.members.get(self.name): - return member.value + return member.name else: return None diff --git a/tests/samples/flags.ui b/tests/samples/flags.ui index 2f0a26e..d13c424 100644 --- a/tests/samples/flags.ui +++ b/tests/samples/flags.ui @@ -7,7 +7,7 @@ corresponding .blp file and regenerate this file with blueprint-compiler. - 1|4 + is_service|handles_open 1 From 2ae41020abfb04649e9791f57c84fc708d428283 Mon Sep 17 00:00:00 2001 From: kotontrion Date: Thu, 21 Nov 2024 09:28:40 +0100 Subject: [PATCH 02/29] Fix flag return value type --- blueprintcompiler/language/values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blueprintcompiler/language/values.py b/blueprintcompiler/language/values.py index e060b65..4cd600d 100644 --- a/blueprintcompiler/language/values.py +++ b/blueprintcompiler/language/values.py @@ -211,7 +211,7 @@ class Flag(AstNode): return self.tokens["value"] @property - def value(self) -> T.Optional[int]: + def value(self) -> T.Optional[str]: type = self.context[ValueTypeCtx].value_type if not isinstance(type, Enumeration): return None From e07da3c33946e7ab4afed9c564a9e7ae0b3fbbb8 Mon Sep 17 00:00:00 2001 From: kotontrion Date: Tue, 26 Nov 2024 10:52:37 +0100 Subject: [PATCH 03/29] flags: use nick instead of name --- blueprintcompiler/language/values.py | 2 +- tests/samples/flags.ui | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/blueprintcompiler/language/values.py b/blueprintcompiler/language/values.py index 4cd600d..96787ee 100644 --- a/blueprintcompiler/language/values.py +++ b/blueprintcompiler/language/values.py @@ -216,7 +216,7 @@ class Flag(AstNode): if not isinstance(type, Enumeration): return None elif member := type.members.get(self.name): - return member.name + return member.nick else: return None diff --git a/tests/samples/flags.ui b/tests/samples/flags.ui index d13c424..44eb2c4 100644 --- a/tests/samples/flags.ui +++ b/tests/samples/flags.ui @@ -7,7 +7,7 @@ corresponding .blp file and regenerate this file with blueprint-compiler. - is_service|handles_open + is-service|handles-open 1 From 404ae767870b6da6005f2f4aaa878deed82829e5 Mon Sep 17 00:00:00 2001 From: James Westman Date: Fri, 17 Jan 2025 17:25:21 -0600 Subject: [PATCH 04/29] Update MAINTENANCE.md --- MAINTENANCE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTENANCE.md b/MAINTENANCE.md index 220c117..3ab4fa2 100644 --- a/MAINTENANCE.md +++ b/MAINTENANCE.md @@ -8,7 +8,7 @@ in the NEWS file. 3. Make a new commit with just these two changes. Use `Release v{version}` as the commit message. Tag the commit as `v{version}` and push the tag. 4. Create a "Post-release version bump" commit. 5. Go to the Releases page in GitLab and create a new release from the tag. -6. Announce the release through relevant channels (Twitter, TWIG, etc.) +6. Announce the release through relevant channels (Mastodon, TWIG, etc.) ## Related projects From a4e0c3701b1510191f72cc606c2fa20d97800444 Mon Sep 17 00:00:00 2001 From: Chris Mayo Date: Thu, 30 Jan 2025 19:23:40 +0000 Subject: [PATCH 05/29] docs: Update overview example using format and compile --- docs/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 34b942c..a71b968 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -26,7 +26,7 @@ Blueprint is a markup language and compiler for GTK 4 user interfaces. using Gtk 4.0; - template MyAppWindow : ApplicationWindow { + template $MyAppWindow: ApplicationWindow { default-width: 600; default-height: 300; title: _("Hello, Blueprint!"); @@ -35,7 +35,7 @@ Blueprint is a markup language and compiler for GTK 4 user interfaces. HeaderBar {} Label { - label: bind MyAppWindow.main_text; + label: bind template.main_text; } } From 394014429e819347d107eb5fa9fd2871bdb3d0ac Mon Sep 17 00:00:00 2001 From: Sertonix Date: Thu, 20 Mar 2025 10:52:57 +0000 Subject: [PATCH 06/29] Sort keys in collect-sections.py This makes sure that the reference_docs.json file is build reproducible. Ref https://reproducible-builds.org/ --- docs/collect-sections.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/collect-sections.py b/docs/collect-sections.py index e6227e7..07bc5f6 100755 --- a/docs/collect-sections.py +++ b/docs/collect-sections.py @@ -132,5 +132,8 @@ if __name__ == "__main__": # print the sections to a json file with open(outfile, "w") as f: json.dump( - {name: section.to_json() for name, section in sections.items()}, f, indent=2 + {name: section.to_json() for name, section in sections.items()}, + f, + indent=2, + sort_keys=True, ) From f93d5d2acd53365f70e48a0002e91e94be37f733 Mon Sep 17 00:00:00 2001 From: Tom Greig Date: Fri, 28 Mar 2025 20:26:19 +0000 Subject: [PATCH 07/29] Handle nested CDATA from nested templates When putting CDATA into the output, any instances of ']]>' in the text are replaced with ']]]]>'. This allows nested templates, e.g. from list views inside list views to work properly. --- blueprintcompiler/outputs/xml/xml_emitter.py | 1 + 1 file changed, 1 insertion(+) diff --git a/blueprintcompiler/outputs/xml/xml_emitter.py b/blueprintcompiler/outputs/xml/xml_emitter.py index ea91e03..d34eff4 100644 --- a/blueprintcompiler/outputs/xml/xml_emitter.py +++ b/blueprintcompiler/outputs/xml/xml_emitter.py @@ -73,6 +73,7 @@ class XmlEmitter: self._needs_newline = False def put_cdata(self, text: str): + text = text.replace("]]>", "]]]]>") self.result += f"" self._needs_newline = False From cc09f3d3bb8e6f273072c1b4727929bf7b0bad83 Mon Sep 17 00:00:00 2001 From: Tom Greig Date: Sun, 30 Mar 2025 10:27:11 +0100 Subject: [PATCH 08/29] Add tests for nested templates Basically just a copy of the list_factory test, but with an extra copy of the list factory inside it. --- tests/samples/list_factory_nested.blp | 17 +++++++++ tests/samples/list_factory_nested.ui | 44 +++++++++++++++++++++++ tests/samples/list_factory_nested_dec.blp | 18 ++++++++++ 3 files changed, 79 insertions(+) create mode 100644 tests/samples/list_factory_nested.blp create mode 100644 tests/samples/list_factory_nested.ui create mode 100644 tests/samples/list_factory_nested_dec.blp diff --git a/tests/samples/list_factory_nested.blp b/tests/samples/list_factory_nested.blp new file mode 100644 index 0000000..86a59b3 --- /dev/null +++ b/tests/samples/list_factory_nested.blp @@ -0,0 +1,17 @@ +using Gtk 4.0; + +Gtk.ListView { + factory: Gtk.BuilderListItemFactory list_item_factory { + template ListItem { + child: Gtk.ListView { + factory: Gtk.BuilderListItemFactory list_item_factory { + template ListItem { + child: Gtk.Label { + label: bind template.item as <$MyObject>.name; + }; + } + }; + }; + } + }; +} diff --git a/tests/samples/list_factory_nested.ui b/tests/samples/list_factory_nested.ui new file mode 100644 index 0000000..44cdb2b --- /dev/null +++ b/tests/samples/list_factory_nested.ui @@ -0,0 +1,44 @@ + + + + + + + + + + +]]> + + + + diff --git a/tests/samples/list_factory_nested_dec.blp b/tests/samples/list_factory_nested_dec.blp new file mode 100644 index 0000000..755491c --- /dev/null +++ b/tests/samples/list_factory_nested_dec.blp @@ -0,0 +1,18 @@ +using Gtk 4.0; + +ListView { + factory: BuilderListItemFactory list_item_factory { + template ListItem { + child: ListView { + factory: BuilderListItemFactory list_item_factory { + template ListItem { + child: Label { + label: bind template.item as <$MyObject>.name; + }; + } + }; + }; + } + }; +} + From f50b898e4ce74d84cfa92ce44e90f9aaca2ec133 Mon Sep 17 00:00:00 2001 From: James Westman Date: Tue, 1 Apr 2025 19:27:59 -0500 Subject: [PATCH 09/29] adw_breakpoint: Fix crash in language server Fix a crash that happened when an AdwBreakpointSetter rule was incomplete, such as when you're still typing it. Fixes #189. --- blueprintcompiler/language/adw_breakpoint.py | 9 ++++++--- blueprintcompiler/outputs/xml/__init__.py | 3 +++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/blueprintcompiler/language/adw_breakpoint.py b/blueprintcompiler/language/adw_breakpoint.py index 4ad5b24..3d2c10d 100644 --- a/blueprintcompiler/language/adw_breakpoint.py +++ b/blueprintcompiler/language/adw_breakpoint.py @@ -81,8 +81,8 @@ class AdwBreakpointSetter(AstNode): return self.tokens["property"] @property - def value(self) -> Value: - return self.children[Value][0] + def value(self) -> T.Optional[Value]: + return self.children[Value][0] if len(self.children[Value]) > 0 else None @property def gir_class(self) -> T.Optional[GirType]: @@ -106,7 +106,10 @@ class AdwBreakpointSetter(AstNode): return None @property - def document_symbol(self) -> DocumentSymbol: + def document_symbol(self) -> T.Optional[DocumentSymbol]: + if self.value is None: + return None + return DocumentSymbol( f"{self.object_id}.{self.property_name}", SymbolKind.Property, diff --git a/blueprintcompiler/outputs/xml/__init__.py b/blueprintcompiler/outputs/xml/__init__.py index 5c03761..15850f7 100644 --- a/blueprintcompiler/outputs/xml/__init__.py +++ b/blueprintcompiler/outputs/xml/__init__.py @@ -308,6 +308,9 @@ class XmlOutput(OutputFormat): elif isinstance(extension, AdwBreakpointSetters): for setter in extension.setters: + if setter.value is None: + continue + attrs = {} if isinstance(setter.value.child, Translated): From 6a77bfee0a5b2a03390c4ed7f945902a070ef697 Mon Sep 17 00:00:00 2001 From: James Westman Date: Sat, 19 Apr 2025 13:27:20 -0500 Subject: [PATCH 10/29] tests: Fix typing --- tests/test_tokenizer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_tokenizer.py b/tests/test_tokenizer.py index 2bca595..ad5f828 100644 --- a/tests/test_tokenizer.py +++ b/tests/test_tokenizer.py @@ -25,7 +25,7 @@ from blueprintcompiler.tokenizer import Token, TokenType, tokenize class TestTokenizer(unittest.TestCase): - def assert_tokenize(self, string: str, expect: [Token]): + def assert_tokenize(self, string: str, expect: list[Token]): try: tokens = tokenize(string) self.assertEqual(len(tokens), len(expect)) From e9d61cb6f915d6688dc46cb9142eb6acae7110f7 Mon Sep 17 00:00:00 2001 From: James Westman Date: Fri, 25 Apr 2025 18:15:15 -0500 Subject: [PATCH 11/29] Update URLs after move to GNOME namespace on GitLab --- .gitlab-ci.yml | 4 ++-- blueprintcompiler/errors.py | 2 +- blueprintcompiler/interactive_port.py | 4 ++-- docs/collect-sections.py | 2 +- docs/flatpak.rst | 2 +- docs/index.rst | 2 +- docs/reference/extensions.rst | 2 +- docs/setup.rst | 4 ++-- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1ec071e..6d373cc 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,7 +3,7 @@ stages: - pages build: - image: registry.gitlab.gnome.org/jwestman/blueprint-compiler + image: registry.gitlab.gnome.org/gnome/blueprint-compiler stage: build script: - black --check --diff ./ tests @@ -33,7 +33,7 @@ build: path: coverage.xml fuzz: - image: registry.gitlab.gnome.org/jwestman/blueprint-compiler + image: registry.gitlab.gnome.org/gnome/blueprint-compiler stage: build script: - meson _build diff --git a/blueprintcompiler/errors.py b/blueprintcompiler/errors.py index 1e7297c..df1c2e1 100644 --- a/blueprintcompiler/errors.py +++ b/blueprintcompiler/errors.py @@ -219,7 +219,7 @@ def report_bug(): # pragma: no cover f"""{Colors.BOLD}{Colors.RED}***** COMPILER BUG ***** The blueprint-compiler program has crashed. Please report the above stacktrace, along with the input file(s) if possible, on GitLab: -{Colors.BOLD}{Colors.BLUE}{Colors.UNDERLINE}https://gitlab.gnome.org/jwestman/blueprint-compiler/-/issues/new?issue +{Colors.BOLD}{Colors.BLUE}{Colors.UNDERLINE}https://gitlab.gnome.org/GNOME/blueprint-compiler/-/issues/new?issue {Colors.CLEAR}""" ) diff --git a/blueprintcompiler/interactive_port.py b/blueprintcompiler/interactive_port.py index 0c37885..12dd485 100644 --- a/blueprintcompiler/interactive_port.py +++ b/blueprintcompiler/interactive_port.py @@ -71,7 +71,7 @@ def decompile_file(in_file, out_file) -> T.Union[str, CouldNotPort]: print( f"""{Colors.FAINT}Either the original XML file had an error, or there is a bug in the porting tool. If you think it's a bug (which is likely), please file an issue on GitLab: -{Colors.BLUE}{Colors.UNDERLINE}https://gitlab.gnome.org/jwestman/blueprint-compiler/-/issues/new?issue{Colors.CLEAR}\n""" +{Colors.BLUE}{Colors.UNDERLINE}https://gitlab.gnome.org/GNOME/blueprint-compiler/-/issues/new?issue{Colors.CLEAR}\n""" ) return CouldNotPort("does not compile") @@ -136,7 +136,7 @@ def step1(): wrap.write( f"""[wrap-git] directory = blueprint-compiler -url = https://gitlab.gnome.org/jwestman/blueprint-compiler.git +url = https://gitlab.gnome.org/GNOME/blueprint-compiler.git revision = {VERSION} depth = 1 diff --git a/docs/collect-sections.py b/docs/collect-sections.py index 07bc5f6..a2dd004 100755 --- a/docs/collect-sections.py +++ b/docs/collect-sections.py @@ -9,7 +9,7 @@ from pathlib import Path __all__ = ["get_docs_section"] -DOCS_ROOT = "https://jwestman.pages.gitlab.gnome.org/blueprint-compiler" +DOCS_ROOT = "https://gnome.pages.gitlab.gnome.org/blueprint-compiler" sections: dict[str, "Section"] = {} diff --git a/docs/flatpak.rst b/docs/flatpak.rst index 86112cf..8081c8d 100644 --- a/docs/flatpak.rst +++ b/docs/flatpak.rst @@ -16,7 +16,7 @@ a module in your flatpak manifest: "sources": [ { "type": "git", - "url": "https://gitlab.gnome.org/jwestman/blueprint-compiler", + "url": "https://gitlab.gnome.org/GNOME/blueprint-compiler", "tag": "v0.16.0" } ] diff --git a/docs/index.rst b/docs/index.rst index a71b968..6cd130f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -59,7 +59,7 @@ Features Links ----- -- `Source code `_ +- `Source code `_ - `Workbench `_ lets you try, preview and export Blueprint - `GNOME Builder `_ provides builtin support - `Vim syntax highlighting plugin by thetek42 `_ diff --git a/docs/reference/extensions.rst b/docs/reference/extensions.rst index 0961d14..2fd5dbb 100644 --- a/docs/reference/extensions.rst +++ b/docs/reference/extensions.rst @@ -10,7 +10,7 @@ Properties are the main way to set values on objects, but they are limited by th Extensions are a feature of ``Gtk.Buildable``--see `Gtk.Buildable.custom_tag_start() `_ for internal details. - Because they aren't part of the type system, they aren't present in typelib files like properties and signals are. Therefore, if a library adds a new extension, syntax for it must be added to Blueprint manually. If there's a commonly used extension that isn't supported by Blueprint, please `file an issue `_. + Because they aren't part of the type system, they aren't present in typelib files like properties and signals are. Therefore, if a library adds a new extension, syntax for it must be added to Blueprint manually. If there's a commonly used extension that isn't supported by Blueprint, please `file an issue `_. .. rst-class:: grammar-block diff --git a/docs/setup.rst b/docs/setup.rst index 839f8f6..914c753 100644 --- a/docs/setup.rst +++ b/docs/setup.rst @@ -8,7 +8,7 @@ Setting up Blueprint on a new or existing project Using the porting tool ~~~~~~~~~~~~~~~~~~~~~~ -Clone `blueprint-compiler `_ +Clone `blueprint-compiler `_ from source. You can install it using ``meson _build`` and ``ninja -C _build install``, or you can leave it uninstalled. @@ -29,7 +29,7 @@ blueprint-compiler works as a meson subproject. [wrap-git] directory = blueprint-compiler - url = https://gitlab.gnome.org/jwestman/blueprint-compiler.git + url = https://gitlab.gnome.org/GNOME/blueprint-compiler.git revision = main depth = 1 From 3816f4fe8da291704d54a9dd945ba253b9233ca1 Mon Sep 17 00:00:00 2001 From: James Westman Date: Fri, 25 Apr 2025 18:26:45 -0500 Subject: [PATCH 12/29] Add .doap file --- blueprint-compiler.doap | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 blueprint-compiler.doap diff --git a/blueprint-compiler.doap b/blueprint-compiler.doap new file mode 100644 index 0000000..f3e4000 --- /dev/null +++ b/blueprint-compiler.doap @@ -0,0 +1,27 @@ + + + Blueprint + A modern language for creating GTK interfaces + Blueprint is a language and associated tooling for building user interfaces for GTK. + + Python + + + + + + + + James Westman + + jwestman + + + From a83c7e936dafa19afd9753138fd66b7e3aaee008 Mon Sep 17 00:00:00 2001 From: James Westman Date: Fri, 25 Apr 2025 18:32:33 -0500 Subject: [PATCH 13/29] black: Update formatting --- blueprintcompiler/parse_tree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blueprintcompiler/parse_tree.py b/blueprintcompiler/parse_tree.py index ae062fb..e590539 100644 --- a/blueprintcompiler/parse_tree.py +++ b/blueprintcompiler/parse_tree.py @@ -17,7 +17,7 @@ # # SPDX-License-Identifier: LGPL-3.0-or-later -""" Utilities for parsing an AST from a token stream. """ +"""Utilities for parsing an AST from a token stream.""" import typing as T from enum import Enum From a12d3f5c81ee231f8bdb87cb06cf8afe5e35f4ad Mon Sep 17 00:00:00 2001 From: James Westman Date: Fri, 25 Apr 2025 20:13:01 -0500 Subject: [PATCH 14/29] decompile: Fix bug in lookup tags A lookup tag with no type attribute would crash the decompiler, even if that was valid. This wasn't caught by the tests since blueprint never generates such XML. Also fixed a bug in the tests that caused decompiler-only tests not to run. --- blueprintcompiler/decompiler.py | 8 +++++--- blueprintcompiler/language/expression.py | 12 +++++++++--- tests/samples/issue_187.ui | 15 +++++++++++++++ tests/samples/issue_187_dec.blp | 7 +++++++ tests/test_samples.py | 10 +++------- 5 files changed, 39 insertions(+), 13 deletions(-) create mode 100644 tests/samples/issue_187.ui create mode 100644 tests/samples/issue_187_dec.blp diff --git a/blueprintcompiler/decompiler.py b/blueprintcompiler/decompiler.py index de6c06f..850b6d8 100644 --- a/blueprintcompiler/decompiler.py +++ b/blueprintcompiler/decompiler.py @@ -255,7 +255,11 @@ def decompile_element( ctx._node_stack.append(xml) ctx.start_block() - gir = decompiler(*args, **kwargs) + + try: + gir = decompiler(*args, **kwargs) + except TypeError as e: + raise UnsupportedError(tag=xml.tag) if not decompiler._skip_children: for child in xml.children: @@ -266,8 +270,6 @@ def decompile_element( except UnsupportedError as e: raise e - except TypeError as e: - raise UnsupportedError(tag=xml.tag) def decompile(data: str) -> str: diff --git a/blueprintcompiler/language/expression.py b/blueprintcompiler/language/expression.py index e0b4246..de6fbf1 100644 --- a/blueprintcompiler/language/expression.py +++ b/blueprintcompiler/language/expression.py @@ -302,12 +302,18 @@ expr.children = [ @decompiler("lookup", skip_children=True, cdata=True) def decompile_lookup( - ctx: DecompileCtx, gir: gir.GirContext, cdata: str, name: str, type: str + ctx: DecompileCtx, + gir: gir.GirContext, + cdata: str, + name: str, + type: T.Optional[str] = None, ): if ctx.parent_node is not None and ctx.parent_node.tag == "property": ctx.print("expr ") - if t := ctx.type_by_cname(type): + if type is None: + type = "" + elif t := ctx.type_by_cname(type): type = decompile.full_name(t) else: type = "$" + type @@ -327,7 +333,7 @@ def decompile_lookup( if constant == ctx.template_class: ctx.print("template." + name) elif constant == "": - ctx.print("item as <" + type + ">." + name) + ctx.print(f"item as <{type}>.{name}") else: ctx.print(constant + "." + name) return diff --git a/tests/samples/issue_187.ui b/tests/samples/issue_187.ui new file mode 100644 index 0000000..941a00f --- /dev/null +++ b/tests/samples/issue_187.ui @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/tests/samples/issue_187_dec.blp b/tests/samples/issue_187_dec.blp new file mode 100644 index 0000000..30b997c --- /dev/null +++ b/tests/samples/issue_187_dec.blp @@ -0,0 +1,7 @@ +using Gtk 4.0; + +template ListItem { + child: Label { + label: bind template.item as <$RecentObject>.filename; + }; +} diff --git a/tests/test_samples.py b/tests/test_samples.py index 1f56eb6..f96d0eb 100644 --- a/tests/test_samples.py +++ b/tests/test_samples.py @@ -181,11 +181,7 @@ class TestSamples(unittest.TestCase): def test_samples(self): # list the samples directory - samples = [ - f.stem - for f in Path(__file__).parent.glob("samples/*.blp") - if not f.stem.endswith("_dec") - ] + samples = [f.stem for f in Path(__file__).parent.glob("samples/*.blp")] samples.sort() for sample in samples: REQUIRE_ADW_1_4 = ["adw_breakpoint"] @@ -215,7 +211,7 @@ class TestSamples(unittest.TestCase): ] # Decompiler-only tests - SKIP_COMPILE = ["issue_177", "translator_comments"] + SKIP_COMPILE = ["issue_177", "issue_187", "translator_comments"] SKIP_DECOMPILE = [ # Comments are not preserved in either direction @@ -228,7 +224,7 @@ class TestSamples(unittest.TestCase): continue with self.subTest(sample): - if sample not in SKIP_COMPILE: + if sample not in SKIP_COMPILE and not sample.endswith("_dec"): self.assert_sample(sample, skip_run=sample in SKIP_RUN) with self.subTest("decompile/" + sample): From 2e42dc68486c62eb250215a756958b2e0000a6ff Mon Sep 17 00:00:00 2001 From: James Westman Date: Sat, 3 May 2025 07:46:34 -0500 Subject: [PATCH 15/29] decompiler: Fix bug in signals with template object If a signal handler had the template as its object, the decompiler would output the class name instead of the 'template' keyword. --- blueprintcompiler/language/gobject_signal.py | 8 +++++++- tests/samples/signal_template_object.blp | 7 +++++++ tests/samples/signal_template_object.ui | 16 ++++++++++++++++ tests/test_samples.py | 1 + 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 tests/samples/signal_template_object.blp create mode 100644 tests/samples/signal_template_object.ui diff --git a/blueprintcompiler/language/gobject_signal.py b/blueprintcompiler/language/gobject_signal.py index 9c27b97..3b4235f 100644 --- a/blueprintcompiler/language/gobject_signal.py +++ b/blueprintcompiler/language/gobject_signal.py @@ -225,8 +225,14 @@ class Signal(AstNode): @decompiler("signal") -def decompile_signal(ctx, gir, name, handler, swapped=None, after="false", object=None): +def decompile_signal( + ctx: DecompileCtx, gir, name, handler, swapped=None, after="false", object=None +): object_name = object or "" + + if object_name == ctx.template_class: + object_name = "template" + name = name.replace("_", "-") line = f"{name} => ${handler}({object_name})" diff --git a/tests/samples/signal_template_object.blp b/tests/samples/signal_template_object.blp new file mode 100644 index 0000000..16dd5a0 --- /dev/null +++ b/tests/samples/signal_template_object.blp @@ -0,0 +1,7 @@ +using Gtk 4.0; + +template $MyTemplate { + Button { + clicked => $my_signal_handler(template); + } +} diff --git a/tests/samples/signal_template_object.ui b/tests/samples/signal_template_object.ui new file mode 100644 index 0000000..c9a680a --- /dev/null +++ b/tests/samples/signal_template_object.ui @@ -0,0 +1,16 @@ + + + + + + diff --git a/tests/test_samples.py b/tests/test_samples.py index f96d0eb..0807d65 100644 --- a/tests/test_samples.py +++ b/tests/test_samples.py @@ -198,6 +198,7 @@ class TestSamples(unittest.TestCase): "parseable", "signal", "signal_not_swapped", + "signal_template_object", "template", "template_binding", "template_binding_extern", From 5c7fb03da79abd9dc691675f4b83a33fe770f091 Mon Sep 17 00:00:00 2001 From: James Westman Date: Wed, 7 May 2025 17:08:26 -0500 Subject: [PATCH 16/29] Fix incorrect error with Adw.AlertDialog responses --- blueprintcompiler/language/contexts.py | 10 ++++++---- tests/samples/issue_195.blp | 11 +++++++++++ tests/samples/issue_195.ui | 16 ++++++++++++++++ 3 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 tests/samples/issue_195.blp create mode 100644 tests/samples/issue_195.ui diff --git a/blueprintcompiler/language/contexts.py b/blueprintcompiler/language/contexts.py index 6e26048..9376211 100644 --- a/blueprintcompiler/language/contexts.py +++ b/blueprintcompiler/language/contexts.py @@ -60,19 +60,21 @@ class ScopeCtx: passed = {} for obj in self._iter_recursive(self.node): - if obj.tokens["id"] is None: + from .gtk_menu import Menu + + if not (isinstance(obj, Object) or isinstance(obj, Menu)) or obj.id is None: continue - if obj.tokens["id"] in passed: + if obj.id in passed: token = obj.group.tokens["id"] if not isinstance(obj, Template) and not isinstance( obj, ExtListItemFactory ): raise CompileError( - f"Duplicate object ID '{obj.tokens['id']}'", + f"Duplicate object ID '{obj.id}'", token.range, ) - passed[obj.tokens["id"]] = obj + passed[obj.id] = obj def _iter_recursive(self, node: AstNode): yield node diff --git a/tests/samples/issue_195.blp b/tests/samples/issue_195.blp new file mode 100644 index 0000000..50b5b95 --- /dev/null +++ b/tests/samples/issue_195.blp @@ -0,0 +1,11 @@ +using Gtk 4.0; +using Adw 1; + +Adw.AlertDialog dialog1 { + responses [ + ok: "Ok", + cancel: "Cancel", + ] +} + +Button cancel {} diff --git a/tests/samples/issue_195.ui b/tests/samples/issue_195.ui new file mode 100644 index 0000000..b57a379 --- /dev/null +++ b/tests/samples/issue_195.ui @@ -0,0 +1,16 @@ + + + + + + + Ok + Cancel + + + + \ No newline at end of file From 4d42bd68c1ad4366d2f2ed6f3c8f887932fd7fc1 Mon Sep 17 00:00:00 2001 From: James Westman Date: Sat, 14 Jun 2025 10:19:25 -0500 Subject: [PATCH 17/29] Post-release version bump --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index f298d15..635fac5 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('blueprint-compiler', - version: '0.16.0', + version: '0.17.0', ) prefix = get_option('prefix') From 71dcc02198f6e61e00d0bd9890bfd236e2bc0ae9 Mon Sep 17 00:00:00 2001 From: James Westman Date: Sat, 14 Jun 2025 10:27:45 -0500 Subject: [PATCH 18/29] Allow inline menus Newer versions of GTK allow menus to be specified inline in properties. --- blueprintcompiler/language/gobject_property.py | 5 ++++- blueprintcompiler/language/gtk_menu.py | 5 ----- blueprintcompiler/outputs/xml/__init__.py | 5 +++++ docs/reference/objects.rst | 2 +- tests/sample_errors/inline_menu.err | 1 - tests/sample_errors/menu_no_id.err | 1 - tests/{sample_errors => samples}/inline_menu.blp | 0 tests/samples/inline_menu.ui | 14 ++++++++++++++ tests/{sample_errors => samples}/menu_no_id.blp | 0 tests/samples/menu_no_id.ui | 10 ++++++++++ 10 files changed, 34 insertions(+), 9 deletions(-) delete mode 100644 tests/sample_errors/inline_menu.err delete mode 100644 tests/sample_errors/menu_no_id.err rename tests/{sample_errors => samples}/inline_menu.blp (100%) create mode 100644 tests/samples/inline_menu.ui rename tests/{sample_errors => samples}/menu_no_id.blp (100%) create mode 100644 tests/samples/menu_no_id.ui diff --git a/blueprintcompiler/language/gobject_property.py b/blueprintcompiler/language/gobject_property.py index 50a7512..c782d2e 100644 --- a/blueprintcompiler/language/gobject_property.py +++ b/blueprintcompiler/language/gobject_property.py @@ -21,12 +21,15 @@ from .binding import Binding from .common import * from .contexts import ValueTypeCtx +from .gtk_menu import menu from .values import ArrayValue, ExprValue, ObjectValue, Value class Property(AstNode): grammar = Statement( - UseIdent("name"), ":", AnyOf(Binding, ExprValue, ObjectValue, Value, ArrayValue) + UseIdent("name"), + ":", + AnyOf(Binding, ExprValue, menu, ObjectValue, Value, ArrayValue), ) @property diff --git a/blueprintcompiler/language/gtk_menu.py b/blueprintcompiler/language/gtk_menu.py index c7ef5f2..bc38f37 100644 --- a/blueprintcompiler/language/gtk_menu.py +++ b/blueprintcompiler/language/gtk_menu.py @@ -60,11 +60,6 @@ class Menu(AstNode): def items(self) -> T.List[T.Union["Menu", "MenuAttribute"]]: return self.children - @validate("menu") - def has_id(self): - if self.tokens["tag"] == "menu" and self.tokens["id"] is None: - raise CompileError("Menu requires an ID") - @validate("id") def object_id_not_reserved(self): if self.id in RESERVED_IDS: diff --git a/blueprintcompiler/outputs/xml/__init__.py b/blueprintcompiler/outputs/xml/__init__.py index 15850f7..32291ee 100644 --- a/blueprintcompiler/outputs/xml/__init__.py +++ b/blueprintcompiler/outputs/xml/__init__.py @@ -139,6 +139,11 @@ class XmlOutput(OutputFormat): self._emit_expression(value.expression, xml) xml.end_tag() + elif isinstance(value, Menu): + xml.start_tag("property", **props) + self._emit_menu(value, xml) + xml.end_tag() + elif isinstance(value, ObjectValue): xml.start_tag("property", **props) self._emit_object(value.object, xml) diff --git a/docs/reference/objects.rst b/docs/reference/objects.rst index 6f76da6..d759abe 100644 --- a/docs/reference/objects.rst +++ b/docs/reference/objects.rst @@ -58,7 +58,7 @@ Properties .. rst-class:: grammar-block - Property = `> ':' ( :ref:`Binding` | :ref:`ExprValue` | :ref:`ObjectValue` | :ref:`Value` ) ';' + Property = `> ':' ( :ref:`Binding` | :ref:`ExprValue` | :ref:`Menu` | :ref:`ObjectValue` | :ref:`Value` ) ';' Properties specify the details of each object, like a label's text, an image's icon name, or the margins on a container. diff --git a/tests/sample_errors/inline_menu.err b/tests/sample_errors/inline_menu.err deleted file mode 100644 index 3115750..0000000 --- a/tests/sample_errors/inline_menu.err +++ /dev/null @@ -1 +0,0 @@ -4,15,4,Namespace Gtk does not contain a type called menu \ No newline at end of file diff --git a/tests/sample_errors/menu_no_id.err b/tests/sample_errors/menu_no_id.err deleted file mode 100644 index e97f033..0000000 --- a/tests/sample_errors/menu_no_id.err +++ /dev/null @@ -1 +0,0 @@ -3,1,4,Menu requires an ID \ No newline at end of file diff --git a/tests/sample_errors/inline_menu.blp b/tests/samples/inline_menu.blp similarity index 100% rename from tests/sample_errors/inline_menu.blp rename to tests/samples/inline_menu.blp diff --git a/tests/samples/inline_menu.ui b/tests/samples/inline_menu.ui new file mode 100644 index 0000000..2910b14 --- /dev/null +++ b/tests/samples/inline_menu.ui @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/tests/sample_errors/menu_no_id.blp b/tests/samples/menu_no_id.blp similarity index 100% rename from tests/sample_errors/menu_no_id.blp rename to tests/samples/menu_no_id.blp diff --git a/tests/samples/menu_no_id.ui b/tests/samples/menu_no_id.ui new file mode 100644 index 0000000..934f6da --- /dev/null +++ b/tests/samples/menu_no_id.ui @@ -0,0 +1,10 @@ + + + + + + From 5a951696a73493c0ddb0430829acc9132c919ca6 Mon Sep 17 00:00:00 2001 From: Matthijs Velsink Date: Fri, 13 Jun 2025 01:51:05 +0200 Subject: [PATCH 19/29] docs: Small improvements for extensions - Add Gtk.Scale mark example - Add ExtScaleMarks to the index - Keep the index alphabetically sorted - Use the same order in the text --- docs/reference/extensions.rst | 52 +++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/docs/reference/extensions.rst b/docs/reference/extensions.rst index 2fd5dbb..3a9ad36 100644 --- a/docs/reference/extensions.rst +++ b/docs/reference/extensions.rst @@ -16,14 +16,15 @@ Properties are the main way to set values on objects, but they are limited by th Extension = :ref:`ExtAccessibility` | :ref:`ExtAdwAlertDialog` - | :ref:`ExtAdwMessageDialog` | :ref:`ExtAdwBreakpoint` + | :ref:`ExtAdwMessageDialog` | :ref:`ExtComboBoxItems` | :ref:`ExtFileFilterMimeTypes` | :ref:`ExtFileFilterPatterns` | :ref:`ExtFileFilterSuffixes` | :ref:`ExtLayout` | :ref:`ExtListItemFactory` + | :ref:`ExtScaleMarks` | :ref:`ExtSizeGroupWidgets` | :ref:`ExtStringListStrings` | :ref:`ExtStyles` @@ -47,25 +48,6 @@ The ``accessibility`` block defines values relevant to accessibility software. T Relations which allow for a list of values, for example `labelled-by`, must be given as a single relation with a list of values instead of duplicating the relation like done in Gtk.Builder. -.. _Syntax ExtAdwBreakpoint: - -Adw.Breakpoint --------------- - -.. rst-class:: grammar-block - - ExtAdwBreakpointCondition = 'condition' '(' `> ')' - ExtAdwBreakpoint = 'setters' '{' ExtAdwBreakpointSetter* '}' - ExtAdwBreakpointSetter = `> '.' `> ':' :ref:`Value ` ';' - -Valid in `Adw.Breakpoint `_. - -Defines the condition for a breakpoint and the properties that will be set at that breakpoint. See the documentation for `Adw.Breakpoint `_. - -.. note:: - - The `Adw.Breakpoint:condition `_ property has type `Adw.BreakpointCondition `_, which GtkBuilder doesn't know how to parse from a string. Therefore, the ``condition`` syntax is used instead. - .. _Syntax ExtAdwAlertDialog: @@ -96,6 +78,26 @@ The ``responses`` block defines the buttons that will be added to the dialog. Th } +.. _Syntax ExtAdwBreakpoint: + +Adw.Breakpoint +-------------- + +.. rst-class:: grammar-block + + ExtAdwBreakpointCondition = 'condition' '(' `> ')' + ExtAdwBreakpoint = 'setters' '{' ExtAdwBreakpointSetter* '}' + ExtAdwBreakpointSetter = `> '.' `> ':' :ref:`Value ` ';' + +Valid in `Adw.Breakpoint `_. + +Defines the condition for a breakpoint and the properties that will be set at that breakpoint. See the documentation for `Adw.Breakpoint `_. + +.. note:: + + The `Adw.Breakpoint:condition `_ property has type `Adw.BreakpointCondition `_, which GtkBuilder doesn't know how to parse from a string. Therefore, the ``condition`` syntax is used instead. + + .. _Syntax ExtAdwMessageDialog: Adw.MessageDialog Responses @@ -262,6 +264,16 @@ Valid in `Gtk.Scale `_. The ``marks`` block defines the marks on a scale. A single ``mark`` has up to three arguments: a value, an optional position, and an optional label. The position can be ``left``, ``right``, ``top``, or ``bottom``. The label may be translated. +.. code-block:: blueprint + + Scale { + marks [ + mark (-1, bottom), + mark (0, top, _("Origin")), + mark (2), + ] + } + .. _Syntax ExtSizeGroupWidgets: From 6e010148b2b340876a8d1ac456819d4232c0ef93 Mon Sep 17 00:00:00 2001 From: James Westman Date: Sat, 14 Jun 2025 15:11:39 -0500 Subject: [PATCH 20/29] Remove donate link from README --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 503d7a3..f01ecf9 100644 --- a/README.md +++ b/README.md @@ -82,10 +82,6 @@ Visual Studio Code - [Blueprint Language Plugin by bodil](https://github.com/bodil/vscode-blueprint) -## Donate - -You can support my work on GitHub Sponsors! - ## Getting in Touch Matrix room: [#blueprint-language:matrix.org](https://matrix.to/#/#blueprint-language:matrix.org) From ee089aa7f9d8164553967a58a56c860d903f7abf Mon Sep 17 00:00:00 2001 From: James Westman Date: Sat, 14 Jun 2025 11:30:25 -0500 Subject: [PATCH 21/29] ci: Configure tarball releases --- .gitlab-ci.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6d373cc..83122d0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,7 +1,19 @@ +include: + - component: "gitlab.gnome.org/GNOME/citemplates/release-service@master" + inputs: + job-stage: "release" + dist-job-name: "build-release-tarball" + tarball-artifact-path: "${TARBALL_ARTIFACT_PATH}" + stages: - build +- release - pages +variables: + MESON_BUILD_DIR: "_build" + TARBALL_ARTIFACT_PATH: "${MESON_BUILD_DIR}/meson-dist/${CI_PROJECT_NAME}-${CI_COMMIT_TAG}.tar.xz" + build: image: registry.gitlab.gnome.org/gnome/blueprint-compiler stage: build @@ -45,6 +57,18 @@ fuzz: - corpus - crashes +build-release-tarball: + stage: build + image: registry.gitlab.gnome.org/gnome/blueprint-compiler + script: + - meson setup "${MESON_BUILD_DIR}" + - xvfb-run meson dist -C "${MESON_BUILD_DIR}" --include-subprojects + artifacts: + name: "${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}" + when: "always" + paths: + - "${TARBALL_ARTIFACT_PATH}" + pages: stage: pages dependencies: From 07c9c9df9cd1b6b4454ecba21ee58211e9144a4b Mon Sep 17 00:00:00 2001 From: James Westman Date: Tue, 1 Jul 2025 21:06:21 -0500 Subject: [PATCH 22/29] Release v0.18.0 --- NEWS.md | 19 +++++++++++++++++++ docs/flatpak.rst | 2 +- meson.build | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index a12dab0..715aab4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,22 @@ +# v0.18.0 + +## Added +- GtkBuilder now allows menus to be specified inline as a property value. Blueprint now supports this as well. + +## Fixed +- Made reference_docs.json build reproducible (Sertonix) +- Correctly emit XML for nested templates (Tom Greig) +- Fix crash in language server while typing an AdwBreakpointSetter rule +- Update URLs after move to GNOME namespace on GitLab +- Fix crash when decompiling a lookup tag with no type attribute +- Fix incorrect result when decompiling a signal that has the template as its object +- Fix an incorrect "Duplicate object ID" error when an Adw.AlertDialog response had the same ID as an object + +## Documentation +- Updated syntax in the example on the Overview page (Chris Mayo) +- Added examples of Gtk.Scale marks (Matthijs Velsink) +- Corrected errors in the index on the Extensions page (Matthijs Velsink) + # v0.16.0 ## Added diff --git a/docs/flatpak.rst b/docs/flatpak.rst index 8081c8d..b2f42a4 100644 --- a/docs/flatpak.rst +++ b/docs/flatpak.rst @@ -17,7 +17,7 @@ a module in your flatpak manifest: { "type": "git", "url": "https://gitlab.gnome.org/GNOME/blueprint-compiler", - "tag": "v0.16.0" + "tag": "v0.18.0" } ] } diff --git a/meson.build b/meson.build index 635fac5..405ed10 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('blueprint-compiler', - version: '0.17.0', + version: '0.18.0', ) prefix = get_option('prefix') From 0dc27cd01d00a68d53b83c75f6e44d69b68d17e8 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Tue, 1 Jul 2025 12:35:12 +0300 Subject: [PATCH 23/29] ci: Use the same build job for creating the dist tarball as well We don't need two jobs and its fine to always run meson dist --- .gitlab-ci.yml | 32 +++++++------------------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 83122d0..a1bdcf5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,18 +1,9 @@ include: + - project: "GNOME/citemplates" + file: "templates/default-rules.yml" - component: "gitlab.gnome.org/GNOME/citemplates/release-service@master" inputs: - job-stage: "release" - dist-job-name: "build-release-tarball" - tarball-artifact-path: "${TARBALL_ARTIFACT_PATH}" - -stages: -- build -- release -- pages - -variables: - MESON_BUILD_DIR: "_build" - TARBALL_ARTIFACT_PATH: "${MESON_BUILD_DIR}/meson-dist/${CI_PROJECT_NAME}-${CI_COMMIT_TAG}.tar.xz" + dist-job-name: "build" build: image: registry.gitlab.gnome.org/gnome/blueprint-compiler @@ -34,11 +25,14 @@ build: - git checkout 5f9e155c1333e84e6f683cdb26b02a5925fd8db3 - ./test.sh - cd .. + - meson dist -C _build --include-subprojects --no-tests + - cp -r "_build/meson-dist/" "${CI_PROJECT_DIR}/public-dist/" coverage: '/TOTAL.*\s([.\d]+)%/' artifacts: paths: - _build - htmlcov + - public-dist reports: coverage_report: coverage_format: cobertura @@ -57,20 +51,8 @@ fuzz: - corpus - crashes -build-release-tarball: - stage: build - image: registry.gitlab.gnome.org/gnome/blueprint-compiler - script: - - meson setup "${MESON_BUILD_DIR}" - - xvfb-run meson dist -C "${MESON_BUILD_DIR}" --include-subprojects - artifacts: - name: "${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}" - when: "always" - paths: - - "${TARBALL_ARTIFACT_PATH}" - pages: - stage: pages + stage: deploy dependencies: - build script: From 60e704ee9abce243fcceca5fd8dd46df43405770 Mon Sep 17 00:00:00 2001 From: Alice Mikhaylenko Date: Sun, 22 Jun 2025 03:03:09 +0400 Subject: [PATCH 24/29] main: Skip unchanged blp files in batch-compile Don't invalidate everything every time, otherwise we rebuild everything even when no file has changed at all. With e.g. Vala this means more or less rebuilding the entire project with no incremental builds. --- blueprintcompiler/main.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/blueprintcompiler/main.py b/blueprintcompiler/main.py index 1c3a1c6..8c47d49 100644 --- a/blueprintcompiler/main.py +++ b/blueprintcompiler/main.py @@ -170,6 +170,18 @@ class BlueprintApp: add_typelib_search_path(typelib_path) for file in opts.inputs: + path = os.path.join( + opts.output_dir, + os.path.relpath(os.path.splitext(file.name)[0] + ".ui", opts.input_dir), + ) + + if os.path.isfile(path): + in_time = os.path.getmtime(file.name) + out_time = os.path.getmtime(path) + + if out_time >= in_time: + continue + data = file.read() file_abs = os.path.abspath(file.name) input_dir_abs = os.path.abspath(opts.input_dir) @@ -186,12 +198,6 @@ class BlueprintApp: for warning in warnings: warning.pretty_print(file.name, data, stream=sys.stderr) - path = os.path.join( - opts.output_dir, - os.path.relpath( - os.path.splitext(file.name)[0] + ".ui", opts.input_dir - ), - ) os.makedirs(os.path.dirname(path), exist_ok=True) with open(path, "w") as file: file.write(xml) From 9cee6f9f8e72f99e78601c67d5db1ae73c14a6c7 Mon Sep 17 00:00:00 2001 From: James Westman Date: Sun, 5 Jan 2025 15:26:25 -0600 Subject: [PATCH 25/29] gtk_a11y: Add new state and property --- blueprintcompiler/language/gtk_a11y.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/blueprintcompiler/language/gtk_a11y.py b/blueprintcompiler/language/gtk_a11y.py index 0cc3cb3..92a975c 100644 --- a/blueprintcompiler/language/gtk_a11y.py +++ b/blueprintcompiler/language/gtk_a11y.py @@ -31,6 +31,7 @@ def get_property_types(gir): "autocomplete": gir.get_type("AccessibleAutocomplete", "Gtk"), "description": StringType(), "has-popup": BoolType(), + "help-text": StringType(), "key-shortcuts": StringType(), "label": StringType(), "level": IntType(), @@ -86,6 +87,7 @@ def get_state_types(gir): "invalid": gir.get_type("AccessibleInvalidState", "Gtk"), "pressed": gir.get_type("AccessibleTristate", "Gtk"), "selected": BoolType(), + "visited": BoolType(), } From fe8a629d4b71672cc5a29be0dfad75c331810290 Mon Sep 17 00:00:00 2001 From: James Westman Date: Sun, 5 Jan 2025 15:34:16 -0600 Subject: [PATCH 26/29] values: Don't allow assigning true/false to object Fix a bug in the type checking code where it would not produce an error if you assigned "true" or "false" to an object property. --- blueprintcompiler/language/values.py | 9 ++++++++- tests/sample_errors/convert_bool_to_obj.blp | 5 +++++ tests/sample_errors/convert_bool_to_obj.err | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 tests/sample_errors/convert_bool_to_obj.blp create mode 100644 tests/sample_errors/convert_bool_to_obj.err diff --git a/blueprintcompiler/language/values.py b/blueprintcompiler/language/values.py index 833a4a3..7fa6bfa 100644 --- a/blueprintcompiler/language/values.py +++ b/blueprintcompiler/language/values.py @@ -338,7 +338,14 @@ class IdentLiteral(AstNode): raise CompileError( '"item" can only be used in an expression literal' ) - elif self.ident not in ["true", "false"]: + elif self.ident in ["true", "false"]: + if expected_type is not None and not isinstance( + expected_type, gir.BoolType + ): + raise CompileError( + f"Cannot assign boolean to {expected_type.full_name}" + ) + else: raise CompileError( f"Could not find object with ID {self.ident}", did_you_mean=( diff --git a/tests/sample_errors/convert_bool_to_obj.blp b/tests/sample_errors/convert_bool_to_obj.blp new file mode 100644 index 0000000..5f856c0 --- /dev/null +++ b/tests/sample_errors/convert_bool_to_obj.blp @@ -0,0 +1,5 @@ +using Gtk 4.0; + +Button { + child: false; +} diff --git a/tests/sample_errors/convert_bool_to_obj.err b/tests/sample_errors/convert_bool_to_obj.err new file mode 100644 index 0000000..389f69c --- /dev/null +++ b/tests/sample_errors/convert_bool_to_obj.err @@ -0,0 +1 @@ +4,10,5,Cannot assign boolean to Gtk.Widget \ No newline at end of file From 61acfbda98e2d350c4516f2dae616b436d46c8b3 Mon Sep 17 00:00:00 2001 From: James Westman Date: Sat, 5 Jul 2025 16:26:26 -0500 Subject: [PATCH 27/29] fuzz: Add option for more complete testing Add a FUZZ_LEVEL environment variable that can be used to test the language server features under the fuzzer in addition to the compiler. It's not enabled by default, but can be useful to run locally. --- tests/fuzz.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/tests/fuzz.py b/tests/fuzz.py index 81a9058..6f1fb06 100644 --- a/tests/fuzz.py +++ b/tests/fuzz.py @@ -7,25 +7,28 @@ from blueprintcompiler.outputs.xml import XmlOutput sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) -from blueprintcompiler import decompiler, gir, parser, tokenizer, utils +from blueprintcompiler import gir, parser, tokenizer from blueprintcompiler.completions import complete from blueprintcompiler.errors import ( - CompileError, CompilerBugError, - MultipleErrors, PrintableError, ) -from blueprintcompiler.tokenizer import Token, TokenType, tokenize +from blueprintcompiler.lsp import LanguageServer + +fuzz_level = int(os.getenv("FUZZ_LEVEL") or "0") @PythonFuzz -def fuzz(buf): +def fuzz(buf: bytes): try: blueprint = buf.decode("ascii") tokens = tokenizer.tokenize(blueprint) ast, errors, warnings = parser.parse(tokens) + if fuzz_level >= 1: + assert_ast_doesnt_crash(blueprint, tokens, ast) + xml = XmlOutput() if errors is None and ast is not None: xml.emit(ast) @@ -37,6 +40,17 @@ def fuzz(buf): pass +def assert_ast_doesnt_crash(text, tokens, ast): + lsp = LanguageServer() + for i in range(len(text) + 1): + ast.get_docs(i) + for i in range(len(text) + 1): + list(complete(lsp, ast, tokens, i)) + for i in range(len(text) + 1): + ast.get_reference(i) + ast.get_document_symbols() + + if __name__ == "__main__": # Make sure Gtk 4.0 is accessible, otherwise every test will fail on that # and nothing interesting will be tested From c75e00253b7679c75068e9f79a5480e7899a9fa2 Mon Sep 17 00:00:00 2001 From: James Westman Date: Sat, 5 Jul 2025 16:45:25 -0500 Subject: [PATCH 28/29] lsp: Fix crash on object references Fix a crash that occurred when you hovered over a reference to an object that has an invalid class name. --- blueprintcompiler/language/gobject_object.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/blueprintcompiler/language/gobject_object.py b/blueprintcompiler/language/gobject_object.py index 1def15b..df87a58 100644 --- a/blueprintcompiler/language/gobject_object.py +++ b/blueprintcompiler/language/gobject_object.py @@ -71,12 +71,15 @@ class Object(AstNode): @property def signature(self) -> str: - if self.id: - return f"{self.class_name.gir_type.full_name} {self.id}" - elif t := self.class_name.gir_type: - return f"{t.full_name}" + if t := self.class_name.gir_type: + result = t.full_name else: - return f"{self.class_name.as_string}" + result = self.class_name.as_string + + if self.id: + result += " " + self.id + + return result @property def document_symbol(self) -> T.Optional[DocumentSymbol]: From a691b962fdb2e89d59e4aeadc6d2f4aa6b6e0922 Mon Sep 17 00:00:00 2001 From: James Westman Date: Sat, 5 Jul 2025 18:08:21 -0500 Subject: [PATCH 29/29] Update regression tests --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a1bdcf5..2ac83f0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -22,7 +22,7 @@ build: - ninja -C _build docs/en - git clone https://gitlab.gnome.org/jwestman/blueprint-regression-tests.git - cd blueprint-regression-tests - - git checkout 5f9e155c1333e84e6f683cdb26b02a5925fd8db3 + - git checkout 57e988aa0f7c1e16fc806a6751df5abffe4bf8a5 - ./test.sh - cd .. - meson dist -C _build --include-subprojects --no-tests