mirror of
https://gitlab.gnome.org/jwestman/blueprint-compiler.git
synced 2025-05-04 15:59:08 -04:00
Format using black
This commit is contained in:
parent
6a36d92380
commit
8fee46ec68
40 changed files with 975 additions and 610 deletions
|
@ -16,7 +16,16 @@ from .gtkbuilder_template import Template
|
|||
from .imports import GtkDirective, Import
|
||||
from .ui import UI
|
||||
from .types import ClassName
|
||||
from .values import TypeValue, IdentValue, TranslatedStringValue, FlagsValue, Flag, QuotedValue, NumberValue, Value
|
||||
from .values import (
|
||||
TypeValue,
|
||||
IdentValue,
|
||||
TranslatedStringValue,
|
||||
FlagsValue,
|
||||
Flag,
|
||||
QuotedValue,
|
||||
NumberValue,
|
||||
Value,
|
||||
)
|
||||
|
||||
from .common import *
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ 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"
|
||||
|
@ -34,5 +34,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."""
|
||||
|
|
|
@ -33,6 +33,7 @@ class ObjectContent(AstNode):
|
|||
def gir_class(self):
|
||||
return self.parent.gir_class
|
||||
|
||||
|
||||
class Object(AstNode):
|
||||
grammar: T.Any = [
|
||||
ConcreteClassName,
|
||||
|
@ -75,13 +76,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:
|
||||
|
|
|
@ -34,12 +34,16 @@ class Property(AstNode):
|
|||
UseIdent("bind_source"),
|
||||
".",
|
||||
UseIdent("bind_property"),
|
||||
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(
|
||||
|
@ -63,19 +67,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:
|
||||
|
@ -91,15 +92,19 @@ 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("bind")
|
||||
def property_bindable(self):
|
||||
if self.tokens["bind"] and self.gir_property is not None and self.gir_property.construct_only:
|
||||
if (
|
||||
self.tokens["bind"]
|
||||
and self.gir_property is not None
|
||||
and self.gir_property.construct_only
|
||||
):
|
||||
raise CompileError(
|
||||
f"{self.gir_property.full_name} can't be bound because it is construct-only",
|
||||
hints=["construct-only properties may only be set to a static value"]
|
||||
hints=["construct-only properties may only be set to a static value"],
|
||||
)
|
||||
|
||||
@validate("name")
|
||||
|
@ -107,7 +112,6 @@ class Property(AstNode):
|
|||
if self.gir_property is not None and not self.gir_property.writable:
|
||||
raise CompileError(f"{self.gir_property.full_name} is not writable")
|
||||
|
||||
|
||||
@validate()
|
||||
def obj_property_type(self):
|
||||
if len(self.children[Object]) == 0:
|
||||
|
@ -115,20 +119,23 @@ 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}"
|
||||
)
|
||||
|
||||
|
||||
@validate("name")
|
||||
def unique_in_parent(self):
|
||||
self.validate_unique_in_parent(
|
||||
f"Duplicate property '{self.tokens['name']}'",
|
||||
check=lambda child: child.tokens["name"] == self.tokens["name"]
|
||||
check=lambda child: child.tokens["name"] == self.tokens["name"],
|
||||
)
|
||||
|
||||
|
||||
@docs("name")
|
||||
def property_docs(self):
|
||||
if self.gir_property is not None:
|
||||
|
|
|
@ -26,19 +26,23 @@ 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
|
||||
|
@ -65,18 +69,15 @@ class Signal(AstNode):
|
|||
def is_after(self) -> bool:
|
||||
return self.tokens["after"] or False
|
||||
|
||||
|
||||
@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:
|
||||
|
@ -92,10 +93,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"]
|
||||
|
@ -103,10 +103,7 @@ 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):
|
||||
|
|
|
@ -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):
|
||||
if gir_type := (
|
||||
gir.get_type("AccessibleProperty", "Gtk").members.get(name)
|
||||
|
@ -174,8 +176,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}"
|
||||
)
|
||||
|
||||
|
||||
|
@ -185,20 +186,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 {")
|
||||
|
|
|
@ -35,12 +35,14 @@ class Item(BaseTypedAttribute):
|
|||
item = Group(
|
||||
Item,
|
||||
[
|
||||
Optional([
|
||||
UseIdent("name"),
|
||||
":",
|
||||
]),
|
||||
Optional(
|
||||
[
|
||||
UseIdent("name"),
|
||||
":",
|
||||
]
|
||||
),
|
||||
VALUE_HOOKS,
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
|
@ -67,7 +69,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]")
|
||||
|
|
|
@ -37,6 +37,7 @@ class Filters(AstNode):
|
|||
f"Duplicate {self.tokens['tag_name']} block",
|
||||
check=lambda child: child.tokens["tag_name"] == self.tokens["tag_name"],
|
||||
)
|
||||
|
||||
wrapped_validator(self)
|
||||
|
||||
|
||||
|
@ -57,12 +58,12 @@ def create_node(tag_name: str, singular: str):
|
|||
[
|
||||
UseQuoted("name"),
|
||||
UseLiteral("tag_name", singular),
|
||||
]
|
||||
],
|
||||
),
|
||||
",",
|
||||
),
|
||||
"]",
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
|
@ -77,31 +78,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}",')
|
||||
|
|
|
@ -45,7 +45,7 @@ layout_prop = Group(
|
|||
UseIdent("name"),
|
||||
":",
|
||||
VALUE_HOOKS.expected("a value"),
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
@ -71,10 +71,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")
|
||||
|
|
|
@ -56,22 +56,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(
|
||||
|
@ -81,7 +71,7 @@ menu_attribute = Group(
|
|||
":",
|
||||
VALUE_HOOKS.expected("a value"),
|
||||
Match(";").expected(),
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
menu_item = Group(
|
||||
|
@ -92,7 +82,7 @@ menu_item = Group(
|
|||
Optional(UseIdent("id")),
|
||||
Match("{").expected(),
|
||||
Until(menu_attribute, "}"),
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
menu_item_shorthand = Group(
|
||||
|
@ -105,58 +95,60 @@ 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 = Group(
|
||||
Menu,
|
||||
[
|
||||
"menu",
|
||||
UseLiteral("tag", "menu"),
|
||||
Optional(UseIdent("id")),
|
||||
menu_contents
|
||||
],
|
||||
["menu", UseLiteral("tag", "menu"), Optional(UseIdent("id")), menu_contents],
|
||||
)
|
||||
|
||||
from .ui import UI
|
||||
|
||||
|
||||
@completer(
|
||||
applies_in=[UI],
|
||||
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(
|
||||
|
@ -165,34 +157,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")
|
||||
|
@ -202,6 +181,7 @@ def decompile_menu(ctx, gir, id=None):
|
|||
else:
|
||||
ctx.print("menu {")
|
||||
|
||||
|
||||
@decompiler("submenu")
|
||||
def decompile_submenu(ctx, gir, id=None):
|
||||
if id:
|
||||
|
@ -209,6 +189,7 @@ def decompile_submenu(ctx, gir, id=None):
|
|||
else:
|
||||
ctx.print("submenu {")
|
||||
|
||||
|
||||
@decompiler("item")
|
||||
def decompile_item(ctx, gir, id=None):
|
||||
if id:
|
||||
|
@ -216,6 +197,7 @@ def decompile_item(ctx, gir, id=None):
|
|||
else:
|
||||
ctx.print("item {")
|
||||
|
||||
|
||||
@decompiler("section")
|
||||
def decompile_section(ctx, gir, id=None):
|
||||
if id:
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -55,7 +55,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]")
|
||||
|
|
|
@ -49,13 +49,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}",')
|
||||
|
|
|
@ -26,18 +26,21 @@ from .common import *
|
|||
|
||||
ALLOWED_PARENTS: T.List[T.Tuple[str, str]] = [
|
||||
("Gtk", "Buildable"),
|
||||
("Gio", "ListStore")
|
||||
("Gio", "ListStore"),
|
||||
]
|
||||
|
||||
|
||||
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,
|
||||
]
|
||||
|
||||
|
@ -53,9 +56,13 @@ class Child(AstNode):
|
|||
if gir_class.assignable_to(parent_type):
|
||||
break
|
||||
else:
|
||||
hints=["only Gio.ListStore or Gtk.Buildable implementors can have children"]
|
||||
hints = [
|
||||
"only Gio.ListStore or Gtk.Buildable implementors can have children"
|
||||
]
|
||||
if "child" in gir_class.properties:
|
||||
hints.append("did you mean to assign this object to the 'child' property?")
|
||||
hints.append(
|
||||
"did you mean to assign this object to the 'child' property?"
|
||||
)
|
||||
raise CompileError(
|
||||
f"{gir_class.full_name} doesn't have children",
|
||||
hints=hints,
|
||||
|
|
|
@ -28,10 +28,12 @@ class Template(Object):
|
|||
grammar = [
|
||||
"template",
|
||||
UseIdent("id").expected("template class name"),
|
||||
Optional([
|
||||
Match(":"),
|
||||
to_parse_node(ClassName).expected("parent class"),
|
||||
]),
|
||||
Optional(
|
||||
[
|
||||
Match(":"),
|
||||
to_parse_node(ClassName).expected("parent class"),
|
||||
]
|
||||
),
|
||||
ObjectContent,
|
||||
]
|
||||
|
||||
|
@ -54,7 +56,9 @@ class Template(Object):
|
|||
|
||||
@validate("id")
|
||||
def unique_in_parent(self):
|
||||
self.validate_unique_in_parent(f"Only one template may be defined per file, but this file contains {len(self.parent.children[Template])}",)
|
||||
self.validate_unique_in_parent(
|
||||
f"Only one template may be defined per file, but this file contains {len(self.parent.children[Template])}",
|
||||
)
|
||||
|
||||
|
||||
@decompiler("template")
|
||||
|
|
|
@ -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"),
|
||||
)
|
||||
|
||||
|
@ -35,7 +39,9 @@ class GtkDirective(AstNode):
|
|||
if version not in ["4.0"]:
|
||||
err = CompileError("Only GTK 4 is supported")
|
||||
if version and 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
|
||||
|
@ -51,7 +57,6 @@ class GtkDirective(AstNode):
|
|||
hints=e.hints,
|
||||
)
|
||||
|
||||
|
||||
@property
|
||||
def gir_namespace(self):
|
||||
# validate the GTK version first to make sure the more specific error
|
||||
|
|
|
@ -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 = [
|
||||
Keyword("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()
|
||||
|
@ -91,18 +83,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:
|
||||
|
@ -135,4 +124,3 @@ class ResponseId(AstNode):
|
|||
|
||||
_object: Object = self.parent.children[Object][0]
|
||||
return _object.tokens["id"]
|
||||
|
||||
|
|
|
@ -41,7 +41,9 @@ class TypeName(AstNode):
|
|||
@validate("class_name")
|
||||
def type_exists(self):
|
||||
if not self.tokens["ignore_gir"] and self.gir_ns is not None:
|
||||
self.root.gir.validate_type(self.tokens["class_name"], self.tokens["namespace"])
|
||||
self.root.gir.validate_type(
|
||||
self.tokens["class_name"], self.tokens["namespace"]
|
||||
)
|
||||
|
||||
@validate("namespace")
|
||||
def gir_ns_exists(self):
|
||||
|
@ -56,7 +58,9 @@ class TypeName(AstNode):
|
|||
@property
|
||||
def gir_type(self) -> T.Optional[gir.Class]:
|
||||
if self.tokens["class_name"] and not self.tokens["ignore_gir"]:
|
||||
return self.root.gir.get_type(self.tokens["class_name"], self.tokens["namespace"])
|
||||
return self.root.gir.get_type(
|
||||
self.tokens["class_name"], self.tokens["namespace"]
|
||||
)
|
||||
return None
|
||||
|
||||
@property
|
||||
|
@ -82,7 +86,9 @@ class ClassName(TypeName):
|
|||
def gir_class_exists(self):
|
||||
if self.gir_type is not None and not isinstance(self.gir_type, Class):
|
||||
if isinstance(self.gir_type, Interface):
|
||||
raise CompileError(f"{self.gir_type.full_name} is an interface, not a class")
|
||||
raise CompileError(
|
||||
f"{self.gir_type.full_name} is an interface, not a class"
|
||||
)
|
||||
else:
|
||||
raise CompileError(f"{self.gir_type.full_name} is not a class")
|
||||
|
||||
|
@ -93,6 +99,5 @@ class ConcreteClassName(ClassName):
|
|||
if isinstance(self.gir_type, Class) and self.gir_type.abstract:
|
||||
raise CompileError(
|
||||
f"{self.gir_type.full_name} can't be instantiated because it's abstract",
|
||||
hints=[f"did you mean to use a subclass of {self.gir_type.full_name}?"]
|
||||
hints=[f"did you mean to use a subclass of {self.gir_type.full_name}?"],
|
||||
)
|
||||
|
||||
|
|
|
@ -27,16 +27,19 @@ 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,
|
||||
menu,
|
||||
Object,
|
||||
), Eof()),
|
||||
Until(
|
||||
AnyOf(
|
||||
Template,
|
||||
menu,
|
||||
Object,
|
||||
),
|
||||
Eof(),
|
||||
),
|
||||
]
|
||||
|
||||
@property
|
||||
|
@ -61,11 +64,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):
|
||||
|
@ -74,7 +79,6 @@ class UI(AstNode):
|
|||
if len(self._gir_errors):
|
||||
raise MultipleErrors(self._gir_errors)
|
||||
|
||||
|
||||
@validate()
|
||||
def unique_ids(self):
|
||||
passed = {}
|
||||
|
@ -84,5 +88,7 @@ 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
|
||||
|
|
|
@ -84,13 +84,21 @@ class QuotedValue(Value):
|
|||
@validate()
|
||||
def validate_for_type(self):
|
||||
type = self.parent.value_type
|
||||
if isinstance(type, gir.IntType) or isinstance(type, gir.UIntType) or isinstance(type, gir.FloatType):
|
||||
if (
|
||||
isinstance(type, gir.IntType)
|
||||
or isinstance(type, gir.UIntType)
|
||||
or isinstance(type, gir.FloatType)
|
||||
):
|
||||
raise CompileError(f"Cannot convert string to number")
|
||||
|
||||
elif isinstance(type, gir.StringType):
|
||||
pass
|
||||
|
||||
elif isinstance(type, gir.Class) or isinstance(type, gir.Interface) or isinstance(type, gir.Boxed):
|
||||
elif (
|
||||
isinstance(type, gir.Class)
|
||||
or isinstance(type, gir.Interface)
|
||||
or isinstance(type, gir.Boxed)
|
||||
):
|
||||
parseable_types = [
|
||||
"Gdk.Paintable",
|
||||
"Gdk.Texture",
|
||||
|
@ -106,8 +114,12 @@ class QuotedValue(Value):
|
|||
if type.full_name not in parseable_types:
|
||||
hints = []
|
||||
if isinstance(type, gir.TypeType):
|
||||
hints.append(f"use the typeof operator: 'typeof({self.tokens('value')})'")
|
||||
raise CompileError(f"Cannot convert string to {type.full_name}", hints=hints)
|
||||
hints.append(
|
||||
f"use the typeof operator: 'typeof({self.tokens('value')})'"
|
||||
)
|
||||
raise CompileError(
|
||||
f"Cannot convert string to {type.full_name}", hints=hints
|
||||
)
|
||||
|
||||
elif type is not None:
|
||||
raise CompileError(f"Cannot convert string to {type.full_name}")
|
||||
|
@ -127,7 +139,9 @@ class NumberValue(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:
|
||||
|
@ -135,13 +149,17 @@ class NumberValue(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 type is not None:
|
||||
raise CompileError(f"Cannot convert number to {type.full_name}")
|
||||
|
@ -164,7 +182,7 @@ class Flag(AstNode):
|
|||
if isinstance(type, gir.Bitfield) and 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()),
|
||||
)
|
||||
|
||||
|
||||
|
@ -189,14 +207,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:
|
||||
|
@ -204,14 +222,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
|
||||
|
@ -223,9 +240,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)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue