loader: an unnamed instance keeps its own name, so $parent reaches the real parent
`framexml::merge` merged the inherited template's `name` onto the instance, so an unnamed child of a named virtual template took the template's name. ItemRack's `<Frame inherits="ItemRackQueueTemplate"/>` then named its texture after the template instead of the parent frame, and `Rack.OnEvent` indexed the missing `ItemRackInv*Queue` global. The reference reads `name` and `id` from the instance alone (`PreLoadXML 0x769770`); drop both from the merge base.
This commit is contained in:
@@ -315,8 +315,9 @@ fn element_from_node(node: roxmltree::Node) -> Element {
|
||||
/// attributes override or extend the template's (case-insensitively). The reference merges
|
||||
/// nothing: `LoadXML` re-enters itself on the one object against each template, the most distant
|
||||
/// first, then the instance (`0x76985c`; `<Frames>` repeat the walk, `0x76a060`), and reads `name`
|
||||
/// and `id` from the instance alone (`PreLoadXML 0x769770`). Here `name` and `virtual` merge like
|
||||
/// any attribute. A cycle is skipped with a warning.
|
||||
/// and `id` from the instance alone (`PreLoadXML 0x769770`). Here every attribute but `name` and
|
||||
/// `id` merges, `virtual` among them, so an unnamed child of a named template stays unnamed. A
|
||||
/// cycle is skipped with a warning.
|
||||
pub fn expand(
|
||||
element: &Element,
|
||||
templates: &HashMap<&str, &Element>,
|
||||
@@ -392,7 +393,15 @@ fn expand_inner(
|
||||
|
||||
/// [`expand`]'s merge; `over`'s tag wins, and its body when it has one.
|
||||
fn merge(base: &Element, over: &Element) -> Element {
|
||||
let mut attrs = base.attrs.clone();
|
||||
// `name` and `id` belong to the instance alone (`PreLoadXML 0x769770`): an unnamed child that
|
||||
// inherits a *named* virtual template stays unnamed, so its regions expand `$parent` against
|
||||
// the real parent frame rather than the template's name. Every other attribute merges.
|
||||
let mut attrs: Vec<(String, String)> = base
|
||||
.attrs
|
||||
.iter()
|
||||
.filter(|(k, _)| !k.eq_ignore_ascii_case("name") && !k.eq_ignore_ascii_case("id"))
|
||||
.cloned()
|
||||
.collect();
|
||||
for (k, v) in &over.attrs {
|
||||
if let Some(slot) = attrs.iter_mut().find(|(ek, _)| ek.eq_ignore_ascii_case(k)) {
|
||||
slot.1 = v.clone();
|
||||
|
||||
@@ -2445,6 +2445,42 @@ mod chunk_name_tests {
|
||||
"the reference's own no-argument contract must reach the same frame"
|
||||
);
|
||||
}
|
||||
|
||||
/// An unnamed child that inherits a *named* virtual template stays unnamed: the reference
|
||||
/// reads `name` from the instance alone (`PreLoadXML 0x769770`), so the child's regions expand
|
||||
/// `$parent` against the real parent frame. ItemRack ships this shape — an unnamed
|
||||
/// `<Frame inherits="ItemRackQueueTemplate"/>` under `ItemRackInv0` names its texture
|
||||
/// `ItemRackInv0Queue`, the global `Rack.OnEvent` looks up (ItemRack.lua:4015).
|
||||
#[test]
|
||||
fn an_unnamed_instance_does_not_take_its_template_name() {
|
||||
let s = UiScript::new().unwrap();
|
||||
let doc = parse(
|
||||
r#"<Ui>
|
||||
<Frame name="ItemRackQueueTemplate" virtual="true">
|
||||
<Layers><Layer level="OVERLAY">
|
||||
<Texture name="$parentQueue"/>
|
||||
</Layer></Layers>
|
||||
</Frame>
|
||||
<CheckButton name="ItemRackInvTemplate" virtual="true">
|
||||
<Frames>
|
||||
<Frame inherits="ItemRackQueueTemplate"/>
|
||||
</Frames>
|
||||
</CheckButton>
|
||||
<CheckButton name="ItemRackInv0" inherits="ItemRackInvTemplate"/>
|
||||
</Ui>"#,
|
||||
);
|
||||
let report = load(&s, &doc, &no_files);
|
||||
assert!(report.errors.is_empty(), "{:?}", report.errors);
|
||||
assert!(
|
||||
s.eval::<bool>("return ItemRackInv0Queue ~= nil").unwrap(),
|
||||
"the unnamed child's texture must be named from the real parent, not the template: {:?}",
|
||||
report.warnings
|
||||
);
|
||||
assert!(
|
||||
s.eval::<bool>("return ItemRackQueueTemplate == nil").unwrap(),
|
||||
"a virtual template must not leak a global named after it"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user