diff --git a/gtkblueprinttool/ast.py b/gtkblueprinttool/ast.py
index 06146cb..ab90536 100644
--- a/gtkblueprinttool/ast.py
+++ b/gtkblueprinttool/ast.py
@@ -21,7 +21,7 @@ import typing as T
from .ast_utils import *
from .errors import assert_true, AlreadyCaughtError, CompileError, CompilerBugError, MultipleErrors
-from .gir import GirContext, get_namespace
+from . import gir
from .lsp_utils import Completion, CompletionItemKind
from .tokenizer import Token
from .utils import lazy_prop
@@ -33,21 +33,21 @@ class UI(AstNode):
@property
def gir(self):
- gir = GirContext()
+ gir_ctx = gir.GirContext()
self._gir_errors = []
try:
- gir.add_namespace(self.children[GtkDirective][0].gir_namespace)
+ gir_ctx.add_namespace(self.children[GtkDirective][0].gir_namespace)
except CompileError as e:
self._gir_errors.append(e)
for i in self.children[Import]:
try:
- gir.add_namespace(i.gir_namespace)
+ gir_ctx.add_namespace(i.gir_namespace)
except CompileError as e:
self._gir_errors.append(e)
- return gir
+ return gir_ctx
@validate()
@@ -86,7 +86,7 @@ class GtkDirective(AstNode):
@property
def gir_namespace(self):
- return get_namespace("Gtk", self.tokens["version"])
+ return gir.get_namespace("Gtk", self.tokens["version"])
def emit_xml(self, xml: XmlEmitter):
@@ -95,8 +95,18 @@ class GtkDirective(AstNode):
class Import(AstNode):
@validate("namespace", "version")
+ def namespace_exists(self):
+ gir.get_namespace(self.tokens["namespace"], self.tokens["version"])
+
+ @property
def gir_namespace(self):
- return get_namespace(self.tokens["namespace"], self.tokens["version"])
+ try:
+ return gir.get_namespace(self.tokens["namespace"], self.tokens["version"])
+ except CompileError:
+ return None
+
+ def emit_xml(self, xml):
+ pass
class Template(AstNode):
diff --git a/gtkblueprinttool/extensions/gtk_menu.py b/gtkblueprinttool/extensions/gtk_menu.py
index 205cfe5..6524c77 100644
--- a/gtkblueprinttool/extensions/gtk_menu.py
+++ b/gtkblueprinttool/extensions/gtk_menu.py
@@ -30,7 +30,7 @@ class Menu(AstNode):
def emit_xml(self, xml: XmlEmitter):
xml.start_tag(self.tokens["tag"], id=self.tokens["id"])
for child in self.children:
- child.emit_xml()
+ child.emit_xml(xml)
xml.end_tag()
@@ -96,7 +96,7 @@ menu_item_shorthand = Group(
)),
Optional(Group(
MenuAttribute,
- Sequence(UseLiteral("name", "verb-icon-name"), value),
+ Sequence(UseLiteral("name", "icon"), value),
)),
StmtEnd().expected("`;`"),
)
diff --git a/tests/samples/binding.blp b/tests/samples/binding.blp
new file mode 100644
index 0000000..e4b4a88
--- /dev/null
+++ b/tests/samples/binding.blp
@@ -0,0 +1,7 @@
+using Gtk 4.0;
+
+Box {
+ visible: bind box2.visible sync-create;
+}
+
+Box box2 {}
diff --git a/tests/samples/binding.ui b/tests/samples/binding.ui
new file mode 100644
index 0000000..7d20e8c
--- /dev/null
+++ b/tests/samples/binding.ui
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/tests/samples/child_type.blp b/tests/samples/child_type.blp
new file mode 100644
index 0000000..8d9f4d7
--- /dev/null
+++ b/tests/samples/child_type.blp
@@ -0,0 +1,7 @@
+using Gtk 4.0;
+
+Window {
+ [titlebar]
+ HeaderBar {
+ }
+}
diff --git a/tests/samples/child_type.ui b/tests/samples/child_type.ui
new file mode 100644
index 0000000..2961bfd
--- /dev/null
+++ b/tests/samples/child_type.ui
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/tests/samples/layout.blp b/tests/samples/layout.blp
new file mode 100644
index 0000000..01e5f5b
--- /dev/null
+++ b/tests/samples/layout.blp
@@ -0,0 +1,10 @@
+using Gtk 4.0;
+
+Grid {
+ Label {
+ layout {
+ column: 0;
+ row: 1;
+ }
+ }
+}
diff --git a/tests/samples/layout.ui b/tests/samples/layout.ui
new file mode 100644
index 0000000..027d010
--- /dev/null
+++ b/tests/samples/layout.ui
@@ -0,0 +1,14 @@
+
+
+
+
+
diff --git a/tests/samples/menu.blp b/tests/samples/menu.blp
new file mode 100644
index 0000000..d4f25dc
--- /dev/null
+++ b/tests/samples/menu.blp
@@ -0,0 +1,20 @@
+using Gtk 4.0;
+
+menu {
+ label: _("menu label");
+ test-custom-attribute: 3.1415;
+
+ submenu {
+ section {
+ label: "test section";
+ }
+
+ item {
+ label: "test item";
+ }
+
+ item "test item shorthand 1";
+ item "test item shorthand 2" "app.test-action";
+ item "test item shorthand 3" "app.test-action" "test-symbolic";
+ }
+}
diff --git a/tests/samples/menu.ui b/tests/samples/menu.ui
new file mode 100644
index 0000000..d008200
--- /dev/null
+++ b/tests/samples/menu.ui
@@ -0,0 +1,28 @@
+
+
+
+
+
diff --git a/tests/samples/property.blp b/tests/samples/property.blp
new file mode 100644
index 0000000..4e7e6f4
--- /dev/null
+++ b/tests/samples/property.blp
@@ -0,0 +1,5 @@
+using Gtk 4.0;
+
+Box {
+ orientation: VERTICAL;
+}
diff --git a/tests/samples/property.ui b/tests/samples/property.ui
new file mode 100644
index 0000000..225ae65
--- /dev/null
+++ b/tests/samples/property.ui
@@ -0,0 +1,7 @@
+
+
+
+
+ VERTICAL
+
+
diff --git a/tests/samples/signal.blp b/tests/samples/signal.blp
new file mode 100644
index 0000000..beda854
--- /dev/null
+++ b/tests/samples/signal.blp
@@ -0,0 +1,6 @@
+using Gtk 4.0;
+
+Button {
+ clicked => on_button_clicked() swapped;
+ notify::visible => on_button_notify_visible();
+}
diff --git a/tests/samples/signal.ui b/tests/samples/signal.ui
new file mode 100644
index 0000000..41c0df3
--- /dev/null
+++ b/tests/samples/signal.ui
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/tests/samples/style.blp b/tests/samples/style.blp
new file mode 100644
index 0000000..6d47e49
--- /dev/null
+++ b/tests/samples/style.blp
@@ -0,0 +1,5 @@
+using Gtk 4.0;
+
+Label {
+ style "class-1", "class-2";
+}
diff --git a/tests/samples/style.ui b/tests/samples/style.ui
new file mode 100644
index 0000000..a216fdb
--- /dev/null
+++ b/tests/samples/style.ui
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/tests/samples/template.blp b/tests/samples/template.blp
new file mode 100644
index 0000000..bcfce82
--- /dev/null
+++ b/tests/samples/template.blp
@@ -0,0 +1,3 @@
+using Gtk 4.0;
+
+template TestTemplate : ApplicationWindow {}
diff --git a/tests/samples/template.ui b/tests/samples/template.ui
new file mode 100644
index 0000000..1485a06
--- /dev/null
+++ b/tests/samples/template.ui
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/tests/samples/using.blp b/tests/samples/using.blp
new file mode 100644
index 0000000..8b11013
--- /dev/null
+++ b/tests/samples/using.blp
@@ -0,0 +1,4 @@
+using Gtk 4.0;
+using GObject 2.0;
+
+GObject.Object {}
diff --git a/tests/samples/using.ui b/tests/samples/using.ui
new file mode 100644
index 0000000..5b81551
--- /dev/null
+++ b/tests/samples/using.ui
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/tests/test_samples.py b/tests/test_samples.py
new file mode 100644
index 0000000..cf5498a
--- /dev/null
+++ b/tests/test_samples.py
@@ -0,0 +1,61 @@
+# test_samples.py
+#
+# Copyright 2021 James Westman
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# This file 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program. If not, see .
+#
+# SPDX-License-Identifier: LGPL-3.0-or-later
+
+
+import difflib # I love Python
+from pathlib import Path
+import unittest
+
+from gtkblueprinttool import tokenizer, parser
+from gtkblueprinttool.errors import PrintableError
+from gtkblueprinttool.tokenizer import Token, TokenType, tokenize
+
+
+class TestSamples(unittest.TestCase):
+ def assert_sample(self, name):
+ with open((Path(__file__).parent / f"samples/{name}.blp").resolve()) as f:
+ blueprint = f.read()
+ with open((Path(__file__).parent / f"samples/{name}.ui").resolve()) as f:
+ expected = f.read()
+
+ tokens = tokenizer.tokenize(blueprint)
+ ast, errors = parser.parse(tokens)
+
+ if errors:
+ raise errors
+ if len(ast.errors):
+ raise MultipleErrors(ast.errors)
+
+ actual = ast.generate()
+ if actual.strip() != expected.strip():
+ diff = difflib.unified_diff(expected.splitlines(), actual.splitlines())
+ print("\n".join(diff))
+ raise AssertionError()
+
+
+ def test_samples(self):
+ self.assert_sample("binding")
+ self.assert_sample("child_type")
+ self.assert_sample("layout")
+ self.assert_sample("menu")
+ self.assert_sample("property")
+ self.assert_sample("signal")
+ self.assert_sample("style")
+ self.assert_sample("template")
+ self.assert_sample("using")