summaryrefslogtreecommitdiff
path: root/library
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-11-08 11:45:54 +0100
committerLaurenz <laurmaedje@gmail.com>2022-11-08 11:45:59 +0100
commita7a4cae2948176119e8995bd8e1868f2d0e65029 (patch)
tree123e8867c939373c1c5ce5a0d20f55192c2467c2 /library
parent0a41844cc4e645e87fe48aa31ed3a4fd40a6ab11 (diff)
Less style properties
Diffstat (limited to 'library')
-rw-r--r--library/src/math/mod.rs30
-rw-r--r--library/src/math/tex.rs19
-rw-r--r--library/src/structure/heading.rs72
-rw-r--r--library/src/text/link.rs71
-rw-r--r--library/src/text/raw.rs13
-rw-r--r--library/src/text/shaping.rs2
6 files changed, 72 insertions, 135 deletions
diff --git a/library/src/math/mod.rs b/library/src/math/mod.rs
index a89b4953..ae3c4a9a 100644
--- a/library/src/math/mod.rs
+++ b/library/src/math/mod.rs
@@ -7,7 +7,7 @@ use std::fmt::Write;
use self::tex::{layout_tex, Texify};
use crate::layout::BlockSpacing;
use crate::prelude::*;
-use crate::text::FontFamily;
+use crate::text::{FallbackList, FontFamily, TextNode};
/// A piece of a mathematical formula.
#[derive(Debug, Clone, Hash)]
@@ -20,9 +20,6 @@ pub struct MathNode {
#[node(Show, Finalize, LayoutInline, Texify)]
impl MathNode {
- /// The math font family.
- #[property(referenced)]
- pub const FAMILY: FontFamily = FontFamily::new("NewComputerModernMath");
/// The spacing above display math.
#[property(resolve, shorthand(around))]
pub const ABOVE: Option<BlockSpacing> = Some(Ratio::one().into());
@@ -44,11 +41,7 @@ impl Show for MathNode {
}
fn show(&self, _: Tracked<dyn World>, _: StyleChain) -> SourceResult<Content> {
- Ok(if self.display {
- self.clone().pack().aligned(Axes::with_x(Some(Align::Center.into())))
- } else {
- self.clone().pack()
- })
+ Ok(self.clone().pack())
}
}
@@ -57,13 +50,20 @@ impl Finalize for MathNode {
&self,
_: Tracked<dyn World>,
styles: StyleChain,
- realized: Content,
+ mut realized: Content,
) -> SourceResult<Content> {
- Ok(if self.display {
- realized.spaced(styles.get(Self::ABOVE), styles.get(Self::BELOW))
- } else {
- realized
- })
+ realized = realized.styled(
+ TextNode::FAMILY,
+ FallbackList(vec![FontFamily::new("NewComputerModernMath")]),
+ );
+
+ if self.display {
+ realized = realized
+ .aligned(Axes::with_x(Some(Align::Center.into())))
+ .spaced(styles.get(Self::ABOVE), styles.get(Self::BELOW))
+ }
+
+ Ok(realized)
}
}
diff --git a/library/src/math/tex.rs b/library/src/math/tex.rs
index 7de68d7b..f924ebbe 100644
--- a/library/src/math/tex.rs
+++ b/library/src/math/tex.rs
@@ -5,9 +5,8 @@ use rex::parser::color::RGBA;
use rex::render::{Backend, Cursor, Renderer};
use typst::font::Font;
-use super::MathNode;
use crate::prelude::*;
-use crate::text::{variant, LinebreakNode, SpaceNode, TextNode};
+use crate::text::{families, variant, LinebreakNode, SpaceNode, TextNode};
/// Turn a math node into TeX math code.
#[capability]
@@ -42,17 +41,21 @@ pub fn layout_tex(
styles: StyleChain,
) -> SourceResult<Frame> {
// Load the font.
- let font = world
- .book()
- .select(styles.get(MathNode::FAMILY).as_str(), variant(styles))
- .and_then(|id| world.font(id))
- .expect("failed to find math font");
+ let variant = variant(styles);
+ let mut font = None;
+ for family in families(styles) {
+ font = world.book().select(family, variant).and_then(|id| world.font(id));
+ if font.as_ref().map_or(false, |font| font.math().is_some()) {
+ break;
+ }
+ }
// Prepare the font context.
+ let font = font.expect("failed to find suitable math font");
let ctx = font
.math()
.map(|math| FontContext::new(font.ttf(), math))
- .expect("font is not suitable for math");
+ .expect("failed to create font context");
// Layout the formula.
let em = styles.get(TextNode::SIZE);
diff --git a/library/src/structure/heading.rs b/library/src/structure/heading.rs
index f93be5d9..fe9b9013 100644
--- a/library/src/structure/heading.rs
+++ b/library/src/structure/heading.rs
@@ -1,6 +1,8 @@
+use typst::font::FontWeight;
+
use crate::layout::{BlockNode, BlockSpacing};
use crate::prelude::*;
-use crate::text::{FontFamily, TextNode, TextSize};
+use crate::text::{TextNode, TextSize};
/// A section heading.
#[derive(Debug, Hash)]
@@ -14,32 +16,10 @@ pub struct HeadingNode {
#[node(Show, Finalize)]
impl HeadingNode {
- /// The heading's font family. Just the normal text family if `auto`.
- #[property(referenced)]
- pub const FAMILY: Leveled<Smart<FontFamily>> = Leveled::Value(Smart::Auto);
- /// The color of text in the heading. Just the normal text color if `auto`.
- #[property(referenced)]
- pub const FILL: Leveled<Smart<Paint>> = Leveled::Value(Smart::Auto);
- /// The size of text in the heading.
- #[property(referenced)]
- pub const SIZE: Leveled<TextSize> = Leveled::Mapping(|level| {
- let size = match level.get() {
- 1 => 1.4,
- 2 => 1.2,
- _ => 1.0,
- };
- TextSize(Em::new(size).into())
- });
-
- /// Whether text in the heading is strengthend.
- #[property(referenced)]
- pub const STRONG: Leveled<bool> = Leveled::Value(true);
- /// Whether text in the heading is emphasized.
- #[property(referenced)]
- pub const EMPH: Leveled<bool> = Leveled::Value(false);
- /// Whether the heading is underlined.
- #[property(referenced)]
- pub const UNDERLINE: Leveled<bool> = Leveled::Value(false);
+ /// Whether the heading appears in the outline.
+ pub const OUTLINED: bool = true;
+ /// Whether the heading is numbered.
+ pub const NUMBERED: bool = true;
/// The spacing above the heading.
#[property(referenced, shorthand(around))]
@@ -55,11 +35,6 @@ impl HeadingNode {
pub const BELOW: Leveled<Option<BlockSpacing>> =
Leveled::Value(Some(Ratio::new(0.55).into()));
- /// Whether the heading appears in the outline.
- pub const OUTLINED: bool = true;
- /// Whether the heading is numbered.
- pub const NUMBERED: bool = true;
-
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
Ok(Self {
body: args.expect("body")?,
@@ -101,30 +76,17 @@ impl Finalize for HeadingNode {
}
let mut map = StyleMap::new();
- map.set(TextNode::SIZE, resolve!(Self::SIZE));
-
- if let Smart::Custom(family) = resolve!(Self::FAMILY) {
- map.set_family(family, styles);
- }
-
- if let Smart::Custom(fill) = resolve!(Self::FILL) {
- map.set(TextNode::FILL, fill);
- }
-
- if resolve!(Self::STRONG) {
- realized = realized.strong();
- }
-
- if resolve!(Self::EMPH) {
- realized = realized.emph();
- }
-
- if resolve!(Self::UNDERLINE) {
- realized = realized.underlined();
- }
+ map.set(TextNode::SIZE, {
+ let size = match self.level.get() {
+ 1 => 1.4,
+ 2 => 1.2,
+ _ => 1.0,
+ };
+ TextSize(Em::new(size).into())
+ });
+ map.set(TextNode::WEIGHT, FontWeight::BOLD);
- realized = realized.styled_with_map(map);
- realized = realized.spaced(
+ realized = realized.styled_with_map(map).spaced(
resolve!(Self::ABOVE).resolve(styles),
resolve!(Self::BELOW).resolve(styles),
);
diff --git a/library/src/text/link.rs b/library/src/text/link.rs
index b74ca530..acd37df6 100644
--- a/library/src/text/link.rs
+++ b/library/src/text/link.rs
@@ -7,31 +7,34 @@ pub struct LinkNode {
/// The destination the link points to.
pub dest: Destination,
/// How the link is represented.
- pub body: Option<Content>,
+ pub body: Content,
}
impl LinkNode {
/// Create a link node from a URL with its bare text.
pub fn from_url(url: EcoString) -> Self {
- Self { dest: Destination::Url(url), body: None }
+ 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 {
- /// The fill color of text in the link. Just the surrounding text color
- /// if `auto`.
- pub const FILL: Smart<Paint> = Smart::Auto;
- /// Whether to underline the link.
- pub const UNDERLINE: Smart<bool> = Smart::Auto;
-
fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
let dest = args.expect::<Destination>("destination")?;
- let body = match dest {
- Destination::Url(_) => args.eat()?,
- Destination::Internal(_) => Some(args.expect("body")?),
- };
- Ok(Self { dest, body }.pack())
+ 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> {
@@ -40,10 +43,7 @@ impl LinkNode {
Destination::Url(url) => Value::Str(url.clone().into()),
Destination::Internal(loc) => Value::Dict(loc.encode()),
}),
- "body" => Some(match &self.body {
- Some(body) => Value::Content(body.clone()),
- None => Value::None,
- }),
+ "body" => Some(Value::Content(self.body.clone())),
_ => None,
}
}
@@ -53,23 +53,13 @@ impl Show for LinkNode {
fn unguard_parts(&self, id: RecipeId) -> Content {
Self {
dest: self.dest.clone(),
- body: self.body.as_ref().map(|body| body.unguard(id)),
+ body: self.body.unguard(id),
}
.pack()
}
fn show(&self, _: Tracked<dyn World>, _: StyleChain) -> SourceResult<Content> {
- 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();
- TextNode::packed(if shorter { text.into() } else { url.clone() })
- }
- Destination::Internal(_) => Content::empty(),
- }))
+ Ok(self.body.clone())
}
}
@@ -77,26 +67,9 @@ impl Finalize for LinkNode {
fn finalize(
&self,
_: Tracked<dyn World>,
- styles: StyleChain,
- mut realized: Content,
+ _: StyleChain,
+ realized: Content,
) -> SourceResult<Content> {
- let mut map = StyleMap::new();
- map.set(TextNode::LINK, Some(self.dest.clone()));
-
- if let Smart::Custom(fill) = styles.get(Self::FILL) {
- map.set(TextNode::FILL, fill);
- }
-
- if match styles.get(Self::UNDERLINE) {
- Smart::Auto => match &self.dest {
- Destination::Url(_) => true,
- Destination::Internal(_) => false,
- },
- Smart::Custom(underline) => underline,
- } {
- realized = realized.underlined();
- }
-
- Ok(realized.styled_with_map(map))
+ Ok(realized.styled(TextNode::LINK, Some(self.dest.clone())))
}
}
diff --git a/library/src/text/raw.rs b/library/src/text/raw.rs
index c6229d59..2041b25e 100644
--- a/library/src/text/raw.rs
+++ b/library/src/text/raw.rs
@@ -6,7 +6,7 @@ use syntect::highlighting::{
use syntect::parsing::SyntaxSet;
use typst::syntax;
-use super::{FontFamily, Hyphenate, LinebreakNode, TextNode};
+use super::{FallbackList, FontFamily, Hyphenate, LinebreakNode, TextNode};
use crate::layout::{BlockNode, BlockSpacing};
use crate::prelude::*;
@@ -24,9 +24,6 @@ impl RawNode {
/// The language to syntax-highlight in.
#[property(referenced)]
pub const LANG: Option<EcoString> = None;
- /// The raw text's font family.
- #[property(referenced)]
- pub const FAMILY: FontFamily = FontFamily::new("IBM Plex Mono");
/// The spacing above block-level raw.
#[property(resolve, shorthand(around))]
pub const ABOVE: Option<BlockSpacing> = Some(Ratio::one().into());
@@ -119,14 +116,16 @@ impl Finalize for RawNode {
styles: StyleChain,
mut realized: Content,
) -> SourceResult<Content> {
- let mut map = StyleMap::new();
- map.set_family(styles.get(Self::FAMILY).clone(), styles);
+ realized = realized.styled(
+ TextNode::FAMILY,
+ FallbackList(vec![FontFamily::new("IBM Plex Mono")]),
+ );
if self.block {
realized = realized.spaced(styles.get(Self::ABOVE), styles.get(Self::BELOW));
}
- Ok(realized.styled_with_map(map))
+ Ok(realized)
}
}
diff --git a/library/src/text/shaping.rs b/library/src/text/shaping.rs
index b67ce411..ac7218a0 100644
--- a/library/src/text/shaping.rs
+++ b/library/src/text/shaping.rs
@@ -552,7 +552,7 @@ pub fn variant(styles: StyleChain) -> FontVariant {
}
/// Resolve a prioritized iterator over the font families.
-fn families(styles: StyleChain) -> impl Iterator<Item = &str> + Clone {
+pub fn families(styles: StyleChain) -> impl Iterator<Item = &str> + Clone {
const FALLBACKS: &[&str] = &[
"ibm plex sans",
"twitter color emoji",