mirror of
https://github.com/typst/typst
synced 2025-05-17 02:25:27 +08:00
87 lines
2.6 KiB
Rust
87 lines
2.6 KiB
Rust
use crate::layout::{LayoutRoot, PageElem};
|
|
use crate::prelude::*;
|
|
|
|
/// The root element of a document and its metadata.
|
|
///
|
|
/// All documents are automatically wrapped in a `document` element. You cannot
|
|
/// create a document element yourself. This function is only used with
|
|
/// [set rules]($styling/#set-rules) to specify document metadata. Such a set
|
|
/// rule must appear before any of the document's contents.
|
|
///
|
|
/// ```example
|
|
/// #set document(title: "Hello")
|
|
///
|
|
/// This has no visible output, but
|
|
/// embeds metadata into the PDF!
|
|
/// ```
|
|
///
|
|
/// Note that metadata set with this function is not rendered within the
|
|
/// document. Instead, it is embedded in the compiled PDF file.
|
|
///
|
|
/// Display: Document
|
|
/// Category: meta
|
|
#[element(Construct, LayoutRoot)]
|
|
pub struct DocumentElem {
|
|
/// The document's title. This is often rendered as the title of the
|
|
/// PDF viewer window.
|
|
pub title: Option<EcoString>,
|
|
|
|
/// The document's authors.
|
|
pub author: Author,
|
|
|
|
/// The page runs.
|
|
#[internal]
|
|
#[variadic]
|
|
pub children: Vec<Content>,
|
|
}
|
|
|
|
impl Construct for DocumentElem {
|
|
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
|
|
bail!(args.span, "can only be used in set rules")
|
|
}
|
|
}
|
|
|
|
impl LayoutRoot for DocumentElem {
|
|
/// Layout the document into a sequence of frames, one per page.
|
|
#[tracing::instrument(name = "DocumentElem::layout_root", skip_all)]
|
|
fn layout_root(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Document> {
|
|
tracing::info!("Document layout");
|
|
|
|
let mut pages = vec![];
|
|
|
|
for mut child in &self.children() {
|
|
let outer = styles;
|
|
let mut styles = styles;
|
|
if let Some((elem, local)) = child.to_styled() {
|
|
styles = outer.chain(local);
|
|
child = elem;
|
|
}
|
|
|
|
if let Some(page) = child.to::<PageElem>() {
|
|
let number = NonZeroUsize::ONE.saturating_add(pages.len());
|
|
let fragment = page.layout(vt, styles, number)?;
|
|
pages.extend(fragment);
|
|
} else {
|
|
bail!(child.span(), "unexpected document child");
|
|
}
|
|
}
|
|
|
|
Ok(Document {
|
|
pages,
|
|
title: self.title(styles),
|
|
author: self.author(styles).0,
|
|
})
|
|
}
|
|
}
|
|
|
|
/// A list of authors.
|
|
#[derive(Debug, Default, Clone, Hash)]
|
|
pub struct Author(Vec<EcoString>);
|
|
|
|
cast! {
|
|
Author,
|
|
self => self.0.into_value(),
|
|
v: EcoString => Self(vec![v]),
|
|
v: Array => Self(v.into_iter().map(Value::cast).collect::<StrResult<_>>()?),
|
|
}
|