vize_l2 0.503.0

L2 - the Davinci semantic IR (codename Disegno): the neutral op family every input dialect lowers into
Documentation
//! The attached-binding printers, split from [`print`](super) along the
//! op-family boundary when `ui.bind`/`ui.on` grew the family past the
//! source budget. The grammar per line mirrors the parse side
//! (`folio/parse/binding_line.rs`): optional fields in fixed order, each
//! separated by exactly one space.

use core::fmt::{Result, Write};

use super::{Style, end_line, indent, print_expr, print_name, quoted};
use crate::dump::owned::{
    Attribute, Bind, Binding, On, SlotContent, VueCloak, VueCssBind, VueDirective, VueHtml,
    VueMemo, VueOnce, VueShow, VueSlotScope, VueSync, VueText,
};
use vize_l0::String;

pub(super) fn print_attribute<W: Write>(
    w: &mut W,
    attribute: &Attribute,
    depth: usize,
    mode: Style,
) -> Result {
    indent(w, depth)?;
    w.write_str("attr ")?;
    let name = attribute.name.as_str();
    if name.contains(['=', '"']) || name.chars().any(char::is_whitespace) {
        quoted(w, name)?;
    } else {
        w.write_str(name)?;
    }
    if let Some(value) = &attribute.value {
        w.write_char('=')?;
        quoted(w, value.as_str())?;
    }
    end_line(w, attribute.span, mode)
}

pub(super) fn print_binding<W: Write>(
    w: &mut W,
    binding: &Binding,
    depth: usize,
    mode: Style,
) -> Result {
    match binding {
        Binding::Bind(bind) => print_bind(w, bind, depth, mode),
        Binding::On(on) => print_on(w, on, depth, mode),
        Binding::Model(model) => {
            indent(w, depth)?;
            w.write_str("ui.model")?;
            if let Some(argument) = &model.argument {
                w.write_str(" name=")?;
                print_name(w, argument, mode)?;
            }
            w.write_str(" read=")?;
            print_expr(w, &model.contract.read, mode)?;
            w.write_str(" write=")?;
            print_expr(w, &model.contract.write, mode)?;
            end_line(w, model.span, mode)?;
            for attribute in &model.attributes {
                print_attribute(w, attribute, depth + 1, mode)?;
            }
            Ok(())
        }
        Binding::SlotContent(content) => print_slot_content(w, content, depth, mode),
        Binding::SlotsObject(object) => {
            indent(w, depth)?;
            // The explicit historical writer retains its published generic
            // record. Only current pages convey the typed operation.
            match mode.grammar {
                crate::dump::codec::Grammar::CurrentV2 => w.write_str("ui.slots-object value=")?,
                crate::dump::codec::Grammar::HistoricalV1 => {
                    w.write_str("vue.directive \"slots\" value=")?
                }
            }
            print_expr(w, &object.value, mode)?;
            end_line(w, object.span, mode)
        }
        Binding::VueDirective(directive) => print_directive(w, directive, depth, mode),
        Binding::VueCssBind(bind) => print_css_bind(w, bind, depth, mode),
        Binding::VueSync(sync) => print_sync(w, sync, depth, mode),
        Binding::VueSlotScope(scope) => print_slot_scope(w, scope, depth, mode),
        Binding::VueOnce(once) => print_once(w, once, depth, mode),
        Binding::VueMemo(memo) => print_memo(w, memo, depth, mode),
        Binding::VueShow(show) => print_show(w, show, depth, mode),
        Binding::VueHtml(html) => print_html(w, html, depth, mode),
        Binding::VueText(text) => print_vue_text(w, text, depth, mode),
        Binding::VueCloak(cloak) => print_cloak(w, cloak, depth, mode),
    }
}

fn print_mods<W: Write>(w: &mut W, modifiers: &[String]) -> Result {
    if modifiers.is_empty() {
        return Ok(());
    }
    if modifiers
        .iter()
        .all(|modifier| !modifier.as_str().contains([',', '"', '\\', '\n', '\r']))
    {
        w.write_str(" mods=\"")?;
        for (i, modifier) in modifiers.iter().enumerate() {
            if i > 0 {
                w.write_char(',')?;
            }
            w.write_str(modifier.as_str())?;
        }
        return w.write_char('"');
    }
    w.write_str(" mods=[")?;
    for (i, modifier) in modifiers.iter().enumerate() {
        if i > 0 {
            w.write_char(',')?;
        }
        quoted(w, modifier.as_str())?;
    }
    w.write_char(']')
}

fn print_bind<W: Write>(w: &mut W, bind: &Bind, depth: usize, mode: Style) -> Result {
    indent(w, depth)?;
    w.write_str("ui.bind")?;
    if let Some(name) = &bind.name {
        w.write_str(" name=")?;
        print_name(w, name, mode)?;
    }
    print_mods(w, &bind.modifiers)?;
    if let Some(value) = &bind.value {
        w.write_str(" value=")?;
        print_expr(w, value, mode)?;
    }
    end_line(w, bind.span, mode)
}

fn print_on<W: Write>(w: &mut W, on: &On, depth: usize, mode: Style) -> Result {
    indent(w, depth)?;
    w.write_str("ui.on")?;
    if let Some(name) = &on.name {
        w.write_str(" name=")?;
        print_name(w, name, mode)?;
    }
    print_mods(w, &on.modifiers)?;
    if let Some(handler) = &on.handler {
        w.write_str(" handler=")?;
        print_expr(w, handler, mode)?;
    }
    if let Some(id) = on.native_handler {
        write!(w, " handler-ref={id}")?;
    }
    end_line(w, on.span, mode)
}

fn print_slot_content<W: Write>(
    w: &mut W,
    content: &SlotContent,
    depth: usize,
    mode: Style,
) -> Result {
    indent(w, depth)?;
    w.write_str("ui.slot-content")?;
    if let Some(name) = &content.name {
        w.write_str(" name=")?;
        print_name(w, name, mode)?;
    }
    print_mods(w, &content.modifiers)?;
    if let Some(params) = &content.params {
        w.write_str(" params=")?;
        print_expr(w, params, mode)?;
    }
    end_line(w, content.span, mode)
}

fn print_directive<W: Write>(
    w: &mut W,
    directive: &VueDirective,
    depth: usize,
    mode: Style,
) -> Result {
    indent(w, depth)?;
    w.write_str("vue.directive ")?;
    quoted(w, directive.name.as_str())?;
    if let Some(argument) = &directive.argument {
        w.write_str(" arg=")?;
        print_name(w, argument, mode)?;
    }
    print_mods(w, &directive.modifiers)?;
    if let Some(value) = &directive.value {
        w.write_str(" value=")?;
        print_expr(w, value, mode)?;
    }
    end_line(w, directive.span, mode)
}

fn print_css_bind<W: Write>(w: &mut W, bind: &VueCssBind, depth: usize, mode: Style) -> Result {
    indent(w, depth)?;
    w.write_str("vue.css-bind value=")?;
    print_expr(w, &bind.value, mode)?;
    end_line(w, bind.span, mode)
}

fn print_sync<W: Write>(w: &mut W, sync: &VueSync, depth: usize, mode: Style) -> Result {
    indent(w, depth)?;
    w.write_str("vue.sync name=")?;
    quoted(w, sync.name.as_str())?;
    print_mods(w, &sync.modifiers)?;
    w.write_str(" value=")?;
    print_expr(w, &sync.value, mode)?;
    end_line(w, sync.span, mode)
}

fn print_slot_scope<W: Write>(
    w: &mut W,
    scope: &VueSlotScope,
    depth: usize,
    mode: Style,
) -> Result {
    indent(w, depth)?;
    w.write_str("vue.slot-scope")?;
    if let Some(name) = &scope.name {
        w.write_str(" name=")?;
        quoted(w, name.as_str())?;
    }
    if let Some(params) = &scope.params {
        w.write_str(" params=")?;
        print_expr(w, params, mode)?;
    }
    end_line(w, scope.span, mode)
}

fn print_once<W: Write>(w: &mut W, once: &VueOnce, depth: usize, mode: Style) -> Result {
    indent(w, depth)?;
    w.write_str("vue.once")?;
    end_line(w, once.span, mode)
}

fn print_memo<W: Write>(w: &mut W, memo: &VueMemo, depth: usize, mode: Style) -> Result {
    indent(w, depth)?;
    w.write_str("vue.memo value=")?;
    print_expr(w, &memo.value, mode)?;
    end_line(w, memo.span, mode)
}

fn print_show<W: Write>(w: &mut W, show: &VueShow, depth: usize, mode: Style) -> Result {
    indent(w, depth)?;
    w.write_str("vue.show value=")?;
    print_expr(w, &show.value, mode)?;
    end_line(w, show.span, mode)
}

fn print_html<W: Write>(w: &mut W, html: &VueHtml, depth: usize, mode: Style) -> Result {
    indent(w, depth)?;
    w.write_str("vue.html")?;
    if let Some(value) = &html.value {
        w.write_str(" value=")?;
        print_expr(w, value, mode)?;
    }
    end_line(w, html.span, mode)
}

fn print_vue_text<W: Write>(w: &mut W, text: &VueText, depth: usize, mode: Style) -> Result {
    indent(w, depth)?;
    w.write_str("vue.text")?;
    if let Some(value) = &text.value {
        w.write_str(" value=")?;
        print_expr(w, value, mode)?;
    }
    end_line(w, text.span, mode)
}

fn print_cloak<W: Write>(w: &mut W, cloak: &VueCloak, depth: usize, mode: Style) -> Result {
    indent(w, depth)?;
    w.write_str("vue.cloak")?;
    end_line(w, cloak.span, mode)
}