summaryrefslogtreecommitdiff
path: root/src/library/text
diff options
context:
space:
mode:
authorMartin Haug <mhaug@live.de>2022-05-27 12:56:20 +0200
committerMartin Haug <mhaug@live.de>2022-05-27 12:56:20 +0200
commit99cb655832161d4ebec73273a15453a8f6acc1b7 (patch)
tree9eb6328dda9cef5ba4b436465cebfca5b7bec076 /src/library/text
parent0170913d5413aab4c1f2bd7d56b9b7138f676012 (diff)
Intra-document links
Diffstat (limited to 'src/library/text')
-rw-r--r--src/library/text/link.rs65
-rw-r--r--src/library/text/mod.rs2
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![];