language: Fix some issues with menus

Blueprint's handling of menus didn't line up with how GtkBuilder handles
them. The root <menu> element must have an ID and may not have
attributes, and menus may not be used inline in a property.
This commit is contained in:
James Westman 2022-03-12 23:55:41 -06:00
parent 93f2a27e35
commit bbad6988fa
No known key found for this signature in database
GPG key ID: CE2DBA0ADB654EA6
18 changed files with 52 additions and 53 deletions

View file

@ -21,11 +21,6 @@ from .values import IdentValue, TranslatedStringValue, FlagsValue, LiteralValue
from .common import * from .common import *
OBJECT_HOOKS.children = [
menu,
Object,
]
OBJECT_CONTENT_HOOKS.children = [ OBJECT_CONTENT_HOOKS.children = [
Signal, Signal,
Property, Property,

View file

@ -31,6 +31,5 @@ from ..parser_utils import *
from ..xml_emitter import XmlEmitter from ..xml_emitter import XmlEmitter
OBJECT_HOOKS = AnyOf()
OBJECT_CONTENT_HOOKS = AnyOf() OBJECT_CONTENT_HOOKS = AnyOf()
VALUE_HOOKS = AnyOf() VALUE_HOOKS = AnyOf()

View file

@ -44,7 +44,7 @@ class Property(AstNode):
UseIdent("name"), UseIdent("name"),
":", ":",
AnyOf( AnyOf(
OBJECT_HOOKS, Object,
VALUE_HOOKS, VALUE_HOOKS,
).expected("a value"), ).expected("a value"),
), ),

View file

@ -20,7 +20,6 @@
from .attributes import BaseAttribute from .attributes import BaseAttribute
from .gobject_object import Object, ObjectContent from .gobject_object import Object, ObjectContent
from .ui import UI
from .common import * from .common import *
@ -31,6 +30,11 @@ class Menu(Object):
child.emit_xml(xml) child.emit_xml(xml)
xml.end_tag() 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 @property
def gir_class(self): def gir_class(self):
return self.root.gir.namespaces["Gtk"].lookup_type("Gio.MenuModel") return self.root.gir.namespaces["Gtk"].lookup_type("Gio.MenuModel")
@ -39,6 +43,11 @@ class Menu(Object):
class MenuAttribute(BaseAttribute): class MenuAttribute(BaseAttribute):
tag_name = "attribute" tag_name = "attribute"
@validate()
def not_in_menu(self):
if self.parent.tokens["tag"] == "menu":
raise CompileError("Menu root may not have attributes")
@property @property
def value_type(self): def value_type(self):
return None return None
@ -128,16 +137,17 @@ menu_contents.children = [
), "}"), ), "}"),
] ]
menu = Group( menu: Group = Group(
Menu, Menu,
[ [
"menu", Keyword("menu"),
UseLiteral("tag", "menu"), UseLiteral("tag", "menu"),
Optional(UseIdent("id")), Optional(UseIdent("id")),
menu_contents menu_contents
], ],
) )
from .ui import UI
@completer( @completer(
applies_in=[UI], applies_in=[UI],

View file

@ -20,6 +20,8 @@
from .. import gir from .. import gir
from .imports import GtkDirective, Import from .imports import GtkDirective, Import
from .gtk_menu import menu
from .gobject_object import Object
from .gtkbuilder_template import Template from .gtkbuilder_template import Template
from .common import * from .common import *
@ -32,7 +34,8 @@ class UI(AstNode):
ZeroOrMore(Import), ZeroOrMore(Import),
Until(AnyOf( Until(AnyOf(
Template, Template,
OBJECT_HOOKS, menu,
Object,
), Eof()), ), Eof()),
] ]

View file

@ -22,7 +22,7 @@ from .errors import MultipleErrors, PrintableError
from .parse_tree import * from .parse_tree import *
from .parser_utils import * from .parser_utils import *
from .tokenizer import TokenType 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]]: def parse(tokens) -> T.Tuple[UI, T.Optional[MultipleErrors], T.List[PrintableError]]:

View file

@ -1,5 +0,0 @@
using Gtk 4.0;
Button {
label: menu {};
}

View file

@ -1 +0,0 @@
4,3,15,Cannot assign Gio.MenuModel to string

View file

@ -0,0 +1,7 @@
using Gtk 4.0;
Button {
label: my_menu;
}
menu my_menu {}

View file

@ -0,0 +1 @@
4,10,7,Cannot assign Gio.MenuModel to string

View file

@ -0,0 +1,5 @@
using Gtk 4.0;
menu {
label: "hi";
}

View file

@ -0,0 +1,2 @@
3,1,4,Menu requires an ID
4,3,12,Menu root may not have attributes

View file

@ -1,5 +0,0 @@
using Gtk 4.0;
MenuButton {
menu-model: menu primary_menu {};
}

View file

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<object class="GtkMenuButton">
<property name="menu-model">
<menu id="primary_menu"></menu>
</property>
</object>
</interface>

View file

@ -1,13 +1,12 @@
using Gtk 4.0; using Gtk 4.0;
menu { menu my_menu {
label: _("menu label"); section {
test-custom-attribute: 3.1415; label: "test section";
}
submenu { submenu {
section { label: "test submenu";
label: "test section";
}
item { item {
label: "test item"; label: "test item";

View file

@ -1,13 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<interface> <interface>
<requires lib="gtk" version="4.0"/> <requires lib="gtk" version="4.0"/>
<menu> <menu id="my_menu">
<attribute name="label" translatable="true">menu label</attribute> <section>
<attribute name="test-custom-attribute">3.1415</attribute> <attribute name="label">test section</attribute>
</section>
<submenu> <submenu>
<section> <attribute name="label">test submenu</attribute>
<attribute name="label">test section</attribute>
</section>
<item> <item>
<attribute name="label">test item</attribute> <attribute name="label">test item</attribute>
</item> </item>
@ -25,4 +24,4 @@
</item> </item>
</submenu> </submenu>
</menu> </menu>
</interface> </interface>

View file

@ -1,13 +1,12 @@
using Gtk 4.0; using Gtk 4.0;
menu { menu my_menu {
label: _("menu label"); section {
test-custom-attribute: "3.1415"; label: "test section";
}
submenu { submenu {
section { label: "test submenu";
label: "test section";
}
item { item {
label: "test item"; label: "test item";

View file

@ -124,7 +124,6 @@ class TestSamples(unittest.TestCase):
self.assert_sample("file_filter") self.assert_sample("file_filter")
self.assert_sample("flags") self.assert_sample("flags")
self.assert_sample("id_prop") self.assert_sample("id_prop")
self.assert_sample("inline_menu")
self.assert_sample("layout") self.assert_sample("layout")
self.assert_sample("menu") self.assert_sample("menu")
self.assert_sample("object_prop") 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_dne")
self.assert_sample_error("a11y_prop_obj_dne") self.assert_sample_error("a11y_prop_obj_dne")
self.assert_sample_error("a11y_prop_type") 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_float_response")
self.assert_sample_error("action_widget_have_no_id") self.assert_sample_error("action_widget_have_no_id")
self.assert_sample_error("action_widget_multiple_default") 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("filters_in_non_file_filter")
self.assert_sample_error("invalid_bool") self.assert_sample_error("invalid_bool")
self.assert_sample_error("layout_in_non_widget") 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("ns_not_imported")
self.assert_sample_error("not_a_class") self.assert_sample_error("not_a_class")
self.assert_sample_error("object_dne") self.assert_sample_error("object_dne")