typst_library/foundations/
context.rs1use comemo::Track;
2
3use crate::diag::{Hint, HintedStrResult, SourceResult, bail};
4use crate::engine::Engine;
5use crate::foundations::{
6 Args, Construct, Content, Func, ShowFn, StyleChain, Value, elem,
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)]
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
78pub const CONTEXT_RULE: ShowFn<ContextElem> = |elem, engine, styles| {
79 let loc = elem.location().unwrap();
80 let context = Context::new(Some(loc), Some(styles));
81 Ok(elem.func.call::<[Value; 0]>(engine, context.track(), [])?.display())
82};