use super::*;
pub(super) fn baked_link_defaults(
vars: &VarTable,
funcs: &FuncTable,
) -> Result<Vec<(String, ResolvedValue)>, Error> {
let mut out = Vec::new();
for d in crate::ledger::defaults::link_defaults() {
out.push((
d.name.clone(),
resolve_groups(&d.groups, d.span, vars, funcs)?,
));
}
Ok(out)
}
fn scope_chain<'a>(nodes: &'a [ResolvedInst], scope: &[String]) -> Vec<&'a ResolvedInst> {
let mut out = Vec::new();
let mut cur = nodes;
for seg in scope {
match scene::find_in_scope(cur, seg, &mut out) {
Some(n) => {
out.push(n);
cur = &n.children;
}
None => break,
}
}
out
}
fn inst_facts(inst: &ResolvedInst) -> NodeFacts {
let mut classes: Vec<String> = inst
.type_chain
.iter()
.map(|t| format!("lini-{t}"))
.collect();
classes.push(format!("lini-{}", inst.kind.as_str()));
classes.extend(inst.applied_styles.iter().cloned());
NodeFacts {
classes,
id: inst.id.clone(),
}
}
fn scope_is_drawing(nodes: &[ResolvedInst], root_attrs: &AttrMap, scope: &[String]) -> bool {
let attrs = scope_chain(nodes, scope)
.last()
.map_or(root_attrs, |c| &c.attrs);
is_drawing(attrs)
}
pub(super) fn link_scope_kind(
nodes: &[ResolvedInst],
root_attrs: &AttrMap,
scope: &[String],
) -> links::LinkScope {
let drawing = scope_is_drawing(nodes, root_attrs, scope);
let flow_in_drawing = if drawing {
None
} else {
let chain = scope_chain(nodes, scope);
let enclosed = is_drawing(root_attrs)
|| chain
.iter()
.take(chain.len().saturating_sub(1))
.any(|c| is_drawing(&c.attrs));
match (enclosed, chain.last()) {
(true, Some(container)) => Some(
container
.type_chain
.first()
.cloned()
.unwrap_or_else(|| container.kind.as_str().to_string()),
),
_ => None,
}
};
let detail = scope_chain(nodes, scope).last().is_some_and(
|c| matches!(c.attrs.get("of"), Some(ResolvedValue::Ident(id)) if is_magnifier(nodes, id)),
);
links::LinkScope {
drawing,
flow_in_drawing,
detail,
}
}
fn is_magnifier(nodes: &[ResolvedInst], id: &str) -> bool {
nodes.iter().any(|n| {
(n.id.as_deref() == Some(id) && n.type_chain.iter().any(|t| t == "magnifier"))
|| is_magnifier(&n.children, id)
})
}
pub(super) fn link_scope(
baked: &[(String, ResolvedValue)],
nodes: &[ResolvedInst],
root_attrs: &AttrMap,
scope: &[String],
) -> (Vec<(String, ResolvedValue)>, Vec<NodeFacts>) {
let chain = scope_chain(nodes, scope);
let mut base = baked.to_vec();
if scope_is_drawing(nodes, root_attrs, scope) {
base.push((
"stroke-width".to_string(),
ResolvedValue::Number(consts::DRAWING_LINK_STROKE_WIDTH),
));
base.push((
"font-size".to_string(),
ResolvedValue::Number(consts::DRAWING_LINK_FONT_SIZE),
));
}
for prop in properties::scope_link_props() {
let nearest = chain
.iter()
.rev()
.find_map(|n| n.attrs.get(prop))
.or_else(|| root_attrs.get(prop));
if let Some(v) = nearest {
base.push((prop.to_string(), v.clone()));
}
}
let mut ancestors: Vec<NodeFacts> = scene::root_facts(root_attrs).into_iter().collect();
ancestors.extend(chain.iter().map(|n| inst_facts(n)));
(base, ancestors)
}