cleanup: Format using black

This commit is contained in:
James Westman 2022-02-23 14:09:18 -06:00
parent 4b42016837
commit af03c2ac0f
36 changed files with 928 additions and 616 deletions

View file

@ -23,17 +23,17 @@ from .common import *
class BaseAttribute(AstNode):
""" A helper class for attribute syntax of the form `name: literal_value;`"""
"""A helper class for attribute syntax of the form `name: literal_value;`"""
tag_name: str = ""
attr_name: str = "name"
def emit_xml(self, xml: XmlEmitter):
value = self.children[Value][0]
attrs = { self.attr_name: self.tokens["name"] }
attrs = {self.attr_name: self.tokens["name"]}
if isinstance(value, TranslatedStringValue):
attrs = { **attrs, **value.attrs }
attrs = {**attrs, **value.attrs}
xml.start_tag(self.tag_name, **attrs)
value.emit_xml(xml)
@ -41,5 +41,5 @@ class BaseAttribute(AstNode):
class BaseTypedAttribute(BaseAttribute):
""" A BaseAttribute whose parent has a value_type property that can assist
in validation. """
"""A BaseAttribute whose parent has a value_type property that can assist
in validation."""

View file

@ -44,6 +44,7 @@ class ObjectContent(AstNode):
for x in self.children:
x.emit_xml(xml)
class Object(AstNode):
grammar: T.Any = [
class_name,
@ -58,8 +59,14 @@ class Object(AstNode):
@validate("class_name")
def gir_class_exists(self):
if self.tokens["class_name"] and not self.tokens["ignore_gir"] and self.gir_ns is not None:
self.root.gir.validate_class(self.tokens["class_name"], self.tokens["namespace"])
if (
self.tokens["class_name"]
and not self.tokens["ignore_gir"]
and self.gir_ns is not None
):
self.root.gir.validate_class(
self.tokens["class_name"], self.tokens["namespace"]
)
@property
def gir_ns(self):
@ -69,15 +76,15 @@ class Object(AstNode):
@property
def gir_class(self):
if self.tokens["class_name"] and not self.tokens["ignore_gir"]:
return self.root.gir.get_class(self.tokens["class_name"], self.tokens["namespace"])
return self.root.gir.get_class(
self.tokens["class_name"], self.tokens["namespace"]
)
@docs("namespace")
def namespace_docs(self):
if ns := self.root.gir.namespaces.get(self.tokens["namespace"]):
return ns.doc
@docs("class_name")
def class_docs(self):
if self.gir_class:
@ -100,10 +107,15 @@ class Object(AstNode):
def emit_xml(self, xml: XmlEmitter):
from .gtkbuilder_child import Child
xml.start_tag("object", **{
"class": self.gir_class.glib_type_name if self.gir_class else self.tokens["class_name"],
"id": self.tokens["id"],
})
xml.start_tag(
"object",
**{
"class": self.gir_class.glib_type_name
if self.gir_class
else self.tokens["class_name"],
"id": self.tokens["id"],
},
)
for child in self.children:
child.emit_xml(xml)
@ -122,13 +134,17 @@ def validate_parent_type(node, ns: str, name: str, err_msg: str):
parent = node.root.gir.get_type(name, ns)
container_type = node.parent_by_type(Object).gir_class
if container_type and not container_type.assignable_to(parent):
raise CompileError(f"{container_type.full_name} is not a {parent.full_name}, so it doesn't have {err_msg}")
raise CompileError(
f"{container_type.full_name} is not a {parent.full_name}, so it doesn't have {err_msg}"
)
@decompiler("object")
def decompile_object(ctx, gir, klass, id=None):
gir_class = ctx.type_by_cname(klass)
klass_name = decompile.full_name(gir_class) if gir_class is not None else "." + klass
klass_name = (
decompile.full_name(gir_class) if gir_class is not None else "." + klass
)
if id is None:
ctx.print(f"{klass_name} {{")
else:

View file

@ -33,12 +33,16 @@ class Property(AstNode):
UseIdent("bind_source").expected("the ID of a source object to bind from"),
".",
UseIdent("bind_property").expected("a property name to bind from"),
ZeroOrMore(AnyOf(
["no-sync-create", UseLiteral("no_sync_create", True)],
["inverted", UseLiteral("inverted", True)],
["bidirectional", UseLiteral("bidirectional", True)],
Match("sync-create").warn("sync-create is deprecated in favor of no-sync-create"),
)),
ZeroOrMore(
AnyOf(
["no-sync-create", UseLiteral("no_sync_create", True)],
["inverted", UseLiteral("inverted", True)],
["bidirectional", UseLiteral("bidirectional", True)],
Match("sync-create").warn(
"sync-create is deprecated in favor of no-sync-create"
),
)
),
),
Statement(
UseIdent("name"),
@ -54,19 +58,16 @@ class Property(AstNode):
def gir_class(self):
return self.parent.parent.gir_class
@property
def gir_property(self):
if self.gir_class is not None:
return self.gir_class.properties.get(self.tokens["name"])
@property
def value_type(self):
if self.gir_property is not None:
return self.gir_property.type
@validate("name")
def property_exists(self):
if self.gir_class is None:
@ -82,10 +83,9 @@ class Property(AstNode):
if self.gir_property is None:
raise CompileError(
f"Class {self.gir_class.full_name} does not contain a property called {self.tokens['name']}",
did_you_mean=(self.tokens["name"], self.gir_class.properties.keys())
did_you_mean=(self.tokens["name"], self.gir_class.properties.keys()),
)
@validate()
def obj_property_type(self):
if len(self.children[Object]) == 0:
@ -93,18 +93,21 @@ class Property(AstNode):
object = self.children[Object][0]
type = self.value_type
if object and type and object.gir_class and not object.gir_class.assignable_to(type):
if (
object
and type
and object.gir_class
and not object.gir_class.assignable_to(type)
):
raise CompileError(
f"Cannot assign {object.gir_class.full_name} to {type.full_name}"
)
@docs("name")
def property_docs(self):
if self.gir_property is not None:
return self.gir_property.doc
def emit_xml(self, xml: XmlEmitter):
values = self.children[Value]
value = values[0] if len(values) == 1 else None
@ -126,7 +129,7 @@ class Property(AstNode):
}
if isinstance(value, TranslatedStringValue):
props = { **props, **value.attrs }
props = {**props, **value.attrs}
if len(self.children[Object]) == 1:
xml.start_tag("property", **props)

View file

@ -25,33 +25,34 @@ from .common import *
class Signal(AstNode):
grammar = Statement(
UseIdent("name"),
Optional([
"::",
UseIdent("detail_name").expected("a signal detail name"),
]),
Optional(
[
"::",
UseIdent("detail_name").expected("a signal detail name"),
]
),
"=>",
UseIdent("handler").expected("the name of a function to handle the signal"),
Match("(").expected("argument list"),
Optional(UseIdent("object")).expected("object identifier"),
Match(")").expected(),
ZeroOrMore(AnyOf(
[Keyword("swapped"), UseLiteral("swapped", True)],
[Keyword("after"), UseLiteral("after", True)],
)),
ZeroOrMore(
AnyOf(
[Keyword("swapped"), UseLiteral("swapped", True)],
[Keyword("after"), UseLiteral("after", True)],
)
),
)
@property
def gir_signal(self):
if self.gir_class is not None:
return self.gir_class.signals.get(self.tokens["name"])
@property
def gir_class(self):
return self.parent.parent.gir_class
@validate("name")
def signal_exists(self):
if self.gir_class is None:
@ -67,10 +68,9 @@ class Signal(AstNode):
if self.gir_signal is None:
raise CompileError(
f"Class {self.gir_class.full_name} does not contain a signal called {self.tokens['name']}",
did_you_mean=(self.tokens["name"], self.gir_class.signals.keys())
did_you_mean=(self.tokens["name"], self.gir_class.signals.keys()),
)
@validate("object")
def object_exists(self):
object_id = self.tokens["object"]
@ -78,17 +78,13 @@ class Signal(AstNode):
return
if self.root.objects_by_id.get(object_id) is None:
raise CompileError(
f"Could not find object with ID '{object_id}'"
)
raise CompileError(f"Could not find object with ID '{object_id}'")
@docs("name")
def signal_docs(self):
if self.gir_signal is not None:
return self.gir_signal.doc
def emit_xml(self, xml: XmlEmitter):
name = self.tokens["name"]
if self.tokens["detail_name"]:
@ -98,7 +94,7 @@ class Signal(AstNode):
name=name,
handler=self.tokens["handler"],
swapped="true" if self.tokens["swapped"] else None,
object=self.tokens["object"]
object=self.tokens["object"],
)

View file

@ -86,6 +86,7 @@ def get_state_types(gir):
"selected": BoolType(),
}
def get_types(gir):
return {
**get_property_types(gir),
@ -93,6 +94,7 @@ def get_types(gir):
**get_state_types(gir),
}
def _get_docs(gir, name):
return (
gir.get_type("AccessibleProperty", "Gtk").members.get(name)
@ -151,7 +153,6 @@ class A11y(AstNode):
def container_is_widget(self):
validate_parent_type(self, "Gtk", "Widget", "accessibility properties")
def emit_xml(self, xml: XmlEmitter):
xml.start_tag("accessibility")
for child in self.children:
@ -165,8 +166,7 @@ class A11y(AstNode):
)
def a11y_completer(ast_node, match_variables):
yield Completion(
"accessibility", CompletionItemKind.Snippet,
snippet="accessibility {\n $0\n}"
"accessibility", CompletionItemKind.Snippet, snippet="accessibility {\n $0\n}"
)
@ -176,20 +176,24 @@ def a11y_completer(ast_node, match_variables):
)
def a11y_name_completer(ast_node, match_variables):
for name, type in get_types(ast_node.root.gir).items():
yield Completion(name, CompletionItemKind.Property, docs=_get_docs(ast_node.root.gir, type))
yield Completion(
name, CompletionItemKind.Property, docs=_get_docs(ast_node.root.gir, type)
)
@decompiler("relation", cdata=True)
def decompile_relation(ctx, gir, name, cdata):
ctx.print_attribute(name, cdata, get_types(ctx.gir).get(name))
@decompiler("state", cdata=True)
def decompile_state(ctx, gir, name, cdata, translatable="false"):
if decompile.truthy(translatable):
ctx.print(f"{name}: _(\"{_escape_quote(cdata)}\");")
ctx.print(f'{name}: _("{_escape_quote(cdata)}");')
else:
ctx.print_attribute(name, cdata, get_types(ctx.gir).get(name))
@decompiler("accessibility")
def decompile_accessibility(ctx, gir):
ctx.print("accessibility {")

View file

@ -35,12 +35,14 @@ class Item(BaseTypedAttribute):
item = Group(
Item,
[
Optional([
UseIdent("name"),
":",
]),
Optional(
[
UseIdent("name"),
":",
]
),
VALUE_HOOKS,
]
],
)
@ -56,7 +58,6 @@ class Items(AstNode):
def container_is_combo_box_text(self):
validate_parent_type(self, "Gtk", "ComboBoxText", "combo box items")
def emit_xml(self, xml: XmlEmitter):
xml.start_tag("items")
for child in self.children:
@ -70,7 +71,4 @@ class Items(AstNode):
matches=new_statement_patterns,
)
def items_completer(ast_node, match_variables):
yield Completion(
"items", CompletionItemKind.Snippet,
snippet="items [$0]"
)
yield Completion("items", CompletionItemKind.Snippet, snippet="items [$0]")

View file

@ -54,12 +54,12 @@ def create_node(tag_name: str, singular: str):
[
UseQuoted("name"),
UseLiteral("tag_name", singular),
]
],
),
",",
),
"]",
]
],
)
@ -74,31 +74,38 @@ suffixes = create_node("suffixes", "suffix")
matches=new_statement_patterns,
)
def file_filter_completer(ast_node, match_variables):
yield Completion("mime-types", CompletionItemKind.Snippet, snippet="mime-types [\"$0\"]")
yield Completion("patterns", CompletionItemKind.Snippet, snippet="patterns [\"$0\"]")
yield Completion("suffixes", CompletionItemKind.Snippet, snippet="suffixes [\"$0\"]")
yield Completion(
"mime-types", CompletionItemKind.Snippet, snippet='mime-types ["$0"]'
)
yield Completion("patterns", CompletionItemKind.Snippet, snippet='patterns ["$0"]')
yield Completion("suffixes", CompletionItemKind.Snippet, snippet='suffixes ["$0"]')
@decompiler("mime-types")
def decompile_mime_types(ctx, gir):
ctx.print("mime-types [")
@decompiler("mime-type", cdata=True)
def decompile_mime_type(ctx, gir, cdata):
ctx.print(f'"{cdata}",')
@decompiler("patterns")
def decompile_patterns(ctx, gir):
ctx.print("patterns [")
@decompiler("pattern", cdata=True)
def decompile_pattern(ctx, gir, cdata):
ctx.print(f'"{cdata}",')
@decompiler("suffixes")
def decompile_suffixes(ctx, gir):
ctx.print("suffixes [")
@decompiler("suffix", cdata=True)
def decompile_suffix(ctx, gir, cdata):
ctx.print(f'"{cdata}",')

View file

@ -38,7 +38,7 @@ layout_prop = Group(
UseIdent("name"),
":",
VALUE_HOOKS.expected("a value"),
)
),
)
@ -53,7 +53,6 @@ class Layout(AstNode):
def container_is_widget(self):
validate_parent_type(self, "Gtk", "Widget", "layout properties")
def emit_xml(self, xml: XmlEmitter):
xml.start_tag("layout")
for child in self.children:
@ -67,10 +66,7 @@ class Layout(AstNode):
matches=new_statement_patterns,
)
def layout_completer(ast_node, match_variables):
yield Completion(
"layout", CompletionItemKind.Snippet,
snippet="layout {\n $0\n}"
)
yield Completion("layout", CompletionItemKind.Snippet, snippet="layout {\n $0\n}")
@decompiler("layout")

View file

@ -48,22 +48,12 @@ menu_contents = Sequence()
menu_section = Group(
Menu,
[
"section",
UseLiteral("tag", "section"),
Optional(UseIdent("id")),
menu_contents
]
["section", UseLiteral("tag", "section"), Optional(UseIdent("id")), menu_contents],
)
menu_submenu = Group(
Menu,
[
"submenu",
UseLiteral("tag", "submenu"),
Optional(UseIdent("id")),
menu_contents
]
["submenu", UseLiteral("tag", "submenu"), Optional(UseIdent("id")), menu_contents],
)
menu_attribute = Group(
@ -73,7 +63,7 @@ menu_attribute = Group(
":",
VALUE_HOOKS.expected("a value"),
Match(";").expected(),
]
],
)
menu_item = Group(
@ -84,7 +74,7 @@ menu_item = Group(
Optional(UseIdent("id")),
Match("{").expected(),
Until(menu_attribute, "}"),
]
],
)
menu_item_shorthand = Group(
@ -97,45 +87,49 @@ menu_item_shorthand = Group(
MenuAttribute,
[UseLiteral("name", "label"), VALUE_HOOKS],
),
Optional([
",",
Optional([
Group(
MenuAttribute,
[UseLiteral("name", "action"), VALUE_HOOKS],
Optional(
[
",",
Optional(
[
Group(
MenuAttribute,
[UseLiteral("name", "action"), VALUE_HOOKS],
),
Optional(
[
",",
Group(
MenuAttribute,
[UseLiteral("name", "icon"), VALUE_HOOKS],
),
]
),
]
),
Optional([
",",
Group(
MenuAttribute,
[UseLiteral("name", "icon"), VALUE_HOOKS],
),
])
])
]),
]
),
Match(")").expected(),
]
],
)
menu_contents.children = [
Match("{"),
Until(AnyOf(
menu_section,
menu_submenu,
menu_item_shorthand,
menu_item,
menu_attribute,
), "}"),
Until(
AnyOf(
menu_section,
menu_submenu,
menu_item_shorthand,
menu_item,
menu_attribute,
),
"}",
),
]
menu = Group(
Menu,
[
"menu",
UseLiteral("tag", "menu"),
Optional(UseIdent("id")),
menu_contents
],
["menu", UseLiteral("tag", "menu"), Optional(UseIdent("id")), menu_contents],
)
@ -144,10 +138,7 @@ menu = Group(
matches=new_statement_patterns,
)
def menu_completer(ast_node, match_variables):
yield Completion(
"menu", CompletionItemKind.Snippet,
snippet="menu {\n $0\n}"
)
yield Completion("menu", CompletionItemKind.Snippet, snippet="menu {\n $0\n}")
@completer(
@ -156,34 +147,21 @@ def menu_completer(ast_node, match_variables):
)
def menu_content_completer(ast_node, match_variables):
yield Completion(
"submenu", CompletionItemKind.Snippet,
snippet="submenu {\n $0\n}"
"submenu", CompletionItemKind.Snippet, snippet="submenu {\n $0\n}"
)
yield Completion(
"section", CompletionItemKind.Snippet,
snippet="section {\n $0\n}"
"section", CompletionItemKind.Snippet, snippet="section {\n $0\n}"
)
yield Completion("item", CompletionItemKind.Snippet, snippet="item {\n $0\n}")
yield Completion(
"item", CompletionItemKind.Snippet,
snippet="item {\n $0\n}"
)
yield Completion(
"item (shorthand)", CompletionItemKind.Snippet,
snippet='item (_("${1:Label}"), "${2:action-name}", "${3:icon-name}")'
"item (shorthand)",
CompletionItemKind.Snippet,
snippet='item (_("${1:Label}"), "${2:action-name}", "${3:icon-name}")',
)
yield Completion(
"label", CompletionItemKind.Snippet,
snippet='label: $0;'
)
yield Completion(
"action", CompletionItemKind.Snippet,
snippet='action: "$0";'
)
yield Completion(
"icon", CompletionItemKind.Snippet,
snippet='icon: "$0";'
)
yield Completion("label", CompletionItemKind.Snippet, snippet="label: $0;")
yield Completion("action", CompletionItemKind.Snippet, snippet='action: "$0";')
yield Completion("icon", CompletionItemKind.Snippet, snippet='icon: "$0";')
@decompiler("menu")
@ -193,6 +171,7 @@ def decompile_menu(ctx, gir, id=None):
else:
ctx.print("menu {")
@decompiler("submenu")
def decompile_submenu(ctx, gir, id=None):
if id:
@ -200,6 +179,7 @@ def decompile_submenu(ctx, gir, id=None):
else:
ctx.print("submenu {")
@decompiler("item")
def decompile_item(ctx, gir, id=None):
if id:
@ -207,6 +187,7 @@ def decompile_item(ctx, gir, id=None):
else:
ctx.print("item {")
@decompiler("section")
def decompile_section(ctx, gir, id=None):
if id:

View file

@ -32,7 +32,7 @@ class Widget(AstNode):
if object is None:
raise CompileError(
f"Could not find object with ID {self.tokens['name']}",
did_you_mean=(self.tokens['name'], self.root.objects_by_id.keys()),
did_you_mean=(self.tokens["name"], self.root.objects_by_id.keys()),
)
elif object.gir_class and not object.gir_class.assignable_to(type):
raise CompileError(

View file

@ -51,7 +51,6 @@ class Strings(AstNode):
def container_is_string_list(self):
validate_parent_type(self, "Gtk", "StringList", "StringList items")
def emit_xml(self, xml: XmlEmitter):
xml.start_tag("items")
for child in self.children:
@ -65,7 +64,4 @@ class Strings(AstNode):
matches=new_statement_patterns,
)
def strings_completer(ast_node, match_variables):
yield Completion(
"strings", CompletionItemKind.Snippet,
snippet="strings [$0]"
)
yield Completion("strings", CompletionItemKind.Snippet, snippet="strings [$0]")

View file

@ -54,13 +54,14 @@ class Styles(AstNode):
matches=new_statement_patterns,
)
def style_completer(ast_node, match_variables):
yield Completion("styles", CompletionItemKind.Keyword, snippet="styles [\"$0\"]")
yield Completion("styles", CompletionItemKind.Keyword, snippet='styles ["$0"]')
@decompiler("style")
def decompile_style(ctx, gir):
ctx.print(f"styles [")
@decompiler("class")
def decompile_style_class(ctx, gir, name):
ctx.print(f'"{name}",')

View file

@ -27,13 +27,15 @@ from .common import *
class Child(AstNode):
grammar = [
Optional([
"[",
Optional(["internal-child", UseLiteral("internal_child", True)]),
UseIdent("child_type").expected("a child type"),
Optional(ResponseId),
"]",
]),
Optional(
[
"[",
Optional(["internal-child", UseLiteral("internal_child", True)]),
UseIdent("child_type").expected("a child type"),
Optional(ResponseId),
"]",
]
),
Object,
]

View file

@ -26,10 +26,12 @@ class Template(Object):
grammar = [
"template",
UseIdent("name").expected("template class name"),
Optional([
Match(":"),
class_name.expected("parent class"),
]),
Optional(
[
Match(":"),
class_name.expected("parent class"),
]
),
ObjectContent,
]

View file

@ -24,8 +24,12 @@ from .common import *
class GtkDirective(AstNode):
grammar = Statement(
Match("using").err("File must start with a \"using Gtk\" directive (e.g. `using Gtk 4.0;`)"),
Match("Gtk").err("File must start with a \"using Gtk\" directive (e.g. `using Gtk 4.0;`)"),
Match("using").err(
'File must start with a "using Gtk" directive (e.g. `using Gtk 4.0;`)'
),
Match("Gtk").err(
'File must start with a "using Gtk" directive (e.g. `using Gtk 4.0;`)'
),
UseNumberText("version").expected("a version number for GTK"),
)
@ -34,17 +38,17 @@ class GtkDirective(AstNode):
if self.tokens["version"] not in ["4.0"]:
err = CompileError("Only GTK 4 is supported")
if self.tokens["version"].startswith("4"):
err.hint("Expected the GIR version, not an exact version number. Use `using Gtk 4.0;`.")
err.hint(
"Expected the GIR version, not an exact version number. Use `using Gtk 4.0;`."
)
else:
err.hint("Expected `using Gtk 4.0;`")
raise err
@property
def gir_namespace(self):
return gir.get_namespace("Gtk", self.tokens["version"])
def emit_xml(self, xml: XmlEmitter):
xml.put_self_closing("requires", lib="gtk", version=self.tokens["version"])

View file

@ -26,21 +26,13 @@ from .common import *
class ResponseId(AstNode):
"""Response ID of action widget."""
ALLOWED_PARENTS: T.List[T.Tuple[str, str]] = [
("Gtk", "Dialog"),
("Gtk", "InfoBar")
]
ALLOWED_PARENTS: T.List[T.Tuple[str, str]] = [("Gtk", "Dialog"), ("Gtk", "InfoBar")]
grammar = [
UseIdent("response"),
"=",
AnyOf(
UseIdent("response_id"),
UseNumber("response_id")
),
Optional([
Keyword("default"), UseLiteral("is_default", True)
])
AnyOf(UseIdent("response_id"), UseNumber("response_id")),
Optional([Keyword("default"), UseLiteral("is_default", True)]),
]
@validate()
@ -88,18 +80,15 @@ class ResponseId(AstNode):
if isinstance(response, int):
if response < 0:
raise CompileError(
"Numeric response type can't be negative")
raise CompileError("Numeric response type can't be negative")
elif isinstance(response, float):
raise CompileError(
"Response type must be GtkResponseType member or integer,"
" not float"
"Response type must be GtkResponseType member or integer," " not float"
)
else:
responses = gir.get_type("ResponseType", "Gtk").members.keys()
if response not in responses:
raise CompileError(
f"Response type \"{response}\" doesn't exist")
raise CompileError(f'Response type "{response}" doesn\'t exist')
@validate("default")
def no_multiple_default(self) -> None:
@ -143,7 +132,7 @@ class ResponseId(AstNode):
xml.start_tag(
"action-widget",
response=self.tokens["response_id"],
default=self.tokens["is_default"]
default=self.tokens["is_default"],
)
xml.put_text(self.widget_id)
xml.end_tag()

View file

@ -25,15 +25,18 @@ from .common import *
class UI(AstNode):
""" The AST node for the entire file """
"""The AST node for the entire file"""
grammar = [
GtkDirective,
ZeroOrMore(Import),
Until(AnyOf(
Template,
OBJECT_HOOKS,
), Eof()),
Until(
AnyOf(
Template,
OBJECT_HOOKS,
),
Eof(),
),
]
@property
@ -59,11 +62,13 @@ class UI(AstNode):
return gir_ctx
@property
def objects_by_id(self):
return { obj.tokens["id"]: obj for obj in self.iterate_children_recursive() if obj.tokens["id"] is not None }
return {
obj.tokens["id"]: obj
for obj in self.iterate_children_recursive()
if obj.tokens["id"] is not None
}
@validate()
def gir_errors(self):
@ -72,17 +77,16 @@ class UI(AstNode):
if len(self._gir_errors):
raise MultipleErrors(self._gir_errors)
@validate()
def at_most_one_template(self):
if len(self.children[Template]) > 1:
for template in self.children[Template][1:]:
raise CompileError(
f"Only one template may be defined per file, but this file contains {len(self.children[Template])}",
template.group.tokens["name"].start, template.group.tokens["name"].end,
template.group.tokens["name"].start,
template.group.tokens["name"].end,
)
@validate()
def unique_ids(self):
passed = {}
@ -92,10 +96,11 @@ class UI(AstNode):
if obj.tokens["id"] in passed:
token = obj.group.tokens["id"]
raise CompileError(f"Duplicate object ID '{obj.tokens['id']}'", token.start, token.end)
raise CompileError(
f"Duplicate object ID '{obj.tokens['id']}'", token.start, token.end
)
passed[obj.tokens["id"]] = obj
def emit_xml(self, xml: XmlEmitter):
xml.start_tag("interface")
for x in self.children:

View file

@ -46,7 +46,7 @@ class TranslatedStringValue(Value):
@property
def attrs(self):
attrs = { "translatable": "true" }
attrs = {"translatable": "true"}
if "context" in self.tokens:
attrs["context"] = self.tokens["context"]
return attrs
@ -71,7 +71,9 @@ class LiteralValue(Value):
try:
int(self.tokens["value"])
except:
raise CompileError(f"Cannot convert {self.group.tokens['value']} to integer")
raise CompileError(
f"Cannot convert {self.group.tokens['value']} to integer"
)
elif isinstance(type, gir.UIntType):
try:
@ -79,13 +81,17 @@ class LiteralValue(Value):
if int(self.tokens["value"]) < 0:
raise Exception()
except:
raise CompileError(f"Cannot convert {self.group.tokens['value']} to unsigned integer")
raise CompileError(
f"Cannot convert {self.group.tokens['value']} to unsigned integer"
)
elif isinstance(type, gir.FloatType):
try:
float(self.tokens["value"])
except:
raise CompileError(f"Cannot convert {self.group.tokens['value']} to float")
raise CompileError(
f"Cannot convert {self.group.tokens['value']} to float"
)
elif isinstance(type, gir.StringType):
pass
@ -100,15 +106,20 @@ class LiteralValue(Value):
"Gtk.ShortcutAction",
]
if type.full_name not in parseable_types:
raise CompileError(f"Cannot convert {self.group.tokens['value']} to {type.full_name}")
raise CompileError(
f"Cannot convert {self.group.tokens['value']} to {type.full_name}"
)
elif type is not None:
raise CompileError(f"Cannot convert {self.group.tokens['value']} to {type.full_name}")
raise CompileError(
f"Cannot convert {self.group.tokens['value']} to {type.full_name}"
)
class Flag(AstNode):
grammar = UseIdent("value")
class FlagsValue(Value):
grammar = [Flag, "|", Delimited(Flag, "|")]
@ -133,14 +144,14 @@ class IdentValue(Value):
if self.tokens["value"] not in type.members:
raise CompileError(
f"{self.tokens['value']} is not a member of {type.full_name}",
did_you_mean=(self.tokens['value'], type.members.keys()),
did_you_mean=(self.tokens["value"], type.members.keys()),
)
elif isinstance(type, gir.BoolType):
if self.tokens["value"] not in ["true", "false"]:
raise CompileError(
f"Expected 'true' or 'false' for boolean value",
did_you_mean=(self.tokens['value'], ["true", "false"]),
did_you_mean=(self.tokens["value"], ["true", "false"]),
)
elif type is not None:
@ -148,14 +159,13 @@ class IdentValue(Value):
if object is None:
raise CompileError(
f"Could not find object with ID {self.tokens['value']}",
did_you_mean=(self.tokens['value'], self.root.objects_by_id.keys()),
did_you_mean=(self.tokens["value"], self.root.objects_by_id.keys()),
)
elif object.gir_class and not object.gir_class.assignable_to(type):
raise CompileError(
f"Cannot assign {object.gir_class.full_name} to {type.full_name}"
)
@docs()
def docs(self):
type = self.parent.value_type
@ -167,9 +177,7 @@ class IdentValue(Value):
elif isinstance(type, gir.GirNode):
return type.doc
def get_semantic_tokens(self) -> T.Iterator[SemanticToken]:
if isinstance(self.parent.value_type, gir.Enumeration):
token = self.group.tokens["value"]
yield SemanticToken(token.start, token.end, SemanticTokenType.EnumMember)