summaryrefslogtreecommitdiff
path: root/library/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-11-26 23:42:40 +0100
committerLaurenz <laurmaedje@gmail.com>2022-11-26 23:52:01 +0100
commit6bafc6391061d4b589dea835705a08b25a4df9f8 (patch)
tree4add85f17fc56da341acfb58a223ea20d80c280a /library/src
parent0579fd4409375aaa9fd8e87a06fd59097b5fcd97 (diff)
Document metadata
Diffstat (limited to 'library/src')
-rw-r--r--library/src/layout/mod.rs37
-rw-r--r--library/src/lib.rs1
-rw-r--r--library/src/prelude.rs2
-rw-r--r--library/src/structure/doc.rs32
-rw-r--r--library/src/structure/document.rs47
-rw-r--r--library/src/structure/mod.rs4
6 files changed, 78 insertions, 45 deletions
diff --git a/library/src/layout/mod.rs b/library/src/layout/mod.rs
index 100e0611..e63a072e 100644
--- a/library/src/layout/mod.rs
+++ b/library/src/layout/mod.rs
@@ -29,7 +29,7 @@ use std::mem;
use comemo::Tracked;
use typed_arena::Arena;
use typst::diag::SourceResult;
-use typst::frame::Frame;
+use typst::doc::Frame;
use typst::geom::*;
use typst::model::{
applicable, capability, realize, Content, Node, SequenceNode, Style, StyleChain,
@@ -40,7 +40,7 @@ use typst::World;
use crate::prelude::*;
use crate::shared::BehavedBuilder;
use crate::structure::{
- DescNode, DocNode, EnumNode, ListItem, ListNode, DESC, ENUM, LIST,
+ DescNode, DocumentNode, EnumNode, ListItem, ListNode, DESC, ENUM, LIST,
};
use crate::text::{
LinebreakNode, ParNode, ParbreakNode, SmartQuoteNode, SpaceNode, TextNode,
@@ -54,7 +54,7 @@ pub trait LayoutRoot {
&self,
world: Tracked<dyn World>,
styles: StyleChain,
- ) -> SourceResult<Vec<Frame>>;
+ ) -> SourceResult<Document>;
}
impl LayoutRoot for Content {
@@ -63,7 +63,7 @@ impl LayoutRoot for Content {
&self,
world: Tracked<dyn World>,
styles: StyleChain,
- ) -> SourceResult<Vec<Frame>> {
+ ) -> SourceResult<Document> {
let scratch = Scratch::default();
let (realized, styles) = realize_root(world, &scratch, self, styles)?;
realized.with::<dyn LayoutRoot>().unwrap().layout_root(world, styles)
@@ -245,7 +245,7 @@ fn realize_root<'a>(
builder.accept(content, styles)?;
builder.interrupt_page(Some(styles))?;
let (pages, shared) = builder.doc.unwrap().pages.finish();
- Ok((DocNode(pages).pack(), shared))
+ Ok((DocumentNode(pages).pack(), shared))
}
/// Realize into a node that is capable of block-level layout.
@@ -357,6 +357,10 @@ impl<'a> Builder<'a> {
}
}
+ if let Some(span) = content.span() {
+ bail!(span, "not allowed here");
+ }
+
Ok(())
}
@@ -378,13 +382,26 @@ impl<'a> Builder<'a> {
map: &StyleMap,
styles: Option<StyleChain<'a>>,
) -> SourceResult<()> {
- if map.interrupts::<PageNode>() {
+ if let Some(Some(span)) = map.interruption::<DocumentNode>() {
+ if self.doc.is_none() {
+ bail!(span, "not allowed here");
+ }
+ if !self.flow.0.is_empty()
+ || !self.par.0.is_empty()
+ || !self.list.items.is_empty()
+ {
+ bail!(span, "must appear before any content");
+ }
+ } else if let Some(Some(span)) = map.interruption::<PageNode>() {
+ if self.doc.is_none() {
+ bail!(span, "not allowed here");
+ }
self.interrupt_page(styles)?;
- } else if map.interrupts::<ParNode>() {
+ } else if map.interruption::<ParNode>().is_some() {
self.interrupt_par()?;
- } else if map.interrupts::<ListNode>()
- || map.interrupts::<EnumNode>()
- || map.interrupts::<DescNode>()
+ } else if map.interruption::<ListNode>().is_some()
+ || map.interruption::<EnumNode>().is_some()
+ || map.interruption::<DescNode>().is_some()
{
self.interrupt_list()?;
}
diff --git a/library/src/lib.rs b/library/src/lib.rs
index 6107cf42..cf8cb490 100644
--- a/library/src/lib.rs
+++ b/library/src/lib.rs
@@ -44,6 +44,7 @@ fn scope() -> Scope {
std.def_fn("smallcaps", text::smallcaps);
// Structure.
+ std.def_node::<structure::DocumentNode>("document");
std.def_node::<structure::RefNode>("ref");
std.def_node::<structure::HeadingNode>("heading");
std.def_node::<structure::ListNode>("list");
diff --git a/library/src/prelude.rs b/library/src/prelude.rs
index 6379e579..bc0ec31d 100644
--- a/library/src/prelude.rs
+++ b/library/src/prelude.rs
@@ -10,7 +10,7 @@ pub use comemo::Tracked;
#[doc(no_inline)]
pub use typst::diag::{bail, error, with_alternative, At, SourceResult, StrResult};
#[doc(no_inline)]
-pub use typst::frame::*;
+pub use typst::doc::*;
#[doc(no_inline)]
pub use typst::geom::*;
#[doc(no_inline)]
diff --git a/library/src/structure/doc.rs b/library/src/structure/doc.rs
deleted file mode 100644
index e471a852..00000000
--- a/library/src/structure/doc.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-use crate::layout::{LayoutRoot, PageNode};
-use crate::prelude::*;
-
-/// A sequence of page runs.
-#[derive(Hash)]
-pub struct DocNode(pub StyleVec<PageNode>);
-
-#[node(LayoutRoot)]
-impl DocNode {}
-
-impl LayoutRoot for DocNode {
- /// Layout the document into a sequence of frames, one per page.
- fn layout_root(
- &self,
- world: Tracked<dyn World>,
- styles: StyleChain,
- ) -> SourceResult<Vec<Frame>> {
- let mut frames = vec![];
- for (page, map) in self.0.iter() {
- let number = 1 + frames.len();
- frames.extend(page.layout(world, number, styles.chain(map))?);
- }
- Ok(frames)
- }
-}
-
-impl Debug for DocNode {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.write_str("Doc ")?;
- self.0.fmt(f)
- }
-}
diff --git a/library/src/structure/document.rs b/library/src/structure/document.rs
new file mode 100644
index 00000000..2e5761e0
--- /dev/null
+++ b/library/src/structure/document.rs
@@ -0,0 +1,47 @@
+use crate::layout::{LayoutRoot, PageNode};
+use crate::prelude::*;
+
+/// The root node of the model.
+#[derive(Hash)]
+pub struct DocumentNode(pub StyleVec<PageNode>);
+
+#[node(LayoutRoot)]
+impl DocumentNode {
+ /// The document's title.
+ #[property(referenced)]
+ pub const TITLE: Option<EcoString> = None;
+
+ /// The document's author.
+ #[property(referenced)]
+ pub const AUTHOR: Option<EcoString> = None;
+}
+
+impl LayoutRoot for DocumentNode {
+ /// Layout the document into a sequence of frames, one per page.
+ fn layout_root(
+ &self,
+ world: Tracked<dyn World>,
+ styles: StyleChain,
+ ) -> SourceResult<Document> {
+ let mut pages = vec![];
+ for (page, map) in self.0.iter() {
+ let number = 1 + pages.len();
+ pages.extend(page.layout(world, number, styles.chain(map))?);
+ }
+
+ Ok(Document {
+ metadata: Metadata {
+ title: styles.get(Self::TITLE).clone(),
+ author: styles.get(Self::AUTHOR).clone(),
+ },
+ pages,
+ })
+ }
+}
+
+impl Debug for DocumentNode {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ f.write_str("Document ")?;
+ self.0.fmt(f)
+ }
+}
diff --git a/library/src/structure/mod.rs b/library/src/structure/mod.rs
index 8e13f76a..a1c27eed 100644
--- a/library/src/structure/mod.rs
+++ b/library/src/structure/mod.rs
@@ -1,12 +1,12 @@
//! Document structuring.
-mod doc;
+mod document;
mod heading;
mod list;
mod reference;
mod table;
-pub use self::doc::*;
+pub use self::document::*;
pub use self::heading::*;
pub use self::list::*;
pub use self::reference::*;