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 {}