1use typst_library::diag::{warning, At, SourceResult};
2use typst_library::foundations::{
3 Element, Fields, Func, Recipe, Selector, ShowableSelector, Styles, Transformation,
4};
5use typst_library::layout::BlockElem;
6use typst_library::model::ParElem;
7use typst_syntax::ast::{self, AstNode};
8
9use crate::{Eval, Vm};
10
11impl Eval for ast::SetRule<'_> {
12 type Output = Styles;
13
14 fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> {
15 if let Some(condition) = self.condition() {
16 if !condition.eval(vm)?.cast::<bool>().at(condition.span())? {
17 return Ok(Styles::new());
18 }
19 }
20
21 let target = self.target();
22 let target = target
23 .eval(vm)?
24 .cast::<Func>()
25 .and_then(|func| {
26 func.element().ok_or_else(|| {
27 "only element functions can be used in set rules".into()
28 })
29 })
30 .at(target.span())?;
31 let args = self.args().eval(vm)?.spanned(self.span());
32 Ok(target.set(&mut vm.engine, args)?.spanned(self.span()).liftable())
33 }
34}
35
36impl Eval for ast::ShowRule<'_> {
37 type Output = Recipe;
38
39 fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> {
40 let selector = self
41 .selector()
42 .map(|sel| sel.eval(vm)?.cast::<ShowableSelector>().at(sel.span()))
43 .transpose()?
44 .map(|selector| selector.0);
45
46 let transform = self.transform();
47 let transform = match transform {
48 ast::Expr::Set(set) => Transformation::Style(set.eval(vm)?),
49 expr => expr.eval(vm)?.cast::<Transformation>().at(transform.span())?,
50 };
51
52 let recipe = Recipe::new(selector, transform, self.span());
53 check_show_par_set_block(vm, &recipe);
54
55 Ok(recipe)
56 }
57}
58
59fn check_show_par_set_block(vm: &mut Vm, recipe: &Recipe) {
61 if_chain::if_chain! {
62 if let Some(Selector::Elem(elem, _)) = recipe.selector();
63 if *elem == Element::of::<ParElem>();
64 if let Transformation::Style(styles) = recipe.transform();
65 if styles.has::<BlockElem>(<BlockElem as Fields>::Enum::Above as _) ||
66 styles.has::<BlockElem>(<BlockElem as Fields>::Enum::Below as _);
67 then {
68 vm.engine.sink.warn(warning!(
69 recipe.span(),
70 "`show par: set block(spacing: ..)` has no effect anymore";
71 hint: "write `set par(spacing: ..)` instead";
72 hint: "this is specific to paragraphs as they are not considered blocks anymore"
73 ))
74 }
75 }
76}