summaryrefslogtreecommitdiff
path: root/src/library
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-12-16 14:43:02 +0100
committerLaurenz <laurmaedje@gmail.com>2021-12-16 14:43:02 +0100
commit958f74f77707340f34ee36d09492bdb74523aa2a (patch)
tree4ab59a7a532c8023a5e8bb4c9a6090886cb4e538 /src/library
parent2a3d0f4b390457174ed09347dd29e97ff9a783e4 (diff)
Set Rules Episode VIII: The First Macro
Diffstat (limited to 'src/library')
-rw-r--r--src/library/flow.rs5
-rw-r--r--src/library/link.rs7
-rw-r--r--src/library/mod.rs3
-rw-r--r--src/library/page.rs49
-rw-r--r--src/library/par.rs32
-rw-r--r--src/library/text.rs117
6 files changed, 107 insertions, 106 deletions
diff --git a/src/library/flow.rs b/src/library/flow.rs
index de6ab812..cfa761b6 100644
--- a/src/library/flow.rs
+++ b/src/library/flow.rs
@@ -134,9 +134,8 @@ impl<'a> FlowLayouter<'a> {
match child {
FlowChild::Break(styles) => {
let chain = styles.chain(&ctx.styles);
- let amount = chain
- .get(ParNode::SPACING)
- .resolve(chain.get(TextNode::SIZE).abs);
+ let em = chain.get(TextNode::SIZE).abs;
+ let amount = chain.get(ParNode::SPACING).resolve(em);
self.layout_absolute(amount.into());
}
FlowChild::Spacing(node) => match node.kind {
diff --git a/src/library/link.rs b/src/library/link.rs
index 114d25a1..40604a62 100644
--- a/src/library/link.rs
+++ b/src/library/link.rs
@@ -21,9 +21,8 @@ pub fn link(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
#[derive(Debug, Hash)]
pub struct LinkNode;
-properties! {
- LinkNode,
-
+#[properties]
+impl LinkNode {
/// An URL to link to.
- URL: Option<String> = None,
+ pub const URL: Option<String> = None;
}
diff --git a/src/library/mod.rs b/src/library/mod.rs
index 1e2ee224..5852f2bb 100644
--- a/src/library/mod.rs
+++ b/src/library/mod.rs
@@ -26,6 +26,8 @@ mod prelude {
pub use std::fmt::{self, Debug, Formatter};
pub use std::rc::Rc;
+ pub use typst_macros::properties;
+
pub use crate::diag::{At, TypResult};
pub use crate::eval::{
Args, Construct, EvalContext, Node, Property, Set, Smart, Styles, Value,
@@ -80,6 +82,7 @@ pub fn new() -> Scope {
std.def_func("block", block);
std.def_func("pagebreak", pagebreak);
std.def_func("parbreak", parbreak);
+ std.def_func("linebreak", linebreak);
std.def_func("stack", stack);
std.def_func("grid", grid);
std.def_func("pad", pad);
diff --git a/src/library/page.rs b/src/library/page.rs
index 0b0cc2d9..3bb5cbd3 100644
--- a/src/library/page.rs
+++ b/src/library/page.rs
@@ -20,27 +20,26 @@ pub struct PageNode {
pub styles: Styles,
}
-properties! {
- PageNode,
-
+#[properties]
+impl PageNode {
/// The unflipped width of the page.
- WIDTH: Smart<Length> = Smart::Custom(Paper::default().width()),
+ pub const WIDTH: Smart<Length> = Smart::Custom(Paper::default().width());
/// The unflipped height of the page.
- HEIGHT: Smart<Length> = Smart::Custom(Paper::default().height()),
+ pub const HEIGHT: Smart<Length> = Smart::Custom(Paper::default().height());
/// The class of paper. Defines the default margins.
- CLASS: PaperClass = Paper::default().class(),
+ pub const CLASS: PaperClass = Paper::default().class();
/// Whether the page is flipped into landscape orientation.
- FLIPPED: bool = false,
+ pub const FLIPPED: bool = false;
/// The left margin.
- LEFT: Smart<Linear> = Smart::Auto,
+ pub const LEFT: Smart<Linear> = Smart::Auto;
/// The right margin.
- RIGHT: Smart<Linear> = Smart::Auto,
+ pub const RIGHT: Smart<Linear> = Smart::Auto;
/// The top margin.
- TOP: Smart<Linear> = Smart::Auto,
+ pub const TOP: Smart<Linear> = Smart::Auto;
/// The bottom margin.
- BOTTOM: Smart<Linear> = Smart::Auto,
+ pub const BOTTOM: Smart<Linear> = Smart::Auto;
/// The page's background color.
- FILL: Option<Paint> = None,
+ pub const FILL: Option<Paint> = None;
}
impl Construct for PageNode {
@@ -54,29 +53,29 @@ impl Construct for PageNode {
impl Set for PageNode {
fn set(styles: &mut Styles, args: &mut Args) -> TypResult<()> {
if let Some(paper) = args.named::<Paper>("paper")?.or_else(|| args.find()) {
- styles.set(PageNode::CLASS, paper.class());
- styles.set(PageNode::WIDTH, Smart::Custom(paper.width()));
- styles.set(PageNode::HEIGHT, Smart::Custom(paper.height()));
+ styles.set(Self::CLASS, paper.class());
+ styles.set(Self::WIDTH, Smart::Custom(paper.width()));
+ styles.set(Self::HEIGHT, Smart::Custom(paper.height()));
}
if let Some(width) = args.named("width")? {
- styles.set(PageNode::CLASS, PaperClass::Custom);
- styles.set(PageNode::WIDTH, width);
+ styles.set(Self::CLASS, PaperClass::Custom);
+ styles.set(Self::WIDTH, width);
}
if let Some(height) = args.named("height")? {
- styles.set(PageNode::CLASS, PaperClass::Custom);
- styles.set(PageNode::HEIGHT, height);
+ styles.set(Self::CLASS, PaperClass::Custom);
+ styles.set(Self::HEIGHT, height);
}
let margins = args.named("margins")?;
- set!(styles, PageNode::FLIPPED => args.named("flipped")?);
- set!(styles, PageNode::LEFT => args.named("left")?.or(margins));
- set!(styles, PageNode::TOP => args.named("top")?.or(margins));
- set!(styles, PageNode::RIGHT => args.named("right")?.or(margins));
- set!(styles, PageNode::BOTTOM => args.named("bottom")?.or(margins));
- set!(styles, PageNode::FILL => args.named("fill")?);
+ set!(styles, Self::FLIPPED => args.named("flipped")?);
+ set!(styles, Self::LEFT => args.named("left")?.or(margins));
+ set!(styles, Self::TOP => args.named("top")?.or(margins));
+ set!(styles, Self::RIGHT => args.named("right")?.or(margins));
+ set!(styles, Self::BOTTOM => args.named("bottom")?.or(margins));
+ set!(styles, Self::FILL => args.named("fill")?);
Ok(())
}
diff --git a/src/library/par.rs b/src/library/par.rs
index d63c2315..9a70b2c7 100644
--- a/src/library/par.rs
+++ b/src/library/par.rs
@@ -14,21 +14,25 @@ pub fn parbreak(_: &mut EvalContext, _: &mut Args) -> TypResult<Value> {
Ok(Value::Node(Node::Parbreak))
}
+/// `linebreak`: Start a new line.
+pub fn linebreak(_: &mut EvalContext, _: &mut Args) -> TypResult<Value> {
+ Ok(Value::Node(Node::Linebreak))
+}
+
/// A node that arranges its children into a paragraph.
#[derive(Hash)]
pub struct ParNode(pub Vec<ParChild>);
-properties! {
- ParNode,
-
+#[properties]
+impl ParNode {
/// The direction for text and inline objects.
- DIR: Dir = Dir::LTR,
+ pub const DIR: Dir = Dir::LTR;
/// How to align text and inline objects in their line.
- ALIGN: Align = Align::Left,
+ pub const ALIGN: Align = Align::Left;
/// The spacing between lines (dependent on scaled font size).
- LEADING: Linear = Relative::new(0.65).into(),
+ pub const LEADING: Linear = Relative::new(0.65).into();
/// The spacing between paragraphs (dependent on scaled font size).
- SPACING: Linear = Relative::new(1.2).into(),
+ pub const SPACING: Linear = Relative::new(1.2).into();
}
impl Construct for ParNode {
@@ -70,10 +74,10 @@ impl Set for ParNode {
align = Some(if dir == Dir::LTR { Align::Left } else { Align::Right });
}
- set!(styles, ParNode::DIR => dir);
- set!(styles, ParNode::ALIGN => align);
- set!(styles, ParNode::LEADING => leading);
- set!(styles, ParNode::SPACING => spacing);
+ set!(styles, Self::DIR => dir);
+ set!(styles, Self::ALIGN => align);
+ set!(styles, Self::LEADING => leading);
+ set!(styles, Self::SPACING => spacing);
Ok(())
}
@@ -266,11 +270,9 @@ impl<'a> ParLayouter<'a> {
}
}
+ let em = ctx.styles.get(TextNode::SIZE).abs;
let align = ctx.styles.get(ParNode::ALIGN);
- let leading = ctx
- .styles
- .get(ParNode::LEADING)
- .resolve(ctx.styles.get(TextNode::SIZE).abs);
+ let leading = ctx.styles.get(ParNode::LEADING).resolve(em);
Self { align, leading, bidi, items, ranges }
}
diff --git a/src/library/text.rs b/src/library/text.rs
index 4baf4bc5..e0cbb1ad 100644
--- a/src/library/text.rs
+++ b/src/library/text.rs
@@ -51,77 +51,76 @@ pub struct TextNode {
pub styles: Styles,
}
-properties! {
- TextNode,
-
+#[properties]
+impl TextNode {
/// A prioritized sequence of font families.
- FAMILY_LIST: Vec<FontFamily> = vec![FontFamily::SansSerif],
+ pub const FAMILY_LIST: Vec<FontFamily> = vec![FontFamily::SansSerif];
/// The serif font family/families.
- SERIF_LIST: Vec<String> = vec!["ibm plex serif".into()],
+ pub const SERIF_LIST: Vec<String> = vec!["ibm plex serif".into()];
/// The sans-serif font family/families.
- SANS_SERIF_LIST: Vec<String> = vec!["ibm plex sans".into()],
+ pub const SANS_SERIF_LIST: Vec<String> = vec!["ibm plex sans".into()];
/// The monospace font family/families.
- MONOSPACE_LIST: Vec<String> = vec!["ibm plex mono".into()],
+ pub const MONOSPACE_LIST: Vec<String> = vec!["ibm plex mono".into()];
/// Whether to allow font fallback when the primary font list contains no
/// match.
- FALLBACK: bool = true,
+ pub const FALLBACK: bool = true;
/// How the font is styled.
- STYLE: FontStyle = FontStyle::Normal,
+ pub const STYLE: FontStyle = FontStyle::Normal;
/// The boldness / thickness of the font's glyphs.
- WEIGHT: FontWeight = FontWeight::REGULAR,
+ pub const WEIGHT: FontWeight = FontWeight::REGULAR;
/// The width of the glyphs.
- STRETCH: FontStretch = FontStretch::NORMAL,
+ pub const STRETCH: FontStretch = FontStretch::NORMAL;
/// Whether the font weight should be increased by 300.
#[fold(bool::bitxor)]
- STRONG: bool = false,
+ pub const STRONG: bool = false;
/// Whether the the font style should be inverted.
#[fold(bool::bitxor)]
- EMPH: bool = false,
+ pub const EMPH: bool = false;
/// Whether a monospace font should be preferred.
- MONOSPACE: bool = false,
+ pub const MONOSPACE: bool = false;
/// The glyph fill color.
- FILL: Paint = RgbaColor::BLACK.into(),
+ pub const FILL: Paint = RgbaColor::BLACK.into();
/// Decorative lines.
#[fold(|a, b| a.into_iter().chain(b).collect())]
- LINES: Vec<LineDecoration> = vec![],
+ pub const LINES: Vec<LineDecoration> = vec![];
/// The size of the glyphs.
#[fold(Linear::compose)]
- SIZE: Linear = Length::pt(11.0).into(),
+ pub const SIZE: Linear = Length::pt(11.0).into();
/// The amount of space that should be added between characters.
- TRACKING: Em = Em::zero(),
+ pub const TRACKING: Em = Em::zero();
/// The top end of the text bounding box.
- TOP_EDGE: VerticalFontMetric = VerticalFontMetric::CapHeight,
+ pub const TOP_EDGE: VerticalFontMetric = VerticalFontMetric::CapHeight;
/// The bottom end of the text bounding box.
- BOTTOM_EDGE: VerticalFontMetric = VerticalFontMetric::Baseline,
+ pub const BOTTOM_EDGE: VerticalFontMetric = VerticalFontMetric::Baseline;
/// Whether to apply kerning ("kern").
- KERNING: bool = true,
+ pub const KERNING: bool = true;
/// Whether small capital glyphs should be used. ("smcp")
- SMALLCAPS: bool = false,
+ pub const SMALLCAPS: bool = false;
/// Whether to apply stylistic alternates. ("salt")
- ALTERNATES: bool = false,
+ pub const ALTERNATES: bool = false;
/// Which stylistic set to apply. ("ss01" - "ss20")
- STYLISTIC_SET: Option<StylisticSet> = None,
+ pub const STYLISTIC_SET: Option<StylisticSet> = None;
/// Whether standard ligatures are active. ("liga", "clig")
- LIGATURES: bool = true,
+ pub const LIGATURES: bool = true;
/// Whether ligatures that should be used sparingly are active. ("dlig")
- DISCRETIONARY_LIGATURES: bool = false,
+ pub const DISCRETIONARY_LIGATURES: bool = false;
/// Whether historical ligatures are active. ("hlig")
- HISTORICAL_LIGATURES: bool = false,
+ pub const HISTORICAL_LIGATURES: bool = false;
/// Which kind of numbers / figures to select.
- NUMBER_TYPE: Smart<NumberType> = Smart::Auto,
+ pub const NUMBER_TYPE: Smart<NumberType> = Smart::Auto;
/// The width of numbers / figures.
- NUMBER_WIDTH: Smart<NumberWidth> = Smart::Auto,
+ pub const NUMBER_WIDTH: Smart<NumberWidth> = Smart::Auto;
/// How to position numbers.
- NUMBER_POSITION: NumberPosition = NumberPosition::Normal,
+ pub const NUMBER_POSITION: NumberPosition = NumberPosition::Normal;
/// Whether to have a slash through the zero glyph. ("zero")
- SLASHED_ZERO: bool = false,
+ pub const SLASHED_ZERO: bool = false;
/// Whether to convert fractions. ("frac")
- FRACTIONS: bool = false,
+ pub const FRACTIONS: bool = false;
/// Raw OpenType features to apply.
- FEATURES: Vec<(Tag, u32)> = vec![],
+ pub const FEATURES: Vec<(Tag, u32)> = vec![];
}
impl Construct for TextNode {
@@ -140,32 +139,32 @@ impl Set for TextNode {
(!families.is_empty()).then(|| families)
});
- set!(styles, TextNode::FAMILY_LIST => list);
- set!(styles, TextNode::SERIF_LIST => args.named("serif")?);
- set!(styles, TextNode::SANS_SERIF_LIST => args.named("sans-serif")?);
- set!(styles, TextNode::MONOSPACE_LIST => args.named("monospace")?);
- set!(styles, TextNode::FALLBACK => args.named("fallback")?);
- set!(styles, TextNode::STYLE => args.named("style")?);
- set!(styles, TextNode::WEIGHT => args.named("weight")?);
- set!(styles, TextNode::STRETCH => args.named("stretch")?);
- set!(styles, TextNode::FILL => args.named("fill")?.or_else(|| args.find()));
- set!(styles, TextNode::SIZE => args.named("size")?.or_else(|| args.find()));
- set!(styles, TextNode::TRACKING => args.named("tracking")?.map(Em::new));
- set!(styles, TextNode::TOP_EDGE => args.named("top-edge")?);
- set!(styles, TextNode::BOTTOM_EDGE => args.named("bottom-edge")?);
- set!(styles, TextNode::KERNING => args.named("kerning")?);
- set!(styles, TextNode::SMALLCAPS => args.named("smallcaps")?);
- set!(styles, TextNode::ALTERNATES => args.named("alternates")?);
- set!(styles, TextNode::STYLISTIC_SET => args.named("stylistic-set")?);
- set!(styles, TextNode::LIGATURES => args.named("ligatures")?);
- set!(styles, TextNode::DISCRETIONARY_LIGATURES => args.named("discretionary-ligatures")?);
- set!(styles, TextNode::HISTORICAL_LIGATURES => args.named("historical-ligatures")?);
- set!(styles, TextNode::NUMBER_TYPE => args.named("number-type")?);
- set!(styles, TextNode::NUMBER_WIDTH => args.named("number-width")?);
- set!(styles, TextNode::NUMBER_POSITION => args.named("number-position")?);
- set!(styles, TextNode::SLASHED_ZERO => args.named("slashed-zero")?);
- set!(styles, TextNode::FRACTIONS => args.named("fractions")?);
- set!(styles, TextNode::FEATURES => args.named("features")?);
+ set!(styles, Self::FAMILY_LIST => list);
+ set!(styles, Self::SERIF_LIST => args.named("serif")?);
+ set!(styles, Self::SANS_SERIF_LIST => args.named("sans-serif")?);
+ set!(styles, Self::MONOSPACE_LIST => args.named("monospace")?);
+ set!(styles, Self::FALLBACK => args.named("fallback")?);
+ set!(styles, Self::STYLE => args.named("style")?);
+ set!(styles, Self::WEIGHT => args.named("weight")?);
+ set!(styles, Self::STRETCH => args.named("stretch")?);
+ set!(styles, Self::FILL => args.named("fill")?.or_else(|| args.find()));
+ set!(styles, Self::SIZE => args.named("size")?.or_else(|| args.find()));
+ set!(styles, Self::TRACKING => args.named("tracking")?.map(Em::new));
+ set!(styles, Self::TOP_EDGE => args.named("top-edge")?);
+ set!(styles, Self::BOTTOM_EDGE => args.named("bottom-edge")?);
+ set!(styles, Self::KERNING => args.named("kerning")?);
+ set!(styles, Self::SMALLCAPS => args.named("smallcaps")?);
+ set!(styles, Self::ALTERNATES => args.named("alternates")?);
+ set!(styles, Self::STYLISTIC_SET => args.named("stylistic-set")?);
+ set!(styles, Self::LIGATURES => args.named("ligatures")?);
+ set!(styles, Self::DISCRETIONARY_LIGATURES => args.named("discretionary-ligatures")?);
+ set!(styles, Self::HISTORICAL_LIGATURES => args.named("historical-ligatures")?);
+ set!(styles, Self::NUMBER_TYPE => args.named("number-type")?);
+ set!(styles, Self::NUMBER_WIDTH => args.named("number-width")?);
+ set!(styles, Self::NUMBER_POSITION => args.named("number-position")?);
+ set!(styles, Self::SLASHED_ZERO => args.named("slashed-zero")?);
+ set!(styles, Self::FRACTIONS => args.named("fractions")?);
+ set!(styles, Self::FEATURES => args.named("features")?);
Ok(())
}