diff --git a/crates/typst/src/foundations/content.rs b/crates/typst/src/foundations/content.rs index d072640b0..4cae8db7e 100644 --- a/crates/typst/src/foundations/content.rs +++ b/crates/typst/src/foundations/content.rs @@ -385,6 +385,19 @@ impl Content { } } + /// Style this content with a full style map in-place. + pub fn style_in_place(&mut self, styles: Styles) { + if styles.is_empty() { + return; + } + + if let Some(style_elem) = self.to_packed_mut::() { + style_elem.styles.apply(styles); + } else { + *self = StyledElem::new(std::mem::take(self), styles).into(); + } + } + /// Queries the content tree for all elements that match the given selector. /// /// Elements produced in `show` rules will not be included in the results. diff --git a/crates/typst/src/model/enum.rs b/crates/typst/src/model/enum.rs index 0eb0f773c..d03c774cc 100644 --- a/crates/typst/src/model/enum.rs +++ b/crates/typst/src/model/enum.rs @@ -7,7 +7,7 @@ use crate::diag::{bail, SourceResult}; use crate::engine::Engine; use crate::foundations::{ cast, elem, scope, Array, Content, Context, NativeElement, Packed, Show, Smart, - StyleChain, + StyleChain, Styles, }; use crate::layout::{ Alignment, Axes, BlockElem, Cell, CellGrid, Em, Fragment, GridLayouter, HAlignment, @@ -316,6 +316,14 @@ pub struct EnumItem { pub body: Content, } +impl Packed { + /// Apply styles to this enum item. + pub fn styled(mut self, styles: Styles) -> Self { + self.body.style_in_place(styles); + self + } +} + cast! { EnumItem, array: Array => { diff --git a/crates/typst/src/model/list.rs b/crates/typst/src/model/list.rs index 34a4a0b2a..ffecc4003 100644 --- a/crates/typst/src/model/list.rs +++ b/crates/typst/src/model/list.rs @@ -4,7 +4,7 @@ use crate::diag::{bail, SourceResult}; use crate::engine::Engine; use crate::foundations::{ cast, elem, scope, Array, Content, Context, Depth, Func, NativeElement, Packed, Show, - Smart, StyleChain, Value, + Smart, StyleChain, Styles, Value, }; use crate::layout::{ Axes, BlockElem, Cell, CellGrid, Em, Fragment, GridLayouter, HAlignment, Length, @@ -206,6 +206,14 @@ pub struct ListItem { pub body: Content, } +impl Packed { + /// Apply styles to this list item. + pub fn styled(mut self, styles: Styles) -> Self { + self.body.style_in_place(styles); + self + } +} + cast! { ListItem, v: Content => v.unpack::().unwrap_or_else(Self::new) diff --git a/crates/typst/src/model/terms.rs b/crates/typst/src/model/terms.rs index da81c2ecb..cb88b02df 100644 --- a/crates/typst/src/model/terms.rs +++ b/crates/typst/src/model/terms.rs @@ -2,6 +2,7 @@ use crate::diag::{bail, SourceResult}; use crate::engine::Engine; use crate::foundations::{ cast, elem, scope, Array, Content, NativeElement, Packed, Show, Smart, StyleChain, + Styles, }; use crate::layout::{ BlockElem, Dir, Em, HElem, Length, Sides, Spacing, StackChild, StackElem, VElem, @@ -168,6 +169,15 @@ pub struct TermItem { pub description: Content, } +impl Packed { + /// Apply styles to this term item. + pub fn styled(mut self, styles: Styles) -> Self { + self.term.style_in_place(styles.clone()); + self.description.style_in_place(styles); + self + } +} + cast! { TermItem, array: Array => { diff --git a/crates/typst/src/realize/mod.rs b/crates/typst/src/realize/mod.rs index 97b39b4a3..a21f8faf0 100644 --- a/crates/typst/src/realize/mod.rs +++ b/crates/typst/src/realize/mod.rs @@ -508,50 +508,26 @@ impl<'a> ListBuilder<'a> { let mut items = items.into_iter().peekable(); let (first, _) = items.peek().unwrap(); let output = if first.is::() { - ListElem::new( - items - .map(|(item, local)| { - let mut item = item.to_packed::().unwrap().clone(); - let body = item.body().clone().styled_with_map(local); - item.push_body(body); - item - }) - .collect(), - ) - .with_tight(self.tight) - .pack() - .spanned(span) + let children = items + .map(|(item, local)| { + item.into_packed::().unwrap().styled(local) + }) + .collect(); + ListElem::new(children).with_tight(self.tight).pack().spanned(span) } else if first.is::() { - EnumElem::new( - items - .map(|(item, local)| { - let mut item = item.to_packed::().unwrap().clone(); - let body = item.body().clone().styled_with_map(local); - item.push_body(body); - item - }) - .collect(), - ) - .with_tight(self.tight) - .pack() - .spanned(span) + let children = items + .map(|(item, local)| { + item.into_packed::().unwrap().styled(local) + }) + .collect(); + EnumElem::new(children).with_tight(self.tight).pack().spanned(span) } else if first.is::() { - TermsElem::new( - items - .map(|(item, local)| { - let mut item = item.to_packed::().unwrap().clone(); - let term = item.term().clone().styled_with_map(local.clone()); - let description = - item.description().clone().styled_with_map(local); - item.push_term(term); - item.push_description(description); - item - }) - .collect(), - ) - .with_tight(self.tight) - .pack() - .spanned(span) + let children = items + .map(|(item, local)| { + item.into_packed::().unwrap().styled(local) + }) + .collect(); + TermsElem::new(children).with_tight(self.tight).pack().spanned(span) } else { unreachable!() };