Handle Finalize alongside Synthesize

This commit is contained in:
Laurenz 2024-01-24 15:47:54 +01:00
parent 1612913f8f
commit a3684352ea
2 changed files with 31 additions and 35 deletions

View File

@ -14,8 +14,8 @@ use smallvec::smallvec;
use crate::diag::{SourceResult, StrResult}; use crate::diag::{SourceResult, StrResult};
use crate::engine::Engine; use crate::engine::Engine;
use crate::foundations::{ use crate::foundations::{
elem, func, scope, ty, Dict, Element, Fields, Guard, IntoValue, Label, NativeElement, elem, func, scope, ty, Dict, Element, Fields, Finalize, Guard, IntoValue, Label,
Recipe, Repr, Selector, Str, Style, Styles, Synthesize, Value, NativeElement, Recipe, Repr, Selector, Str, Style, Styles, Synthesize, Value,
}; };
use crate::introspection::{Locatable, Location, Meta, MetaElem}; use crate::introspection::{Locatable, Location, Meta, MetaElem};
use crate::layout::{AlignElem, Alignment, Axes, Length, MoveElem, PadElem, Rel, Sides}; use crate::layout::{AlignElem, Alignment, Axes, Length, MoveElem, PadElem, Rel, Sides};
@ -147,10 +147,11 @@ impl Content {
/// Whether the content needs to be realized specially. /// Whether the content needs to be realized specially.
pub fn needs_preparation(&self) -> bool { pub fn needs_preparation(&self) -> bool {
(self.can::<dyn Locatable>() !self.inner.prepared
|| self.can::<dyn Synthesize>() && (self.can::<dyn Locatable>()
|| self.label().is_some()) || self.can::<dyn Synthesize>()
&& !self.inner.prepared || self.can::<dyn Finalize>()
|| self.label().is_some())
} }
/// Check whether a show rule recipe is disabled. /// Check whether a show rule recipe is disabled.

View File

@ -107,58 +107,53 @@ pub fn realize(
elem.set_location(location); elem.set_location(location);
} }
if let Some(elem) = elem.with_mut::<dyn Synthesize>() { if let Some(synthesizable) = elem.with_mut::<dyn Synthesize>() {
elem.synthesize(engine, styles)?; synthesizable.synthesize(engine, styles)?;
} }
elem.mark_prepared(); elem.mark_prepared();
if elem.location().is_some() { let span = elem.span();
let span = elem.span(); let meta = elem.location().is_some().then(|| Meta::Elem(elem.clone()));
let meta = Meta::Elem(elem.clone());
return Ok(Some( let mut content = elem;
(elem + MetaElem::new().pack().spanned(span)) if let Some(finalizable) = target.with::<dyn Finalize>() {
.styled(MetaElem::set_data(smallvec![meta])), content = finalizable.finalize(content, styles);
));
} }
return Ok(Some(elem)); if let Some(meta) = meta {
return Ok(Some(
(content + MetaElem::new().pack().spanned(span))
.styled(MetaElem::set_data(smallvec![meta])),
));
} else {
return Ok(Some(content));
}
} }
// Find out how many recipes there are. // Find out how many recipes there are.
let mut n = styles.recipes().count(); let mut n = styles.recipes().count();
// Find an applicable recipe. // Find an applicable show rule recipe.
let mut realized = None;
for recipe in styles.recipes() { for recipe in styles.recipes() {
let guard = Guard::Nth(n); let guard = Guard::Nth(n);
if recipe.applicable(target) && !target.is_guarded(guard) { if recipe.applicable(target) && !target.is_guarded(guard) {
if let Some(content) = try_apply(engine, target, recipe, guard)? { if let Some(content) = try_apply(engine, target, recipe, guard)? {
realized = Some(content); return Ok(Some(content));
break;
} }
} }
n -= 1; n -= 1;
} }
// Realize if there was no matching recipe. // Apply the built-in show rule if there was no matching recipe.
if let Some(showable) = target.with::<dyn Show>() { let guard = Guard::Base(target.func());
let guard = Guard::Base(target.func()); if !target.is_guarded(guard) {
if realized.is_none() && !target.is_guarded(guard) { if let Some(showable) = target.with::<dyn Show>() {
realized = Some(showable.show(engine, styles)?); return Ok(Some(showable.show(engine, styles)?));
} }
} }
// Finalize only if this is the first application for this element. Ok(None)
if let Some(elem) = target.with::<dyn Finalize>() {
if target.is_pristine() {
if let Some(already) = realized {
realized = Some(elem.finalize(already, styles));
}
}
}
Ok(realized)
} }
/// Try to apply a recipe to the target. /// Try to apply a recipe to the target.