decompiler: Support sub-templates

Support GtkBuilderListItemFactory syntax by decompiling the nested XML,
rather than preserving it as a string literal.
This commit is contained in:
James Westman 2024-08-24 13:04:21 -05:00
parent 25d9826aea
commit 21d5ce86e9
6 changed files with 60 additions and 20 deletions

View file

@ -51,9 +51,10 @@ class LineType(Enum):
class DecompileCtx: class DecompileCtx:
def __init__(self) -> None: def __init__(self, parent_gir: T.Optional[GirContext] = None) -> None:
self.sub_decompiler = parent_gir is not None
self._result: str = "" self._result: str = ""
self.gir = GirContext() self.gir = parent_gir or GirContext()
self._blocks_need_end: T.List[str] = [] self._blocks_need_end: T.List[str] = []
self._last_line_type: LineType = LineType.NONE self._last_line_type: LineType = LineType.NONE
self._obj_type_stack: list[T.Optional[GirType]] = [] self._obj_type_stack: list[T.Optional[GirType]] = []
@ -63,15 +64,19 @@ class DecompileCtx:
@property @property
def result(self) -> str: def result(self) -> str:
import_lines = sorted( imports = ""
[
f"using {ns} {namespace.version};" if not self.sub_decompiler:
for ns, namespace in self.gir.namespaces.items() import_lines = sorted(
if ns != "Gtk" [
] f"using {ns} {namespace.version};"
) for ns, namespace in self.gir.namespaces.items()
full_string = "\n".join(["using Gtk 4.0;", *import_lines]) + self._result if ns != "Gtk"
return formatter.format(full_string) ]
)
imports += "\n".join(["using Gtk 4.0;", *import_lines])
return formatter.format(imports + self._result)
def type_by_cname(self, cname: str) -> T.Optional[GirType]: def type_by_cname(self, cname: str) -> T.Optional[GirType]:
if type := self.gir.get_type_by_cname(cname): if type := self.gir.get_type_by_cname(cname):
@ -131,6 +136,7 @@ class DecompileCtx:
for child in self.root_node.children: for child in self.root_node.children:
if child.tag == "template": if child.tag == "template":
return child["class"] return child["class"]
return None return None
def find_object(self, id: str) -> T.Optional[Element]: def find_object(self, id: str) -> T.Optional[Element]:
@ -273,7 +279,7 @@ def decompile(data: str) -> str:
return ctx.result return ctx.result
def decompile_string(data): def decompile_string(data: str) -> str:
ctx = DecompileCtx() ctx = DecompileCtx()
xml = parse_string(data) xml = parse_string(data)
@ -417,6 +423,16 @@ def decompile_property(
ctx.print(f"{name}: {translatable};") ctx.print(f"{name}: {translatable};")
elif gir is None or gir.properties.get(name) is None: elif gir is None or gir.properties.get(name) is None:
ctx.print(f"{name}: {escape_quote(cdata)};") ctx.print(f"{name}: {escape_quote(cdata)};")
elif (
gir.assignable_to(ctx.gir.get_class("BuilderListItemFactory", "Gtk"))
and name == "bytes"
):
sub_ctx = DecompileCtx(ctx.gir)
xml = parse_string(cdata)
decompile_element(sub_ctx, None, xml)
ctx.print(sub_ctx.result)
else: else:
_, string = ctx.decompile_value(cdata, gir.properties.get(name).type) _, string = ctx.decompile_value(cdata, gir.properties.get(name).type)
ctx.print(f"{name}: {string};") ctx.print(f"{name}: {string};")

View file

@ -0,0 +1,11 @@
using Gtk 4.0;
ListView {
factory: BuilderListItemFactory list_item_factory {
template ListItem {
child: Label {
label: bind template.item as <$MyObject>.name;
};
}
};
}

View file

@ -1,8 +1,11 @@
using Gtk 4.0; using Gtk 4.0;
using Adw 1;
Gtk.BuilderListItemFactory { Gtk.BuilderListItemFactory {
template ListItem { template ListItem {
child: Gtk.Label label {}; child: Adw.Bin {
Gtk.Label label {}
};
} }
} }

View file

@ -11,7 +11,11 @@ corresponding .blp file and regenerate this file with blueprint-compiler.
<interface> <interface>
<template class="GtkListItem"> <template class="GtkListItem">
<property name="child"> <property name="child">
<object class="GtkLabel" id="label"></object> <object class="AdwBin">
<child>
<object class="GtkLabel" id="label"></object>
</child>
</object>
</property> </property>
</template> </template>
</interface>]]></property> </interface>]]></property>

View file

@ -0,0 +1,12 @@
using Gtk 4.0;
using Adw 1;
BuilderListItemFactory {
template ListItem {
child: Adw.Bin {
Label label {}
};
}
}
Label label {}

View file

@ -212,14 +212,8 @@ class TestSamples(unittest.TestCase):
SKIP_DECOMPILE = [ SKIP_DECOMPILE = [
# Not implemented yet # Not implemented yet
"action_widgets", "action_widgets",
# Not implemented yet
"gtkcolumnview",
# Comments are not preserved in either direction # Comments are not preserved in either direction
"comments", "comments",
# Not implemented yet
"list_factory",
# Not implemented yet
"subscope",
] ]
if sample in REQUIRE_ADW_1_4 and not self.have_adw_1_4: if sample in REQUIRE_ADW_1_4 and not self.have_adw_1_4: