diff options
Diffstat (limited to 'src/library')
| -rw-r--r-- | src/library/text/link.rs | 65 | ||||
| -rw-r--r-- | src/library/text/mod.rs | 2 |
2 files changed, 49 insertions, 18 deletions
diff --git a/src/library/text/link.rs b/src/library/text/link.rs index 728b594f..2ce7a469 100644 --- a/src/library/text/link.rs +++ b/src/library/text/link.rs @@ -5,8 +5,8 @@ use crate::util::EcoString; /// Link text and other elements to an URL. #[derive(Debug, Hash)] pub struct LinkNode { - /// The url the link points to. - pub url: EcoString, + /// The destination the link points to. + pub dest: Destination, /// How the link is represented. pub body: Option<Content>, } @@ -17,20 +17,36 @@ impl LinkNode { /// if `auto`. pub const FILL: Smart<Paint> = Smart::Auto; /// Whether to underline link. - pub const UNDERLINE: bool = true; + pub const UNDERLINE: Smart<bool> = Smart::Auto; fn construct(_: &mut Machine, args: &mut Args) -> TypResult<Content> { - Ok(Content::show(Self { - url: args.expect::<EcoString>("url")?, - body: args.eat()?, + Ok(Content::show({ + let dest = args.expect::<Destination>("destination")?; + let body = match dest { + Destination::Url(_) => args.eat()?, + Destination::Internal(_, _) => Some(args.expect("body")?), + }; + Self { dest, body } })) } } +castable! { + Destination, + Expected: "string or dictionary with `page`, `x`, and `y` keys", + Value::Str(string) => Self::Url(string), + Value::Dict(dict) => { + let page: i64 = dict.get(&EcoString::from_str("page"))?.clone().cast()?; + let x: RawLength = dict.get(&EcoString::from_str("x"))?.clone().cast()?; + let y: RawLength = dict.get(&EcoString::from_str("y"))?.clone().cast()?; + Self::Internal(page as usize, Point::new(x.length, y.length)) + }, +} + impl Show for LinkNode { fn unguard(&self, sel: Selector) -> ShowNode { Self { - url: self.url.clone(), + dest: self.dest.clone(), body: self.body.as_ref().map(|body| body.unguard(sel)), } .pack() @@ -38,7 +54,14 @@ impl Show for LinkNode { fn encode(&self, _: StyleChain) -> Dict { dict! { - "url" => Value::Str(self.url.clone()), + "url" => match &self.dest { + Destination::Url(url) => Value::Str(url.clone()), + Destination::Internal(page, point) => Value::Dict(dict!{ + "page" => Value::Int(*page as i64), + "x" => Value::Length(point.x.into()), + "y" => Value::Length(point.y.into()), + }), + }, "body" => match &self.body { Some(body) => Value::Content(body.clone()), None => Value::None, @@ -47,14 +70,16 @@ impl Show for LinkNode { } fn realize(&self, _: &mut Context, _: StyleChain) -> TypResult<Content> { - Ok(self.body.clone().unwrap_or_else(|| { - let url = &self.url; - let mut text = url.as_str(); - for prefix in ["mailto:", "tel:"] { - text = text.trim_start_matches(prefix); + Ok(self.body.clone().unwrap_or_else(|| match &self.dest { + Destination::Url(url) => { + let mut text = url.as_str(); + for prefix in ["mailto:", "tel:"] { + text = text.trim_start_matches(prefix); + } + let shorter = text.len() < url.len(); + Content::Text(if shorter { text.into() } else { url.clone() }) } - let shorter = text.len() < url.len(); - Content::Text(if shorter { text.into() } else { url.clone() }) + Destination::Internal(_, _) => panic!("missing body"), })) } @@ -65,13 +90,19 @@ impl Show for LinkNode { mut realized: Content, ) -> TypResult<Content> { let mut map = StyleMap::new(); - map.set(TextNode::LINK, Some(self.url.clone())); + map.set(TextNode::LINK, Some(self.dest.clone())); if let Smart::Custom(fill) = styles.get(Self::FILL) { map.set(TextNode::FILL, fill); } - if styles.get(Self::UNDERLINE) { + if match styles.get(Self::UNDERLINE) { + Smart::Auto => match &self.dest { + Destination::Url(_) => true, + Destination::Internal(_, _) => false, + }, + Smart::Custom(underline) => underline, + } { realized = realized.underlined(); } diff --git a/src/library/text/mod.rs b/src/library/text/mod.rs index bbe397ca..a1089486 100644 --- a/src/library/text/mod.rs +++ b/src/library/text/mod.rs @@ -122,7 +122,7 @@ impl TextNode { pub const SMALLCAPS: bool = false; /// An URL the text should link to. #[property(skip, referenced)] - pub const LINK: Option<EcoString> = None; + pub const LINK: Option<Destination> = None; /// Decorative lines. #[property(skip, fold)] pub const DECO: Decoration = vec![]; |
