Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Enchants

An enchant is a bracketed expression list attached to a widget, sitting between the attrs and the body:

use xrune::ui;
struct Velocity { vx: i32, vy: i32 }
struct Collider;
impl Collider { fn circle(_: i32) -> Self { Self } }
fn app(parent: i32) {
ui! {
    :(
        parent: parent
    :)
physic_obj (x: 100, y: 200) [
    Velocity { vx: 1, vy: 0 },
    Collider::circle(10),
] {}
}
}
fn main() {}

Enchants are arbitrary syn::Expr values — typically component literals, struct constructors, or marker tags. The rune retrieves them via DsWidget::get_enchants() and decides what to do (spawn them as ECS components, attach them as middleware, store them on the entity).

Position

The order is fixed: name (attrs) [enchants] { children }. All four parts after name are independently optional:

use xrune::ui;
#[derive(Debug)] struct TagMarker;
#[derive(Debug)] struct Tag1Marker;
#[derive(Debug)] struct Tag2Marker;
fn app(parent: i32) {
let Tag = TagMarker;
let Tag1 = Tag1Marker;
let Tag2 = Tag2Marker;
ui! {
    :(
        parent: parent
    :)
root_widget {
    foo                                     /* no parens, no enchants, no body */
    foo (a: 1)                              /* attrs only */
    foo (a: 1) [Tag] {}                     /* attrs + enchants + empty body */
    foo [Tag1, Tag2] {}                     /* enchants without attrs */
    foo () [Tag] {}                         /* equivalent: empty attrs + enchants */
}
}
}
fn main() {}

The rune always receives a Vec for each slot — empty vectors when the shape was omitted.

Use-case shape

Enchants are intentionally untyped — they’re how a rune lets users attach anything to a node without reserving a syntactic slot for it. A typical ECS-shaped rune turns each enchant expression into a component inserted onto the spawned entity:

use xrune::ui;
struct Position { x: f32, y: f32 }
struct Health(i32);
const PlayerControlled: () = ();
fn app(parent: i32) {
ui! {
    :(
        parent: parent
    :)
sprite (texture: "hero.png") [
    Position { x: 0.0, y: 0.0 },
    Health(100),
    PlayerControlled,
] {}
}
}
fn main() {}

A debug rune simply prints them. xrune-fmt re-emits them verbatim.

Source-of-truth

The parsing branch lives in DsWidget::parse (ds_widget.rs). inscribe_widget carries an enchants: &[syn::Expr] slice for the rune to consume.