From 7e4f80523d2471067fc25e7fbd12849d0e46b2ff Mon Sep 17 00:00:00 2001 From: Sonny Piers Date: Thu, 21 Mar 2024 20:40:18 +0100 Subject: [PATCH 01/82] Post-release version bump --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 6e19cab..b91fd8c 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('blueprint-compiler', - version: '0.12.0', + version: '0.12.1', ) subdir('docs') From 729939ad9386ba4c45eb2c9e451473fa0be5a37f Mon Sep 17 00:00:00 2001 From: Dexter Reed Date: Tue, 26 Mar 2024 18:30:23 +0000 Subject: [PATCH 02/82] docs: Fix misspelt `Doggo`, fix duplicate `Maniatic Launcher` --- docs/index.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 20e71b6..1837e2a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -93,7 +93,7 @@ Built with Blueprint - `Dev Toolbox `_ - `Dialect `_ - `Diccionario de la Lengua `_ -- `Dogg `_ +- `Doggo `_ - `Dosage `_ - `Dynamic Wallpaper `_ - `Extension Manager `_ @@ -119,7 +119,6 @@ Built with Blueprint - `Letterpress `_ - `Login Manager Settings `_ - `Maniatic Launcher `_ -- `Maniatic Launcher `_ - `Master Key `_ - `Misson Center `_ - `NewCaw `_ From 6a078ee075e7ff0818d03234600b166ccb2b50cb Mon Sep 17 00:00:00 2001 From: James Westman Date: Sat, 6 Apr 2024 14:30:48 -0500 Subject: [PATCH 03/82] Add warning for unused imports --- blueprintcompiler/ast_utils.py | 2 +- blueprintcompiler/errors.py | 4 ++++ blueprintcompiler/language/common.py | 1 + blueprintcompiler/language/imports.py | 11 +++++++++++ blueprintcompiler/language/types.py | 3 ++- blueprintcompiler/language/ui.py | 17 +++++++++++++++++ blueprintcompiler/lsp.py | 3 +++ blueprintcompiler/tokenizer.py | 7 +++++++ tests/sample_errors/deprecations.blp | 1 - tests/sample_errors/deprecations.err | 2 +- tests/sample_errors/warn_unused_import.blp | 5 +++++ tests/sample_errors/warn_unused_import.err | 1 + tests/samples/parseable.blp | 1 - 13 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 tests/sample_errors/warn_unused_import.blp create mode 100644 tests/sample_errors/warn_unused_import.err diff --git a/blueprintcompiler/ast_utils.py b/blueprintcompiler/ast_utils.py index a63729d..c874358 100644 --- a/blueprintcompiler/ast_utils.py +++ b/blueprintcompiler/ast_utils.py @@ -125,7 +125,7 @@ class AstNode: return self.parent.root @property - def range(self): + def range(self) -> Range: return Range(self.group.start, self.group.end, self.group.text) def parent_by_type(self, type: T.Type[TType]) -> TType: diff --git a/blueprintcompiler/errors.py b/blueprintcompiler/errors.py index a28c05d..01058fd 100644 --- a/blueprintcompiler/errors.py +++ b/blueprintcompiler/errors.py @@ -140,6 +140,10 @@ class DeprecatedWarning(CompileWarning): pass +class UnusedWarning(CompileWarning): + pass + + class UpgradeWarning(CompileWarning): category = "upgrade" color = Colors.PURPLE diff --git a/blueprintcompiler/language/common.py b/blueprintcompiler/language/common.py index 8a6ce9b..29df47d 100644 --- a/blueprintcompiler/language/common.py +++ b/blueprintcompiler/language/common.py @@ -35,6 +35,7 @@ from ..errors import ( CompileWarning, DeprecatedWarning, MultipleErrors, + UnusedWarning, UpgradeWarning, ) from ..gir import ( diff --git a/blueprintcompiler/language/imports.py b/blueprintcompiler/language/imports.py index e34901c..bf5dddd 100644 --- a/blueprintcompiler/language/imports.py +++ b/blueprintcompiler/language/imports.py @@ -88,6 +88,17 @@ class Import(AstNode): def namespace_exists(self): gir.get_namespace(self.tokens["namespace"], self.tokens["version"]) + @validate() + def unused(self): + if self.namespace not in self.root.used_imports: + raise UnusedWarning( + f"Unused import: {self.namespace}", + self.range, + actions=[ + CodeAction("Remove import", "", self.range.with_trailing_newline) + ], + ) + @property def gir_namespace(self): try: diff --git a/blueprintcompiler/language/types.py b/blueprintcompiler/language/types.py index b3fb586..fe45c4d 100644 --- a/blueprintcompiler/language/types.py +++ b/blueprintcompiler/language/types.py @@ -78,9 +78,10 @@ class TypeName(AstNode): ) @property - def gir_ns(self): + def gir_ns(self) -> T.Optional[gir.Namespace]: if not self.tokens["extern"]: return self.root.gir.namespaces.get(self.tokens["namespace"] or "Gtk") + return None @property def gir_type(self) -> gir.GirType: diff --git a/blueprintcompiler/language/ui.py b/blueprintcompiler/language/ui.py index 8aaf359..d55a22a 100644 --- a/blueprintcompiler/language/ui.py +++ b/blueprintcompiler/language/ui.py @@ -27,6 +27,7 @@ from .gtk_menu import Menu, menu from .gtkbuilder_template import Template from .imports import GtkDirective, Import from .translation_domain import TranslationDomain +from .types import TypeName class UI(AstNode): @@ -121,6 +122,22 @@ class UI(AstNode): Range(pos, pos, self.group.text), ) + @cached_property + def used_imports(self) -> T.Optional[T.Set[str]]: + def _iter_recursive(node: AstNode): + yield node + for child in node.children: + if isinstance(child, AstNode): + yield from _iter_recursive(child) + + result = set() + for node in _iter_recursive(self): + if isinstance(node, TypeName): + ns = node.gir_ns + if ns is not None: + result.add(ns.name) + return result + @context(ScopeCtx) def scope_ctx(self) -> ScopeCtx: return ScopeCtx(node=self) diff --git a/blueprintcompiler/lsp.py b/blueprintcompiler/lsp.py index cdf0c83..903bfb7 100644 --- a/blueprintcompiler/lsp.py +++ b/blueprintcompiler/lsp.py @@ -475,6 +475,9 @@ class LanguageServer: if isinstance(err, DeprecationWarning): result["tags"] = [DiagnosticTag.Deprecated] + if isinstance(err, UnusedWarning): + result["tags"] = [DiagnosticTag.Unnecessary] + if len(err.references) > 0: result["relatedInformation"] = [ { diff --git a/blueprintcompiler/tokenizer.py b/blueprintcompiler/tokenizer.py index 6cc0761..85bce95 100644 --- a/blueprintcompiler/tokenizer.py +++ b/blueprintcompiler/tokenizer.py @@ -127,6 +127,13 @@ class Range: def text(self) -> str: return self.original_text[self.start : self.end] + @property + def with_trailing_newline(self) -> "Range": + if len(self.original_text) > self.end and self.original_text[self.end] == "\n": + return Range(self.start, self.end + 1, self.original_text) + else: + return self + @staticmethod def join(a: T.Optional["Range"], b: T.Optional["Range"]) -> T.Optional["Range"]: if a is None: diff --git a/tests/sample_errors/deprecations.blp b/tests/sample_errors/deprecations.blp index 1554a0b..f67f002 100644 --- a/tests/sample_errors/deprecations.blp +++ b/tests/sample_errors/deprecations.blp @@ -1,5 +1,4 @@ using Gtk 4.0; -using Gio 2.0; Dialog { use-header-bar: 1; diff --git a/tests/sample_errors/deprecations.err b/tests/sample_errors/deprecations.err index 6059412..e3abd61 100644 --- a/tests/sample_errors/deprecations.err +++ b/tests/sample_errors/deprecations.err @@ -1 +1 @@ -4,1,6,Gtk.Dialog is deprecated \ No newline at end of file +3,1,6,Gtk.Dialog is deprecated \ No newline at end of file diff --git a/tests/sample_errors/warn_unused_import.blp b/tests/sample_errors/warn_unused_import.blp new file mode 100644 index 0000000..bcfd1f6 --- /dev/null +++ b/tests/sample_errors/warn_unused_import.blp @@ -0,0 +1,5 @@ +using Gtk 4.0; +using GLib 2.0; +using Gio 2.0; + +Gio.Cancellable {} diff --git a/tests/sample_errors/warn_unused_import.err b/tests/sample_errors/warn_unused_import.err new file mode 100644 index 0000000..d779e56 --- /dev/null +++ b/tests/sample_errors/warn_unused_import.err @@ -0,0 +1 @@ +2,1,15,Unused import: GLib \ No newline at end of file diff --git a/tests/samples/parseable.blp b/tests/samples/parseable.blp index f4e8c2f..5320baf 100644 --- a/tests/samples/parseable.blp +++ b/tests/samples/parseable.blp @@ -1,5 +1,4 @@ using Gtk 4.0; -using Gio 2.0; Gtk.Shortcut { trigger: "Escape"; From 1c8d7daea27a25685e1ecd4f2c9813a9b7801de7 Mon Sep 17 00:00:00 2001 From: James Westman Date: Sat, 6 Apr 2024 14:31:36 -0500 Subject: [PATCH 04/82] lsp: Fix deprecation warnings --- blueprintcompiler/lsp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blueprintcompiler/lsp.py b/blueprintcompiler/lsp.py index 903bfb7..25705d1 100644 --- a/blueprintcompiler/lsp.py +++ b/blueprintcompiler/lsp.py @@ -472,7 +472,7 @@ class LanguageServer: ), } - if isinstance(err, DeprecationWarning): + if isinstance(err, DeprecatedWarning): result["tags"] = [DiagnosticTag.Deprecated] if isinstance(err, UnusedWarning): From 84e529a4a81d5e9c29e9a65318ff44b81b09ced6 Mon Sep 17 00:00:00 2001 From: Gregor Niehl Date: Sat, 27 Apr 2024 12:04:44 +0000 Subject: [PATCH 05/82] Formatter CLI: Provide option to suppress diff --- blueprintcompiler/main.py | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/blueprintcompiler/main.py b/blueprintcompiler/main.py index 1a9bd98..5b4cad8 100644 --- a/blueprintcompiler/main.py +++ b/blueprintcompiler/main.py @@ -90,6 +90,13 @@ class BlueprintApp: default=2, type=int, ) + format.add_argument( + "-n", + "--no-diff", + help="Do not print a full diff of the changes", + default=False, + action="store_true", + ) format.add_argument( "inputs", nargs="+", @@ -221,23 +228,25 @@ class BlueprintApp: file.write(formatted_str) happened = "Formatted" - diff_lines = [] - a_lines = data.splitlines(keepends=True) - b_lines = formatted_str.splitlines(keepends=True) + if not opts.no_diff: + diff_lines = [] + a_lines = data.splitlines(keepends=True) + b_lines = formatted_str.splitlines(keepends=True) - for line in difflib.unified_diff( - a_lines, b_lines, fromfile=file.name, tofile=file.name, n=5 - ): - # Work around https://bugs.python.org/issue2142 - # See: - # https://www.gnu.org/software/diffutils/manual/html_node/Incomplete-Lines.html - if line[-1] == "\n": - diff_lines.append(line) - else: - diff_lines.append(line + "\n") - diff_lines.append("\\ No newline at end of file\n") + for line in difflib.unified_diff( + a_lines, b_lines, fromfile=file.name, tofile=file.name, n=5 + ): + # Work around https://bugs.python.org/issue2142 + # See: + # https://www.gnu.org/software/diffutils/manual/html_node/Incomplete-Lines.html + if line[-1] == "\n": + diff_lines.append(line) + else: + diff_lines.append(line + "\n") + diff_lines.append("\\ No newline at end of file\n") + + print("".join(diff_lines)) - print("".join(diff_lines)) to_print = Colors.BOLD if errored: to_print += f"{Colors.RED}Skipped {file.name}: Will not overwrite file with compile errors" From 988e69ab25140eb1773cf0eabfaa52b62b21d93c Mon Sep 17 00:00:00 2001 From: James Westman Date: Thu, 2 May 2024 20:10:40 -0500 Subject: [PATCH 06/82] lang: Allow ColumnView widgets to be built Allow BuilderListItemFactory to contain Gtk.ColumnViewRow or Gtk.ColumnViewCell templates, in addition to Gtk.ListItem templates. This is necessary for people to use Gtk.ColumnView idiomatically in Blueprint. Fixes #157. --- .../language/gtk_list_item_factory.py | 15 ++++-- blueprintcompiler/outputs/xml/__init__.py | 2 +- docs/reference/extensions.rst | 2 +- tests/sample_errors/list_factory.err | 2 +- tests/samples/gtkcolumnview.blp | 17 ++++++ tests/samples/gtkcolumnview.ui | 53 +++++++++++++++++++ 6 files changed, 85 insertions(+), 6 deletions(-) create mode 100644 tests/samples/gtkcolumnview.blp create mode 100644 tests/samples/gtkcolumnview.ui diff --git a/blueprintcompiler/language/gtk_list_item_factory.py b/blueprintcompiler/language/gtk_list_item_factory.py index 7d05422..5b6177f 100644 --- a/blueprintcompiler/language/gtk_list_item_factory.py +++ b/blueprintcompiler/language/gtk_list_item_factory.py @@ -39,7 +39,10 @@ class ExtListItemFactory(AstNode): @property def gir_class(self): - return self.root.gir.get_type("ListItem", "Gtk") + if self.type_name is not None: + return self.type_name.gir_type + else: + return self.root.gir.get_type("ListItem", "Gtk") @validate("template") def container_is_builder_list(self): @@ -57,8 +60,14 @@ class ExtListItemFactory(AstNode): @validate() def type_is_list_item(self): if self.type_name is not None: - if self.type_name.glib_type_name != "GtkListItem": - raise CompileError(f"Only Gtk.ListItem is allowed as a type here") + if self.type_name.glib_type_name not in ( + "GtkListItem", + "GtkColumnViewRow", + "GtkColumnViewCell", + ): + raise CompileError( + f"Only Gtk.ListItem, Gtk.ColumnViewRow, or Gtk.ColumnViewCell is allowed as a type here" + ) @validate("template") def type_name_upgrade(self): diff --git a/blueprintcompiler/outputs/xml/__init__.py b/blueprintcompiler/outputs/xml/__init__.py index 8707ee6..f23dacb 100644 --- a/blueprintcompiler/outputs/xml/__init__.py +++ b/blueprintcompiler/outputs/xml/__init__.py @@ -377,7 +377,7 @@ class XmlOutput(OutputFormat): elif isinstance(extension, ExtListItemFactory): child_xml = XmlEmitter() child_xml.start_tag("interface") - child_xml.start_tag("template", **{"class": "GtkListItem"}) + child_xml.start_tag("template", **{"class": extension.gir_class}) self._emit_object_or_template(extension, child_xml) child_xml.end_tag() child_xml.end_tag() diff --git a/docs/reference/extensions.rst b/docs/reference/extensions.rst index 744326f..a7b7b93 100644 --- a/docs/reference/extensions.rst +++ b/docs/reference/extensions.rst @@ -224,7 +224,7 @@ Valid in `Gtk.BuilderListItemFactory `_. The template object can be referenced with the ``template`` keyword. +The template type must be `Gtk.ListItem `_, `Gtk.ColumnViewRow `_, or `Gtk.ColumnViewCell `_ The template object can be referenced with the ``template`` keyword. .. code-block:: blueprint diff --git a/tests/sample_errors/list_factory.err b/tests/sample_errors/list_factory.err index adfd57b..1d4dfaa 100644 --- a/tests/sample_errors/list_factory.err +++ b/tests/sample_errors/list_factory.err @@ -1 +1 @@ -4,3,17,Only Gtk.ListItem is allowed as a type here \ No newline at end of file +4,3,17,Only Gtk.ListItem, Gtk.ColumnViewRow, or Gtk.ColumnViewCell is allowed as a type here \ No newline at end of file diff --git a/tests/samples/gtkcolumnview.blp b/tests/samples/gtkcolumnview.blp new file mode 100644 index 0000000..9f11dd3 --- /dev/null +++ b/tests/samples/gtkcolumnview.blp @@ -0,0 +1,17 @@ +using Gtk 4.0; + +ColumnView { + row-factory: BuilderListItemFactory { + template ColumnViewRow {} + }; + + ColumnViewColumn { + factory: BuilderListItemFactory { + template ColumnViewCell { + child: Label { + label: bind template.item as <$MyObject>.name; + }; + } + }; + } +} diff --git a/tests/samples/gtkcolumnview.ui b/tests/samples/gtkcolumnview.ui new file mode 100644 index 0000000..53126b0 --- /dev/null +++ b/tests/samples/gtkcolumnview.ui @@ -0,0 +1,53 @@ + + + + + + + + + + + +]]> + + + + + + + + + + +]]> + + + + + + \ No newline at end of file From c502dee36bebe38efe0fe8534540ba62c743cc4c Mon Sep 17 00:00:00 2001 From: James Westman Date: Thu, 2 May 2024 20:16:37 -0500 Subject: [PATCH 07/82] output: Don't add @generated notice to subtemplates There's already a notice at the top of the file, it doesn't need to be in subtemplates. Fixes #158. --- blueprintcompiler/outputs/xml/__init__.py | 2 +- tests/samples/gtkcolumnview.ui | 10 ---------- tests/samples/list_factory.ui | 5 ----- tests/samples/subscope.ui | 5 ----- 4 files changed, 1 insertion(+), 21 deletions(-) diff --git a/blueprintcompiler/outputs/xml/__init__.py b/blueprintcompiler/outputs/xml/__init__.py index f23dacb..862df14 100644 --- a/blueprintcompiler/outputs/xml/__init__.py +++ b/blueprintcompiler/outputs/xml/__init__.py @@ -375,7 +375,7 @@ class XmlOutput(OutputFormat): xml.end_tag() elif isinstance(extension, ExtListItemFactory): - child_xml = XmlEmitter() + child_xml = XmlEmitter(generated_notice=False) child_xml.start_tag("interface") child_xml.start_tag("template", **{"class": extension.gir_class}) self._emit_object_or_template(extension, child_xml) diff --git a/tests/samples/gtkcolumnview.ui b/tests/samples/gtkcolumnview.ui index 53126b0..22c09e8 100644 --- a/tests/samples/gtkcolumnview.ui +++ b/tests/samples/gtkcolumnview.ui @@ -10,11 +10,6 @@ corresponding .blp file and regenerate this file with blueprint-compiler. - ]]> @@ -25,11 +20,6 @@ corresponding .blp file and regenerate this file with blueprint-compiler. -