summaryrefslogtreecommitdiff
path: root/crates/typst-library/src/meta/document.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-07-02 19:59:52 +0200
committerLaurenz <laurmaedje@gmail.com>2023-07-02 20:07:43 +0200
commitebfdb1dafa430786db10dad2ef7d5467c1bdbed1 (patch)
tree2bbc24ddb4124c4bb14dec0e536129d4de37b056 /crates/typst-library/src/meta/document.rs
parent3ab19185093d7709f824b95b979060ce125389d8 (diff)
Move everything into `crates/` directory
Diffstat (limited to 'crates/typst-library/src/meta/document.rs')
-rw-r--r--crates/typst-library/src/meta/document.rs86
1 files changed, 86 insertions, 0 deletions
diff --git a/crates/typst-library/src/meta/document.rs b/crates/typst-library/src/meta/document.rs
new file mode 100644
index 00000000..db036e0a
--- /dev/null
+++ b/crates/typst-library/src/meta/document.rs
@@ -0,0 +1,86 @@
+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<_>>()?),
+}