typst_library/introspection/
location.rs

1use std::fmt::{self, Debug, Formatter};
2use std::num::NonZeroUsize;
3
4use ecow::EcoString;
5
6use crate::engine::Engine;
7use crate::foundations::{func, scope, ty, Repr};
8use crate::layout::Position;
9use crate::model::Numbering;
10
11/// Identifies an element in the document.
12///
13/// A location uniquely identifies an element in the document and lets you
14/// access its absolute position on the pages. You can retrieve the current
15/// location with the [`here`] function and the location of a queried or shown
16/// element with the [`location()`]($content.location) method on content.
17///
18/// # Locatable elements { #locatable }
19/// Currently, only a subset of element functions is locatable. Aside from
20/// headings and figures, this includes equations, references, quotes and all
21/// elements with an explicit label. As a result, you _can_ query for e.g.
22/// [`strong`] elements, but you will find only those that have an explicit
23/// label attached to them. This limitation will be resolved in the future.
24#[ty(scope)]
25#[derive(Copy, Clone, Eq, PartialEq, Hash)]
26pub struct Location(u128);
27
28impl Location {
29    /// Create a new location from a unique hash.
30    pub fn new(hash: u128) -> Self {
31        Self(hash)
32    }
33
34    /// Extract the raw hash.
35    pub fn hash(self) -> u128 {
36        self.0
37    }
38
39    /// Produces a well-known variant of this location.
40    ///
41    /// This is a synthetic location created from another one and is used, for
42    /// example, in bibliography management to create individual linkable
43    /// locations for reference entries from the bibliography's location.
44    pub fn variant(self, n: usize) -> Self {
45        Self(typst_utils::hash128(&(self.0, n)))
46    }
47}
48
49#[scope]
50impl Location {
51    /// Returns the page number for this location.
52    ///
53    /// Note that this does not return the value of the [page counter]($counter)
54    /// at this location, but the true page number (starting from one).
55    ///
56    /// If you want to know the value of the page counter, use
57    /// `{counter(page).at(loc)}` instead.
58    ///
59    /// Can be used with [`here`] to retrieve the physical page position
60    /// of the current context:
61    /// ```example
62    /// #context [
63    ///   I am located on
64    ///   page #here().page()
65    /// ]
66    /// ```
67    #[func]
68    pub fn page(self, engine: &mut Engine) -> NonZeroUsize {
69        engine.introspector.page(self)
70    }
71
72    /// Returns a dictionary with the page number and the x, y position for this
73    /// location. The page number starts at one and the coordinates are measured
74    /// from the top-left of the page.
75    ///
76    /// If you only need the page number, use `page()` instead as it allows
77    /// Typst to skip unnecessary work.
78    #[func]
79    pub fn position(self, engine: &mut Engine) -> Position {
80        engine.introspector.position(self)
81    }
82
83    /// Returns the page numbering pattern of the page at this location. This
84    /// can be used when displaying the page counter in order to obtain the
85    /// local numbering. This is useful if you are building custom indices or
86    /// outlines.
87    ///
88    /// If the page numbering is set to `{none}` at that location, this function
89    /// returns `{none}`.
90    #[func]
91    pub fn page_numbering(self, engine: &mut Engine) -> Option<Numbering> {
92        engine.introspector.page_numbering(self).cloned()
93    }
94}
95
96impl Debug for Location {
97    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
98        write!(f, "Location({})", self.0)
99    }
100}
101
102impl Repr for Location {
103    fn repr(&self) -> EcoString {
104        "..".into()
105    }
106}
107
108/// Makes this element as locatable through the introspector.
109pub trait Locatable {}
110
111/// Marks this element as not being queryable even though it is locatable for
112/// internal reasons.
113pub trait Unqueriable {}