From bbad6988fafee618b5c0e3749c03e5fbd62c2da7 Mon Sep 17 00:00:00 2001 From: James Westman Date: Sat, 12 Mar 2022 23:55:41 -0600 Subject: [PATCH] language: Fix some issues with menus Blueprint's handling of menus didn't line up with how GtkBuilder handles them. The root element must have an ID and may not have attributes, and menus may not be used inline in a property. --- blueprintcompiler/language/__init__.py | 5 ----- blueprintcompiler/language/common.py | 1 - blueprintcompiler/language/gobject_property.py | 2 +- blueprintcompiler/language/gtk_menu.py | 16 +++++++++++++--- blueprintcompiler/language/ui.py | 5 ++++- blueprintcompiler/parser.py | 2 +- tests/sample_errors/assign_inline_menu.blp | 5 ----- tests/sample_errors/assign_inline_menu.err | 1 - tests/sample_errors/assign_menu.blp | 7 +++++++ tests/sample_errors/assign_menu.err | 1 + tests/sample_errors/menu_errors.blp | 5 +++++ tests/sample_errors/menu_errors.err | 2 ++ tests/samples/inline_menu.blp | 5 ----- tests/samples/inline_menu.ui | 9 --------- tests/samples/menu.blp | 11 +++++------ tests/samples/menu.ui | 13 ++++++------- tests/samples/menu_dec.blp | 11 +++++------ tests/test_samples.py | 4 ++-- 18 files changed, 52 insertions(+), 53 deletions(-) delete mode 100644 tests/sample_errors/assign_inline_menu.blp delete mode 100644 tests/sample_errors/assign_inline_menu.err create mode 100644 tests/sample_errors/assign_menu.blp create mode 100644 tests/sample_errors/assign_menu.err create mode 100644 tests/sample_errors/menu_errors.blp create mode 100644 tests/sample_errors/menu_errors.err delete mode 100644 tests/samples/inline_menu.blp delete mode 100644 tests/samples/inline_menu.ui 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 @@ - - menu label - 3.1415 + +
+ test section +
-
- test section -
+ test submenu test item @@ -25,4 +24,4 @@
- \ 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")