summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--benches/oneshot.rs2
-rw-r--r--src/eval/mod.rs2
-rw-r--r--src/eval/template.rs123
-rw-r--r--src/eval/walk.rs30
-rw-r--r--src/geom/paint.rs2
-rw-r--r--src/layout/par.rs8
-rw-r--r--src/layout/shaping.rs38
-rw-r--r--src/lib.rs30
-rw-r--r--src/library/elements.rs8
-rw-r--r--src/library/layout.rs54
-rw-r--r--src/library/mod.rs3
-rw-r--r--src/library/text.rs34
-rw-r--r--src/style/mod.rs (renamed from src/eval/state.rs)89
-rw-r--r--src/style/paper.rs (renamed from src/paper.rs)54
-rw-r--r--tests/typeset.rs13
15 files changed, 248 insertions, 242 deletions
diff --git a/benches/oneshot.rs b/benches/oneshot.rs
index dda3c572..57e3b339 100644
--- a/benches/oneshot.rs
+++ b/benches/oneshot.rs
@@ -60,7 +60,7 @@ fn bench_eval(iai: &mut Iai) {
fn bench_to_tree(iai: &mut Iai) {
let (mut ctx, id) = context();
let module = ctx.evaluate(id).unwrap();
- iai.run(|| module.template.to_tree(ctx.state()));
+ iai.run(|| module.template.to_tree(ctx.style()));
}
fn bench_layout(iai: &mut Iai) {
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index 384ebb2b..2adf785e 100644
--- a/src/eval/mod.rs
+++ b/src/eval/mod.rs
@@ -12,7 +12,6 @@ mod capture;
mod function;
mod ops;
mod scope;
-mod state;
mod template;
mod walk;
@@ -22,7 +21,6 @@ pub use capture::*;
pub use dict::*;
pub use function::*;
pub use scope::*;
-pub use state::*;
pub use template::*;
pub use value::*;
pub use walk::*;
diff --git a/src/eval/template.rs b/src/eval/template.rs
index 42b35fc3..0ea312e5 100644
--- a/src/eval/template.rs
+++ b/src/eval/template.rs
@@ -4,13 +4,14 @@ use std::mem;
use std::ops::{Add, AddAssign};
use std::rc::Rc;
-use super::{State, Str};
+use super::Str;
use crate::diag::StrResult;
use crate::geom::{Align, Dir, Gen, GenAxis, Length, Linear, Sides, Size};
use crate::layout::{
Decoration, LayoutNode, LayoutTree, PadNode, PageRun, ParChild, ParNode, StackChild,
StackNode,
};
+use crate::style::Style;
use crate::util::EcoString;
/// A template value: `[*Hi* there]`.
@@ -33,15 +34,15 @@ enum TemplateNode {
/// Spacing.
Spacing(GenAxis, Linear),
/// An inline node builder.
- Inline(Rc<dyn Fn(&State) -> LayoutNode>, Vec<Decoration>),
+ Inline(Rc<dyn Fn(&Style) -> LayoutNode>, Vec<Decoration>),
/// An block node builder.
- Block(Rc<dyn Fn(&State) -> LayoutNode>),
- /// Save the current state.
+ Block(Rc<dyn Fn(&Style) -> LayoutNode>),
+ /// Save the current style.
Save,
- /// Restore the last saved state.
+ /// Restore the last saved style.
Restore,
- /// A function that can modify the current state.
- Modify(Rc<dyn Fn(&mut State)>),
+ /// A function that can modify the current style.
+ Modify(Rc<dyn Fn(&mut Style)>),
}
impl Template {
@@ -53,7 +54,7 @@ impl Template {
/// Create a template from a builder for an inline-level node.
pub fn from_inline<F, T>(f: F) -> Self
where
- F: Fn(&State) -> T + 'static,
+ F: Fn(&Style) -> T + 'static,
T: Into<LayoutNode>,
{
let node = TemplateNode::Inline(Rc::new(move |s| f(s).into()), vec![]);
@@ -63,7 +64,7 @@ impl Template {
/// Create a template from a builder for a block-level node.
pub fn from_block<F, T>(f: F) -> Self
where
- F: Fn(&State) -> T + 'static,
+ F: Fn(&Style) -> T + 'static,
T: Into<LayoutNode>,
{
let node = TemplateNode::Block(Rc::new(move |s| f(s).into()));
@@ -98,7 +99,7 @@ impl Template {
/// Add text, but in monospace.
pub fn monospace(&mut self, text: impl Into<EcoString>) {
self.save();
- self.modify(|state| state.font_mut().monospace = true);
+ self.modify(|style| style.text_mut().monospace = true);
self.text(text);
self.restore();
}
@@ -126,16 +127,16 @@ impl Template {
self.make_mut().push(TemplateNode::Save);
}
- /// Ensure that later nodes are untouched by state modifications made since
+ /// Ensure that later nodes are untouched by style modifications made since
/// the last snapshot.
pub fn restore(&mut self) {
self.make_mut().push(TemplateNode::Restore);
}
- /// Modify the state.
+ /// Modify the style.
pub fn modify<F>(&mut self, f: F)
where
- F: Fn(&mut State) + 'static,
+ F: Fn(&mut Style) + 'static,
{
self.make_mut().push(TemplateNode::Modify(Rc::new(f)));
}
@@ -143,7 +144,7 @@ impl Template {
/// Return a new template which is modified from start to end.
pub fn modified<F>(self, f: F) -> Self
where
- F: Fn(&mut State) + 'static,
+ F: Fn(&mut Style) + 'static,
{
let mut wrapper = Self::new();
wrapper.save();
@@ -153,18 +154,18 @@ impl Template {
wrapper
}
- /// Build the stack node resulting from instantiating the template in the
- /// given state.
- pub fn to_stack(&self, state: &State) -> StackNode {
- let mut builder = Builder::new(state, false);
+ /// Build the stack node resulting from instantiating the template with the
+ /// given style.
+ pub fn to_stack(&self, style: &Style) -> StackNode {
+ let mut builder = Builder::new(style, false);
builder.template(self);
builder.build_stack()
}
- /// Build the layout tree resulting from instantiating the template in the
- /// given state.
- pub fn to_tree(&self, state: &State) -> LayoutTree {
- let mut builder = Builder::new(state, true);
+ /// Build the layout tree resulting from instantiating the template with the
+ /// given style.
+ pub fn to_tree(&self, style: &Style) -> LayoutTree {
+ let mut builder = Builder::new(style, true);
builder.template(self);
builder.build_tree()
}
@@ -238,10 +239,10 @@ impl Add<Template> for Str {
/// Transforms from template to layout representation.
struct Builder {
- /// The active state.
- state: State,
- /// Snapshots of the state.
- snapshots: Vec<State>,
+ /// The current style.
+ style: Style,
+ /// Snapshots of the style.
+ snapshots: Vec<Style>,
/// The tree of finished page runs.
tree: LayoutTree,
/// When we are building the top-level layout trees, this contains metrics
@@ -252,14 +253,14 @@ struct Builder {
}
impl Builder {
- /// Create a new builder with a base state.
- fn new(state: &State, pages: bool) -> Self {
+ /// Create a new builder with a base style.
+ fn new(style: &Style, pages: bool) -> Self {
Self {
- state: state.clone(),
+ style: style.clone(),
snapshots: vec![],
tree: LayoutTree { runs: vec![] },
- page: pages.then(|| PageBuilder::new(state, true)),
- stack: StackBuilder::new(state),
+ page: pages.then(|| PageBuilder::new(style, true)),
+ stack: StackBuilder::new(style),
}
}
@@ -273,11 +274,11 @@ impl Builder {
/// Build a template node.
fn node(&mut self, node: &TemplateNode) {
match node {
- TemplateNode::Save => self.snapshots.push(self.state.clone()),
+ TemplateNode::Save => self.snapshots.push(self.style.clone()),
TemplateNode::Restore => {
- let state = self.snapshots.pop().unwrap();
- let newpage = state.page != self.state.page;
- self.state = state;
+ let style = self.snapshots.pop().unwrap();
+ let newpage = style.page != self.style.page;
+ self.style = style;
if newpage {
self.pagebreak(true, false);
}
@@ -288,9 +289,9 @@ impl Builder {
TemplateNode::Pagebreak(keep) => self.pagebreak(*keep, true),
TemplateNode::Text(text, decos) => self.text(text, decos),
TemplateNode::Spacing(axis, amount) => self.spacing(*axis, *amount),
- TemplateNode::Inline(f, decos) => self.inline(f(&self.state), decos),
- TemplateNode::Block(f) => self.block(f(&self.state)),
- TemplateNode::Modify(f) => f(&mut self.state),
+ TemplateNode::Inline(f, decos) => self.inline(f(&self.style), decos),
+ TemplateNode::Block(f) => self.block(f(&self.style)),
+ TemplateNode::Modify(f) => f(&mut self.style),
}
}
@@ -306,16 +307,16 @@ impl Builder {
/// Apply a forced paragraph break.
fn parbreak(&mut self) {
- let amount = self.state.par_spacing();
- self.stack.finish_par(&self.state);
+ let amount = self.style.par_spacing();
+ self.stack.finish_par(&self.style);
self.stack.push_soft(StackChild::Spacing(amount.into()));
}
/// Apply a forced page break.
fn pagebreak(&mut self, keep: bool, hard: bool) {
if let Some(builder) = &mut self.page {
- let page = mem::replace(builder, PageBuilder::new(&self.state, hard));
- let stack = mem::replace(&mut self.stack, StackBuilder::new(&self.state));
+ let page = mem::replace(builder, PageBuilder::new(&self.style, hard));
+ let stack = mem::replace(&mut self.stack, StackBuilder::new(&self.style));
self.tree.runs.extend(page.build(stack.build(), keep));
}
}
@@ -327,14 +328,14 @@ impl Builder {
/// Push an inline node into the active paragraph.
fn inline(&mut self, node: impl Into<LayoutNode>, decos: &[Decoration]) {
- let align = self.state.aligns.inline;
+ let align = self.style.aligns.inline;
self.stack.par.push(ParChild::Any(node.into(), align, decos.to_vec()));
}
/// Push a block node into the active stack, finishing the active paragraph.
fn block(&mut self, node: impl Into<LayoutNode>) {
self.parbreak();
- let aligns = self.state.aligns;
+ let aligns = self.style.aligns;
self.stack.push(StackChild::Any(node.into(), aligns));
self.parbreak();
}
@@ -343,7 +344,7 @@ impl Builder {
fn spacing(&mut self, axis: GenAxis, amount: Linear) {
match axis {
GenAxis::Block => {
- self.stack.finish_par(&self.state);
+ self.stack.finish_par(&self.style);
self.stack.push_hard(StackChild::Spacing(amount));
}
GenAxis::Inline => {
@@ -365,8 +366,8 @@ impl Builder {
self.tree
}
- /// Construct a text node with the given text and settings from the active
- /// state.
+ /// Construct a text node with the given text and settings from the current
+ /// style.
fn make_text_node(
&self,
text: impl Into<EcoString>,
@@ -374,8 +375,8 @@ impl Builder {
) -> ParChild {
ParChild::Text(
text.into(),
- self.state.aligns.inline,
- Rc::clone(&self.state.font),
+ self.style.aligns.inline,
+ Rc::clone(&self.style.text),
decos,
)
}
@@ -388,10 +389,10 @@ struct PageBuilder {
}
impl PageBuilder {
- fn new(state: &State, hard: bool) -> Self {
+ fn new(style: &Style, hard: bool) -> Self {
Self {
- size: state.page.size,
- padding: state.page.margins(),
+ size: style.page.size,
+ padding: style.page.margins(),
hard,
}
}
@@ -413,12 +414,12 @@ struct StackBuilder {
}
impl StackBuilder {
- fn new(state: &State) -> Self {
+ fn new(style: &Style) -> Self {
Self {
- dirs: state.dirs,
+ dirs: Gen::new(style.dir, Dir::TTB),
children: vec![],
last: Last::None,
- par: ParBuilder::new(state),
+ par: ParBuilder::new(style),
}
}
@@ -436,8 +437,8 @@ impl StackBuilder {
self.children.push(child);
}
- fn finish_par(&mut self, state: &State) {
- let par = mem::replace(&mut self.par, ParBuilder::new(state));
+ fn finish_par(&mut self, style: &Style) {
+ let par = mem::replace(&mut self.par, ParBuilder::new(style));
if let Some(par) = par.build() {
self.push(par);
}
@@ -462,11 +463,11 @@ struct ParBuilder {
}
impl ParBuilder {
- fn new(state: &State) -> Self {
+ fn new(style: &Style) -> Self {
Self {
- aligns: state.aligns,
- dir: state.dirs.inline,
- line_spacing: state.line_spacing(),
+ aligns: style.aligns,
+ dir: style.dir,
+ line_spacing: style.line_spacing(),
children: vec![],
last: Last::None,
}
diff --git a/src/eval/walk.rs b/src/eval/walk.rs
index 1755dab9..90361141 100644
--- a/src/eval/walk.rs
+++ b/src/eval/walk.rs
@@ -2,7 +2,7 @@ use std::rc::Rc;
use super::{Eval, EvalContext, Str, Template, Value};
use crate::diag::TypResult;
-use crate::geom::Gen;
+use crate::geom::{Dir, Gen};
use crate::layout::{ParChild, ParNode, StackChild, StackNode};
use crate::syntax::*;
use crate::util::BoolExt;
@@ -28,8 +28,8 @@ impl Walk for MarkupNode {
Self::Space => ctx.template.space(),
Self::Linebreak(_) => ctx.template.linebreak(),
Self::Parbreak(_) => ctx.template.parbreak(),
- Self::Strong(_) => ctx.template.modify(|s| s.font_mut().strong.flip()),
- Self::Emph(_) => ctx.template.modify(|s| s.font_mut().emph.flip()),
+ Self::Strong(_) => ctx.template.modify(|s| s.text_mut().strong.flip()),
+ Self::Emph(_) => ctx.template.modify(|s| s.text_mut().emph.flip()),
Self::Text(text) => ctx.template.text(text),
Self::Raw(raw) => raw.walk(ctx)?,
Self::Heading(heading) => heading.walk(ctx)?,
@@ -73,11 +73,11 @@ impl Walk for HeadingNode {
ctx.template.parbreak();
ctx.template.save();
- ctx.template.modify(move |state| {
- let font = state.font_mut();
+ ctx.template.modify(move |style| {
+ let text = style.text_mut();
let upscale = 1.6 - 0.1 * level as f64;
- font.size *= upscale;
- font.strong = true;
+ text.size *= upscale;
+ text.strong = true;
});
ctx.template += body;
ctx.template.restore();
@@ -105,23 +105,23 @@ impl Walk for EnumNode {
}
fn walk_item(ctx: &mut EvalContext, label: Str, body: Template) {
- ctx.template += Template::from_block(move |state| {
+ ctx.template += Template::from_block(move |style| {
let label = ParNode {
- dir: state.dirs.inline,
- line_spacing: state.line_spacing(),
+ dir: style.dir,
+ line_spacing: style.line_spacing(),
children: vec![ParChild::Text(
(&label).into(),
- state.aligns.inline,
- Rc::clone(&state.font),
+ style.aligns.inline,
+ Rc::clone(&style.text),
vec![],
)],
};
StackNode {
- dirs: Gen::new(state.dirs.block, state.dirs.inline),
+ dirs: Gen::new(Dir::TTB, style.dir),
children: vec![
StackChild::Any(label.into(), Gen::default()),
- StackChild::Spacing((state.font.size / 2.0).into()),
- StackChild::Any(body.to_stack(&state).into(), Gen::default()),
+ StackChild::Spacing((style.text.size / 2.0).into()),
+ StackChild::Any(body.to_stack(&style).into(), Gen::default()),
],
}
});
diff --git a/src/geom/paint.rs b/src/geom/paint.rs
index 2ac11b56..1d82966c 100644
--- a/src/geom/paint.rs
+++ b/src/geom/paint.rs
@@ -59,7 +59,7 @@ impl FromStr for RgbaColor {
/// - `7a03c2` (without alpha),
/// - `abcdefff` (with alpha).
///
- /// Both lower and upper case is fine.
+ /// The hashtag is optional and both lower and upper case are fine.
fn from_str(hex_str: &str) -> Result<Self, Self::Err> {
let hex_str = hex_str.strip_prefix('#').unwrap_or(hex_str);
if !hex_str.is_ascii() {
diff --git a/src/layout/par.rs b/src/layout/par.rs
index 7f087eb3..cf37f005 100644
--- a/src/layout/par.rs
+++ b/src/layout/par.rs
@@ -6,7 +6,7 @@ use unicode_bidi::{BidiInfo, Level};
use xi_unicode::LineBreakIterator;
use super::*;
-use crate::eval::FontState;
+use crate::style::TextStyle;
use crate::util::{EcoString, RangeExt, SliceExt};
type Range = std::ops::Range<usize>;
@@ -29,7 +29,7 @@ pub enum ParChild {
/// Spacing between other nodes.
Spacing(Linear),
/// A run of text and how to align it in its line.
- Text(EcoString, Align, Rc<FontState>, Vec<Decoration>),
+ Text(EcoString, Align, Rc<TextStyle>, Vec<Decoration>),
/// Any child node and how to align it in its line.
Any(LayoutNode, Align, Vec<Decoration>),
}
@@ -139,11 +139,11 @@ impl<'a> ParLayouter<'a> {
items.push(ParItem::Spacing(resolved));
ranges.push(range);
}
- ParChild::Text(_, align, state, decos) => {
+ ParChild::Text(_, align, style, decos) => {
// TODO: Also split by language and script.
for (subrange, dir) in split_runs(&bidi, range) {
let text = &bidi.text[subrange.clone()];
- let shaped = shape(ctx, text, dir, state);
+ let shaped = shape(ctx, text, dir, style);
items.push(ParItem::Text(shaped, *align, decos));
ranges.push(subrange);
}
diff --git a/src/layout/shaping.rs b/src/layout/shaping.rs
index dc680276..4580ebf5 100644
--- a/src/layout/shaping.rs
+++ b/src/layout/shaping.rs
@@ -4,9 +4,9 @@ use std::ops::Range;
use rustybuzz::UnicodeBuffer;
use super::{Element, Frame, Glyph, LayoutContext, Text};
-use crate::eval::FontState;
use crate::font::{Face, FaceId, FontVariant};
use crate::geom::{Dir, Em, Length, Point, Size};
+use crate::style::TextStyle;
use crate::util::SliceExt;
/// Shape text into [`ShapedText`].
@@ -14,7 +14,7 @@ pub fn shape<'a>(
ctx: &mut LayoutContext,
text: &'a str,
dir: Dir,
- state: &'a FontState,
+ style: &'a TextStyle,
) -> ShapedText<'a> {
let mut glyphs = vec![];
if !text.is_empty() {
@@ -24,19 +24,19 @@ pub fn shape<'a>(
0,
text,
dir,
- state.size,
- state.variant(),
- state.families(),
+ style.size,
+ style.variant(),
+ style.families(),
None,
);
}
- let (size, baseline) = measure(ctx, &glyphs, state);
+ let (size, baseline) = measure(ctx, &glyphs, style);
ShapedText {
text,
dir,
- state,
+ style,
size,
baseline,
glyphs: Cow::Owned(glyphs),
@@ -54,7 +54,7 @@ pub struct ShapedText<'a> {
/// The text direction.
pub dir: Dir,
/// The properties used for font selection.
- pub state: &'a FontState,
+ pub style: &'a TextStyle,
/// The font size.
pub size: Size,
/// The baseline from the top of the frame.
@@ -93,9 +93,9 @@ impl<'a> ShapedText<'a> {
let mut text = Text {
face_id,
- size: self.state.size,
+ size: self.style.size,
width: Length::zero(),
- fill: self.state.fill,
+ fill: self.style.fill,
glyphs: vec![],
};
@@ -123,17 +123,17 @@ impl<'a> ShapedText<'a> {
text_range: Range<usize>,
) -> ShapedText<'a> {
if let Some(glyphs) = self.slice_safe_to_break(text_range.clone()) {
- let (size, baseline) = measure(ctx, glyphs, self.state);
+ let (size, baseline) = measure(ctx, glyphs, self.style);
Self {
text: &self.text[text_range],
dir: self.dir,
- state: self.state,
+ style: self.style,
size,
baseline,
glyphs: Cow::Borrowed(glyphs),
}
} else {
- shape(ctx, &self.text[text_range], self.dir, self.state)
+ shape(ctx, &self.text[text_range], self.dir, self.style)
}
}
@@ -334,7 +334,7 @@ fn shape_segment<'a>(
fn measure(
ctx: &mut LayoutContext,
glyphs: &[ShapedGlyph],
- state: &FontState,
+ style: &TextStyle,
) -> (Size, Length) {
let mut width = Length::zero();
let mut top = Length::zero();
@@ -342,15 +342,15 @@ fn measure(
// Expand top and bottom by reading the face's vertical metrics.
let mut expand = |face: &Face| {
- top.set_max(face.vertical_metric(state.top_edge, state.size));
- bottom.set_max(-face.vertical_metric(state.bottom_edge, state.size));
+ top.set_max(face.vertical_metric(style.top_edge, style.size));
+ bottom.set_max(-face.vertical_metric(style.bottom_edge, style.size));
};
if glyphs.is_empty() {
// When there are no glyphs, we just use the vertical metrics of the
// first available font.
- for family in state.families() {
- if let Some(face_id) = ctx.fonts.select(family, state.variant) {
+ for family in style.families() {
+ if let Some(face_id) = ctx.fonts.select(family, style.variant) {
expand(ctx.fonts.get(face_id));
break;
}
@@ -361,7 +361,7 @@ fn measure(
expand(face);
for glyph in group {
- width += glyph.x_advance.to_length(state.size);
+ width += glyph.x_advance.to_length(style.size);
}
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 4ac40d96..ed90fed4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -8,7 +8,7 @@
//! - **Evaluation:** The next step is to [evaluate] the markup. This produces a
//! [module], consisting of a scope of values that were exported by the code
//! and a template with the contents of the module. This template can be
-//! [instantiated] in a state to produce a layout tree, a high-level, fully
+//! [instantiated] with a style to produce a layout tree, a high-level, fully
//! styled representation of the document. The nodes of this tree are
//! self-contained and order-independent and thus much better suited for
//! layouting than the raw markup.
@@ -18,7 +18,6 @@
//! - **Exporting:** The finished layout can be exported into a supported
//! format. Currently, the only supported output format is [PDF].
//!
-
//! [tokens]: parse::Tokens
//! [parsed]: parse::parse
//! [markup]: syntax::Markup
@@ -40,16 +39,16 @@ pub mod image;
pub mod layout;
pub mod library;
pub mod loading;
-pub mod paper;
pub mod parse;
pub mod source;
+pub mod style;
pub mod syntax;
pub mod util;
use std::rc::Rc;
use crate::diag::TypResult;
-use crate::eval::{Module, Scope, State};
+use crate::eval::{Module, Scope};
use crate::font::FontStore;
use crate::image::ImageStore;
#[cfg(feature = "layout-cache")]
@@ -57,6 +56,7 @@ use crate::layout::{EvictionPolicy, LayoutCache};
use crate::layout::{Frame, LayoutTree};
use crate::loading::Loader;
use crate::source::{SourceId, SourceStore};
+use crate::style::Style;
use crate::syntax::Markup;
/// The core context which holds the loader, configuration and cached artifacts.
@@ -74,8 +74,8 @@ pub struct Context {
pub layouts: LayoutCache,
/// The standard library scope.
std: Scope,
- /// The default state.
- state: State,
+ /// The default style.
+ style: Style,
}
impl Context {
@@ -94,9 +94,9 @@ impl Context {
&self.std
}
- /// A read-only reference to the state.
- pub fn state(&self) -> &State {
- &self.state
+ /// A read-only reference to the style.
+ pub fn style(&self) -> &Style {
+ &self.style
}
/// Parse a source file and return the resulting markup.
@@ -113,7 +113,7 @@ impl Context {
/// Execute a source file and produce the resulting layout tree.
pub fn execute(&mut self, id: SourceId) -> TypResult<LayoutTree> {
let module = self.evaluate(id)?;
- Ok(module.template.to_tree(&self.state))
+ Ok(module.template.to_tree(&self.style))
}
/// Typeset a source file into a collection of layouted frames.
@@ -139,7 +139,7 @@ impl Context {
/// This struct is created by [`Context::builder`].
pub struct ContextBuilder {
std: Option<Scope>,
- state: Option<State>,
+ style: Option<Style>,
#[cfg(feature = "layout-cache")]
policy: EvictionPolicy,
#[cfg(feature = "layout-cache")]
@@ -155,8 +155,8 @@ impl ContextBuilder {
}
/// The initial properties for page size, font selection and so on.
- pub fn state(mut self, state: State) -> Self {
- self.state = Some(state);
+ pub fn style(mut self, style: Style) -> Self {
+ self.style = Some(style);
self
}
@@ -188,7 +188,7 @@ impl ContextBuilder {
#[cfg(feature = "layout-cache")]
layouts: LayoutCache::new(self.policy, self.max_size),
std: self.std.unwrap_or(library::new()),
- state: self.state.unwrap_or_default(),
+ style: self.style.unwrap_or_default(),
}
}
}
@@ -197,7 +197,7 @@ impl Default for ContextBuilder {
fn default() -> Self {
Self {
std: None,
- state: None,
+ style: None,
#[cfg(feature = "layout-cache")]
policy: EvictionPolicy::default(),
#[cfg(feature = "layout-cache")]
diff --git a/src/library/elements.rs b/src/library/elements.rs
index 9680dfee..51f8dc98 100644
--- a/src/library/elements.rs
+++ b/src/library/elements.rs
@@ -61,12 +61,12 @@ fn rect_impl(
fill: Option<Color>,
body: Template,
) -> Value {
- Value::Template(Template::from_inline(move |state| {
+ Value::Template(Template::from_inline(move |style| {
let mut node = LayoutNode::new(FixedNode {
width,
height,
aspect,
- child: body.to_stack(state).into(),
+ child: body.to_stack(style).into(),
});
if let Some(fill) = fill {
@@ -114,7 +114,7 @@ fn ellipse_impl(
fill: Option<Color>,
body: Template,
) -> Value {
- Value::Template(Template::from_inline(move |state| {
+ Value::Template(Template::from_inline(move |style| {
// This padding ratio ensures that the rectangular padded region fits
// perfectly into the ellipse.
const PAD: f64 = 0.5 - SQRT_2 / 4.0;
@@ -125,7 +125,7 @@ fn ellipse_impl(
aspect,
child: LayoutNode::new(PadNode {
padding: Sides::splat(Relative::new(PAD).into()),
- child: body.to_stack(state).into(),
+ child: body.to_stack(style).into(),
}),
});
diff --git a/src/library/layout.rs b/src/library/layout.rs
index 089b80cf..c8b22f88 100644
--- a/src/library/layout.rs
+++ b/src/library/layout.rs
@@ -1,6 +1,6 @@
use super::*;
use crate::layout::{FixedNode, GridNode, PadNode, StackChild, StackNode, TrackSizing};
-use crate::paper::{Paper, PaperClass};
+use crate::style::{Paper, PaperClass};
/// `page`: Configure pages.
pub fn page(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
@@ -21,8 +21,8 @@ pub fn page(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
let bottom = args.named("bottom")?;
let flip = args.named("flip")?;
- ctx.template.modify(move |state| {
- let page = state.page_mut();
+ ctx.template.modify(move |style| {
+ let page = style.page_mut();
if let Some(paper) = paper {
page.class = paper.class();
@@ -98,13 +98,13 @@ pub fn align(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
}
let realign = |template: &mut Template| {
- template.modify(move |state| {
+ template.modify(move |style| {
if let Some(horizontal) = horizontal {
- state.aligns.inline = horizontal;
+ style.aligns.inline = horizontal;
}
if let Some(vertical) = vertical {
- state.aligns.block = vertical;
+ style.aligns.block = vertical;
}
});
@@ -147,12 +147,12 @@ pub fn boxed(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
let width = args.named("width")?;
let height = args.named("height")?;
let body: Template = args.eat().unwrap_or_default();
- Ok(Value::Template(Template::from_inline(move |state| {
+ Ok(Value::Template(Template::from_inline(move |style| {
FixedNode {
width,
height,
aspect: None,
- child: body.to_stack(state).into(),
+ child: body.to_stack(style).into(),
}
})))
}
@@ -160,8 +160,8 @@ pub fn boxed(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
/// `block`: Place content in a block.
pub fn block(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
let body: Template = args.expect("body")?;
- Ok(Value::Template(Template::from_block(move |state| {
- body.to_stack(state)
+ Ok(Value::Template(Template::from_block(move |style| {
+ body.to_stack(style)
})))
}
@@ -181,10 +181,10 @@ pub fn pad(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
bottom.or(all).unwrap_or_default(),
);
- Ok(Value::Template(Template::from_block(move |state| {
+ Ok(Value::Template(Template::from_block(move |style| {
PadNode {
padding,
- child: body.to_stack(&state).into(),
+ child: body.to_stack(&style).into(),
}
})))
}
@@ -208,20 +208,20 @@ pub fn stack(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
let spacing = args.named("spacing")?;
let list: Vec<Child> = args.all().collect();
- Ok(Value::Template(Template::from_block(move |state| {
- let mut dirs = Gen::new(None, dir).unwrap_or(state.dirs);
+ Ok(Value::Template(Template::from_block(move |style| {
+ let mut dirs = Gen::new(style.dir, dir.unwrap_or(Dir::TTB));
// If the directions become aligned, fix up the inline direction since
// that's the one that is not user-defined.
- if dirs.block.axis() == dirs.inline.axis() {
- dirs.inline = state.dirs.block;
+ if dirs.inline.axis() == dirs.block.axis() {
+ dirs.inline = Dir::TTB;
}
// Use the current alignments for all children, but take care to apply
// them to the correct axes (by swapping them if the stack axes are
- // different from the state axes).
- let mut aligns = state.aligns;
- if dirs.block.axis() == state.dirs.inline.axis() {
+ // different from the style axes).
+ let mut aligns = style.aligns;
+ if dirs.inline.axis() != style.dir.axis() {
aligns = Gen::new(aligns.block, aligns.inline);
}
@@ -240,7 +240,7 @@ pub fn stack(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
children.push(StackChild::Spacing(v));
}
- let node = template.to_stack(state).into();
+ let node = template.to_stack(style).into();
children.push(StackChild::Any(node, aligns));
delayed = spacing;
}
@@ -293,10 +293,12 @@ pub fn grid(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
let children: Vec<Template> = args.all().collect();
- Ok(Value::Template(Template::from_block(move |state| {
+ Ok(Value::Template(Template::from_block(move |style| {
// If the directions become aligned, try to fix up the direction which
// is not user-defined.
- let mut dirs = Gen::new(column_dir, row_dir).unwrap_or(state.dirs);
+ let mut dirs =
+ Gen::new(column_dir.unwrap_or(style.dir), row_dir.unwrap_or(Dir::TTB));
+
if dirs.block.axis() == dirs.inline.axis() {
let target = if column_dir.is_some() {
&mut dirs.block
@@ -304,15 +306,15 @@ pub fn grid(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
&mut dirs.inline
};
- *target = if target.axis() == state.dirs.inline.axis() {
- state.dirs.block
+ *target = if target.axis() == style.dir.axis() {
+ Dir::TTB
} else {
- state.dirs.inline
+ style.dir
};
}
let children =
- children.iter().map(|child| child.to_stack(&state).into()).collect();
+ children.iter().map(|child| child.to_stack(&style).into()).collect();
GridNode {
dirs,
diff --git a/src/library/mod.rs b/src/library/mod.rs
index d99eb24d..7c8f4a93 100644
--- a/src/library/mod.rs
+++ b/src/library/mod.rs
@@ -17,10 +17,11 @@ use std::convert::TryFrom;
use std::rc::Rc;
use crate::diag::{At, TypResult};
-use crate::eval::{Args, Array, EvalContext, Scope, State, Str, Template, Value};
+use crate::eval::{Args, Array, EvalContext, Scope, Str, Template, Value};
use crate::font::{FontFamily, FontStretch, FontStyle, FontWeight, VerticalFontMetric};
use crate::geom::*;
use crate::layout::LayoutNode;
+use crate::style::Style;
use crate::syntax::{Span, Spanned};
/// Construct a scope containing all standard library definitions.
diff --git a/src/library/text.rs b/src/library/text.rs
index b532b20b..fa334620 100644
--- a/src/library/text.rs
+++ b/src/library/text.rs
@@ -48,55 +48,55 @@ pub fn font(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
let fallback = args.named("fallback")?;
let body = args.eat::<Template>();
- let f = move |state: &mut State| {
- let font = state.font_mut();
+ let f = move |style_: &mut Style| {
+ let text = style_.text_mut();
if let Some(size) = size {
- font.size = size.resolve(font.size);
+ text.size = size.resolve(text.size);
}
if let Some(style) = style {
- font.variant.style = style;
+ text.variant.style = style;
}
if let Some(weight) = weight {
- font.variant.weight = weight;
+ text.variant.weight = weight;
}
if let Some(stretch) = stretch {
- font.variant.stretch = stretch;
+ text.variant.stretch = stretch;
}
if let Some(top_edge) = top_edge {
- font.top_edge = top_edge;
+ text.top_edge = top_edge;
}
if let Some(bottom_edge) = bottom_edge {
- font.bottom_edge = bottom_edge;
+ text.bottom_edge = bottom_edge;
}
if let Some(fill) = fill {
- font.fill = Paint::Color(fill);
+ text.fill = Paint::Color(fill);
}
if let Some(FontDef(list)) = &list {
- font.families_mut().list = list.clone();
+ text.families_mut().list = list.clone();
}
if let Some(FamilyDef(serif)) = &serif {
- font.families_mut().serif = serif.clone();
+ text.families_mut().serif = serif.clone();
}
if let Some(FamilyDef(sans_serif)) = &sans_serif {
- font.families_mut().sans_serif = sans_serif.clone();
+ text.families_mut().sans_serif = sans_serif.clone();
}
if let Some(FamilyDef(monospace)) = &monospace {
- font.families_mut().monospace = monospace.clone();
+ text.families_mut().monospace = monospace.clone();
}
if let Some(fallback) = fallback {
- font.fallback = fallback;
+ text.fallback = fallback;
}
};
@@ -113,8 +113,8 @@ pub fn par(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
let par_spacing = args.named("spacing")?;
let line_spacing = args.named("leading")?;
- ctx.template.modify(move |state| {
- let par = state.par_mut();
+ ctx.template.modify(move |style| {
+ let par = style.par_mut();
if let Some(par_spacing) = par_spacing {
par.par_spacing = par_spacing;
@@ -144,7 +144,7 @@ pub fn lang(ctx: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
};
if let Some(dir) = dir {
- ctx.template.modify(move |state| state.dirs.inline = dir);
+ ctx.template.modify(move |style| style.dir = dir);
}
ctx.template.parbreak();
diff --git a/src/eval/state.rs b/src/style/mod.rs
index 5d8d3172..f59ea32e 100644
--- a/src/eval/state.rs
+++ b/src/style/mod.rs
@@ -1,68 +1,73 @@
+//! Style properties.
+
+mod paper;
+
+pub use paper::*;
+
use std::rc::Rc;
use crate::font::{
FontFamily, FontStretch, FontStyle, FontVariant, FontWeight, VerticalFontMetric,
};
use crate::geom::*;
-use crate::paper::{PaperClass, ISO_A4};
-/// Defines an set of properties a template can be instantiated with.
+/// Defines a set of properties a template can be instantiated with.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct State {
+pub struct Style {
/// The direction for text and other inline objects.
- pub dirs: Gen<Dir>,
+ pub dir: Dir,
/// The alignments of layouts in their parents.
pub aligns: Gen<Align>,
/// The page settings.
- pub page: Rc<PageState>,
+ pub page: Rc<PageStyle>,
/// The paragraph settings.
- pub par: Rc<ParState>,
- /// The font settings.
- pub font: Rc<FontState>,
+ pub par: Rc<ParStyle>,
+ /// The current text settings.
+ pub text: Rc<TextStyle>,
}
-impl State {
- /// Access the `page` state mutably.
- pub fn page_mut(&mut self) -> &mut PageState {
+impl Style {
+ /// Access the `page` style mutably.
+ pub fn page_mut(&mut self) -> &mut PageStyle {
Rc::make_mut(&mut self.page)
}
- /// Access the `par` state mutably.
- pub fn par_mut(&mut self) -> &mut ParState {
+ /// Access the `par` style mutably.
+ pub fn par_mut(&mut self) -> &mut ParStyle {
Rc::make_mut(&mut self.par)
}
- /// Access the `font` state mutably.
- pub fn font_mut(&mut self) -> &mut FontState {
- Rc::make_mut(&mut self.font)
+ /// Access the `text` style mutably.
+ pub fn text_mut(&mut self) -> &mut TextStyle {
+ Rc::make_mut(&mut self.text)
}
/// The resolved line spacing.
pub fn line_spacing(&self) -> Length {
- self.par.line_spacing.resolve(self.font.size)
+ self.par.line_spacing.resolve(self.text.size)
}
/// The resolved paragraph spacing.
pub fn par_spacing(&self) -> Length {
- self.par.par_spacing.resolve(self.font.size)
+ self.par.par_spacing.resolve(self.text.size)
}
}
-impl Default for State {
+impl Default for Style {
fn default() -> Self {
Self {
- dirs: Gen::new(Dir::LTR, Dir::TTB),
+ dir: Dir::LTR,
aligns: Gen::splat(Align::Start),
- page: Rc::new(PageState::default()),
- par: Rc::new(ParState::default()),
- font: Rc::new(FontState::default()),
+ page: Rc::new(PageStyle::default()),
+ par: Rc::new(ParStyle::default()),
+ text: Rc::new(TextStyle::default()),
}
}
}
-/// Defines page properties.
+/// Defines style properties of pages.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct PageState {
+pub struct PageStyle {
/// The class of this page.
pub class: PaperClass,
/// The width and height of the page.
@@ -72,7 +77,7 @@ pub struct PageState {
pub margins: Sides<Option<Linear>>,
}
-impl PageState {
+impl PageStyle {
/// The resolved margins.
pub fn margins(&self) -> Sides<Linear> {
let default = self.class.default_margins();
@@ -85,9 +90,9 @@ impl PageState {
}
}
-impl Default for PageState {
+impl Default for PageStyle {
fn default() -> Self {
- let paper = ISO_A4;
+ let paper = Paper::ISO_A4;
Self {
class: paper.class(),
size: paper.size(),
@@ -96,16 +101,16 @@ impl Default for PageState {
}
}
-/// Defines paragraph properties.
+/// Defines style properties of paragraphs.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct ParState {
+pub struct ParStyle {
/// The spacing between paragraphs (dependent on scaled font size).
pub par_spacing: Linear,
/// The spacing between lines (dependent on scaled font size).
pub line_spacing: Linear,
}
-impl Default for ParState {
+impl Default for ParStyle {
fn default() -> Self {
Self {
par_spacing: Relative::new(1.2).into(),
@@ -114,9 +119,9 @@ impl Default for ParState {
}
}
-/// Defines font properties.
+/// Defines style properties of text.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct FontState {
+pub struct TextStyle {
/// The font size.
pub size: Length,
/// The selected font variant (the final variant also depends on `strong`
@@ -130,7 +135,7 @@ pub struct FontState {
pub fill: Paint,
/// A list of font families with generic class definitions (the final
/// family list also depends on `monospace`).
- pub families: Rc<FamilyState>,
+ pub families: Rc<FamilyStyle>,
/// Whether 300 extra font weight should be added to what is defined by the
/// `variant`.
pub strong: bool,
@@ -142,7 +147,7 @@ pub struct FontState {
pub fallback: bool,
}
-impl FontState {
+impl TextStyle {
/// The resolved variant with `strong` and `emph` factored in.
pub fn variant(&self) -> FontVariant {
let mut variant = self.variant;
@@ -188,13 +193,13 @@ impl FontState {
head.iter().chain(core).chain(tail).map(String::as_str)
}
- /// Access the `families` state mutably.
- pub fn families_mut(&mut self) -> &mut FamilyState {
+ /// Access the `families` style mutably.
+ pub fn families_mut(&mut self) -> &mut FamilyStyle {
Rc::make_mut(&mut self.families)
}
}
-impl Default for FontState {
+impl Default for TextStyle {
fn default() -> Self {
Self {
size: Length::pt(11.0),
@@ -206,7 +211,7 @@ impl Default for FontState {
top_edge: VerticalFontMetric::CapHeight,
bottom_edge: VerticalFontMetric::Baseline,
fill: Paint::Color(Color::Rgba(RgbaColor::BLACK)),
- families: Rc::new(FamilyState::default()),
+ families: Rc::new(FamilyStyle::default()),
strong: false,
emph: false,
monospace: false,
@@ -215,9 +220,9 @@ impl Default for FontState {
}
}
-/// Font family definitions.
+/// Font list with family definitions.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct FamilyState {
+pub struct FamilyStyle {
/// The user-defined list of font families.
pub list: Rc<Vec<FontFamily>>,
/// Definition of serif font families.
@@ -230,7 +235,7 @@ pub struct FamilyState {
pub base: Rc<Vec<String>>,
}
-impl Default for FamilyState {
+impl Default for FamilyStyle {
fn default() -> Self {
Self {
list: Rc::new(vec![FontFamily::SansSerif]),
diff --git a/src/paper.rs b/src/style/paper.rs
index 8dbee265..bc317308 100644
--- a/src/paper.rs
+++ b/src/style/paper.rs
@@ -1,5 +1,3 @@
-//! Predefined papers.
-
use crate::geom::{Length, Linear, Relative, Sides, Size};
/// Specification of a paper.
@@ -13,23 +11,6 @@ pub struct Paper {
height: f64,
}
-impl Paper {
- /// The paper with the given name.
- pub fn from_name(name: &str) -> Option<Self> {
- parse_paper(name)
- }
-
- /// The class of the paper.
- pub fn class(self) -> PaperClass {
- self.class
- }
-
- /// The size of the paper.
- pub fn size(self) -> Size {
- Size::new(Length::mm(self.width), Length::mm(self.height))
- }
-}
-
/// Defines default margins for a class of related papers.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum PaperClass {
@@ -57,21 +38,38 @@ impl PaperClass {
macro_rules! papers {
($(($var:ident: $class:ident, $width:expr, $height: expr, $($pats:tt)*))*) => {
- $(papers!(@$var, stringify!($($pats)*), $class, $width, $height);)*
+ impl Paper {
+ /// Parse a paper from its name.
+ ///
+ /// Both lower and upper case are fine.
+ pub fn from_name(name: &str) -> Option<Self> {
+ match name.to_lowercase().as_str() {
+ $($($pats)* => Some(Self::$var),)*
+ _ => None,
+ }
+ }
+
+ /// The class of the paper.
+ pub fn class(self) -> PaperClass {
+ self.class
+ }
- fn parse_paper(paper: &str) -> Option<Paper> {
- match paper.to_lowercase().as_str() {
- $($($pats)* => Some($var),)*
- _ => None,
+ /// The size of the paper.
+ pub fn size(self) -> Size {
+ Size::new(Length::mm(self.width), Length::mm(self.height))
}
}
+
+ /// Predefined papers.
+ ///
+ /// Each paper is parsable from its name in kebab-case.
+ impl Paper {
+ $(papers!(@$var, stringify!($($pats)*), $class, $width, $height);)*
+ }
};
(@$var:ident, $names:expr, $class:ident, $width:expr, $height:expr) => {
- #[doc = "Paper with name `"]
- #[doc = $names]
- #[doc = "`."]
- pub const $var: Paper = Paper {
+ pub const $var: Self = Self {
class: PaperClass::$class,
width: $width,
height: $height,
diff --git a/tests/typeset.rs b/tests/typeset.rs
index 5ca81da5..913e172a 100644
--- a/tests/typeset.rs
+++ b/tests/typeset.rs
@@ -10,7 +10,7 @@ use ttf_parser::{GlyphId, OutlineBuilder};
use walkdir::WalkDir;
use typst::diag::Error;
-use typst::eval::{State, Value};
+use typst::eval::Value;
use typst::font::Face;
use typst::geom::{
self, Color, Length, Paint, PathElement, Point, RgbaColor, Sides, Size,
@@ -22,6 +22,7 @@ use typst::layout::{layout, Element, Frame, Geometry, Text};
use typst::loading::FsLoader;
use typst::parse::Scanner;
use typst::source::SourceFile;
+use typst::style::Style;
use typst::syntax::{Pos, Span};
use typst::Context;
@@ -62,10 +63,10 @@ fn main() {
// We want to have "unbounded" pages, so we allow them to be infinitely
// large and fit them to match their content.
- let mut state = State::default();
- state.page_mut().size = Size::new(Length::pt(120.0), Length::inf());
- state.page_mut().margins = Sides::splat(Some(Length::pt(10.0).into()));
- state.font_mut().size = Length::pt(10.0);
+ let mut style = Style::default();
+ style.page_mut().size = Size::new(Length::pt(120.0), Length::inf());
+ style.page_mut().margins = Sides::splat(Some(Length::pt(10.0).into()));
+ style.text_mut().size = Length::pt(10.0);
// Hook up an assert function into the global scope.
let mut std = typst::library::new();
@@ -83,7 +84,7 @@ fn main() {
// Create loader and context.
let loader = FsLoader::new().with_path(FONT_DIR).wrap();
- let mut ctx = Context::builder().std(std).state(state).build(loader);
+ let mut ctx = Context::builder().std(std).style(style).build(loader);
// Run all the tests.
let mut ok = true;