typst_library/foundations/
label.rs

1use ecow::{eco_format, EcoString};
2use typst_utils::{PicoStr, ResolvedPicoStr};
3
4use crate::foundations::{func, scope, ty, Repr, Str};
5
6/// A label for an element.
7///
8/// Inserting a label into content attaches it to the closest preceding element
9/// that is not a space. The preceding element must be in the same scope as the
10/// label, which means that `[Hello #[<label>]]`, for instance, wouldn't work.
11///
12/// A labelled element can be [referenced]($ref), [queried]($query) for, and
13/// [styled]($styling) through its label.
14///
15/// Once constructed, you can get the name of a label using
16/// [`str`]($str/#constructor).
17///
18/// # Example
19/// ```example
20/// #show <a>: set text(blue)
21/// #show label("b"): set text(red)
22///
23/// = Heading <a>
24/// *Strong* #label("b")
25/// ```
26///
27/// # Syntax
28/// This function also has dedicated syntax: You can create a label by enclosing
29/// its name in angle brackets. This works both in markup and code. A label's
30/// name can contain letters, numbers, `_`, `-`, `:`, and `.`.
31///
32/// Note that there is a syntactical difference when using the dedicated syntax
33/// for this function. In the code below, the `[<a>]` terminates the heading and
34/// thus attaches to the heading itself, whereas the `[#label("b")]` is part of
35/// the heading and thus attaches to the heading's text.
36///
37/// ```typ
38/// // Equivalent to `#heading[Introduction] <a>`.
39/// = Introduction <a>
40///
41/// // Equivalent to `#heading[Conclusion #label("b")]`.
42/// = Conclusion #label("b")
43/// ```
44///
45/// Currently, labels can only be attached to elements in markup mode, not in
46/// code mode. This might change in the future.
47#[ty(scope, cast)]
48#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
49pub struct Label(PicoStr);
50
51impl Label {
52    /// Creates a label from an interned string.
53    pub fn new(name: PicoStr) -> Self {
54        Self(name)
55    }
56
57    /// Resolves the label to a string.
58    pub fn resolve(self) -> ResolvedPicoStr {
59        self.0.resolve()
60    }
61
62    /// Turns this label into its inner interned string.
63    pub fn into_inner(self) -> PicoStr {
64        self.0
65    }
66}
67
68#[scope]
69impl Label {
70    /// Creates a label from a string.
71    #[func(constructor)]
72    pub fn construct(
73        /// The name of the label.
74        name: Str,
75    ) -> Label {
76        Self(PicoStr::intern(name.as_str()))
77    }
78}
79
80impl Repr for Label {
81    fn repr(&self) -> EcoString {
82        eco_format!("<{}>", self.resolve())
83    }
84}
85
86impl From<Label> for PicoStr {
87    fn from(value: Label) -> Self {
88        value.into_inner()
89    }
90}
91
92/// Indicates that an element cannot be labelled.
93pub trait Unlabellable {}