1use std::any::{Any, TypeId};
2use std::fmt::{self, Debug, Formatter};
3use std::hash::{Hash, Hasher};
4use std::{mem, ptr};
5
6use comemo::Tracked;
7use ecow::{eco_vec, EcoString, EcoVec};
8use smallvec::SmallVec;
9use typst_syntax::Span;
10use typst_utils::LazyHash;
11
12use crate::diag::{SourceResult, Trace, Tracepoint};
13use crate::engine::Engine;
14use crate::foundations::{
15 cast, ty, Content, Context, Element, Func, NativeElement, OneOrMultiple, Repr,
16 Selector,
17};
18use crate::text::{FontFamily, FontList, TextElem};
19
20#[ty(cast)]
22#[derive(Default, PartialEq, Clone, Hash)]
23pub struct Styles(EcoVec<LazyHash<Style>>);
24
25impl Styles {
26 pub const fn new() -> Self {
28 Self(EcoVec::new())
29 }
30
31 pub fn is_empty(&self) -> bool {
33 self.0.is_empty()
34 }
35
36 pub fn iter(&self) -> impl Iterator<Item = &Style> {
38 self.0.iter().map(|style| &**style)
39 }
40
41 pub fn as_slice(&self) -> &[LazyHash<Style>] {
43 self.0.as_slice()
44 }
45
46 pub fn set(&mut self, style: impl Into<Style>) {
52 self.0.push(LazyHash::new(style.into()));
53 }
54
55 pub fn unset(&mut self) {
57 self.0.pop();
58 }
59
60 pub fn apply(&mut self, mut outer: Self) {
62 outer.0.extend(mem::take(self).0);
63 *self = outer;
64 }
65
66 pub fn apply_one(&mut self, outer: Style) {
68 self.0.insert(0, LazyHash::new(outer));
69 }
70
71 pub fn spanned(mut self, span: Span) -> Self {
73 for entry in self.0.make_mut() {
74 if let Style::Property(property) = &mut **entry {
75 property.span = span;
76 }
77 }
78 self
79 }
80
81 pub fn outside(mut self) -> Self {
83 for entry in self.0.make_mut() {
84 match &mut **entry {
85 Style::Property(property) => property.outside = true,
86 Style::Recipe(recipe) => recipe.outside = true,
87 _ => {}
88 }
89 }
90 self
91 }
92
93 pub fn liftable(mut self) -> Self {
95 for entry in self.0.make_mut() {
96 if let Style::Property(property) = &mut **entry {
97 property.liftable = true;
98 }
99 }
100 self
101 }
102
103 pub fn has<T: NativeElement>(&self, field: u8) -> bool {
105 let elem = T::elem();
106 self.0
107 .iter()
108 .filter_map(|style| style.property())
109 .any(|property| property.is_of(elem) && property.id == field)
110 }
111
112 pub fn set_family(&mut self, preferred: FontFamily, existing: StyleChain) {
115 self.set(TextElem::set_font(FontList(
116 std::iter::once(preferred)
117 .chain(TextElem::font_in(existing).into_iter().cloned())
118 .collect(),
119 )));
120 }
121}
122
123impl From<LazyHash<Style>> for Styles {
124 fn from(style: LazyHash<Style>) -> Self {
125 Self(eco_vec![style])
126 }
127}
128
129impl From<Style> for Styles {
130 fn from(style: Style) -> Self {
131 Self(eco_vec![LazyHash::new(style)])
132 }
133}
134
135impl IntoIterator for Styles {
136 type Item = LazyHash<Style>;
137 type IntoIter = ecow::vec::IntoIter<Self::Item>;
138
139 fn into_iter(self) -> Self::IntoIter {
140 self.0.into_iter()
141 }
142}
143
144impl FromIterator<LazyHash<Style>> for Styles {
145 fn from_iter<T: IntoIterator<Item = LazyHash<Style>>>(iter: T) -> Self {
146 Self(iter.into_iter().collect())
147 }
148}
149
150impl Debug for Styles {
151 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
152 f.write_str("Styles ")?;
153 f.debug_list().entries(&self.0).finish()
154 }
155}
156
157impl Repr for Styles {
158 fn repr(&self) -> EcoString {
159 "..".into()
160 }
161}
162
163#[derive(Clone, Hash)]
165pub enum Style {
166 Property(Property),
168 Recipe(Recipe),
170 Revocation(RecipeIndex),
176}
177
178impl Style {
179 pub fn property(&self) -> Option<&Property> {
181 match self {
182 Self::Property(property) => Some(property),
183 _ => None,
184 }
185 }
186
187 pub fn recipe(&self) -> Option<&Recipe> {
189 match self {
190 Self::Recipe(recipe) => Some(recipe),
191 _ => None,
192 }
193 }
194
195 pub fn span(&self) -> Span {
197 match self {
198 Self::Property(property) => property.span,
199 Self::Recipe(recipe) => recipe.span,
200 Self::Revocation(_) => Span::detached(),
201 }
202 }
203
204 pub fn element(&self) -> Option<Element> {
207 match self {
208 Style::Property(property) => Some(property.elem),
209 Style::Recipe(recipe) => match recipe.selector {
210 Some(Selector::Elem(elem, _)) => Some(elem),
211 _ => None,
212 },
213 Style::Revocation(_) => None,
214 }
215 }
216
217 pub fn liftable(&self) -> bool {
220 match self {
221 Self::Property(property) => property.liftable,
222 Self::Recipe(_) => true,
223 Self::Revocation(_) => false,
224 }
225 }
226
227 pub fn outside(&self) -> bool {
230 match self {
231 Self::Property(property) => property.outside,
232 Self::Recipe(recipe) => recipe.outside,
233 Self::Revocation(_) => false,
234 }
235 }
236
237 pub fn wrap(self) -> LazyHash<Style> {
239 LazyHash::new(self)
240 }
241}
242
243impl Debug for Style {
244 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
245 match self {
246 Self::Property(property) => property.fmt(f),
247 Self::Recipe(recipe) => recipe.fmt(f),
248 Self::Revocation(guard) => guard.fmt(f),
249 }
250 }
251}
252
253impl From<Property> for Style {
254 fn from(property: Property) -> Self {
255 Self::Property(property)
256 }
257}
258
259impl From<Recipe> for Style {
260 fn from(recipe: Recipe) -> Self {
261 Self::Recipe(recipe)
262 }
263}
264
265#[derive(Clone, Hash)]
267pub struct Property {
268 elem: Element,
270 id: u8,
272 value: Block,
274 span: Span,
276 liftable: bool,
278 outside: bool,
280}
281
282impl Property {
283 pub fn new<E, T>(id: u8, value: T) -> Self
285 where
286 E: NativeElement,
287 T: Debug + Clone + Hash + Send + Sync + 'static,
288 {
289 Self {
290 elem: E::elem(),
291 id,
292 value: Block::new(value),
293 span: Span::detached(),
294 liftable: false,
295 outside: false,
296 }
297 }
298
299 pub fn is(&self, elem: Element, id: u8) -> bool {
301 self.elem == elem && self.id == id
302 }
303
304 pub fn is_of(&self, elem: Element) -> bool {
306 self.elem == elem
307 }
308
309 pub fn wrap(self) -> LazyHash<Style> {
311 Style::Property(self).wrap()
312 }
313}
314
315impl Debug for Property {
316 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
317 write!(
318 f,
319 "Set({}.{}: ",
320 self.elem.name(),
321 self.elem.field_name(self.id).unwrap()
322 )?;
323 self.value.fmt(f)?;
324 write!(f, ")")
325 }
326}
327
328#[derive(Hash)]
334struct Block(Box<dyn Blockable>);
335
336impl Block {
337 fn new<T: Blockable>(value: T) -> Self {
339 Self(Box::new(value))
340 }
341
342 fn downcast<T: 'static>(&self) -> Option<&T> {
344 self.0.as_any().downcast_ref()
345 }
346}
347
348impl Debug for Block {
349 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
350 self.0.fmt(f)
351 }
352}
353
354impl Clone for Block {
355 fn clone(&self) -> Self {
356 self.0.dyn_clone()
357 }
358}
359
360trait Blockable: Debug + Send + Sync + 'static {
365 fn as_any(&self) -> &dyn Any;
367
368 fn dyn_hash(&self, state: &mut dyn Hasher);
370
371 fn dyn_clone(&self) -> Block;
373}
374
375impl<T: Debug + Clone + Hash + Send + Sync + 'static> Blockable for T {
376 fn as_any(&self) -> &dyn Any {
377 self
378 }
379
380 fn dyn_hash(&self, mut state: &mut dyn Hasher) {
381 TypeId::of::<Self>().hash(&mut state);
384 self.hash(&mut state);
385 }
386
387 fn dyn_clone(&self) -> Block {
388 Block(Box::new(self.clone()))
389 }
390}
391
392impl Hash for dyn Blockable {
393 fn hash<H: Hasher>(&self, state: &mut H) {
394 self.dyn_hash(state);
395 }
396}
397
398#[derive(Clone, PartialEq, Hash)]
400pub struct Recipe {
401 selector: Option<Selector>,
407 transform: Transformation,
409 span: Span,
411 outside: bool,
414}
415
416impl Recipe {
417 pub fn new(
419 selector: Option<Selector>,
420 transform: Transformation,
421 span: Span,
422 ) -> Self {
423 Self { selector, transform, span, outside: false }
424 }
425
426 pub fn selector(&self) -> Option<&Selector> {
428 self.selector.as_ref()
429 }
430
431 pub fn transform(&self) -> &Transformation {
433 &self.transform
434 }
435
436 pub fn span(&self) -> Span {
438 self.span
439 }
440
441 pub fn apply(
443 &self,
444 engine: &mut Engine,
445 context: Tracked<Context>,
446 content: Content,
447 ) -> SourceResult<Content> {
448 let mut content = match &self.transform {
449 Transformation::Content(content) => content.clone(),
450 Transformation::Func(func) => {
451 let mut result = func.call(engine, context, [content.clone()]);
452 if self.selector.is_some() {
453 let point = || Tracepoint::Show(content.func().name().into());
454 result = result.trace(engine.world, point, content.span());
455 }
456 result?.display()
457 }
458 Transformation::Style(styles) => content.styled_with_map(styles.clone()),
459 };
460 if content.span().is_detached() {
461 content = content.spanned(self.span);
462 }
463 Ok(content)
464 }
465}
466
467impl Debug for Recipe {
468 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
469 f.write_str("Show(")?;
470 if let Some(selector) = &self.selector {
471 selector.fmt(f)?;
472 f.write_str(", ")?;
473 }
474 self.transform.fmt(f)
475 }
476}
477
478#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
480pub struct RecipeIndex(pub usize);
481
482#[derive(Clone, PartialEq, Hash)]
484pub enum Transformation {
485 Content(Content),
487 Func(Func),
489 Style(Styles),
491}
492
493impl Debug for Transformation {
494 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
495 match self {
496 Self::Content(content) => content.fmt(f),
497 Self::Func(func) => func.fmt(f),
498 Self::Style(styles) => styles.fmt(f),
499 }
500 }
501}
502
503cast! {
504 Transformation,
505 content: Content => Self::Content(content),
506 func: Func => Self::Func(func),
507}
508
509#[derive(Default, Clone, Copy, Hash)]
517pub struct StyleChain<'a> {
518 head: &'a [LazyHash<Style>],
520 tail: Option<&'a Self>,
522}
523
524impl<'a> StyleChain<'a> {
525 pub fn new(root: &'a Styles) -> Self {
527 Self { head: &root.0, tail: None }
528 }
529
530 pub fn chain<'b, C>(&'b self, local: &'b C) -> StyleChain<'b>
536 where
537 C: Chainable + ?Sized,
538 {
539 Chainable::chain(local, self)
540 }
541
542 pub fn get<T: Clone + 'static>(
544 self,
545 func: Element,
546 id: u8,
547 inherent: Option<&T>,
548 default: impl Fn() -> T,
549 ) -> T {
550 self.properties::<T>(func, id, inherent)
551 .next()
552 .cloned()
553 .unwrap_or_else(default)
554 }
555
556 pub fn get_ref<T: 'static>(
559 self,
560 func: Element,
561 id: u8,
562 inherent: Option<&'a T>,
563 default: impl Fn() -> &'a T,
564 ) -> &'a T {
565 self.properties::<T>(func, id, inherent)
566 .next()
567 .unwrap_or_else(default)
568 }
569
570 pub fn get_folded<T: Fold + Clone + 'static>(
573 self,
574 func: Element,
575 id: u8,
576 inherent: Option<&T>,
577 default: impl Fn() -> T,
578 ) -> T {
579 fn next<T: Fold>(
580 mut values: impl Iterator<Item = T>,
581 default: &impl Fn() -> T,
582 ) -> T {
583 values
584 .next()
585 .map(|value| value.fold(next(values, default)))
586 .unwrap_or_else(default)
587 }
588 next(self.properties::<T>(func, id, inherent).cloned(), &default)
589 }
590
591 fn properties<T: 'static>(
593 self,
594 func: Element,
595 id: u8,
596 inherent: Option<&'a T>,
597 ) -> impl Iterator<Item = &'a T> {
598 inherent.into_iter().chain(
599 self.entries()
600 .filter_map(|style| style.property())
601 .filter(move |property| property.is(func, id))
602 .map(|property| &property.value)
603 .map(move |value| {
604 value.downcast().unwrap_or_else(|| {
605 panic!(
606 "attempted to read a value of a different type than was written {}.{}: {:?}",
607 func.name(),
608 func.field_name(id).unwrap(),
609 value
610 )
611 })
612 }),
613 )
614 }
615
616 pub fn entries(self) -> Entries<'a> {
618 Entries { inner: [].as_slice().iter(), links: self.links() }
619 }
620
621 pub fn recipes(self) -> impl Iterator<Item = &'a Recipe> {
623 self.entries().filter_map(|style| style.recipe())
624 }
625
626 pub fn links(self) -> Links<'a> {
628 Links(Some(self))
629 }
630
631 pub fn to_map(self) -> Styles {
633 let mut styles: EcoVec<_> = self.entries().cloned().collect();
634 styles.make_mut().reverse();
635 Styles(styles)
636 }
637
638 pub fn suffix(self, len: usize) -> Styles {
641 let mut styles = EcoVec::new();
642 let take = self.links().count().saturating_sub(len);
643 for link in self.links().take(take) {
644 styles.extend(link.iter().cloned().rev());
645 }
646 styles.make_mut().reverse();
647 Styles(styles)
648 }
649
650 pub fn pop(&mut self) {
652 *self = self.tail.copied().unwrap_or_default();
653 }
654
655 pub fn trunk(iter: impl IntoIterator<Item = Self>) -> Option<Self> {
657 let mut iter = iter.into_iter();
659 let mut trunk = iter.next()?;
660 let mut depth = trunk.links().count();
661
662 for mut chain in iter {
663 let len = chain.links().count();
664 if len < depth {
665 for _ in 0..depth - len {
666 trunk.pop();
667 }
668 depth = len;
669 } else if len > depth {
670 for _ in 0..len - depth {
671 chain.pop();
672 }
673 }
674
675 while depth > 0 && chain != trunk {
676 trunk.pop();
677 chain.pop();
678 depth -= 1;
679 }
680 }
681
682 Some(trunk)
683 }
684}
685
686impl Debug for StyleChain<'_> {
687 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
688 f.write_str("StyleChain ")?;
689 f.debug_list()
690 .entries(self.entries().collect::<Vec<_>>().into_iter().rev())
691 .finish()
692 }
693}
694
695impl PartialEq for StyleChain<'_> {
696 fn eq(&self, other: &Self) -> bool {
697 ptr::eq(self.head, other.head)
698 && match (self.tail, other.tail) {
699 (Some(a), Some(b)) => ptr::eq(a, b),
700 (None, None) => true,
701 _ => false,
702 }
703 }
704}
705
706pub trait Chainable {
708 fn chain<'a>(&'a self, outer: &'a StyleChain<'_>) -> StyleChain<'a>;
710}
711
712impl Chainable for LazyHash<Style> {
713 fn chain<'a>(&'a self, outer: &'a StyleChain<'_>) -> StyleChain<'a> {
714 StyleChain {
715 head: std::slice::from_ref(self),
716 tail: Some(outer),
717 }
718 }
719}
720
721impl Chainable for [LazyHash<Style>] {
722 fn chain<'a>(&'a self, outer: &'a StyleChain<'_>) -> StyleChain<'a> {
723 if self.is_empty() {
724 *outer
725 } else {
726 StyleChain { head: self, tail: Some(outer) }
727 }
728 }
729}
730
731impl<const N: usize> Chainable for [LazyHash<Style>; N] {
732 fn chain<'a>(&'a self, outer: &'a StyleChain<'_>) -> StyleChain<'a> {
733 Chainable::chain(self.as_slice(), outer)
734 }
735}
736
737impl Chainable for Styles {
738 fn chain<'a>(&'a self, outer: &'a StyleChain<'_>) -> StyleChain<'a> {
739 Chainable::chain(self.0.as_slice(), outer)
740 }
741}
742
743pub struct Entries<'a> {
745 inner: std::slice::Iter<'a, LazyHash<Style>>,
746 links: Links<'a>,
747}
748
749impl<'a> Iterator for Entries<'a> {
750 type Item = &'a LazyHash<Style>;
751
752 fn next(&mut self) -> Option<Self::Item> {
753 loop {
754 if let Some(entry) = self.inner.next_back() {
755 return Some(entry);
756 }
757
758 match self.links.next() {
759 Some(next) => self.inner = next.iter(),
760 None => return None,
761 }
762 }
763 }
764}
765
766pub struct Links<'a>(Option<StyleChain<'a>>);
768
769impl<'a> Iterator for Links<'a> {
770 type Item = &'a [LazyHash<Style>];
771
772 fn next(&mut self) -> Option<Self::Item> {
773 let StyleChain { head, tail } = self.0?;
774 self.0 = tail.copied();
775 Some(head)
776 }
777}
778
779pub trait Resolve {
781 type Output;
783
784 fn resolve(self, styles: StyleChain) -> Self::Output;
786}
787
788impl<T: Resolve> Resolve for Option<T> {
789 type Output = Option<T::Output>;
790
791 fn resolve(self, styles: StyleChain) -> Self::Output {
792 self.map(|v| v.resolve(styles))
793 }
794}
795
796pub trait Fold {
807 fn fold(self, outer: Self) -> Self;
809}
810
811impl Fold for bool {
812 fn fold(self, _: Self) -> Self {
813 self
814 }
815}
816
817impl<T: Fold> Fold for Option<T> {
818 fn fold(self, outer: Self) -> Self {
819 match (self, outer) {
820 (Some(inner), Some(outer)) => Some(inner.fold(outer)),
821 (inner, _) => inner,
824 }
825 }
826}
827
828impl<T> Fold for Vec<T> {
829 fn fold(self, mut outer: Self) -> Self {
830 outer.extend(self);
831 outer
832 }
833}
834
835impl<T, const N: usize> Fold for SmallVec<[T; N]> {
836 fn fold(self, mut outer: Self) -> Self {
837 outer.extend(self);
838 outer
839 }
840}
841
842impl<T> Fold for OneOrMultiple<T> {
843 fn fold(self, mut outer: Self) -> Self {
844 outer.0.extend(self.0);
845 outer
846 }
847}
848
849pub trait AlternativeFold {
861 fn fold_or(self, outer: Self) -> Self;
864}
865
866impl<T: Fold> AlternativeFold for Option<T> {
867 fn fold_or(self, outer: Self) -> Self {
868 match (self, outer) {
869 (Some(inner), Some(outer)) => Some(inner.fold(outer)),
870 (inner, outer) => inner.or(outer),
873 }
874 }
875}
876
877#[derive(Debug, Default, Clone, Copy, PartialEq, Hash)]
879pub struct Depth(pub usize);
880
881impl Fold for Depth {
882 fn fold(self, outer: Self) -> Self {
883 Self(outer.0 + self.0)
884 }
885}