mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
229 lines
6.8 KiB
Rust
229 lines
6.8 KiB
Rust
use crate::prelude::*;
|
|
|
|
/// Provides access to the location of content.
|
|
///
|
|
/// This is useful in combination with [queries]($func/query),
|
|
/// [counters]($func/counter), [state]($func/state), and [links]($func/link).
|
|
/// See their documentation for more details.
|
|
///
|
|
/// ```example
|
|
/// #locate(loc => [
|
|
/// My locatation: \
|
|
/// #loc.position()!
|
|
/// ])
|
|
/// ```
|
|
///
|
|
/// ## Methods
|
|
/// ### page()
|
|
/// Return the page number for this location.
|
|
///
|
|
/// Note that this does not return the value of the [page counter]($func/counter)
|
|
/// at this location, but the true page number (starting from one).
|
|
///
|
|
/// If you want to know the value of the page counter, use
|
|
/// `{counter(page).at(loc)}` instead.
|
|
///
|
|
/// - returns: integer
|
|
///
|
|
/// ### position()
|
|
/// Return a dictionary with the page number and the x, y position for this
|
|
/// location. The page number starts at one and the coordinates are measured
|
|
/// from the top-left of the page.
|
|
///
|
|
/// If you only need the page number, use `page()` instead as it allows Typst
|
|
/// to skip unnecessary work.
|
|
///
|
|
/// - returns: dictionary
|
|
///
|
|
/// ### page-numbering()
|
|
/// Returns the page numbering pattern of the page at this location. This can be
|
|
/// used when displaying the page counter in order to obtain the local numbering.
|
|
/// This is useful if you are building custom indices or outlines.
|
|
///
|
|
/// If the page numbering is set to `none` at that location, this function returns `none`.
|
|
///
|
|
/// - returns: string or function or none
|
|
///
|
|
/// Display: Locate
|
|
/// Category: meta
|
|
/// Returns: content
|
|
#[func]
|
|
pub fn locate(
|
|
/// A function that receives a `location`. Its return value is displayed
|
|
/// in the document.
|
|
///
|
|
/// This function is called once for each time the content returned by
|
|
/// `locate` appears in the document. That makes it possible to generate
|
|
/// content that depends on its own location in the document.
|
|
func: Func,
|
|
) -> Value {
|
|
LocateElem::new(func).pack().into()
|
|
}
|
|
|
|
/// Executes a `locate` call.
|
|
///
|
|
/// Display: Locate
|
|
/// Category: special
|
|
#[element(Locatable, Show)]
|
|
struct LocateElem {
|
|
/// The function to call with the location.
|
|
#[required]
|
|
func: Func,
|
|
}
|
|
|
|
impl Show for LocateElem {
|
|
#[tracing::instrument(name = "LocateElem::show", skip(self, vt))]
|
|
fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> {
|
|
if !vt.introspector.init() {
|
|
return Ok(Content::empty());
|
|
}
|
|
|
|
let location = self.0.location().unwrap();
|
|
Ok(self.func().call_vt(vt, [location.into()])?.display())
|
|
}
|
|
}
|
|
|
|
/// Provides access to active styles.
|
|
///
|
|
/// The styles are currently opaque and only useful in combination with the
|
|
/// [`measure`]($func/measure) function. See its documentation for more details.
|
|
/// In the future, the provided styles might also be directly accessed to look
|
|
/// up styles defined by [set rules]($styling/#set-rules).
|
|
///
|
|
/// ```example
|
|
/// #let thing(body) = style(styles => {
|
|
/// let size = measure(body, styles)
|
|
/// [Width of "#body" is #size.width]
|
|
/// })
|
|
///
|
|
/// #thing[Hey] \
|
|
/// #thing[Welcome]
|
|
/// ```
|
|
///
|
|
/// Display: Style
|
|
/// Category: meta
|
|
/// Returns: content
|
|
#[func]
|
|
pub fn style(
|
|
/// A function to call with the styles. Its return value is displayed
|
|
/// in the document.
|
|
///
|
|
/// This function is called once for each time the content returned by
|
|
/// `style` appears in the document. That makes it possible to generate
|
|
/// content that depends on the style context it appears in.
|
|
func: Func,
|
|
) -> Value {
|
|
StyleElem::new(func).pack().into()
|
|
}
|
|
|
|
/// Executes a style access.
|
|
///
|
|
/// Display: Style
|
|
/// Category: special
|
|
#[element(Show)]
|
|
struct StyleElem {
|
|
/// The function to call with the styles.
|
|
#[required]
|
|
func: Func,
|
|
}
|
|
|
|
impl Show for StyleElem {
|
|
#[tracing::instrument(name = "StyleElem::show", skip_all)]
|
|
fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
|
|
Ok(self.func().call_vt(vt, [styles.to_map().into()])?.display())
|
|
}
|
|
}
|
|
|
|
/// Provides access to the current outer container's (or page's, if none) size
|
|
/// (width and height).
|
|
///
|
|
/// The given function must accept a single parameter, `size`, which is a
|
|
/// dictionary with keys `width` and `height`, both of type
|
|
/// [`length`]($type/length).
|
|
///
|
|
|
|
/// ```example
|
|
/// #let text = lorem(30)
|
|
/// #layout(size => style(styles => [
|
|
/// #let (height,) = measure(
|
|
/// block(width: size.width, text),
|
|
/// styles,
|
|
/// )
|
|
/// This text is #height high with
|
|
/// the current page width: \
|
|
/// #text
|
|
/// ]))
|
|
/// ```
|
|
///
|
|
/// If the `layout` call is placed inside of a box width a width of `{800pt}`
|
|
/// and a height of `{400pt}`, then the specified function will be given the
|
|
/// parameter `{(width: 800pt, height: 400pt)}`. If it placed directly into the
|
|
/// page it receives the page's dimensions minus its margins. This is mostly
|
|
/// useful in combination with [measurement]($func/measure).
|
|
///
|
|
/// You can also use this function to resolve [`ratio`]($type/ratio) to fixed
|
|
/// lengths. This might come in handy if you're building your own layout
|
|
/// abstractions.
|
|
///
|
|
/// ```example
|
|
/// #layout(size => {
|
|
/// let half = 50% * size.width
|
|
/// [Half a page is #half wide.]
|
|
/// })
|
|
/// ```
|
|
///
|
|
/// Note that this function will provide an infinite width or height if one of
|
|
/// the page width or height is `auto`, respectively.
|
|
///
|
|
/// Display: Layout
|
|
/// Category: meta
|
|
/// Returns: content
|
|
#[func]
|
|
pub fn layout(
|
|
/// A function to call with the outer container's size. Its return value is
|
|
/// displayed in the document.
|
|
///
|
|
/// The container's size is given as a [dictionary]($type/dictionary) with
|
|
/// the keys `width` and `height`.
|
|
///
|
|
/// This function is called once for each time the content returned by
|
|
/// `layout` appears in the document. That makes it possible to generate
|
|
/// content that depends on the size of the container it is inside of.
|
|
func: Func,
|
|
) -> Value {
|
|
LayoutElem::new(func).pack().into()
|
|
}
|
|
|
|
/// Executes a `layout` call.
|
|
///
|
|
/// Display: Layout
|
|
/// Category: special
|
|
#[element(Layout)]
|
|
struct LayoutElem {
|
|
/// The function to call with the outer container's (or page's) size.
|
|
#[required]
|
|
func: Func,
|
|
}
|
|
|
|
impl Layout for LayoutElem {
|
|
#[tracing::instrument(name = "LayoutElem::layout", skip_all)]
|
|
fn layout(
|
|
&self,
|
|
vt: &mut Vt,
|
|
styles: StyleChain,
|
|
regions: Regions,
|
|
) -> SourceResult<Fragment> {
|
|
// Gets the current region's base size, which will be the size of the outer container,
|
|
// or of the page if there is no such container.
|
|
let Size { x, y } = regions.base();
|
|
let size_dict = dict! { "width" => x, "height" => y }.into();
|
|
|
|
let result = self
|
|
.func()
|
|
.call_vt(vt, [size_dict])? // calls func(size)
|
|
.display();
|
|
|
|
result.layout(vt, styles, regions)
|
|
}
|
|
}
|