summaryrefslogtreecommitdiff
path: root/src/exec
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-07-29 13:21:25 +0200
committerLaurenz <laurmaedje@gmail.com>2021-07-29 13:28:19 +0200
commit2c6127dea611944abb09a0d38375ad7cf9baced0 (patch)
tree6572d169d4ce26edc38a880860ebae2f49639fb8 /src/exec
parent7d15dc634b3be1b6e284bb6b2450e3736d3e6e8d (diff)
Refactor state
Diffstat (limited to 'src/exec')
-rw-r--r--src/exec/context.rs18
-rw-r--r--src/exec/mod.rs18
-rw-r--r--src/exec/state.rs206
3 files changed, 127 insertions, 115 deletions
diff --git a/src/exec/context.rs b/src/exec/context.rs
index 3a3eb702..4d351692 100644
--- a/src/exec/context.rs
+++ b/src/exec/context.rs
@@ -3,13 +3,13 @@ use std::rc::Rc;
use super::{Exec, ExecWithMap, State};
use crate::diag::{Diag, DiagSet, Pass};
-use crate::util::EcoString;
use crate::eval::{ExprMap, Template};
use crate::geom::{Align, Dir, Gen, GenAxis, Length, Linear, Sides, Size};
use crate::layout::{
LayoutNode, LayoutTree, PadNode, PageRun, ParChild, ParNode, StackChild, StackNode,
};
use crate::syntax::{Span, SyntaxTree};
+use crate::util::EcoString;
use crate::Context;
/// The context for execution.
@@ -76,10 +76,10 @@ impl ExecContext {
/// Push text, but in monospace.
pub fn push_monospace_text(&mut self, text: impl Into<EcoString>) {
- let prev = Rc::clone(&self.state.text);
- self.state.text_mut().monospace = true;
+ let prev = Rc::clone(&self.state.font);
+ self.state.font_mut().monospace = true;
self.push_text(text);
- self.state.text = prev;
+ self.state.font = prev;
}
/// Push a word space into the active paragraph.
@@ -121,7 +121,7 @@ impl ExecContext {
/// Apply a forced paragraph break.
pub fn parbreak(&mut self) {
- let amount = self.state.text.par_spacing();
+ let amount = self.state.par_spacing();
self.stack.finish_par(&self.state);
self.stack.push_soft(StackChild::Spacing(amount));
}
@@ -148,7 +148,7 @@ impl ExecContext {
ParChild::Text(
text.into(),
self.state.aligns.cross,
- Rc::clone(&self.state.text),
+ Rc::clone(&self.state.font),
)
}
}
@@ -187,7 +187,7 @@ struct StackBuilder {
impl StackBuilder {
fn new(state: &State) -> Self {
Self {
- dirs: Gen::new(state.dir, Dir::TTB),
+ dirs: state.dirs,
children: vec![],
last: Last::None,
par: ParBuilder::new(state),
@@ -237,8 +237,8 @@ impl ParBuilder {
fn new(state: &State) -> Self {
Self {
aligns: state.aligns,
- dir: state.dir,
- line_spacing: state.text.line_spacing(),
+ dir: state.dirs.cross,
+ line_spacing: state.line_spacing(),
children: vec![],
last: Last::None,
}
diff --git a/src/exec/mod.rs b/src/exec/mod.rs
index ff4faa22..8bac76e8 100644
--- a/src/exec/mod.rs
+++ b/src/exec/mod.rs
@@ -9,12 +9,12 @@ pub use state::*;
use std::fmt::Write;
use crate::diag::Pass;
-use crate::util::EcoString;
use crate::eval::{ExprMap, Template, TemplateFunc, TemplateNode, TemplateTree, Value};
-use crate::geom::{Dir, Gen};
+use crate::geom::Gen;
use crate::layout::{LayoutTree, StackChild, StackNode};
use crate::pretty::pretty;
use crate::syntax::*;
+use crate::util::EcoString;
use crate::Context;
/// Execute a template to produce a layout tree.
@@ -57,8 +57,8 @@ impl ExecWithMap for SyntaxNode {
Self::Space => ctx.push_word_space(),
Self::Linebreak(_) => ctx.linebreak(),
Self::Parbreak(_) => ctx.parbreak(),
- Self::Strong(_) => ctx.state.text_mut().strong ^= true,
- Self::Emph(_) => ctx.state.text_mut().emph ^= true,
+ Self::Strong(_) => ctx.state.font_mut().strong ^= true,
+ Self::Emph(_) => ctx.state.font_mut().emph ^= true,
Self::Raw(n) => n.exec(ctx),
Self::Heading(n) => n.exec_with_map(ctx, map),
Self::List(n) => n.exec_with_map(ctx, map),
@@ -87,10 +87,10 @@ impl ExecWithMap for HeadingNode {
ctx.parbreak();
let snapshot = ctx.state.clone();
- let text = ctx.state.text_mut();
+ let font = ctx.state.font_mut();
let upscale = 1.6 - 0.1 * self.level as f64;
- text.size *= upscale;
- text.strong = true;
+ font.size *= upscale;
+ font.strong = true;
self.body.exec_with_map(ctx, map);
ctx.state = snapshot;
@@ -118,11 +118,11 @@ fn exec_item(ctx: &mut ExecContext, label: EcoString, body: &SyntaxTree, map: &E
let label = ctx.exec_stack(|ctx| ctx.push_text(label));
let body = ctx.exec_tree_stack(body, map);
let stack = StackNode {
- dirs: Gen::new(Dir::TTB, ctx.state.dir),
+ dirs: Gen::new(ctx.state.dirs.main, ctx.state.dirs.cross),
aspect: None,
children: vec![
StackChild::Any(label.into(), Gen::default()),
- StackChild::Spacing(ctx.state.text.size / 2.0),
+ StackChild::Spacing(ctx.state.font.size / 2.0),
StackChild::Any(body.into(), Gen::default()),
],
};
diff --git a/src/exec/state.rs b/src/exec/state.rs
index 51bbe395..ce30e042 100644
--- a/src/exec/state.rs
+++ b/src/exec/state.rs
@@ -12,29 +12,52 @@ use crate::paper::{PaperClass, PAPER_A4};
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct State {
/// The direction for text and other inline objects.
- pub dir: Dir,
+ pub dirs: Gen<Dir>,
/// The current alignments of layouts in their parents.
pub aligns: Gen<Align>,
/// The current page settings.
- pub page: PageState,
- /// The current text settings.
- pub text: Rc<TextState>,
+ pub page: Rc<PageState>,
+ /// The current paragraph settings.
+ pub par: Rc<ParState>,
+ /// The current font settings.
+ pub font: Rc<FontState>,
}
impl State {
- /// Access the `text` state mutably.
- pub fn text_mut(&mut self) -> &mut TextState {
- Rc::make_mut(&mut self.text)
+ /// Access the `page` state mutably.
+ pub fn page_mut(&mut self) -> &mut PageState {
+ Rc::make_mut(&mut self.page)
+ }
+
+ /// Access the `par` state mutably.
+ pub fn par_mut(&mut self) -> &mut ParState {
+ 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)
+ }
+
+ /// The resolved line spacing.
+ pub fn line_spacing(&self) -> Length {
+ self.par.line_spacing.resolve(self.font.size)
+ }
+
+ /// The resolved paragraph spacing.
+ pub fn par_spacing(&self) -> Length {
+ self.par.par_spacing.resolve(self.font.size)
}
}
impl Default for State {
fn default() -> Self {
Self {
- dir: Dir::LTR,
+ dirs: Gen::new(Dir::LTR, Dir::TTB),
aligns: Gen::splat(Align::Start),
- page: PageState::default(),
- text: Rc::new(TextState::default()),
+ page: Rc::new(PageState::default()),
+ par: Rc::new(ParState::default()),
+ font: Rc::new(FontState::default()),
}
}
}
@@ -75,15 +98,27 @@ impl Default for PageState {
}
}
-/// Defines text properties.
+/// Style paragraph properties.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct TextState {
- /// A list of font families with generic class definitions (the final
- /// family list also depends on `monospace`).
- pub families: Rc<FamilyList>,
- /// The selected font variant (the final variant also depends on `strong`
- /// and `emph`).
- pub variant: FontVariant,
+pub struct ParState {
+ /// 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 {
+ fn default() -> Self {
+ Self {
+ par_spacing: Relative::new(1.0).into(),
+ line_spacing: Relative::new(0.5).into(),
+ }
+ }
+}
+
+/// Defines font properties.
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+pub struct FontState {
/// Whether the strong toggle is active or inactive. This determines
/// whether the next `*` adds or removes font weight.
pub strong: bool,
@@ -94,19 +129,18 @@ pub struct TextState {
pub monospace: bool,
/// The font size.
pub size: Length,
- /// The spacing between words (dependent on scaled font size).
- // TODO: Don't ignore this.
- pub word_spacing: Linear,
- /// The spacing between lines (dependent on scaled font size).
- pub line_spacing: Linear,
- /// The spacing between paragraphs (dependent on scaled font size).
- pub par_spacing: Linear,
+ /// The selected font variant (the final variant also depends on `strong`
+ /// and `emph`).
+ pub variant: FontVariant,
/// The top end of the text bounding box.
pub top_edge: VerticalFontMetric,
/// The bottom end of the text bounding box.
pub bottom_edge: VerticalFontMetric,
/// Glyph color.
pub fill: Paint,
+ /// A list of font families with generic class definitions (the final
+ /// family list also depends on `monospace`).
+ pub families: Rc<FamilyState>,
/// The specifications for a strikethrough line, if any.
pub strikethrough: Option<Rc<LineState>>,
/// The specifications for a underline, if any.
@@ -115,22 +149,7 @@ pub struct TextState {
pub overline: Option<Rc<LineState>>,
}
-impl TextState {
- /// Access the `families` list mutably.
- pub fn families_mut(&mut self) -> &mut FamilyList {
- Rc::make_mut(&mut self.families)
- }
-
- /// The resolved family iterator.
- pub fn families(&self) -> impl Iterator<Item = &str> + Clone {
- let head = if self.monospace {
- self.families.monospace.as_slice()
- } else {
- &[]
- };
- head.iter().map(String::as_str).chain(self.families.iter())
- }
-
+impl FontState {
/// The resolved variant with `strong` and `emph` factored in.
pub fn variant(&self) -> FontVariant {
let mut variant = self.variant;
@@ -150,26 +169,39 @@ impl TextState {
variant
}
- /// The resolved word spacing.
- pub fn word_spacing(&self) -> Length {
- self.word_spacing.resolve(self.size)
- }
+ /// The resolved family iterator.
+ pub fn families(&self) -> impl Iterator<Item = &str> + Clone {
+ let head = if self.monospace {
+ self.families.monospace.as_slice()
+ } else {
+ &[]
+ };
- /// The resolved line spacing.
- pub fn line_spacing(&self) -> Length {
- self.line_spacing.resolve(self.size)
+ let core = self.families.list.iter().flat_map(move |family: &FontFamily| {
+ match family {
+ FontFamily::Named(name) => std::slice::from_ref(name),
+ FontFamily::Serif => &self.families.serif,
+ FontFamily::SansSerif => &self.families.sans_serif,
+ FontFamily::Monospace => &self.families.monospace,
+ }
+ });
+
+ head.iter()
+ .chain(core)
+ .chain(self.families.base.iter())
+ .map(String::as_str)
}
- /// The resolved paragraph spacing.
- pub fn par_spacing(&self) -> Length {
- self.par_spacing.resolve(self.size)
+ /// Access the `families` state mutably.
+ pub fn families_mut(&mut self) -> &mut FamilyState {
+ Rc::make_mut(&mut self.families)
}
}
-impl Default for TextState {
+impl Default for FontState {
fn default() -> Self {
Self {
- families: Rc::new(FamilyList::default()),
+ families: Rc::new(FamilyState::default()),
variant: FontVariant {
style: FontStyle::Normal,
weight: FontWeight::REGULAR,
@@ -179,9 +211,6 @@ impl Default for TextState {
emph: false,
monospace: false,
size: Length::pt(11.0),
- word_spacing: Relative::new(0.25).into(),
- line_spacing: Relative::new(0.5).into(),
- par_spacing: Relative::new(1.0).into(),
top_edge: VerticalFontMetric::CapHeight,
bottom_edge: VerticalFontMetric::Baseline,
fill: Paint::Color(Color::Rgba(RgbaColor::BLACK)),
@@ -194,63 +223,46 @@ impl Default for TextState {
/// Font family definitions.
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
-pub struct FamilyList {
+pub struct FamilyState {
/// The user-defined list of font families.
- pub list: Vec<FontFamily>,
+ pub list: Rc<Vec<FontFamily>>,
/// Definition of serif font families.
- pub serif: Vec<String>,
+ pub serif: Rc<Vec<String>>,
/// Definition of sans-serif font families.
- pub sans_serif: Vec<String>,
+ pub sans_serif: Rc<Vec<String>>,
/// Definition of monospace font families used for raw text.
- pub monospace: Vec<String>,
- /// Base fonts that are tried if the list has no match.
- pub base: Vec<String>,
-}
-
-impl FamilyList {
- /// Flat iterator over this map's family names.
- pub fn iter(&self) -> impl Iterator<Item = &str> + Clone {
- self.list
- .iter()
- .flat_map(move |family: &FontFamily| {
- match family {
- FontFamily::Named(name) => std::slice::from_ref(name),
- FontFamily::Serif => &self.serif,
- FontFamily::SansSerif => &self.sans_serif,
- FontFamily::Monospace => &self.monospace,
- }
- })
- .chain(&self.base)
- .map(String::as_str)
- }
+ pub monospace: Rc<Vec<String>>,
+ /// Base fonts that are tried as last resort.
+ pub base: Rc<Vec<String>>,
}
-impl Default for FamilyList {
+impl Default for FamilyState {
fn default() -> Self {
Self {
- list: vec![FontFamily::Serif],
- serif: vec!["eb garamond".into()],
- sans_serif: vec!["pt sans".into()],
- monospace: vec!["inconsolata".into()],
- base: vec!["twitter color emoji".into(), "latin modern math".into()],
+ list: Rc::new(vec![FontFamily::Serif]),
+ serif: Rc::new(vec!["eb garamond".into()]),
+ sans_serif: Rc::new(vec!["pt sans".into()]),
+ monospace: Rc::new(vec!["inconsolata".into()]),
+ base: Rc::new(vec![
+ "twitter color emoji".into(),
+ "latin modern math".into(),
+ ]),
}
}
}
-/// Describes a line that is positioned over, under or on top of text.
+/// Defines a line that is positioned over, under or on top of text.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct LineState {
- /// Stroke color of the line.
- ///
- /// Defaults to the text color if `None`.
+ /// Stroke color of the line, defaults to the text color if `None`.
pub stroke: Option<Paint>,
- /// Thickness of the line's stroke. Calling functions should attempt to
- /// read this value from the appropriate font tables if this is `None`.
+ /// Thickness of the line's strokes (dependent on scaled font size), read
+ /// from the font tables if `None`.
pub thickness: Option<Linear>,
- /// Position of the line relative to the baseline. Calling functions should
- /// attempt to read this value from the appropriate font tables if this is
- /// `None`.
+ /// Position of the line relative to the baseline (dependent on scaled font
+ /// size), read from the font tables if `None`.
pub offset: Option<Linear>,
- /// Amount that the line will be longer or shorter than its associated text.
+ /// Amount that the line will be longer or shorter than its associated text
+ /// (dependent on scaled font size).
pub extent: Linear,
}