1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
use typst::eval::Datetime;
use crate::layout::{LayoutRoot, PageElem};
use crate::meta::ManualPageCounter;
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.
#[elem(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 document's keywords.
pub keywords: Keywords,
/// The document's creation date.
///
/// If this is `{auto}` (default), Typst uses the current date and time.
/// Setting it to `{none}` prevents Typst from embedding any creation date
/// into the PDF metadata.
///
/// The year component must be at least zero in order to be embedded into a
/// PDF.
pub date: Smart<Option<Datetime>>,
/// 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![];
let mut page_counter = ManualPageCounter::new();
let children = self.children();
let mut iter = children.iter().peekable();
while let Some(mut child) = iter.next() {
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 extend_to = iter.peek().and_then(|&next| {
next.to_styled()
.map_or(next, |(elem, _)| elem)
.to::<PageElem>()?
.clear_to(styles)
});
let fragment = page.layout(vt, styles, &mut page_counter, extend_to)?;
pages.extend(fragment);
} else {
bail!(child.span(), "unexpected document child");
}
}
Ok(Document {
pages,
title: self.title(styles),
author: self.author(styles).0,
keywords: self.keywords(styles).0,
date: self.date(styles),
})
}
}
/// 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<_>>()?),
}
/// A list of keywords.
#[derive(Debug, Default, Clone, Hash)]
pub struct Keywords(Vec<EcoString>);
cast! {
Keywords,
self => self.0.into_value(),
v: EcoString => Self(vec![v]),
v: Array => Self(v.into_iter().map(Value::cast).collect::<StrResult<_>>()?),
}
|