summaryrefslogtreecommitdiff
path: root/src/eval
diff options
context:
space:
mode:
Diffstat (limited to 'src/eval')
-rw-r--r--src/eval/mod.rs2
-rw-r--r--src/eval/scope.rs1
-rw-r--r--src/eval/state.rs180
-rw-r--r--src/eval/value.rs6
4 files changed, 186 insertions, 3 deletions
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index 65fc71c4..d21fbc7f 100644
--- a/src/eval/mod.rs
+++ b/src/eval/mod.rs
@@ -2,8 +2,10 @@
mod dict;
mod scope;
+mod state;
mod value;
pub use dict::*;
pub use scope::*;
+pub use state::*;
pub use value::*;
diff --git a/src/eval/scope.rs b/src/eval/scope.rs
index 8e6576d1..d4b24880 100644
--- a/src/eval/scope.rs
+++ b/src/eval/scope.rs
@@ -6,6 +6,7 @@ use std::fmt::{self, Debug, Formatter};
use super::value::FuncValue;
/// A map from identifiers to functions.
+#[derive(Clone, PartialEq)]
pub struct Scope {
functions: HashMap<String, FuncValue>,
}
diff --git a/src/eval/state.rs b/src/eval/state.rs
new file mode 100644
index 00000000..d6e0b195
--- /dev/null
+++ b/src/eval/state.rs
@@ -0,0 +1,180 @@
+//! State.
+
+use fontdock::{fallback, FallbackTree, FontStretch, FontStyle, FontVariant, FontWeight};
+
+use super::Scope;
+use crate::geom::{Insets, Linear, Sides, Size};
+use crate::layout::{Dir, GenAlign, LayoutAlign, LayoutSystem};
+use crate::length::Length;
+use crate::paper::{Paper, PaperClass, PAPER_A4};
+
+/// The active evaluation state.
+#[derive(Debug, Clone, PartialEq)]
+pub struct State {
+ /// The scope that contains function definitions.
+ pub scope: Scope,
+ /// The text state.
+ pub text: TextState,
+ /// The page state.
+ pub page: PageState,
+ /// The active layouting system.
+ pub sys: LayoutSystem,
+ /// The active alignments.
+ pub align: LayoutAlign,
+}
+
+impl Default for State {
+ fn default() -> Self {
+ Self {
+ scope: crate::library::_std(),
+ text: TextState::default(),
+ page: PageState::default(),
+ sys: LayoutSystem::new(Dir::LTR, Dir::TTB),
+ align: LayoutAlign::new(GenAlign::Start, GenAlign::Start),
+ }
+ }
+}
+
+/// Defines which fonts to use and how to space text.
+#[derive(Debug, Clone, PartialEq)]
+pub struct TextState {
+ /// A tree of font family names and generic class names.
+ pub fallback: FallbackTree,
+ /// The selected font variant.
+ pub variant: FontVariant,
+ /// Whether the strong toggle is active or inactive. This determines
+ /// whether the next `*` adds or removes font weight.
+ pub strong: bool,
+ /// Whether the emphasis toggle is active or inactive. This determines
+ /// whether the next `_` makes italic or non-italic.
+ pub emph: bool,
+ /// The font size.
+ pub font_size: FontSize,
+ /// The word spacing (relative to the the font size).
+ pub word_spacing: Linear,
+ /// The line spacing (relative to the the font size).
+ pub line_spacing: Linear,
+ /// The paragraphs spacing (relative to the the font size).
+ pub par_spacing: Linear,
+}
+
+impl TextState {
+ /// The absolute font size.
+ pub fn font_size(&self) -> f64 {
+ self.font_size.eval()
+ }
+
+ /// The absolute word spacing.
+ pub fn word_spacing(&self) -> f64 {
+ self.word_spacing.eval(self.font_size())
+ }
+
+ /// The absolute line spacing.
+ pub fn line_spacing(&self) -> f64 {
+ self.line_spacing.eval(self.font_size())
+ }
+
+ /// The absolute paragraph spacing.
+ pub fn paragraph_spacing(&self) -> f64 {
+ self.par_spacing.eval(self.font_size())
+ }
+}
+
+impl Default for TextState {
+ fn default() -> Self {
+ Self {
+ fallback: fallback! {
+ list: ["sans-serif"],
+ classes: {
+ "serif" => ["source serif pro", "noto serif"],
+ "sans-serif" => ["source sans pro", "noto sans"],
+ "monospace" => ["source code pro", "noto sans mono"],
+ "math" => ["latin modern math", "serif"],
+ },
+ base: [
+ "source sans pro", "noto sans", "segoe ui emoji",
+ "noto emoji", "latin modern math",
+ ],
+ },
+ variant: FontVariant {
+ style: FontStyle::Normal,
+ weight: FontWeight::REGULAR,
+ stretch: FontStretch::Normal,
+ },
+ strong: false,
+ emph: false,
+ font_size: FontSize::abs(Length::pt(11.0).as_raw()),
+ word_spacing: Linear::rel(0.25),
+ line_spacing: Linear::rel(0.2),
+ par_spacing: Linear::rel(0.5),
+ }
+ }
+}
+
+/// The font size, defined by base and scale.
+#[derive(Debug, Clone, PartialEq)]
+pub struct FontSize {
+ /// The base font size, updated whenever the font size is set absolutely.
+ pub base: f64,
+ /// The scale to apply on the base font size, updated when the font size
+ /// is set relatively.
+ pub scale: Linear,
+}
+
+impl FontSize {
+ /// Create a new font size.
+ pub fn new(base: f64, scale: Linear) -> Self {
+ Self { base, scale }
+ }
+
+ /// Create a new font size with the given `base` and a scale of `1.0`.
+ pub fn abs(base: f64) -> Self {
+ Self::new(base, Linear::rel(1.0))
+ }
+
+ /// Compute the absolute font size.
+ pub fn eval(&self) -> f64 {
+ self.scale.eval(self.base)
+ }
+}
+
+/// Defines the size and margins of a page.
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub struct PageState {
+ /// The class of this page.
+ pub class: PaperClass,
+ /// The width and height of the page.
+ pub size: Size,
+ /// The amount of white space in the order [left, top, right, bottom]. If a
+ /// side is set to `None`, the default for the paper class is used.
+ pub margins: Sides<Option<Linear>>,
+}
+
+impl PageState {
+ /// The default page style for the given paper.
+ pub fn new(paper: Paper) -> Self {
+ Self {
+ class: paper.class,
+ size: paper.size(),
+ margins: Sides::uniform(None),
+ }
+ }
+
+ /// The absolute insets.
+ pub fn insets(&self) -> Insets {
+ let Size { width, height } = self.size;
+ let default = self.class.default_margins();
+ Insets {
+ x0: -self.margins.left.unwrap_or(default.left).eval(width),
+ y0: -self.margins.top.unwrap_or(default.top).eval(height),
+ x1: -self.margins.right.unwrap_or(default.right).eval(width),
+ y1: -self.margins.bottom.unwrap_or(default.bottom).eval(height),
+ }
+ }
+}
+
+impl Default for PageState {
+ fn default() -> Self {
+ Self::new(PAPER_A4)
+ }
+}
diff --git a/src/eval/value.rs b/src/eval/value.rs
index f6c1fcd7..f88c0704 100644
--- a/src/eval/value.rs
+++ b/src/eval/value.rs
@@ -12,7 +12,7 @@ use crate::geom::Linear;
use crate::layout::{Command, Commands, Dir, LayoutContext, SpecAlign};
use crate::paper::Paper;
use crate::syntax::{Ident, Span, SpanWith, Spanned, SynNode, SynTree};
-use crate::{DynFuture, Feedback, Pass};
+use crate::{DynFuture, Feedback};
/// A computational value.
#[derive(Clone, PartialEq)]
@@ -149,13 +149,13 @@ impl Debug for Value {
pub struct FuncValue(pub Rc<FuncType>);
/// The signature of executable functions.
-type FuncType = dyn Fn(Span, DictValue, LayoutContext<'_>) -> DynFuture<Pass<Value>>;
+type FuncType = dyn Fn(DictValue, &mut LayoutContext) -> DynFuture<Value>;
impl FuncValue {
/// Create a new function value from a rust function or closure.
pub fn new<F: 'static>(f: F) -> Self
where
- F: Fn(Span, DictValue, LayoutContext<'_>) -> DynFuture<Pass<Value>>,
+ F: Fn(DictValue, &mut LayoutContext) -> DynFuture<Value>,
{
Self(Rc::new(f))
}