diff --git a/blueprintcompiler/language/__init__.py b/blueprintcompiler/language/__init__.py
index 68c3d8a..7673419 100644
--- a/blueprintcompiler/language/__init__.py
+++ b/blueprintcompiler/language/__init__.py
@@ -21,11 +21,6 @@ from .values import IdentValue, TranslatedStringValue, FlagsValue, LiteralValue
from .common import *
-OBJECT_HOOKS.children = [
- menu,
- Object,
-]
-
OBJECT_CONTENT_HOOKS.children = [
Signal,
Property,
diff --git a/blueprintcompiler/language/common.py b/blueprintcompiler/language/common.py
index 12dbc52..ca5bc9e 100644
--- a/blueprintcompiler/language/common.py
+++ b/blueprintcompiler/language/common.py
@@ -31,6 +31,5 @@ from ..parser_utils import *
from ..xml_emitter import XmlEmitter
-OBJECT_HOOKS = AnyOf()
OBJECT_CONTENT_HOOKS = AnyOf()
VALUE_HOOKS = AnyOf()
diff --git a/blueprintcompiler/language/gobject_property.py b/blueprintcompiler/language/gobject_property.py
index 99e51fd..b13dd06 100644
--- a/blueprintcompiler/language/gobject_property.py
+++ b/blueprintcompiler/language/gobject_property.py
@@ -44,7 +44,7 @@ class Property(AstNode):
UseIdent("name"),
":",
AnyOf(
- OBJECT_HOOKS,
+ Object,
VALUE_HOOKS,
).expected("a value"),
),
diff --git a/blueprintcompiler/language/gtk_menu.py b/blueprintcompiler/language/gtk_menu.py
index 2932e9a..8826036 100644
--- a/blueprintcompiler/language/gtk_menu.py
+++ b/blueprintcompiler/language/gtk_menu.py
@@ -20,7 +20,6 @@
from .attributes import BaseAttribute
from .gobject_object import Object, ObjectContent
-from .ui import UI
from .common import *
@@ -31,6 +30,11 @@ class Menu(Object):
child.emit_xml(xml)
xml.end_tag()
+ @validate("menu")
+ def has_id(self):
+ if self.tokens["tag"] == "menu" and self.tokens["id"] is None:
+ raise CompileError("Menu requires an ID")
+
@property
def gir_class(self):
return self.root.gir.namespaces["Gtk"].lookup_type("Gio.MenuModel")
@@ -39,6 +43,11 @@ class Menu(Object):
class MenuAttribute(BaseAttribute):
tag_name = "attribute"
+ @validate()
+ def not_in_menu(self):
+ if self.parent.tokens["tag"] == "menu":
+ raise CompileError("Menu root may not have attributes")
+
@property
def value_type(self):
return None
@@ -128,16 +137,17 @@ menu_contents.children = [
), "}"),
]
-menu = Group(
+menu: Group = Group(
Menu,
[
- "menu",
+ Keyword("menu"),
UseLiteral("tag", "menu"),
Optional(UseIdent("id")),
menu_contents
],
)
+from .ui import UI
@completer(
applies_in=[UI],
diff --git a/blueprintcompiler/language/ui.py b/blueprintcompiler/language/ui.py
index e7020c9..3ced164 100644
--- a/blueprintcompiler/language/ui.py
+++ b/blueprintcompiler/language/ui.py
@@ -20,6 +20,8 @@
from .. import gir
from .imports import GtkDirective, Import
+from .gtk_menu import menu
+from .gobject_object import Object
from .gtkbuilder_template import Template
from .common import *
@@ -32,7 +34,8 @@ class UI(AstNode):
ZeroOrMore(Import),
Until(AnyOf(
Template,
- OBJECT_HOOKS,
+ menu,
+ Object,
), Eof()),
]
diff --git a/blueprintcompiler/parser.py b/blueprintcompiler/parser.py
index 6064481..dc80bc2 100644
--- a/blueprintcompiler/parser.py
+++ b/blueprintcompiler/parser.py
@@ -22,7 +22,7 @@ from .errors import MultipleErrors, PrintableError
from .parse_tree import *
from .parser_utils import *
from .tokenizer import TokenType
-from .language import OBJECT_HOOKS, OBJECT_CONTENT_HOOKS, VALUE_HOOKS, Template, UI
+from .language import OBJECT_CONTENT_HOOKS, VALUE_HOOKS, Template, UI
def parse(tokens) -> T.Tuple[UI, T.Optional[MultipleErrors], T.List[PrintableError]]:
diff --git a/tests/sample_errors/assign_inline_menu.blp b/tests/sample_errors/assign_inline_menu.blp
deleted file mode 100644
index 9e5a944..0000000
--- a/tests/sample_errors/assign_inline_menu.blp
+++ /dev/null
@@ -1,5 +0,0 @@
-using Gtk 4.0;
-
-Button {
- label: menu {};
-}
diff --git a/tests/sample_errors/assign_inline_menu.err b/tests/sample_errors/assign_inline_menu.err
deleted file mode 100644
index aec5ce9..0000000
--- a/tests/sample_errors/assign_inline_menu.err
+++ /dev/null
@@ -1 +0,0 @@
-4,3,15,Cannot assign Gio.MenuModel to string
diff --git a/tests/sample_errors/assign_menu.blp b/tests/sample_errors/assign_menu.blp
new file mode 100644
index 0000000..682ae9c
--- /dev/null
+++ b/tests/sample_errors/assign_menu.blp
@@ -0,0 +1,7 @@
+using Gtk 4.0;
+
+Button {
+ label: my_menu;
+}
+
+menu my_menu {}
diff --git a/tests/sample_errors/assign_menu.err b/tests/sample_errors/assign_menu.err
new file mode 100644
index 0000000..366297c
--- /dev/null
+++ b/tests/sample_errors/assign_menu.err
@@ -0,0 +1 @@
+4,10,7,Cannot assign Gio.MenuModel to string
diff --git a/tests/sample_errors/menu_errors.blp b/tests/sample_errors/menu_errors.blp
new file mode 100644
index 0000000..05c9c88
--- /dev/null
+++ b/tests/sample_errors/menu_errors.blp
@@ -0,0 +1,5 @@
+using Gtk 4.0;
+
+menu {
+ label: "hi";
+}
diff --git a/tests/sample_errors/menu_errors.err b/tests/sample_errors/menu_errors.err
new file mode 100644
index 0000000..046dc08
--- /dev/null
+++ b/tests/sample_errors/menu_errors.err
@@ -0,0 +1,2 @@
+3,1,4,Menu requires an ID
+4,3,12,Menu root may not have attributes
diff --git a/tests/samples/inline_menu.blp b/tests/samples/inline_menu.blp
deleted file mode 100644
index f4ee067..0000000
--- a/tests/samples/inline_menu.blp
+++ /dev/null
@@ -1,5 +0,0 @@
-using Gtk 4.0;
-
-MenuButton {
- menu-model: menu primary_menu {};
-}
diff --git a/tests/samples/inline_menu.ui b/tests/samples/inline_menu.ui
deleted file mode 100644
index a6f2bcc..0000000
--- a/tests/samples/inline_menu.ui
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
diff --git a/tests/samples/menu.blp b/tests/samples/menu.blp
index f15dbdb..3246d59 100644
--- a/tests/samples/menu.blp
+++ b/tests/samples/menu.blp
@@ -1,13 +1,12 @@
using Gtk 4.0;
-menu {
- label: _("menu label");
- test-custom-attribute: 3.1415;
+menu my_menu {
+ section {
+ label: "test section";
+ }
submenu {
- section {
- label: "test section";
- }
+ label: "test submenu";
item {
label: "test item";
diff --git a/tests/samples/menu.ui b/tests/samples/menu.ui
index a84fa57..443c048 100644
--- a/tests/samples/menu.ui
+++ b/tests/samples/menu.ui
@@ -1,13 +1,12 @@
-
\ No newline at end of file
+
diff --git a/tests/samples/menu_dec.blp b/tests/samples/menu_dec.blp
index bc4ddf1..6e1e8b1 100644
--- a/tests/samples/menu_dec.blp
+++ b/tests/samples/menu_dec.blp
@@ -1,13 +1,12 @@
using Gtk 4.0;
-menu {
- label: _("menu label");
- test-custom-attribute: "3.1415";
+menu my_menu {
+ section {
+ label: "test section";
+ }
submenu {
- section {
- label: "test section";
- }
+ label: "test submenu";
item {
label: "test item";
diff --git a/tests/test_samples.py b/tests/test_samples.py
index 4c4b17c..e1deec5 100644
--- a/tests/test_samples.py
+++ b/tests/test_samples.py
@@ -124,7 +124,6 @@ class TestSamples(unittest.TestCase):
self.assert_sample("file_filter")
self.assert_sample("flags")
self.assert_sample("id_prop")
- self.assert_sample("inline_menu")
self.assert_sample("layout")
self.assert_sample("menu")
self.assert_sample("object_prop")
@@ -147,7 +146,7 @@ class TestSamples(unittest.TestCase):
self.assert_sample_error("a11y_prop_dne")
self.assert_sample_error("a11y_prop_obj_dne")
self.assert_sample_error("a11y_prop_type")
- self.assert_sample_error("assign_inline_menu")
+ self.assert_sample_error("assign_menu")
self.assert_sample_error("action_widget_float_response")
self.assert_sample_error("action_widget_have_no_id")
self.assert_sample_error("action_widget_multiple_default")
@@ -165,6 +164,7 @@ class TestSamples(unittest.TestCase):
self.assert_sample_error("filters_in_non_file_filter")
self.assert_sample_error("invalid_bool")
self.assert_sample_error("layout_in_non_widget")
+ self.assert_sample_error("menu_errors")
self.assert_sample_error("ns_not_imported")
self.assert_sample_error("not_a_class")
self.assert_sample_error("object_dne")