diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-11-29 13:37:25 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-11-29 14:18:13 +0100 |
| commit | 0efe669278a5e1c3f2985eba2f3360e91159c54a (patch) | |
| tree | 502712857c48f0decb5e698257c0a96d358a436e /library/src/meta | |
| parent | 836692e73cff0356e409a9ba5b4887b86809d4ca (diff) | |
Reorganize library and tests
Diffstat (limited to 'library/src/meta')
| -rw-r--r-- | library/src/meta/document.rs | 48 | ||||
| -rw-r--r-- | library/src/meta/link.rs | 66 | ||||
| -rw-r--r-- | library/src/meta/mod.rs | 9 | ||||
| -rw-r--r-- | library/src/meta/reference.rs | 26 |
4 files changed, 149 insertions, 0 deletions
diff --git a/library/src/meta/document.rs b/library/src/meta/document.rs new file mode 100644 index 00000000..309e1bda --- /dev/null +++ b/library/src/meta/document.rs @@ -0,0 +1,48 @@ +use crate::layout::{LayoutRoot, PageNode}; +use crate::prelude::*; + +/// The root node that represents a full document. +#[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(); + let fragment = page.layout(world, number, styles.chain(map))?; + pages.extend(fragment); + } + + 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/meta/link.rs b/library/src/meta/link.rs new file mode 100644 index 00000000..44da9c5d --- /dev/null +++ b/library/src/meta/link.rs @@ -0,0 +1,66 @@ +use crate::prelude::*; +use crate::text::TextNode; + +/// Link text and other elements to a destination. +#[derive(Debug, Hash)] +pub struct LinkNode { + /// The destination the link points to. + pub dest: Destination, + /// How the link is represented. + pub body: Content, +} + +impl LinkNode { + /// Create a link node from a URL with its bare text. + pub fn from_url(url: EcoString) -> Self { + let mut text = url.as_str(); + for prefix in ["mailto:", "tel:"] { + text = text.trim_start_matches(prefix); + } + let shorter = text.len() < url.len(); + let body = TextNode::packed(if shorter { text.into() } else { url.clone() }); + Self { dest: Destination::Url(url), body } + } +} + +#[node(Show, Finalize)] +impl LinkNode { + /// A destination the text should be linked to. + #[property(skip, referenced)] + pub(crate) const DEST: Option<Destination> = None; + + fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> { + let dest = args.expect::<Destination>("destination")?; + Ok(match dest { + Destination::Url(url) => match args.eat()? { + Some(body) => Self { dest: Destination::Url(url), body }, + None => Self::from_url(url), + }, + Destination::Internal(_) => Self { dest, body: args.expect("body")? }, + } + .pack()) + } + + fn field(&self, name: &str) -> Option<Value> { + match name { + "url" => Some(match &self.dest { + Destination::Url(url) => Value::Str(url.clone().into()), + Destination::Internal(loc) => Value::Dict(loc.encode()), + }), + "body" => Some(Value::Content(self.body.clone())), + _ => None, + } + } +} + +impl Show for LinkNode { + fn show(&self, _: Tracked<dyn World>, _: StyleChain) -> Content { + self.body.clone() + } +} + +impl Finalize for LinkNode { + fn finalize(&self, realized: Content) -> Content { + realized.styled(Self::DEST, Some(self.dest.clone())) + } +} diff --git a/library/src/meta/mod.rs b/library/src/meta/mod.rs new file mode 100644 index 00000000..31a69ccc --- /dev/null +++ b/library/src/meta/mod.rs @@ -0,0 +1,9 @@ +//! Interaction between document parts. + +mod document; +mod link; +mod reference; + +pub use self::document::*; +pub use self::link::*; +pub use self::reference::*; diff --git a/library/src/meta/reference.rs b/library/src/meta/reference.rs new file mode 100644 index 00000000..948aa6f6 --- /dev/null +++ b/library/src/meta/reference.rs @@ -0,0 +1,26 @@ +use crate::prelude::*; +use crate::text::TextNode; + +/// A reference to a label. +#[derive(Debug, Hash)] +pub struct RefNode(pub EcoString); + +#[node(Show)] +impl RefNode { + fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> { + Ok(Self(args.expect("target")?).pack()) + } + + fn field(&self, name: &str) -> Option<Value> { + match name { + "target" => Some(Value::Str(self.0.clone().into())), + _ => None, + } + } +} + +impl Show for RefNode { + fn show(&self, _: Tracked<dyn World>, _: StyleChain) -> Content { + TextNode::packed(format_eco!("@{}", self.0)) + } +} |
