1mod element;
2mod field;
3mod packed;
4mod raw;
5mod vtable;
6
7pub use self::element::*;
8pub use self::field::*;
9pub use self::packed::Packed;
10pub use self::vtable::{ContentVtable, FieldVtable};
11#[doc(inline)]
12pub use typst_macros::elem;
13
14use std::fmt::{self, Debug, Formatter};
15use std::hash::Hash;
16use std::iter::{self, Sum};
17use std::ops::{Add, AddAssign, ControlFlow};
18
19use comemo::Tracked;
20use ecow::{EcoString, eco_format};
21use serde::{Serialize, Serializer};
22
23use typst_syntax::Span;
24use typst_utils::singleton;
25
26use crate::diag::{SourceResult, StrResult};
27use crate::engine::Engine;
28use crate::foundations::{
29 Context, Dict, IntoValue, Label, Property, Recipe, RecipeIndex, Repr, Selector, Str,
30 Style, StyleChain, Styles, Value, func, repr, scope, ty,
31};
32use crate::introspection::Location;
33use crate::layout::{AlignElem, Alignment, Axes, Length, MoveElem, PadElem, Rel, Sides};
34use crate::model::{Destination, EmphElem, LinkElem, LinkMarker, StrongElem};
35use crate::pdf::{ArtifactElem, ArtifactKind};
36use crate::text::UnderlineElem;
37
38#[ty(scope, cast)]
82#[derive(Clone, PartialEq, Hash)]
83#[repr(transparent)]
84pub struct Content(raw::RawContent);
85
86impl Content {
87 pub fn new<T: NativeElement>(elem: T) -> Self {
89 Self(raw::RawContent::new(elem))
90 }
91
92 pub fn empty() -> Self {
94 singleton!(Content, SequenceElem::default().pack()).clone()
95 }
96
97 pub fn elem(&self) -> Element {
99 self.0.elem()
100 }
101
102 pub fn span(&self) -> Span {
104 self.0.span()
105 }
106
107 pub fn spanned(mut self, span: Span) -> Self {
109 if self.0.span().is_detached() {
110 *self.0.span_mut() = span;
111 }
112 self
113 }
114
115 pub fn label(&self) -> Option<Label> {
117 self.0.meta().label
118 }
119
120 pub fn labelled(mut self, label: Label) -> Self {
122 self.set_label(label);
123 self
124 }
125
126 pub fn set_label(&mut self, label: Label) {
128 self.0.meta_mut().label = Some(label);
129 }
130
131 pub fn located(mut self, loc: Location) -> Self {
138 self.set_location(loc);
139 self
140 }
141
142 pub fn set_location(&mut self, location: Location) {
144 self.0.meta_mut().location = Some(location);
145 }
146
147 pub fn is_guarded(&self, index: RecipeIndex) -> bool {
149 self.0.meta().lifecycle.contains(index.0)
150 }
151
152 pub fn guarded(mut self, index: RecipeIndex) -> Self {
154 self.0.meta_mut().lifecycle.insert(index.0);
155 self
156 }
157
158 pub fn is_prepared(&self) -> bool {
160 self.0.meta().lifecycle.contains(0)
161 }
162
163 pub fn mark_prepared(&mut self) {
165 self.0.meta_mut().lifecycle.insert(0);
166 }
167
168 pub fn get(
174 &self,
175 id: u8,
176 styles: Option<StyleChain>,
177 ) -> Result<Value, FieldAccessError> {
178 if id == 255
179 && let Some(label) = self.label()
180 {
181 return Ok(label.into_value());
182 }
183
184 match self.0.handle().field(id) {
185 Some(handle) => match styles {
186 Some(styles) => handle.get_with_styles(styles),
187 None => handle.get(),
188 }
189 .ok_or(FieldAccessError::Unset),
190 None => Err(FieldAccessError::Unknown),
191 }
192 }
193
194 pub fn get_by_name(&self, name: &str) -> Result<Value, FieldAccessError> {
199 if name == "label" {
200 return self
201 .label()
202 .map(|label| label.into_value())
203 .ok_or(FieldAccessError::Unknown);
204 }
205
206 match self.elem().field_id(name).and_then(|id| self.0.handle().field(id)) {
207 Some(handle) => handle.get().ok_or(FieldAccessError::Unset),
208 None => Err(FieldAccessError::Unknown),
209 }
210 }
211
212 pub fn field(&self, id: u8) -> StrResult<Value> {
218 self.get(id, None)
219 .map_err(|e| e.message(self, self.elem().field_name(id).unwrap()))
220 }
221
222 pub fn field_by_name(&self, name: &str) -> StrResult<Value> {
228 self.get_by_name(name).map_err(|e| e.message(self, name))
229 }
230
231 pub fn materialize(&mut self, styles: StyleChain) {
233 for id in 0..self.elem().vtable().fields.len() as u8 {
234 self.0.handle_mut().field(id).unwrap().materialize(styles);
235 }
236 }
237
238 pub fn sequence(iter: impl IntoIterator<Item = Self>) -> Self {
240 let vec: Vec<_> = iter.into_iter().collect();
241 if vec.is_empty() {
242 Self::empty()
243 } else if vec.len() == 1 {
244 vec.into_iter().next().unwrap()
245 } else {
246 SequenceElem::new(vec).into()
247 }
248 }
249
250 pub fn is<T: NativeElement>(&self) -> bool {
252 self.0.is::<T>()
253 }
254
255 pub fn to_packed<T: NativeElement>(&self) -> Option<&Packed<T>> {
257 Packed::from_ref(self)
258 }
259
260 pub fn to_packed_mut<T: NativeElement>(&mut self) -> Option<&mut Packed<T>> {
262 Packed::from_mut(self)
263 }
264
265 pub fn into_packed<T: NativeElement>(self) -> Result<Packed<T>, Self> {
267 Packed::from_owned(self)
268 }
269
270 pub fn unpack<T: NativeElement>(self) -> Result<T, Self> {
272 self.into_packed::<T>().map(Packed::unpack)
273 }
274
275 pub fn can<C>(&self) -> bool
277 where
278 C: ?Sized + 'static,
279 {
280 self.elem().can::<C>()
281 }
282
283 pub fn with<C>(&self) -> Option<&C>
286 where
287 C: ?Sized + 'static,
288 {
289 self.0.with::<C>()
290 }
291
292 pub fn with_mut<C>(&mut self) -> Option<&mut C>
295 where
296 C: ?Sized + 'static,
297 {
298 self.0.with_mut::<C>()
299 }
300
301 pub fn is_empty(&self) -> bool {
303 let Some(sequence) = self.to_packed::<SequenceElem>() else {
304 return false;
305 };
306
307 sequence.children.is_empty()
308 }
309
310 pub fn sequence_recursive_for_each<'a>(&'a self, f: &mut impl FnMut(&'a Self)) {
312 if let Some(sequence) = self.to_packed::<SequenceElem>() {
313 for child in &sequence.children {
314 child.sequence_recursive_for_each(f);
315 }
316 } else {
317 f(self);
318 }
319 }
320
321 pub fn styled_with_recipe(
323 self,
324 engine: &mut Engine,
325 context: Tracked<Context>,
326 recipe: Recipe,
327 ) -> SourceResult<Self> {
328 if recipe.selector().is_none() {
329 recipe.apply(engine, context, self)
330 } else {
331 Ok(self.styled(recipe))
332 }
333 }
334
335 pub fn repeat(&self, count: usize) -> Self {
337 Self::sequence(std::iter::repeat_with(|| self.clone()).take(count))
338 }
339
340 pub fn set<E, const I: u8>(self, field: Field<E, I>, value: E::Type) -> Self
342 where
343 E: SettableProperty<I>,
344 E::Type: Debug + Clone + Hash + Send + Sync + 'static,
345 {
346 self.styled(Property::new(field, value))
347 }
348
349 pub fn styled(mut self, style: impl Into<Style>) -> Self {
351 if let Some(style_elem) = self.to_packed_mut::<StyledElem>() {
352 style_elem.styles.apply_one(style.into());
353 self
354 } else {
355 self.styled_with_map(style.into().into())
356 }
357 }
358
359 pub fn styled_with_map(mut self, styles: Styles) -> Self {
361 if styles.is_empty() {
362 return self;
363 }
364
365 if let Some(style_elem) = self.to_packed_mut::<StyledElem>() {
366 style_elem.styles.apply(styles);
367 self
368 } else {
369 StyledElem::new(self, styles).into()
370 }
371 }
372
373 pub fn style_in_place(&mut self, styles: Styles) {
375 if styles.is_empty() {
376 return;
377 }
378
379 if let Some(style_elem) = self.to_packed_mut::<StyledElem>() {
380 style_elem.styles.apply(styles);
381 } else {
382 *self = StyledElem::new(std::mem::take(self), styles).into();
383 }
384 }
385
386 pub fn query_first_naive(&self, selector: &Selector) -> Option<Content> {
393 self.traverse(&mut |element| -> ControlFlow<Content> {
394 if selector.matches(&element, None) {
395 ControlFlow::Break(element)
396 } else {
397 ControlFlow::Continue(())
398 }
399 })
400 .break_value()
401 }
402
403 pub fn plain_text(&self) -> EcoString {
405 let mut text = EcoString::new();
406 let _ = self.traverse(&mut |element| -> ControlFlow<()> {
407 if let Some(textable) = element.with::<dyn PlainText>() {
408 textable.plain_text(&mut text);
409 }
410 ControlFlow::Continue(())
411 });
412 text
413 }
414
415 pub fn traverse<F, B>(&self, f: &mut F) -> ControlFlow<B>
417 where
418 F: FnMut(Content) -> ControlFlow<B>,
419 {
420 fn walk_value<F, B>(value: Value, f: &mut F) -> ControlFlow<B>
424 where
425 F: FnMut(Content) -> ControlFlow<B>,
426 {
427 match value {
428 Value::Content(content) => content.traverse(f),
429 Value::Array(array) => {
430 for value in array {
431 walk_value(value, f)?;
432 }
433 ControlFlow::Continue(())
434 }
435 _ => ControlFlow::Continue(()),
436 }
437 }
438
439 f(self.clone())?;
441 for (_, value) in self.fields() {
442 walk_value(value, f)?;
443 }
444 ControlFlow::Continue(())
445 }
446}
447
448impl Content {
449 pub fn strong(self) -> Self {
451 let span = self.span();
452 StrongElem::new(self).pack().spanned(span)
453 }
454
455 pub fn emph(self) -> Self {
457 let span = self.span();
458 EmphElem::new(self).pack().spanned(span)
459 }
460
461 pub fn underlined(self) -> Self {
463 let span = self.span();
464 UnderlineElem::new(self).pack().spanned(span)
465 }
466
467 pub fn linked(self, dest: Destination, alt: Option<EcoString>) -> Self {
469 let span = self.span();
470 LinkMarker::new(self, alt)
471 .pack()
472 .spanned(span)
473 .set(LinkElem::current, Some(dest))
474 }
475
476 pub fn aligned(self, align: Alignment) -> Self {
478 self.set(AlignElem::alignment, align)
479 }
480
481 pub fn padded(self, padding: Sides<Rel<Length>>) -> Self {
483 let span = self.span();
484 PadElem::new(self)
485 .with_left(padding.left)
486 .with_top(padding.top)
487 .with_right(padding.right)
488 .with_bottom(padding.bottom)
489 .pack()
490 .spanned(span)
491 }
492
493 pub fn moved(self, delta: Axes<Rel<Length>>) -> Self {
495 let span = self.span();
496 MoveElem::new(self)
497 .with_dx(delta.x)
498 .with_dy(delta.y)
499 .pack()
500 .spanned(span)
501 }
502
503 pub fn artifact(self, kind: ArtifactKind) -> Self {
505 let span = self.span();
506 ArtifactElem::new(self).with_kind(kind).pack().spanned(span)
507 }
508}
509
510#[scope]
511impl Content {
512 #[func]
518 pub fn func(&self) -> Element {
519 self.elem()
520 }
521
522 #[func]
524 pub fn has(
525 &self,
526 field: Str,
528 ) -> bool {
529 if field.as_str() == "label" {
530 return self.label().is_some();
531 }
532
533 let Some(id) = self.elem().field_id(&field) else {
534 return false;
535 };
536
537 match self.0.handle().field(id) {
538 Some(field) => field.has(),
539 None => false,
540 }
541 }
542
543 #[func]
547 pub fn at(
548 &self,
549 field: Str,
551 #[named]
553 default: Option<Value>,
554 ) -> StrResult<Value> {
555 self.get_by_name(&field)
556 .or_else(|e| default.ok_or(e))
557 .map_err(|e| e.message_no_default(self, &field))
558 }
559
560 #[func]
569 pub fn fields(&self) -> Dict {
570 let mut dict = Dict::new();
571 for field in self.0.handle().fields() {
572 if let Some(value) = field.get() {
573 dict.insert(field.name.into(), value);
574 }
575 }
576 if let Some(label) = self.label() {
577 dict.insert("label".into(), label.into_value());
578 }
579 dict
580 }
581
582 #[func]
587 pub fn location(&self) -> Option<Location> {
588 self.0.meta().location
589 }
590}
591
592impl Default for Content {
593 fn default() -> Self {
594 Self::empty()
595 }
596}
597
598impl Debug for Content {
599 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
600 self.0.fmt(f)
601 }
602}
603
604impl<T: NativeElement> From<T> for Content {
605 fn from(value: T) -> Self {
606 Self::new(value)
607 }
608}
609
610impl Repr for Content {
611 fn repr(&self) -> EcoString {
612 self.0.handle().repr().unwrap_or_else(|| {
613 let fields = self
614 .0
615 .handle()
616 .fields()
617 .filter_map(|field| field.get().map(|v| (field.name, v.repr())))
618 .map(|(name, value)| eco_format!("{name}: {value}"))
619 .collect::<Vec<_>>();
620 eco_format!(
621 "{}{}",
622 self.elem().name(),
623 repr::pretty_array_like(&fields, false),
624 )
625 })
626 }
627}
628
629impl Add for Content {
630 type Output = Self;
631
632 fn add(self, mut rhs: Self) -> Self::Output {
633 let mut lhs = self;
634 match (lhs.to_packed_mut::<SequenceElem>(), rhs.to_packed_mut::<SequenceElem>()) {
635 (Some(seq_lhs), Some(rhs)) => {
636 seq_lhs.children.extend(rhs.children.iter().cloned());
637 lhs
638 }
639 (Some(seq_lhs), None) => {
640 seq_lhs.children.push(rhs);
641 lhs
642 }
643 (None, Some(rhs_seq)) => {
644 rhs_seq.children.insert(0, lhs);
645 rhs
646 }
647 (None, None) => Self::sequence([lhs, rhs]),
648 }
649 }
650}
651
652impl<'a> Add<&'a Self> for Content {
653 type Output = Self;
654
655 fn add(self, rhs: &'a Self) -> Self::Output {
656 let mut lhs = self;
657 match (lhs.to_packed_mut::<SequenceElem>(), rhs.to_packed::<SequenceElem>()) {
658 (Some(seq_lhs), Some(rhs)) => {
659 seq_lhs.children.extend(rhs.children.iter().cloned());
660 lhs
661 }
662 (Some(seq_lhs), None) => {
663 seq_lhs.children.push(rhs.clone());
664 lhs
665 }
666 (None, Some(_)) => {
667 let mut rhs = rhs.clone();
668 rhs.to_packed_mut::<SequenceElem>().unwrap().children.insert(0, lhs);
669 rhs
670 }
671 (None, None) => Self::sequence([lhs, rhs.clone()]),
672 }
673 }
674}
675
676impl AddAssign for Content {
677 fn add_assign(&mut self, rhs: Self) {
678 *self = std::mem::take(self) + rhs;
679 }
680}
681
682impl AddAssign<&Self> for Content {
683 fn add_assign(&mut self, rhs: &Self) {
684 *self = std::mem::take(self) + rhs;
685 }
686}
687
688impl Sum for Content {
689 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
690 Self::sequence(iter)
691 }
692}
693
694impl Serialize for Content {
695 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
696 where
697 S: Serializer,
698 {
699 serializer.collect_map(
700 iter::once(("func".into(), self.func().name().into_value()))
701 .chain(self.fields()),
702 )
703 }
704}
705
706#[elem(Debug, Repr)]
708pub struct SequenceElem {
709 #[required]
711 pub children: Vec<Content>,
712}
713
714impl Debug for SequenceElem {
715 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
716 write!(f, "Sequence ")?;
717 f.debug_list().entries(&self.children).finish()
718 }
719}
720
721#[allow(clippy::derivable_impls)]
723impl Default for SequenceElem {
724 fn default() -> Self {
725 Self { children: Default::default() }
726 }
727}
728
729impl Repr for SequenceElem {
730 fn repr(&self) -> EcoString {
731 if self.children.is_empty() {
732 "[]".into()
733 } else {
734 let elements = crate::foundations::repr::pretty_array_like(
735 &self.children.iter().map(|c| c.repr()).collect::<Vec<_>>(),
736 false,
737 );
738 eco_format!("sequence{}", elements)
739 }
740 }
741}
742
743#[elem(Debug, Repr, PartialEq)]
745pub struct StyledElem {
746 #[required]
748 pub child: Content,
749 #[required]
751 pub styles: Styles,
752}
753
754impl Debug for StyledElem {
755 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
756 for style in self.styles.iter() {
757 writeln!(f, "#{style:?}")?;
758 }
759 self.child.fmt(f)
760 }
761}
762
763impl PartialEq for StyledElem {
764 fn eq(&self, other: &Self) -> bool {
765 self.child == other.child
766 }
767}
768
769impl Repr for StyledElem {
770 fn repr(&self) -> EcoString {
771 eco_format!("styled(child: {}, ..)", self.child.repr())
772 }
773}
774
775impl<T: NativeElement> IntoValue for T {
776 fn into_value(self) -> Value {
777 Value::Content(self.pack())
778 }
779}