typst_library/foundations/
context.rs1use comemo::Track;
2
3use crate::diag::{bail, Hint, HintedStrResult, SourceResult};
4use crate::engine::Engine;
5use crate::foundations::{
6 elem, Args, Construct, Content, Func, Packed, Show, StyleChain, Value,
7};
8use crate::introspection::{Locatable, Location};
9
10#[derive(Debug, Default, Clone, Hash)]
16pub struct Context<'a> {
17 pub location: Option<Location>,
19 pub styles: Option<StyleChain<'a>>,
21}
22
23impl<'a> Context<'a> {
24 pub fn none() -> Self {
26 Self::default()
27 }
28
29 pub fn new(location: Option<Location>, styles: Option<StyleChain<'a>>) -> Self {
31 Self { location, styles }
32 }
33}
34
35#[comemo::track]
36impl<'a> Context<'a> {
37 pub fn location(&self) -> HintedStrResult<Location> {
39 require(self.location)
40 }
41
42 pub fn styles(&self) -> HintedStrResult<StyleChain<'a>> {
44 require(self.styles)
45 }
46
47 pub fn introspect(&self) -> HintedStrResult<()> {
49 require(self.location.map(|_| ()).or(self.styles.map(|_| ())))
50 }
51}
52
53fn require<T>(val: Option<T>) -> HintedStrResult<T> {
56 val.ok_or("can only be used when context is known")
57 .hint("try wrapping this in a `context` expression")
58 .hint(
59 "the `context` expression should wrap everything that depends on this function",
60 )
61}
62
63#[elem(Construct, Locatable, Show)]
65pub struct ContextElem {
66 #[required]
68 #[internal]
69 func: Func,
70}
71
72impl Construct for ContextElem {
73 fn construct(_: &mut Engine, args: &mut Args) -> SourceResult<Content> {
74 bail!(args.span, "cannot be constructed manually");
75 }
76}
77
78impl Show for Packed<ContextElem> {
79 #[typst_macros::time(name = "context", span = self.span())]
80 fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
81 let loc = self.location().unwrap();
82 let context = Context::new(Some(loc), Some(styles));
83 Ok(self.func.call::<[Value; 0]>(engine, context.track(), [])?.display())
84 }
85}