summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bin/main.rs1
-rw-r--r--src/diagnostic.rs91
-rw-r--r--src/export/pdf.rs35
-rw-r--r--src/func.rs4
-rw-r--r--src/layout/actions.rs23
-rw-r--r--src/layout/line.rs25
-rw-r--r--src/layout/mod.rs25
-rw-r--r--src/layout/model.rs9
-rw-r--r--src/layout/stack.rs51
-rw-r--r--src/layout/text.rs17
-rw-r--r--src/length.rs (renamed from src/size.rs)285
-rw-r--r--src/lib.rs35
-rw-r--r--src/library/font.rs27
-rw-r--r--src/library/layout.rs27
-rw-r--r--src/library/mod.rs1
-rw-r--r--src/library/page.rs21
-rw-r--r--src/library/spacing.rs19
-rw-r--r--src/paper.rs275
-rw-r--r--src/problem.rs94
-rw-r--r--src/style.rs303
-rw-r--r--src/syntax/expr.rs55
-rw-r--r--src/syntax/func/keys.rs1
-rw-r--r--src/syntax/func/maps.rs67
-rw-r--r--src/syntax/func/mod.rs8
-rw-r--r--src/syntax/func/values.rs43
-rw-r--r--src/syntax/mod.rs6
-rw-r--r--src/syntax/parsing.rs74
-rw-r--r--src/syntax/scope.rs22
-rw-r--r--src/syntax/span.rs94
-rw-r--r--src/syntax/test.rs6
-rw-r--r--src/syntax/tokens.rs52
31 files changed, 880 insertions, 916 deletions
diff --git a/src/bin/main.rs b/src/bin/main.rs
index 1b490397..b191b437 100644
--- a/src/bin/main.rs
+++ b/src/bin/main.rs
@@ -8,7 +8,6 @@ use typstc::{Typesetter, DebugErrorProvider};
use typstc::toddle::query::fs::EagerFsProvider;
use typstc::export::pdf;
-
fn main() {
if let Err(err) = run() {
eprintln!("error: {}", err);
diff --git a/src/diagnostic.rs b/src/diagnostic.rs
new file mode 100644
index 00000000..a5c5d0b8
--- /dev/null
+++ b/src/diagnostic.rs
@@ -0,0 +1,91 @@
+//! Diagnostics (errors / warnings) in source code.
+//!
+//! There are no fatal errors. The document will always compile and yield a
+//! layout. However, this is a best effort process and bad things will still
+//! generate errors and warnings.
+
+use serde::Serialize;
+use crate::syntax::span::SpanVec;
+
+/// A list of spanned diagnostics.
+pub type Diagnostics = SpanVec<Diagnostic>;
+
+/// A diagnostic that arose in parsing or layouting.
+#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
+pub struct Diagnostic {
+ /// How severe / important the diagnostic is.
+ pub level: Level,
+ /// A message describing the diagnostic.
+ pub message: String,
+}
+
+/// How severe / important a diagnostic is.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub enum Level {
+ Warning,
+ Error,
+}
+
+impl Diagnostic {
+ /// Create a new diagnostic from message and level.
+ pub fn new(message: impl Into<String>, level: Level) -> Self {
+ Self { message: message.into(), level }
+ }
+}
+
+/// Construct a diagnostic with `Error` level.
+///
+/// ```
+/// # use typstc::error;
+/// # use typstc::syntax::span::Span;
+/// # use typstc::Feedback;
+/// # let span = Span::ZERO;
+/// # let mut feedback = Feedback::new();
+/// # let name = "";
+/// // Create formatted error values.
+/// let error = error!("expected {}", name);
+///
+/// // Create spanned errors.
+/// let spanned = error!(span, "there is an error here");
+///
+/// // Create an error and directly add it to existing feedback.
+/// error!(@feedback, span, "oh no!");
+/// ```
+#[macro_export]
+macro_rules! error {
+ ($($tts:tt)*) => {
+ $crate::__impl_diagnostic!($crate::diagnostic::Level::Error; $($tts)*)
+ };
+}
+
+/// Construct a diagnostic with `Warning` level.
+///
+/// This works exactly like `error!`. See its documentation for more
+/// information.
+#[macro_export]
+macro_rules! warning {
+ ($($tts:tt)*) => {
+ $crate::__impl_diagnostic!($crate::diagnostic::Level::Warning; $($tts)*)
+ };
+}
+
+/// Backs the `error!` and `warning!` macros.
+#[macro_export]
+#[doc(hidden)]
+macro_rules! __impl_diagnostic {
+ ($level:expr; @$feedback:expr, $($tts:tt)*) => {
+ $feedback.diagnostics.push($crate::__impl_diagnostic!($level; $($tts)*));
+ };
+
+ ($level:expr; $fmt:literal $($tts:tt)*) => {
+ $crate::diagnostic::Diagnostic::new(format!($fmt $($tts)*), $level)
+ };
+
+ ($level:expr; $span:expr, $fmt:literal $($tts:tt)*) => {
+ $crate::syntax::span::Spanned::new(
+ $crate::__impl_diagnostic!($level; $fmt $($tts)*),
+ $span,
+ )
+ };
+}
diff --git a/src/export/pdf.rs b/src/export/pdf.rs
index 5c38084b..42587e5f 100644
--- a/src/export/pdf.rs
+++ b/src/export/pdf.rs
@@ -23,8 +23,7 @@ use toddle::tables::{
use crate::GlobalFontLoader;
use crate::layout::{MultiLayout, Layout, LayoutAction};
-use crate::size::Size;
-
+use crate::length::Length;
/// Export a layouted list of boxes. The same font loader as used for
/// layouting needs to be passed in here since the layout only contains
@@ -128,8 +127,8 @@ impl<'a, W: Write> PdfExporter<'a, W> {
let rect = Rect::new(
0.0,
0.0,
- page.dimensions.x.to_pt(),
- page.dimensions.y.to_pt(),
+ page.dimensions.x.to_pt() as f32,
+ page.dimensions.y.to_pt() as f32,
);
self.writer.write_obj(
@@ -167,14 +166,14 @@ impl<'a, W: Write> PdfExporter<'a, W> {
LayoutAction::SetFont(id, size) => {
active_font = (self.font_remap[id], size.to_pt());
- text.tf(active_font.0 as u32 + 1, size.to_pt());
+ text.tf(active_font.0 as u32 + 1, size.to_pt() as f32);
}
LayoutAction::WriteText(string) => {
if let Some(pos) = next_pos.take() {
let x = pos.x.to_pt();
- let y = (page.dimensions.y - pos.y - Size::pt(active_font.1)).to_pt();
- text.tm(1.0, 0.0, 0.0, 1.0, x, y);
+ let y = (page.dimensions.y - pos.y - Length::pt(active_font.1)).to_pt();
+ text.tm(1.0, 0.0, 0.0, 1.0, x as f32, y as f32);
}
text.tj(self.fonts[active_font.0].encode_text(&string)?);
@@ -219,8 +218,8 @@ impl<'a, W: Write> PdfExporter<'a, W> {
// Extract information from the head and hmtx tables.
let head = font.read_table::<Header>()?;
- let font_unit_ratio = 1.0 / (head.units_per_em as f32);
- let font_unit_to_size = |x| Size::pt(font_unit_ratio * x);
+ let font_unit_ratio = 1.0 / (head.units_per_em as f64);
+ let font_unit_to_size = |x| Length::pt(font_unit_ratio * x);
let font_unit_to_glyph_unit = |fu| {
let size = font_unit_to_size(fu);
(1000.0 * size.to_pt()).round() as GlyphUnit
@@ -228,10 +227,10 @@ impl<'a, W: Write> PdfExporter<'a, W> {
let italic = head.mac_style.contains(MacStyleFlags::ITALIC);
let bounding_box = Rect::new(
- font_unit_to_glyph_unit(head.x_min as f32),
- font_unit_to_glyph_unit(head.y_min as f32),
- font_unit_to_glyph_unit(head.x_max as f32),
- font_unit_to_glyph_unit(head.y_max as f32),
+ font_unit_to_glyph_unit(head.x_min as f64),
+ font_unit_to_glyph_unit(head.y_min as f64),
+ font_unit_to_glyph_unit(head.x_max as f64),
+ font_unit_to_glyph_unit(head.y_max as f64),
);
// Transform the width into PDF units.
@@ -239,7 +238,7 @@ impl<'a, W: Write> PdfExporter<'a, W> {
.read_table::<HorizontalMetrics>()?
.metrics
.iter()
- .map(|m| font_unit_to_glyph_unit(m.advance_width as f32))
+ .map(|m| font_unit_to_glyph_unit(m.advance_width as f64))
.collect();
// Write the CID font referencing the font descriptor.
@@ -274,12 +273,12 @@ impl<'a, W: Write> PdfExporter<'a, W> {
// Write the font descriptor (contains the global information about the font).
self.writer.write_obj(id + 2, FontDescriptor::new(base_font, flags, italic_angle)
.font_bbox(bounding_box)
- .ascent(font_unit_to_glyph_unit(os2.s_typo_ascender as f32))
- .descent(font_unit_to_glyph_unit(os2.s_typo_descender as f32))
+ .ascent(font_unit_to_glyph_unit(os2.s_typo_ascender as f64))
+ .descent(font_unit_to_glyph_unit(os2.s_typo_descender as f64))
.cap_height(font_unit_to_glyph_unit(
- os2.s_cap_height.unwrap_or(os2.s_typo_ascender) as f32,
+ os2.s_cap_height.unwrap_or(os2.s_typo_ascender) as f64,
))
- .stem_v((10.0 + 0.244 * (os2.us_weight_class as f32 - 50.0)) as GlyphUnit)
+ .stem_v((10.0 + 0.244 * (os2.us_weight_class as f64 - 50.0)) as GlyphUnit)
.font_file_2(id + 4)
)?;
diff --git a/src/func.rs b/src/func.rs
index e948d049..af3cd091 100644
--- a/src/func.rs
+++ b/src/func.rs
@@ -52,8 +52,8 @@ pub trait ParseFunc {
///
/// parse(header, body, state, f) {
/// let body = body!(opt: body, state, f);
-/// let hidden = header.args.pos.get::<bool>(&mut f.problems)
-/// .or_missing(&mut f.problems, header.name.span, "hidden")
+/// let hidden = header.args.pos.get::<bool>(&mut f.diagnostics)
+/// .or_missing(&mut f.diagnostics, header.name.span, "hidden")
/// .unwrap_or(false);
///
/// HiderFunc { body: if hidden { None } else { body } }
diff --git a/src/layout/actions.rs b/src/layout/actions.rs
index 8b50edfa..317cff25 100644
--- a/src/layout/actions.rs
+++ b/src/layout/actions.rs
@@ -4,23 +4,22 @@ use std::fmt::{self, Debug, Formatter};
use serde::ser::{Serialize, Serializer, SerializeTuple};
use toddle::query::FontIndex;
-use crate::size::{Size, Size2D};
+use crate::length::{Length, Size};
use super::Layout;
use self::LayoutAction::*;
-
/// A layouting action, which is the basic building block layouts are composed
/// of.
#[derive(Clone, PartialEq)]
pub enum LayoutAction {
/// Move to an absolute position.
- MoveAbsolute(Size2D),
+ MoveAbsolute(Size),
/// Set the font given the index from the font loader and font size.
- SetFont(FontIndex, Size),
+ SetFont(FontIndex, Length),
/// Write text at the current position.
WriteText(String),
/// Visualize a box for debugging purposes.
- DebugBox(Size2D),
+ DebugBox(Size),
}
impl Serialize for LayoutAction {
@@ -81,11 +80,11 @@ impl Debug for LayoutAction {
/// position.
#[derive(Debug, Clone, PartialEq)]
pub struct LayoutActions {
- origin: Size2D,
+ origin: Size,
actions: Vec<LayoutAction>,
- active_font: (FontIndex, Size),
- next_pos: Option<Size2D>,
- next_font: Option<(FontIndex, Size)>,
+ active_font: (FontIndex, Length),
+ next_pos: Option<Size>,
+ next_font: Option<(FontIndex, Length)>,
}
impl LayoutActions {
@@ -93,8 +92,8 @@ impl LayoutActions {
pub fn new() -> LayoutActions {
LayoutActions {
actions: vec![],
- origin: Size2D::ZERO,
- active_font: (FontIndex::MAX, Size::ZERO),
+ origin: Size::ZERO,
+ active_font: (FontIndex::MAX, Length::ZERO),
next_pos: None,
next_font: None,
}
@@ -126,7 +125,7 @@ impl LayoutActions {
/// Add a layout at a position. All move actions inside the layout are
/// translated by the position.
- pub fn add_layout(&mut self, position: Size2D, layout: Layout) {
+ pub fn add_layout(&mut self, position: Size, layout: Layout) {
self.flush_position();
self.origin = position;
diff --git a/src/layout/line.rs b/src/layout/line.rs
index 18ace29f..1bb36204 100644
--- a/src/layout/line.rs
+++ b/src/layout/line.rs
@@ -11,7 +11,6 @@
use super::stack::{StackLayouter, StackContext};
use super::*;
-
/// Performs the line layouting.
#[derive(Debug)]
pub struct LineLayouter {
@@ -40,7 +39,7 @@ pub struct LineContext {
/// extent of the layout.
pub debug: bool,
/// The line spacing.
- pub line_spacing: Size,
+ pub line_spacing: Length,
}
/// A line run is a sequence of boxes with the same alignment that are arranged
@@ -49,10 +48,10 @@ pub struct LineContext {
#[derive(Debug)]
struct LineRun {
/// The so-far accumulated layouts in the line.
- layouts: Vec<(Size, Layout)>,
- /// The width (primary size) and maximal height (secondary size) of the
+ layouts: Vec<(Length, Layout)>,
+ /// The width (primary length) and maximal height (secondary length) of the
/// line.
- size: Size2D,
+ size: Size,
/// The alignment of all layouts in the line.
///
/// When a new run is created the alignment is yet to be determined. Once a
@@ -61,7 +60,7 @@ struct LineRun {
alignment: Option<LayoutAlignment>,
/// If another line run with different alignment already took up some space
/// of the line, this run has less space and how much is stored here.
- usable: Option<Size>,
+ usable: Option<Length>,
/// A possibly cached soft spacing or spacing state.
last_spacing: LastSpacing,
}
@@ -156,7 +155,7 @@ impl LineLayouter {
///
/// This specifies how much more fits before a line break needs to be
/// issued.
- fn usable(&self) -> Size2D {
+ fn usable(&self) -> Size {
// The base is the usable space per stack layouter.
let mut usable = self.stack.usable().generalized(self.ctx.axes);
@@ -171,7 +170,7 @@ impl LineLayouter {
}
/// Add spacing along the primary axis to the line.
- pub fn add_primary_spacing(&mut self, mut spacing: Size, kind: SpacingKind) {
+ pub fn add_primary_spacing(&mut self, mut spacing: Length, kind: SpacingKind) {
match kind {
// A hard space is simply an empty box.
SpacingKind::Hard => {
@@ -197,7 +196,7 @@ impl LineLayouter {
}
/// Finish the line and add secondary spacing to the underlying stack.
- pub fn add_secondary_spacing(&mut self, spacing: Size, kind: SpacingKind) {
+ pub fn add_secondary_spacing(&mut self, spacing: Length, kind: SpacingKind) {
self.finish_line_if_not_empty();
self.stack.add_spacing(spacing, kind)
}
@@ -219,7 +218,7 @@ impl LineLayouter {
}
/// Update the line spacing.
- pub fn set_line_spacing(&mut self, line_spacing: Size) {
+ pub fn set_line_spacing(&mut self, line_spacing: Length) {
self.ctx.line_spacing = line_spacing;
}
@@ -235,7 +234,7 @@ impl LineLayouter {
/// Whether the currently set line is empty.
pub fn line_is_empty(&self) -> bool {
- self.run.size == Size2D::ZERO && self.run.layouts.is_empty()
+ self.run.size == Size::ZERO && self.run.layouts.is_empty()
}
/// Finish the last line and compute the final list of boxes.
@@ -265,7 +264,7 @@ impl LineLayouter {
- layout.dimensions.primary(self.ctx.axes),
};
- let pos = Size2D::with_x(x);
+ let pos = Size::with_x(x);
actions.add_layout(pos, layout);
}
@@ -293,7 +292,7 @@ impl LineRun {
fn new() -> LineRun {
LineRun {
layouts: vec![],
- size: Size2D::ZERO,
+ size: Size::ZERO,
alignment: None,
usable: None,
last_spacing: LastSpacing::Hard,
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 01d402db..4863d554 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -5,7 +5,7 @@ use smallvec::SmallVec;
use serde::Serialize;
use toddle::query::FontIndex;
-use crate::size::{Size, Size2D, SizeBox};
+use crate::length::{Length, Size, Margins};
use self::prelude::*;
pub mod line;
@@ -27,7 +27,6 @@ pub mod prelude {
pub use super::Alignment::{self, *};
}
-
/// A collection of layouts.
pub type MultiLayout = Vec<Layout>;
@@ -35,7 +34,7 @@ pub type MultiLayout = Vec<Layout>;
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct Layout {
/// The size of the box.
- pub dimensions: Size2D,
+ pub dimensions: Size,
/// How to align this layout in a parent container.
#[serde(skip)]
pub alignment: LayoutAlignment,
@@ -66,9 +65,9 @@ pub type LayoutSpaces = SmallVec<[LayoutSpace; 2]>;
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct LayoutSpace {
/// The maximum size of the box to layout in.
- pub dimensions: Size2D,
+ pub dimensions: Size,
/// Padding that should be respected on each side.
- pub padding: SizeBox,
+ pub padding: Margins,
/// Whether to expand the dimensions of the resulting layout to the full
/// dimensions of this space or to shrink them to fit the content.
pub expansion: LayoutExpansion,
@@ -77,12 +76,12 @@ pub struct LayoutSpace {
impl LayoutSpace {
/// The offset from the origin to the start of content, that is,
/// `(padding.left, padding.top)`.
- pub fn start(&self) -> Size2D {
- Size2D::new(self.padding.left, self.padding.top)
+ pub fn start(&self) -> Size {
+ Size::new(self.padding.left, self.padding.top)
}
/// The actually usable area (dimensions minus padding).
- pub fn usable(&self) -> Size2D {
+ pub fn usable(&self) -> Size {
self.dimensions.unpadded(self.padding)
}
@@ -90,7 +89,7 @@ impl LayoutSpace {
pub fn usable_space(&self) -> LayoutSpace {
LayoutSpace {
dimensions: self.usable(),
- padding: SizeBox::ZERO,
+ padding: Margins::ZERO,
expansion: LayoutExpansion::new(false, false),
}
}
@@ -369,17 +368,17 @@ enum LastSpacing {
/// The last item was hard spacing.
Hard,
/// The last item was soft spacing with the given width and level.
- Soft(Size, u32),
+ Soft(Length, u32),
/// The last item was not spacing.
None,
}
impl LastSpacing {
- /// The size of the soft space if this is a soft space or zero otherwise.
- fn soft_or_zero(self) -> Size {
+ /// The length of the soft space if this is a soft space or zero otherwise.
+ fn soft_or_zero(self) -> Length {
match self {
LastSpacing::Soft(space, _) => space,
- _ => Size::ZERO,
+ _ => Length::ZERO,
}
}
}
diff --git a/src/layout/model.rs b/src/layout/model.rs
index 91d21037..a15598d2 100644
--- a/src/layout/model.rs
+++ b/src/layout/model.rs
@@ -10,14 +10,13 @@ use toddle::query::FontStyle;
use crate::{Pass, Feedback};
use crate::GlobalFontLoader;
use crate::style::{LayoutStyle, PageStyle, TextStyle};
-use crate::size::{Size, Size2D};
+use crate::length::{Length, Size};
use crate::syntax::{Model, SyntaxModel, Node, Decoration};
use crate::syntax::span::{Span, Spanned};
use super::line::{LineLayouter, LineContext};
use super::text::{layout_text, TextContext};
use super::*;
-
/// Performs the model layouting.
#[derive(Debug)]
pub struct ModelLayouter<'a> {
@@ -36,7 +35,7 @@ pub struct LayoutContext<'a> {
/// The style for pages and text.
pub style: &'a LayoutStyle,
/// The base unpadded dimensions of this container (for relative sizing).
- pub base: Size2D,
+ pub base: Size,
/// The spaces to layout in.
pub spaces: LayoutSpaces,
/// Whether to have repeated spaces or to use only the first and only once.
@@ -76,7 +75,7 @@ pub enum Command<'a> {
/// Add spacing of given [kind](super::SpacingKind) along the primary or
/// secondary axis. The spacing kind defines how the spacing interacts with
/// surrounding spacing.
- AddSpacing(Size, SpacingKind, GenericAxis),
+ AddSpacing(Length, SpacingKind, GenericAxis),
/// Start a new line.
BreakLine,
@@ -159,7 +158,7 @@ impl<'a> ModelLayouter<'a> {
for Spanned { v: node, span } in &model.nodes {
let decorate = |this: &mut ModelLayouter, deco| {
- this.feedback.decos.push(Spanned::new(deco, *span));
+ this.feedback.decorations.push(Spanned::new(deco, *span));
};
match node {
diff --git a/src/layout/stack.rs b/src/layout/stack.rs
index 891815e9..20d99fa6 100644
--- a/src/layout/stack.rs
+++ b/src/layout/stack.rs
@@ -22,10 +22,9 @@
//! sentence in the second box.
use smallvec::smallvec;
-use crate::size::ValueBox;
+use crate::length::Value4;
use super::*;
-
/// Performs the stack layouting.
#[derive(Debug)]
pub struct StackLayouter {
@@ -66,14 +65,14 @@ struct Space {
/// The so-far accumulated layouts.
layouts: Vec<(LayoutAxes, Layout)>,
/// The specialized size of this space.
- size: Size2D,
+ size: Size,
/// The specialized remaining space.
- usable: Size2D,
+ usable: Size,
/// The specialized extra-needed dimensions to affect the size at all.
- extra: Size2D,
+ extra: Size,
/// The rulers of a space dictate which alignments for new boxes are still
/// allowed and which require a new space to be started.
- rulers: ValueBox<Alignment>,
+ rulers: Value4<Alignment>,
/// The last added spacing if the last added thing was spacing.
last_spacing: LastSpacing,
}
@@ -129,13 +128,13 @@ impl StackLayouter {
}
/// Add secondary spacing to the stack.
- pub fn add_spacing(&mut self, mut spacing: Size, kind: SpacingKind) {
+ pub fn add_spacing(&mut self, mut spacing: Length, kind: SpacingKind) {
match kind {
// A hard space is simply an empty box.
SpacingKind::Hard => {
// Reduce the spacing such that it definitely fits.
spacing.min_eq(self.space.usable.secondary(self.ctx.axes));
- let dimensions = Size2D::with_y(spacing);
+ let dimensions = Size::with_y(spacing);
self.update_metrics(dimensions);
self.space.layouts.push((self.ctx.axes, Layout {
@@ -165,17 +164,17 @@ impl StackLayouter {
/// Update the size metrics to reflect that a layout or spacing with the
/// given generalized dimensions has been added.
- fn update_metrics(&mut self, dimensions: Size2D) {
+ fn update_metrics(&mut self, dimensions: Size) {
let axes = self.ctx.axes;
let mut size = self.space.size.generalized(axes);
let mut extra = self.space.extra.generalized(axes);
- size.x += (dimensions.x - extra.x).max(Size::ZERO);
- size.y += (dimensions.y - extra.y).max(Size::ZERO);
+ size.x += (dimensions.x - extra.x).max(Length::ZERO);
+ size.y += (dimensions.y - extra.y).max(Length::ZERO);
extra.x.max_eq(dimensions.x);
- extra.y = (extra.y - dimensions.y).max(Size::ZERO);
+ extra.y = (extra.y - dimensions.y).max(Length::ZERO);
self.space.size = size.specialized(axes);
self.space.extra = extra.specialized(axes);
@@ -233,7 +232,7 @@ impl StackLayouter {
/// Move to the first space that can fit the given dimensions or do nothing
/// if no space is capable of that.
- pub fn skip_to_fitting_space(&mut self, dimensions: Size2D) {
+ pub fn skip_to_fitting_space(&mut self, dimensions: Size) {
let start = self.next_space();
for (index, space) in self.ctx.spaces[start..].iter().enumerate() {
if space.usable().fits(dimensions) {
@@ -251,7 +250,7 @@ impl StackLayouter {
let mut spaces = smallvec![LayoutSpace {
dimensions,
- padding: SizeBox::ZERO,
+ padding: Margins::ZERO,
expansion: LayoutExpansion::new(false, false),
}];
@@ -263,15 +262,15 @@ impl StackLayouter {
}
/// The remaining usable size.
- pub fn usable(&self) -> Size2D {
+ pub fn usable(&self) -> Size {
self.space.usable
- - Size2D::with_y(self.space.last_spacing.soft_or_zero())
+ - Size::with_y(self.space.last_spacing.soft_or_zero())
.specialized(self.ctx.axes)
}
/// Whether the current layout space (not subspace) is empty.
pub fn space_is_empty(&self) -> bool {
- self.space.size == Size2D::ZERO && self.space.layouts.is_empty()
+ self.space.size == Size::ZERO && self.space.layouts.is_empty()
}
/// Whether the current layout space is the last is the followup list.
@@ -310,7 +309,7 @@ impl StackLayouter {
let start = space.start();
let mut bounds = vec![];
- let mut bound = SizeBox {
+ let mut bound = Margins {
left: start.x,
top: start.y,
right: start.x + self.space.size.x,
@@ -337,7 +336,7 @@ impl StackLayouter {
// The `x` field stores the maximal primary extent in one axis-aligned
// run, while the `y` fields stores the accumulated secondary extent.
- let mut extent = Size2D::ZERO;
+ let mut extent = Size::ZERO;
let mut rotation = Vertical;
for (bound, entry) in bounds.iter_mut().zip(&self.space.layouts).rev() {
@@ -349,7 +348,7 @@ impl StackLayouter {
// is reset for this new axis-aligned run.
if rotation != axes.secondary.axis() {
extent.y = extent.x;
- extent.x = Size::ZERO;
+ extent.x = Length::ZERO;
rotation = axes.secondary.axis();
}
@@ -383,11 +382,11 @@ impl StackLayouter {
// The space in which this layout is aligned is given by the
// distances between the borders of it's bounding box.
let usable =
- Size2D::new(bound.right - bound.left, bound.bottom - bound.top)
+ Size::new(bound.right - bound.left, bound.bottom - bound.top)
.generalized(axes);
let local = usable.anchor(alignment, axes) - size.anchor(alignment, axes);
- let pos = Size2D::new(bound.left, bound.top) + local.specialized(axes);
+ let pos = Size::new(bound.left, bound.top) + local.specialized(axes);
actions.add_layout(pos, layout);
}
@@ -417,15 +416,15 @@ impl StackLayouter {
}
impl Space {
- fn new(index: usize, hard: bool, usable: Size2D) -> Space {
+ fn new(index: usize, hard: bool, usable: Size) -> Space {
Space {
index,
hard,
layouts: vec![],
- size: Size2D::ZERO,
+ size: Size::ZERO,
usable,
- extra: Size2D::ZERO,
- rulers: ValueBox::with_all(Origin),
+ extra: Size::ZERO,
+ rulers: Value4::with_all(Origin),
last_spacing: LastSpacing::Hard,
}
}
diff --git a/src/layout/text.rs b/src/layout/text.rs
index 286ccc68..cbe40214 100644
--- a/src/layout/text.rs
+++ b/src/layout/text.rs
@@ -8,11 +8,10 @@ use toddle::query::{FontQuery, FontIndex};
use toddle::tables::{CharMap, Header, HorizontalMetrics};
use crate::GlobalFontLoader;
-use crate::size::{Size, Size2D};
+use crate::length::{Length, Size};
use crate::style::TextStyle;
use super::*;
-
/// Performs the text layouting.
#[derive(Debug)]
struct TextLayouter<'a> {
@@ -21,7 +20,7 @@ struct TextLayouter<'a> {
actions: LayoutActions,
buffer: String,
active_font: FontIndex,
- width: Size,
+ width: Length,
}
/// The context for text layouting.
@@ -54,7 +53,7 @@ impl<'a> TextLayouter<'a> {
actions: LayoutActions::new(),
buffer: String::new(),
active_font: FontIndex::MAX,
- width: Size::ZERO,
+ width: Length::ZERO,
}
}
@@ -77,7 +76,7 @@ impl<'a> TextLayouter<'a> {
}
Layout {
- dimensions: Size2D::new(self.width, self.ctx.style.font_size()),
+ dimensions: Size::new(self.width, self.ctx.style.font_size()),
alignment: self.ctx.alignment,
actions: self.actions.into_vec(),
}
@@ -110,7 +109,7 @@ impl<'a> TextLayouter<'a> {
/// Select the best font for a character and return its index along with
/// the width of the char in the font.
- async fn select_font(&mut self, c: char) -> Option<(FontIndex, Size)> {
+ async fn select_font(&mut self, c: char) -> Option<(FontIndex, Length)> {
let mut loader = self.ctx.loader.borrow_mut();
let mut variant = self.ctx.style.variant;
@@ -127,8 +126,8 @@ impl<'a> TextLayouter<'a> {
if let Some((font, index)) = loader.get(query).await {
// Determine the width of the char.
let header = font.read_table::<Header>().ok()?;
- let font_unit_ratio = 1.0 / (header.units_per_em as f32);
- let font_unit_to_size = |x| Size::pt(font_unit_ratio * x);
+ let font_unit_ratio = 1.0 / (header.units_per_em as f64);
+ let font_unit_to_size = |x| Length::pt(font_unit_ratio * x);
let glyph = font
.read_table::<CharMap>()
@@ -139,7 +138,7 @@ impl<'a> TextLayouter<'a> {
.read_table::<HorizontalMetrics>()
.ok()?
.get(glyph)?
- .advance_width as f32;
+ .advance_width as f64;
let char_width = font_unit_to_size(glyph_width)
* self.ctx.style.font_size().to_pt();
diff --git a/src/size.rs b/src/length.rs
index e97b9248..8131a6e9 100644
--- a/src/size.rs
+++ b/src/length.rs
@@ -8,173 +8,166 @@ use serde::Serialize;
use crate::layout::prelude::*;
-
/// A general spacing type.
#[derive(Default, Copy, Clone, PartialEq, PartialOrd, Serialize)]
#[serde(transparent)]
-pub struct Size {
- /// The size in typographic points (1/72 inches).
- pub points: f32,
+pub struct Length {
+ /// The length in typographic points (1/72 inches).
+ pub points: f64,
}
-impl Size {
- /// The zeroed size.
- pub const ZERO: Size = Size { points: 0.0 };
+impl Length {
+ /// The zeroed length.
+ pub const ZERO: Length = Length { points: 0.0 };
- /// Create a size from an amount of points.
- pub fn pt(points: f32) -> Size { Size { points } }
+ /// Create a length from an amount of points.
+ pub fn pt(points: f64) -> Length { Length { points } }
- /// Create a size from an amount of millimeters.
- pub fn mm(mm: f32) -> Size { Size { points: 2.83465 * mm } }
+ /// Create a length from an amount of millimeters.
+ pub fn mm(mm: f64) -> Length { Length { points: 2.83465 * mm } }
- /// Create a size from an amount of centimeters.
- pub fn cm(cm: f32) -> Size { Size { points: 28.3465 * cm } }
+ /// Create a length from an amount of centimeters.
+ pub fn cm(cm: f64) -> Length { Length { points: 28.3465 * cm } }
- /// Create a size from an amount of inches.
- pub fn inches(inches: f32) -> Size { Size { points: 72.0 * inches } }
+ /// Create a length from an amount of inches.
+ pub fn inches(inches: f64) -> Length { Length { points: 72.0 * inches } }
- /// Convert this size into points.
- pub fn to_pt(self) -> f32 { self.points }
+ /// Convert this length into points.
+ pub fn to_pt(self) -> f64 { self.points }
- /// Convert this size into millimeters.
- pub fn to_mm(self) -> f32 { self.points * 0.352778 }
+ /// Convert this length into millimeters.
+ pub fn to_mm(self) -> f64 { self.points * 0.352778 }
- /// Convert this size into centimeters.
- pub fn to_cm(self) -> f32 { self.points * 0.0352778 }
+ /// Convert this length into centimeters.
+ pub fn to_cm(self) -> f64 { self.points * 0.0352778 }
- /// Convert this size into inches.
- pub fn to_inches(self) -> f32 { self.points * 0.0138889 }
+ /// Convert this length into inches.
+ pub fn to_inches(self) -> f64 { self.points * 0.0138889 }
- /// The maximum of this and the other size.
- pub fn max(self, other: Size) -> Size {
+ /// The maximum of this and the other length.
+ pub fn max(self, other: Length) -> Length {
if self > other { self } else { other }
}
- /// The minimum of this and the other size.
- pub fn min(self, other: Size) -> Size {
+ /// The minimum of this and the other length.
+ pub fn min(self, other: Length) -> Length {
if self <= other { self } else { other }
}
- /// Set this size to the maximum of itself and the other size.
- pub fn max_eq(&mut self, other: Size) { *self = self.max(other); }
+ /// Set this length to the maximum of itself and the other length.
+ pub fn max_eq(&mut self, other: Length) { *self = self.max(other); }
- /// Set this size to the minimum of itself and the other size.
- pub fn min_eq(&mut self, other: Size) { *self = self.min(other); }
+ /// Set this length to the minimum of itself and the other length.
+ pub fn min_eq(&mut self, other: Length) { *self = self.min(other); }
/// The anchor position along the given direction for an item with the given
- /// alignment in a container with this size.
- pub fn anchor(self, alignment: Alignment, direction: Direction) -> Size {
+ /// alignment in a container with this length.
+ pub fn anchor(self, alignment: Alignment, direction: Direction) -> Length {
match (direction.is_positive(), alignment) {
- (true, Origin) | (false, End) => Size::ZERO,
+ (true, Origin) | (false, End) => Length::ZERO,
(_, Center) => self / 2,
(true, End) | (false, Origin) => self,
}
}
}
-impl Display for Size {
+impl Display for Length {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}pt", self.points)
}
}
-impl Debug for Size {
+impl Debug for Length {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Display::fmt(self, f)
}
}
-impl Neg for Size {
- type Output = Size;
+impl Neg for Length {
+ type Output = Length;
- fn neg(self) -> Size {
- Size { points: -self.points }
+ fn neg(self) -> Length {
+ Length { points: -self.points }
}
}
-impl Sum for Size {
- fn sum<I>(iter: I) -> Size
- where I: Iterator<Item = Size> {
- iter.fold(Size::ZERO, Add::add)
+impl Sum for Length {
+ fn sum<I>(iter: I) -> Length
+ where I: Iterator<Item = Length> {
+ iter.fold(Length::ZERO, Add::add)
}
}
-/// Either an absolute size or a factor of some entity.
+/// Either an absolute length or a factor of some entity.
#[derive(Copy, Clone, PartialEq)]
#[allow(missing_docs)]
-pub enum ScaleSize {
- Absolute(Size),
- Scaled(f32),
+pub enum ScaleLength {
+ Absolute(Length),
+ Scaled(f64),
}
-impl ScaleSize {
+impl ScaleLength {
/// Use the absolute value or scale the entity.
- pub fn scaled(&self, entity: Size) -> Size {
+ pub fn scaled(&self, entity: Length) -> Length {
match self {
- ScaleSize::Absolute(s) => *s,
- ScaleSize::Scaled(s) => *s * entity,
+ ScaleLength::Absolute(s) => *s,
+ ScaleLength::Scaled(s) => *s * entity,
}
}
}
-impl Display for ScaleSize {
+impl Display for ScaleLength {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
- ScaleSize::Absolute(size) => write!(f, "{}", size),
- ScaleSize::Scaled(scale) => write!(f, "{}%", scale * 100.0),
+ ScaleLength::Absolute(length) => write!(f, "{}", length),
+ ScaleLength::Scaled(scale) => write!(f, "{}%", scale * 100.0),
}
}
}
-impl Debug for ScaleSize {
+impl Debug for ScaleLength {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Display::fmt(self, f)
}
}
-/// A scale size that is scaled by the font size.
-pub type FSize = ScaleSize;
-
-/// A scale size that is scaled by the size of the padded parent container.
-pub type PSize = ScaleSize;
-
/// A value in two dimensions.
#[derive(Default, Copy, Clone, Eq, PartialEq, Serialize)]
-pub struct Value2D<T> {
+pub struct Value2<T> {
/// The horizontal component.
pub x: T,
/// The vertical component.
pub y: T,
}
-impl<T: Clone> Value2D<T> {
+impl<T: Clone> Value2<T> {
/// Create a new 2D-value from two values.
- pub fn new(x: T, y: T) -> Value2D<T> { Value2D { x, y } }
+ pub fn new(x: T, y: T) -> Value2<T> { Value2 { x, y } }
/// Create a new 2D-value with `x` set to a value and `y` to default.
- pub fn with_x(x: T) -> Value2D<T> where T: Default {
- Value2D { x, y: T::default() }
+ pub fn with_x(x: T) -> Value2<T> where T: Default {
+ Value2 { x, y: T::default() }
}
/// Create a new 2D-value with `y` set to a value and `x` to default.
- pub fn with_y(y: T) -> Value2D<T> where T: Default {
- Value2D { x: T::default(), y }
+ pub fn with_y(y: T) -> Value2<T> where T: Default {
+ Value2 { x: T::default(), y }
}
/// Create a new 2D-value with the primary axis set to a value and the other
/// one to default.
- pub fn with_primary(v: T, axes: LayoutAxes) -> Value2D<T> where T: Default {
- Value2D::with_x(v).generalized(axes)
+ pub fn with_primary(v: T, axes: LayoutAxes) -> Value2<T> where T: Default {
+ Value2::with_x(v).generalized(axes)
}
/// Create a new 2D-value with the secondary axis set to a value and the
/// other one to default.
- pub fn with_secondary(v: T, axes: LayoutAxes) -> Value2D<T> where T: Default {
- Value2D::with_y(v).generalized(axes)
+ pub fn with_secondary(v: T, axes: LayoutAxes) -> Value2<T> where T: Default {
+ Value2::with_y(v).generalized(axes)
}
/// Create a 2D-value with `x` and `y` set to the same value `s`.
- pub fn with_all(s: T) -> Value2D<T> { Value2D { x: s.clone(), y: s } }
+ pub fn with_all(s: T) -> Value2<T> { Value2 { x: s.clone(), y: s } }
/// Get the specificed component.
pub fn get(self, axis: SpecificAxis) -> T {
@@ -216,16 +209,16 @@ impl<T: Clone> Value2D<T> {
/// axes, that is:
/// - `x` describes the primary axis instead of the horizontal one.
/// - `y` describes the secondary axis instead of the vertical one.
- pub fn generalized(self, axes: LayoutAxes) -> Value2D<T> {
+ pub fn generalized(self, axes: LayoutAxes) -> Value2<T> {
match axes.primary.axis() {
Horizontal => self,
- Vertical => Value2D { x: self.y, y: self.x },
+ Vertical => Value2 { x: self.y, y: self.x },
}
}
/// Returns the specialized version of this generalized Size2D (inverse to
/// `generalized`).
- pub fn specialized(self, axes: LayoutAxes) -> Value2D<T> {
+ pub fn specialized(self, axes: LayoutAxes) -> Value2<T> {
// In fact, generalized is its own inverse. For reasons of clarity
// at the call site, we still have this second function.
self.generalized(axes)
@@ -237,7 +230,7 @@ impl<T: Clone> Value2D<T> {
}
}
-impl<T> Debug for Value2D<T> where T: Debug {
+impl<T> Debug for Value2<T> where T: Debug {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_list()
.entry(&self.x)
@@ -247,83 +240,61 @@ impl<T> Debug for Value2D<T> where T: Debug {
}
/// A position or extent in 2-dimensional space.
-pub type Size2D = Value2D<Size>;
+pub type Size = Value2<Length>;
-impl Size2D {
- /// The zeroed 2D-size.
- pub const ZERO: Size2D = Size2D { x: Size::ZERO, y: Size::ZERO };
+impl Size {
+ /// The zeroed 2D-length.
+ pub const ZERO: Size = Size { x: Length::ZERO, y: Length::ZERO };
- /// Whether the given 2D-size fits into this one, that is, both coordinate
+ /// Whether the given 2D-length fits into this one, that is, both coordinate
/// values are smaller or equal.
- pub fn fits(self, other: Size2D) -> bool {
+ pub fn fits(self, other: Size) -> bool {
self.x >= other.x && self.y >= other.y
}
- /// Return a 2D-size padded by the paddings of the given box.
- pub fn padded(self, padding: SizeBox) -> Size2D {
- Size2D {
+ /// Return a 2D-length padded by the paddings of the given box.
+ pub fn padded(self, padding: Margins) -> Size {
+ Size {
x: self.x + padding.left + padding.right,
y: self.y + padding.top + padding.bottom,
}
}
- /// Return a 2D-size reduced by the paddings of the given box.
- pub fn unpadded(self, padding: SizeBox) -> Size2D {
- Size2D {
+ /// Return a 2D-length reduced by the paddings of the given box.
+ pub fn unpadded(self, padding: Margins) -> Size {
+ Size {
x: self.x - padding.left - padding.right,
y: self.y - padding.top - padding.bottom,
}
}
/// The anchor position along the given axis for an item with the given
- /// alignment in a container with this size.
+ /// alignment in a container with this length.
///
- /// This assumes the size to be generalized such that `x` corresponds to the
+ /// This assumes the length to be generalized such that `x` corresponds to the
/// primary axis.
- pub fn anchor(self, alignment: LayoutAlignment, axes: LayoutAxes) -> Size2D {
- Size2D {
+ pub fn anchor(self, alignment: LayoutAlignment, axes: LayoutAxes) -> Size {
+ Size {
x: self.x.anchor(alignment.primary, axes.primary),
y: self.y.anchor(alignment.secondary, axes.secondary),
}
}
}
-impl Neg for Size2D {
- type Output = Size2D;
+impl Neg for Size {
+ type Output = Size;
- fn neg(self) -> Size2D {
- Size2D {
+ fn neg(self) -> Size {
+ Size {
x: -self.x,
y: -self.y,
}
}
}
-/// A value that is stretchable in an interval from a minimal through an optimal
-/// to a maximal value.
-#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Serialize)]
-pub struct StretchValue<T> {
- /// The minimum this value can be stretched to.
- pub min: T,
- /// The optimum for this value.
- pub opt: T,
- /// The maximum this value can be stretched to.
- pub max: T,
-}
-
-impl<T> StretchValue<T> {
- /// Create a new stretch size from minimum, optimal and maximum values.
- pub fn new(min: T, opt: T, max: T) -> StretchValue<T> {
- StretchValue { min, opt, max }
- }
-}
-
-/// A size that is stretchable.
-pub type StretchSize = StretchValue<Size>;
-
/// A value in four dimensions.
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Serialize)]
-pub struct ValueBox<T> {
+pub struct Value4<T> {
/// The left extent.
pub left: T,
/// The top extent.
@@ -334,15 +305,15 @@ pub struct ValueBox<T> {
pub bottom: T,
}
-impl<T: Clone> ValueBox<T> {
+impl<T: Clone> Value4<T> {
/// Create a new box from four sizes.
- pub fn new(left: T, top: T, right: T, bottom: T) -> ValueBox<T> {
- ValueBox { left, top, right, bottom }
+ pub fn new(left: T, top: T, right: T, bottom: T) -> Value4<T> {
+ Value4 { left, top, right, bottom }
}
/// Create a box with all four fields set to the same value `s`.
- pub fn with_all(value: T) -> ValueBox<T> {
- ValueBox {
+ pub fn with_all(value: T) -> Value4<T> {
+ Value4 {
left: value.clone(),
top: value.clone(),
right: value.clone(),
@@ -369,7 +340,7 @@ impl<T: Clone> ValueBox<T> {
/// Set all values to the given value.
pub fn set_all(&mut self, value: T) {
- *self = ValueBox::with_all(value);
+ *self = Value4::with_all(value);
}
/// Set the `left` and `right` values.
@@ -385,47 +356,47 @@ impl<T: Clone> ValueBox<T> {
}
}
-/// A size in four dimensions.
-pub type SizeBox = ValueBox<Size>;
+/// A length in four dimensions.
+pub type Margins = Value4<Length>;
-impl SizeBox {
- /// The zeroed size box.
- pub const ZERO: SizeBox = SizeBox {
- left: Size::ZERO,
- top: Size::ZERO,
- right: Size::ZERO,
- bottom: Size::ZERO,
+impl Margins {
+ /// The zeroed length box.
+ pub const ZERO: Margins = Margins {
+ left: Length::ZERO,
+ top: Length::ZERO,
+ right: Length::ZERO,
+ bottom: Length::ZERO,
};
}
-impl FromStr for Size {
- type Err = ParseSizeError;
+impl FromStr for Length {
+ type Err = ParseLengthError;
- fn from_str(src: &str) -> Result<Size, ParseSizeError> {
+ fn from_str(src: &str) -> Result<Length, ParseLengthError> {
let func = match () {
- _ if src.ends_with("pt") => Size::pt,
- _ if src.ends_with("mm") => Size::mm,
- _ if src.ends_with("cm") => Size::cm,
- _ if src.ends_with("in") => Size::inches,
- _ => return Err(ParseSizeError(())),
+ _ if src.ends_with("pt") => Length::pt,
+ _ if src.ends_with("mm") => Length::mm,
+ _ if src.ends_with("cm") => Length::cm,
+ _ if src.ends_with("in") => Length::inches,
+ _ => return Err(ParseLengthError),
};
Ok(func(src[..src.len() - 2]
- .parse::<f32>()
- .map_err(|_| ParseSizeError(()))?))
+ .parse::<f64>()
+ .map_err(|_| ParseLengthError)?))
}
}
-/// An error which can be returned when parsing a size.
+/// An error which can be returned when parsing a length.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub struct ParseSizeError(());
+pub struct ParseLengthError;
-impl std::error::Error for ParseSizeError {}
+impl std::error::Error for ParseLengthError {}
-impl Display for ParseSizeError {
+impl Display for ParseLengthError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.write_str("invalid string for size")
+ f.write_str("invalid string for length")
}
}
@@ -448,7 +419,7 @@ macro_rules! implement_traits {
})*
$(implement_traits!(@$w i32, $ty $t $o $($rest)*);)*
- $(implement_traits!(@$w f32, $ty $t $o $($rest)*);)*
+ $(implement_traits!(@$w f64, $ty $t $o $($rest)*);)*
};
(@front $num:ty, $ty:ident $t:ident $o:ident
@@ -458,7 +429,7 @@ macro_rules! implement_traits {
impl $tr<$ty> for $num {
type Output = $ty;
fn $tf($t, $o: $ty) -> $ty {
- $ty { $($f: $tr::$tf($t as f32, $o.$f),)* }
+ $ty { $($f: $tr::$tf($t as f64, $o.$f),)* }
}
}
};
@@ -470,12 +441,12 @@ macro_rules! implement_traits {
impl $tr<$num> for $ty {
type Output = $ty;
fn $tf($t, $o: $num) -> $ty {
- $ty { $($f: $tr::$tf($t.$f, $o as f32),)* }
+ $ty { $($f: $tr::$tf($t.$f, $o as f64),)* }
}
}
impl $at<$num> for $ty {
- fn $af(&mut $t, $o: $num) { $($at::$af(&mut $t.$f, $o as f32);)* }
+ fn $af(&mut $t, $o: $num) { $($at::$af(&mut $t.$f, $o as f64);)* }
}
};
}
@@ -499,5 +470,5 @@ macro_rules! implement_size {
};
}
-implement_size! { Size(self, other) [points] }
-implement_size! { Size2D(self, other) [x, y] }
+implement_size! { Length(self, other) [points] }
+implement_size! { Size(self, other) [x, y] }
diff --git a/src/lib.rs b/src/lib.rs
index 8f5bbdd6..77abb6ad 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -27,12 +27,11 @@ use toddle::{Font, OwnedData};
use toddle::query::{FontLoader, SharedFontLoader};
use toddle::query::{FontProvider, FontIndex, FontDescriptor};
-use crate::problem::Problems;
+use crate::diagnostic::Diagnostics;
use crate::layout::MultiLayout;
use crate::style::{LayoutStyle, PageStyle, TextStyle};
-use crate::syntax::{SyntaxModel, Scope, Decoration, ParseState, parse};
-use crate::syntax::span::{Position, SpanVec, offset_spans};
-
+use crate::syntax::{Decorations, SyntaxModel, Scope, ParseState, parse};
+use crate::syntax::span::{Offset, Pos};
/// Declare a module and reexport all its contents.
macro_rules! pub_use_mod {
@@ -45,17 +44,17 @@ macro_rules! pub_use_mod {
#[macro_use]
mod macros;
#[macro_use]
-pub mod problem;
+pub mod diagnostic;
pub mod export;
#[macro_use]
pub mod func;
pub mod layout;
pub mod library;
-pub mod size;
+pub mod length;
+pub mod paper;
pub mod style;
pub mod syntax;
-
/// Transforms source code into typesetted layouts.
///
/// A typesetter can be configured through various methods.
@@ -112,7 +111,7 @@ impl Typesetter {
/// Parse source code into a syntax tree.
pub fn parse(&self, src: &str) -> Pass<SyntaxModel> {
- parse(src, Position::ZERO, &self.parse_state)
+ parse(src, Pos::ZERO, &self.parse_state)
}
/// Layout a syntax tree and return the produced layout.
@@ -176,18 +175,18 @@ impl<T> Pass<T> {
/// User feedback data accumulated during a compilation pass.
#[derive(Debug, Default, Clone, Eq, PartialEq)]
pub struct Feedback {
- /// Problems in the source code.
- pub problems: Problems,
+ /// Diagnostics in the source code.
+ pub diagnostics: Diagnostics,
/// Decorations of the source code for semantic syntax highlighting.
- pub decos: SpanVec<Decoration>,
+ pub decorations: Decorations,
}
impl Feedback {
/// Create a new feedback instance without errors and decos.
pub fn new() -> Feedback {
Feedback {
- problems: vec![],
- decos: vec![],
+ diagnostics: vec![],
+ decorations: vec![],
}
}
@@ -199,15 +198,15 @@ impl Feedback {
/// Add other feedback data to this feedback.
pub fn extend(&mut self, other: Feedback) {
- self.problems.extend(other.problems);
- self.decos.extend(other.decos);
+ self.diagnostics.extend(other.diagnostics);
+ self.decorations.extend(other.decorations);
}
/// Add more feedback whose spans are local and need to be offset by an
/// `offset` to be correct in this feedback's context.
- pub fn extend_offset(&mut self, more: Feedback, offset: Position) {
- self.problems.extend(offset_spans(more.problems, offset));
- self.decos.extend(offset_spans(more.decos, offset));
+ pub fn extend_offset(&mut self, more: Feedback, offset: Pos) {
+ self.diagnostics.extend(more.diagnostics.offset(offset));
+ self.decorations.extend(more.decorations.offset(offset));
}
}
diff --git a/src/library/font.rs b/src/library/font.rs
index 9f7902f6..28b79115 100644
--- a/src/library/font.rs
+++ b/src/library/font.rs
@@ -1,8 +1,7 @@
use toddle::query::{FontWeight, FontStyle};
-use crate::size::FSize;
+use crate::length::ScaleLength;
use super::*;
-
function! {
/// `font.family`: Set the font family.
#[derive(Debug, Clone, PartialEq)]
@@ -13,17 +12,17 @@ function! {
}
parse(header, body, ctx, f) {
- let list = header.args.pos.get_all::<StringLike>(&mut f.problems)
+ let list = header.args.pos.get_all::<StringLike>(&mut f.diagnostics)
.map(|s| s.0.to_lowercase())
.collect();
let tuples: Vec<_> = header.args.key
- .get_all::<String, Tuple>(&mut f.problems)
+ .get_all::<String, Tuple>(&mut f.diagnostics)
.collect();
let classes = tuples.into_iter()
.map(|(class, mut tuple)| {
- let fallback = tuple.get_all::<StringLike>(&mut f.problems)
+ let fallback = tuple.get_all::<StringLike>(&mut f.diagnostics)
.map(|s| s.0.to_lowercase())
.collect();
(class.to_lowercase(), fallback)
@@ -64,8 +63,8 @@ function! {
parse(header, body, ctx, f) {
FontStyleFunc {
body: body!(opt: body, ctx, f),
- style: header.args.pos.get::<FontStyle>(&mut f.problems)
- .or_missing(&mut f.problems, header.name.span, "style"),
+ style: header.args.pos.get::<FontStyle>(&mut f.diagnostics)
+ .or_missing(&mut f.diagnostics, header.name.span, "style"),
}
}
@@ -84,7 +83,7 @@ function! {
parse(header, body, ctx, f) {
let body = body!(opt: body, ctx, f);
- let weight = header.args.pos.get::<Spanned<(FontWeight, bool)>>(&mut f.problems)
+ let weight = header.args.pos.get::<Spanned<(FontWeight, bool)>>(&mut f.diagnostics)
.map(|Spanned { v: (weight, is_clamped), span }| {
if is_clamped {
warning!(
@@ -96,7 +95,7 @@ function! {
weight
})
- .or_missing(&mut f.problems, header.name.span, "weight");
+ .or_missing(&mut f.diagnostics, header.name.span, "weight");
FontWeightFunc { body, weight }
}
@@ -111,25 +110,25 @@ function! {
#[derive(Debug, Clone, PartialEq)]
pub struct FontSizeFunc {
body: Option<SyntaxModel>,
- size: Option<FSize>,
+ size: Option<ScaleLength>,
}
parse(header, body, ctx, f) {
FontSizeFunc {
body: body!(opt: body, ctx, f),
- size: header.args.pos.get::<FSize>(&mut f.problems)
- .or_missing(&mut f.problems, header.name.span, "size")
+ size: header.args.pos.get::<ScaleLength>(&mut f.diagnostics)
+ .or_missing(&mut f.diagnostics, header.name.span, "size")
}
}
layout(self, ctx, f) {
styled(&self.body, ctx, self.size, |t, s| {
match s {
- FSize::Absolute(size) => {
+ ScaleLength::Absolute(size) => {
t.base_font_size = size;
t.font_scale = 1.0;
}
- FSize::Scaled(scale) => t.font_scale = scale,
+ ScaleLength::Scaled(scale) => t.font_scale = scale,
}
})
}
diff --git a/src/library/layout.rs b/src/library/layout.rs
index 9fac37b7..2d0e3ac5 100644
--- a/src/library/layout.rs
+++ b/src/library/layout.rs
@@ -1,7 +1,6 @@
-use crate::size::PSize;
+use crate::length::ScaleLength;
use super::*;
-
function! {
/// `align`: Aligns content along the layouting axes.
#[derive(Debug, Clone, PartialEq)]
@@ -13,14 +12,14 @@ function! {
parse(header, body, ctx, f) {
AlignFunc {
body: body!(opt: body, ctx, f),
- map: PosAxisMap::parse::<AxisKey>(&mut f.problems, &mut header.args),
+ map: PosAxisMap::parse::<AxisKey>(&mut f.diagnostics, &mut header.args),
}
}
layout(self, ctx, f) {
ctx.base = ctx.spaces[0].dimensions;
- let map = self.map.dedup(&mut f.problems, ctx.axes, |alignment| {
+ let map = self.map.dedup(&mut f.diagnostics, ctx.axes, |alignment| {
alignment.axis().map(|s| s.to_generic(ctx.axes))
});
@@ -61,14 +60,14 @@ function! {
DirectionFunc {
name_span: header.name.span,
body: body!(opt: body, ctx, f),
- map: PosAxisMap::parse::<AxisKey>(&mut f.problems, &mut header.args),
+ map: PosAxisMap::parse::<AxisKey>(&mut f.diagnostics, &mut header.args),
}
}
layout(self, ctx, f) {
ctx.base = ctx.spaces[0].dimensions;
- let map = self.map.dedup(&mut f.problems, ctx.axes, |direction| {
+ let map = self.map.dedup(&mut f.diagnostics, ctx.axes, |direction| {
Some(direction.axis().to_generic(ctx.axes))
});
@@ -103,15 +102,15 @@ function! {
#[derive(Debug, Clone, PartialEq)]
pub struct BoxFunc {
body: SyntaxModel,
- extents: AxisMap<PSize>,
+ extents: AxisMap<ScaleLength>,
debug: Option<bool>,
}
parse(header, body, ctx, f) {
BoxFunc {
body: body!(opt: body, ctx, f).unwrap_or(SyntaxModel::new()),
- extents: AxisMap::parse::<ExtentKey>(&mut f.problems, &mut header.args.key),
- debug: header.args.key.get::<bool>(&mut f.problems, "debug"),
+ extents: AxisMap::parse::<ExtentKey>(&mut f.diagnostics, &mut header.args.key),
+ debug: header.args.key.get::<bool>(&mut f.diagnostics, "debug"),
}
}
@@ -123,12 +122,12 @@ function! {
ctx.debug = debug;
}
- let map = self.extents.dedup(&mut f.problems, ctx.axes);
+ let map = self.extents.dedup(&mut f.diagnostics, ctx.axes);
for &axis in &[Horizontal, Vertical] {
- if let Some(psize) = map.get(axis) {
- let size = psize.scaled(ctx.base.get(axis));
- *ctx.base.get_mut(axis) = size;
- *ctx.spaces[0].dimensions.get_mut(axis) = size;
+ if let Some(scale) = map.get(axis) {
+ let length = scale.scaled(ctx.base.get(axis));
+ *ctx.base.get_mut(axis) = length;
+ *ctx.spaces[0].dimensions.get_mut(axis) = length;
*ctx.spaces[0].expansion.get_mut(axis) = true;
}
}
diff --git a/src/library/mod.rs b/src/library/mod.rs
index e1aa4ac2..433a4c73 100644
--- a/src/library/mod.rs
+++ b/src/library/mod.rs
@@ -8,7 +8,6 @@ pub_use_mod!(layout);
pub_use_mod!(page);
pub_use_mod!(spacing);
-
/// Create a scope with all standard functions.
pub fn std() -> Scope {
let mut std = Scope::new::<ValFunc>();
diff --git a/src/library/page.rs b/src/library/page.rs
index 1e782f8f..dd63a0a7 100644
--- a/src/library/page.rs
+++ b/src/library/page.rs
@@ -1,23 +1,22 @@
-use crate::size::Size;
-use crate::style::{Paper, PaperClass};
+use crate::length::Length;
+use crate::paper::{Paper, PaperClass};
use super::*;
-
function! {
/// `page.size`: Set the size of pages.
#[derive(Debug, Clone, PartialEq)]
pub struct PageSizeFunc {
paper: Option<Paper>,
- extents: AxisMap<Size>,
+ extents: AxisMap<Length>,
flip: bool,
}
parse(header, body, state, f) {
body!(nope: body, f);
PageSizeFunc {
- paper: header.args.pos.get::<Paper>(&mut f.problems),
- extents: AxisMap::parse::<ExtentKey>(&mut f.problems, &mut header.args.key),
- flip: header.args.key.get::<bool>(&mut f.problems, "flip").unwrap_or(false),
+ paper: header.args.pos.get::<Paper>(&mut f.diagnostics),
+ extents: AxisMap::parse::<ExtentKey>(&mut f.diagnostics, &mut header.args.key),
+ flip: header.args.key.get::<bool>(&mut f.diagnostics, "flip").unwrap_or(false),
}
}
@@ -26,12 +25,12 @@ function! {
if let Some(paper) = self.paper {
style.class = paper.class;
- style.dimensions = paper.dimensions;
+ style.dimensions = paper.size();
} else {
style.class = PaperClass::Custom;
}
- let map = self.extents.dedup(&mut f.problems, ctx.axes);
+ let map = self.extents.dedup(&mut f.diagnostics, ctx.axes);
map.with(Horizontal, |&width| style.dimensions.x = width);
map.with(Vertical, |&height| style.dimensions.y = height);
@@ -53,13 +52,13 @@ function! {
parse(header, body, state, f) {
body!(nope: body, f);
PageMarginsFunc {
- padding: PaddingMap::parse(&mut f.problems, &mut header.args),
+ padding: PaddingMap::parse(&mut f.diagnostics, &mut header.args),
}
}
layout(self, ctx, f) {
let mut style = ctx.style.page;
- self.padding.apply(&mut f.problems, ctx.axes, &mut style.margins);
+ self.padding.apply(&mut f.diagnostics, ctx.axes, &mut style.margins);
vec![SetPageStyle(style)]
}
}
diff --git a/src/library/spacing.rs b/src/library/spacing.rs
index adca20af..5ae25a92 100644
--- a/src/library/spacing.rs
+++ b/src/library/spacing.rs
@@ -1,10 +1,9 @@
-use crate::size::FSize;
+use crate::length::ScaleLength;
use crate::layout::SpacingKind;
use super::*;
use self::ContentKind::*;
-
function! {
/// `line.break`, `n`: Ends the current line.
#[derive(Debug, Default, Clone, PartialEq)]
@@ -41,7 +40,7 @@ function! {
pub struct ContentSpacingFunc {
body: Option<SyntaxModel>,
content: ContentKind,
- spacing: Option<f32>,
+ spacing: Option<f64>,
}
type Meta = ContentKind;
@@ -50,9 +49,9 @@ function! {
ContentSpacingFunc {
body: body!(opt: body, state, f),
content: meta,
- spacing: header.args.pos.get::<f64>(&mut f.problems)
- .map(|num| num as f32)
- .or_missing(&mut f.problems, header.name.span, "spacing"),
+ spacing: header.args.pos.get::<f64>(&mut f.diagnostics)
+ .map(|num| num as f64)
+ .or_missing(&mut f.diagnostics, header.name.span, "spacing"),
}
}
@@ -79,7 +78,7 @@ function! {
/// `spacing`, `h`, `v`: Adds spacing along an axis.
#[derive(Debug, Clone, PartialEq)]
pub struct SpacingFunc {
- spacing: Option<(AxisKey, FSize)>,
+ spacing: Option<(AxisKey, ScaleLength)>,
}
type Meta = Option<SpecificAxis>;
@@ -88,11 +87,11 @@ function! {
body!(nope: body, f);
SpacingFunc {
spacing: if let Some(axis) = meta {
- header.args.pos.get::<FSize>(&mut f.problems)
+ header.args.pos.get::<ScaleLength>(&mut f.diagnostics)
.map(|s| (AxisKey::Specific(axis), s))
} else {
- header.args.key.get_with_key::<AxisKey, FSize>(&mut f.problems)
- }.or_missing(&mut f.problems, header.name.span, "spacing"),
+ header.args.key.get_with_key::<AxisKey, ScaleLength>(&mut f.diagnostics)
+ }.or_missing(&mut f.diagnostics, header.name.span, "spacing"),
}
}
diff --git a/src/paper.rs b/src/paper.rs
new file mode 100644
index 00000000..ba2dc212
--- /dev/null
+++ b/src/paper.rs
@@ -0,0 +1,275 @@
+//! Predefined papers.
+
+use crate::length::{Length, Size, Value4, ScaleLength};
+
+/// Specification of a paper.
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub struct Paper {
+ /// The kind of paper, which defines the default margins.
+ pub class: PaperClass,
+ /// The width of the paper.
+ pub width: Length,
+ /// The height of the paper.
+ pub height: Length,
+}
+
+impl Paper {
+ /// The paper with the given name.
+ pub fn from_name(name: &str) -> Option<Paper> {
+ parse_paper(name)
+ }
+
+ /// The size of the paper.
+ pub fn size(self) -> Size {
+ Size::new(self.width, self.height)
+ }
+}
+
+/// Paper classes define default margins for a class of related papers.
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+#[allow(missing_docs)]
+pub enum PaperClass {
+ Custom,
+ Base,
+ US,
+ Newspaper,
+ Book,
+}
+
+impl PaperClass {
+ /// The default margins for this page class.
+ pub fn default_margins(self) -> Value4<ScaleLength> {
+ use PaperClass::*;
+ let values = |l, t, r, b| Value4::new(
+ ScaleLength::Scaled(l),
+ ScaleLength::Scaled(t),
+ ScaleLength::Scaled(r),
+ ScaleLength::Scaled(b),
+ );
+
+ match self {
+ Custom => values(0.1190, 0.0842, 0.1190, 0.0842),
+ Base => values(0.1190, 0.0842, 0.1190, 0.0842),
+ US => values(0.1760, 0.1092, 0.1760, 0.0910),
+ Newspaper => values(0.0455, 0.0587, 0.0455, 0.0294),
+ Book => values(0.1200, 0.0852, 0.1500, 0.0965),
+ }
+ }
+}
+
+macro_rules! papers {
+ ($(($var:ident: $class:ident, $width:expr, $height: expr, $($pats:tt)*))*) => {
+ $(papers!(@$var, stringify!($($pats)*), $class, $width, $height);)*
+
+ fn parse_paper(paper: &str) -> Option<Paper> {
+ match paper.to_lowercase().as_str() {
+ $($($pats)* => Some($var),)*
+ _ => None,
+ }
+ }
+ };
+
+ (@$var:ident, $names:expr, $class:ident, $width:expr, $height:expr) => {
+ #[doc = "Paper with name `"]
+ #[doc = $names]
+ #[doc = "`."]
+ pub const $var: Paper = Paper {
+ width: Length { points: 2.83465 * $width },
+ height: Length { points: 2.83465 * $height },
+ class: PaperClass::$class,
+ };
+ };
+}
+
+// All paper sizes in mm.
+papers! {
+ // ---------------------------------------------------------------------- //
+ // ISO 216
+
+ // A Series
+ (PAPER_A0: Base, 841.0, 1189.0, "a0" | "poster")
+ (PAPER_A1: Base, 594.0, 841.0, "a1")
+ (PAPER_A2: Base, 420.0, 594.0, "a2")
+ (PAPER_A3: Base, 297.0, 420.0, "a3")
+ (PAPER_A4: Base, 210.0, 297.0, "a4")
+ (PAPER_A5: Base, 148.0, 210.0, "a5")
+ (PAPER_A6: Book, 105.0, 148.0, "a6")
+ (PAPER_A7: Base, 74.0, 105.0, "a7" | "iso-7810-id-2" | "id-2" | "visa" | "flyer")
+ (PAPER_A8: Base, 52.0, 74.0, "a8")
+ (PAPER_A9: Base, 37.0, 52.0, "a9")
+ (PAPER_A10: Base, 26.0, 37.0, "a10")
+ (PAPER_A11: Base, 18.0, 26.0, "a11")
+
+ // B Series
+ (PAPER_B1: Base, 707.0, 1000.0, "b1" | "flipchart")
+ (PAPER_B2: Base, 500.0, 707.0, "b2")
+ (PAPER_B3: Base, 353.0, 500.0, "b3")
+ (PAPER_B4: Base, 250.0, 353.0, "b4" | "sheet-music")
+ (PAPER_B5: Book, 176.0, 250.0, "b5")
+ (PAPER_B6: Book, 125.0, 176.0, "b6" | "book")
+ (PAPER_B7: Base, 88.0, 125.0, "b7" | "passport" | "iso-7810-id-3" | "id-3")
+ (PAPER_B8: Base, 62.0, 88.0, "b8")
+
+ // C Series
+ (PAPER_C3: Base, 324.0, 458.0, "c3")
+ (PAPER_C4: Base, 229.0, 324.0, "c4")
+ (PAPER_C5: Base, 162.0, 229.0, "c5")
+ (PAPER_C6: Base, 114.0, 162.0, "c6")
+ (PAPER_C7: Base, 81.0, 114.0, "c7")
+ (PAPER_C8: Base, 57.0, 81.0, "c8")
+
+ // D Series (DIN extension to ISO)
+ (PAPER_D3: Base, 272.0, 385.0, "din-d3")
+ (PAPER_D4: Base, 192.0, 272.0, "din-d4")
+ (PAPER_D5: Base, 136.0, 192.0, "din-d5" | "dvd")
+ (PAPER_D6: Base, 96.0, 136.0, "din-d6")
+ (PAPER_D7: Base, 68.0, 96.0, "din-d7")
+ (PAPER_D8: Base, 48.0, 68.0, "din-d8")
+
+ // Academically relevant SIS extensions
+ (PAPER_G5: Base, 169.0, 239.0, "sis-g5")
+ (PAPER_E5: Base, 115.0, 220.0, "sis-e5")
+
+ // ---------------------------------------------------------------------- //
+ // Unites States
+
+ // Customary
+ (PAPER_FOLIO: US, 210.0, 330.0, "folio" | "us-folio" | "us-f4")
+ (PAPER_LETTER: US, 216.0, 279.0, "letter" | "ansi-a" |
+ "american-quarto" | "carta")
+ (PAPER_LEGAL: US, 216.0, 356.0, "legal")
+ (PAPER_TABLOID: Newspaper, 279.0, 432.0, "tabloid" | "ansi-b")
+ (PAPER_LEDGER: Base, 432.0, 279.0, "ledger")
+ (PAPER_JUNIOR_LEGAL: US, 127.0, 203.0, "junior-legal" | "index-card")
+ (PAPER_HALF_LETTER: Base, 140.0, 216.0, "half-letter")
+ (PAPER_GOVERNMENT_LETTER: US, 203.0, 267.0, "government-letter")
+ (PAPER_GOVERNMENT_LEGAL: US, 216.0, 330.0, "government-legal" | "officio")
+
+ // ANSI Extensions
+ (PAPER_ANSI_C: Base, 432.0, 559.0, "ansi-c")
+ (PAPER_ANSI_D: Base, 559.0, 864.0, "ansi-d")
+ (PAPER_ANSI_E: Base, 864.0, 1118.0, "ansi-e")
+ (PAPER_ENGINEERING_F: Base, 711.0, 1016.0, "engineering-f" | "engineering" |
+ "navfac" | "aerospace")
+
+ // Architectural Paper
+ (PAPER_ARCH_A: Base, 229.0, 305.0, "arch-a" | "arch-1")
+ (PAPER_ARCH_B: Base, 305.0, 457.0, "arch-b" | "arch-2" | "extra-tabloide")
+ (PAPER_ARCH_C: Base, 457.0, 610.0, "arch-c" | "arch-3")
+ (PAPER_ARCH_D: Base, 610.0, 914.0, "arch-d" | "arch-4")
+ (PAPER_ARCH_E1: Base, 762.0, 1067.0, "arch-e1" | "arch-5")
+ (PAPER_ARCH_E: Base, 914.0, 1219.0, "arch-e" | "arch-6")
+
+ // ---------------------------------------------------------------------- //
+ // Japan
+
+ // JIS B Series
+ (PAPER_JIS_B0: Base, 1030.0, 1456.0, "jis-b0" | "jb0")
+ (PAPER_JIS_B1: Base, 728.0, 1030.0, "jis-b1" | "jb1")
+ (PAPER_JIS_B2: Base, 515.0, 728.0, "jis-b2" | "jb2")
+ (PAPER_JIS_B3: Base, 364.0, 515.0, "jis-b3" | "jb3")
+ (PAPER_JIS_B4: Base, 257.0, 364.0, "jis-b4" | "jb4")
+ (PAPER_JIS_B5: Base, 182.0, 257.0, "jis-b5" | "jb5")
+ (PAPER_JIS_B6: Base, 128.0, 182.0, "jis-b6" | "jb6")
+ (PAPER_JIS_B7: Base, 91.0, 128.0, "jis-b7" | "jb7")
+ (PAPER_JIS_B8: Base, 64.0, 91.0, "jis-b8" | "jb8")
+ (PAPER_JIS_B9: Base, 45.0, 64.0, "jis-b9" | "jb9")
+ (PAPER_JIS_B10: Base, 32.0, 45.0, "jis-b10" | "jb10")
+ (PAPER_JIS_B11: Base, 22.0, 32.0, "jis-b11" | "jb11")
+
+ // Traditional
+ (PAPER_SHIROKU_BAN_4: Base, 264.0, 379.0, "shiroku-ban-4")
+ (PAPER_SHIROKU_BAN_5: Base, 189.0, 262.0, "shiroku-ban-5")
+ (PAPER_SHIROKU_BAN_6: Base, 127.0, 188.0, "shiroku-ban-6")
+ (PAPER_KIKU_4: Base, 227.0, 306.0, "kiku-4")
+ (PAPER_KIKU_5: Base, 151.0, 227.0, "kiku-5")
+
+ // ---------------------------------------------------------------------- //
+ // China
+
+ // Chinese D Series
+ (PAPER_SAC_D0: Base, 764.0, 1064.0, "sac-d0" | "cn-d0")
+ (PAPER_SAC_D1: Base, 532.0, 760.0, "sac-d1" | "cn-d1")
+ (PAPER_SAC_D2: Base, 380.0, 528.0, "sac-d2" | "cn-d2")
+ (PAPER_SAC_D3: Base, 264.0, 376.0, "sac-d3" | "cn-d3")
+ (PAPER_SAC_D4: Base, 188.0, 260.0, "sac-d4" | "cn-d4")
+ (PAPER_SAC_D5: Base, 130.0, 184.0, "sac-d5" | "cn-d5")
+ (PAPER_SAC_D6: Base, 92.0, 126.0, "sac-d6" | "cn-d6")
+
+ // ---------------------------------------------------------------------- //
+ // United Kingdom Imperial (Assortment)
+
+ (PAPER_MONARCH: Base, 184.0, 267.0, "monarch")
+ (PAPER_QUARTO: Base, 229.0, 279.0, "quarto" | "us-quarto")
+ (PAPER_UK_QUARTO: Base, 203.0, 254.0, "uk-quarto" | "imperial-quarto")
+ (PAPER_UK_FOOLSCAP: Base, 343.0, 432.0, "foolscap" | "us-foolscap")
+ (PAPER_FOOLSCAP: Base, 203.0, 330.0, "imperial-foolscap" | "uk-foolscap")
+ (PAPER_POTT: Base, 318.0, 381.0, "pott")
+ (PAPER_CROWN: Base, 318.0, 508.0, "crown")
+ (PAPER_PINCHED_POST: Base, 375.0, 470.0, "pinched-post")
+ (PAPER_POST: Base, 394.0, 489.0, "post")
+ (PAPER_LARGE_POST: Base, 419.0, 533.0, "large-post")
+ (PAPER_DEMY: Base, 445.0, 572.0, "demy")
+ (PAPER_ROYAL: Base, 508.0, 635.0, "royal")
+ (PAPER_DOUBLE_CROWN: Base, 508.0, 762.0, "double-crown" | "theatre")
+ (PAPER_ELEPHANT: Base, 584.0, 711.0, "elephant")
+ (PAPER_DOUBLE_ROYAL: Base, 635.0, 1016.0, "double-royal" | "rail")
+ (PAPER_QUAD_CROWN: Base, 762.0, 1016.0, "quad-crown" | "cinema")
+
+ // ---------------------------------------------------------------------- //
+ // French Traditional (AFNOR)
+
+ (PAPER_CLOCHE: Base, 300.0, 400.0, "cloche")
+ (PAPER_POT: Base, 310.0, 400.0, "pot" | "ecolier" | "écolier")
+ (PAPER_TELLIERE: Base, 340.0, 440.0, "telliere" | "tellière")
+ (PAPER_COURONNE_ECRITURE: Base, 360.0, 460.0, "couronne-ecriture" |
+ "couronne" | "couronne-écriture")
+ (PAPER_COURONNE_EDITION: Base, 370.0, 470.0, "couronne-edition" |
+ "couronne-édition")
+ (PAPER_ROBERTO: Base, 390.0, 500.0, "roberto")
+ (PAPER_ECU: Base, 400.0, 520.0, "ecu" | "écu")
+ (PAPER_COQUILLE: Base, 440.0, 560.0, "coquille")
+ (PAPER_CARRE: Base, 450.0, 560.0, "carre" | "carré")
+ (PAPER_CAVALIER: Base, 460.0, 620.0, "cavalier")
+ (PAPER_DEMI_RAISIN: Base, 325.0, 500.0, "demi-raisin")
+ (PAPER_RAISIN: Base, 500.0, 650.0, "raisin" | "dessin")
+ (PAPER_DOUBLE_RAISIN: Base, 650.0, 1000.0, "double-raisin")
+ (PAPER_JESUS: Base, 560.0, 760.0, "jesus" | "jésus")
+ (PAPER_SOLEIL: Base, 600.0, 800.0, "soleil")
+ (PAPER_COLOMBIER_AFFICHE: Base, 600.0, 800.0, "colombier-affiche" | "affiche")
+ (PAPER_COLOMBIER_COMMERCIAL: Base, 630.0, 900.0, "colombier-commercial")
+ (PAPER_PETIT_AIGLE: Base, 700.0, 940.0, "petit-aigle")
+ (PAPER_GRAND_AIGLE: Base, 750.0, 1060.0, "grand-aigle" | "napoleon")
+ (PAPER_GRAND_MONDE: Base, 900.0, 1260.0, "grand-monde")
+ (PAPER_UNIVERS: Base, 1000.0, 1300.0, "univers" | "universe")
+
+ // ---------------------------------------------------------------------- //
+ // Newspaper
+
+ (PAPER_COMPACT: Newspaper, 280.0, 430.0, "compact")
+ (PAPER_BERLINER: Newspaper, 315.0, 470.0, "berliner" | "midi")
+ (PAPER_RHENISH: Newspaper, 350.0, 520.0, "rhenish")
+ (PAPER_BROADSHEET: Newspaper, 381.0, 578.0, "broadsheet" | "newspaper")
+ (PAPER_NEW_YORK_TIMES: Newspaper, 305.0, 559.0, "new-york-times" | "times")
+
+ // ---------------------------------------------------------------------- //
+ // Books
+
+ (PAPER_FOLIO_BOOK: Book, 304.8, 482.6, "book-folio")
+ (PAPER_QUARTO_BOOK: Book, 241.3, 304.8, "book-quarto")
+ (PAPER_OCTAVO_BOOK: Book, 152.4, 228.6, "book-octavo")
+ (PAPER_16_MO_BOOK: Book, 101.6, 171.45, "book-16mo")
+ (PAPER_32_MO_BOOK: Book, 88.9, 139.7, "book-32mo")
+
+ // ---------------------------------------------------------------------- //
+ // Various
+
+ (PAPER_ID_1: Base, 85.6, 53.98, "id-card" | "id-1" | "iso-7810-id-1" |
+ "eu-business-card" | "business-card")
+ (PAPER_US_BUSINESS_CARD: Base, 88.9, 50.8, "us-business-card")
+ (PAPER_JP_BUSINESS_CARD: Base, 91.0, 55.0, "jp-business-card")
+ (PAPER_CN_BUSINESS_CARD: Base, 90.0, 54.0, "cn-business-card")
+ (PAPER_A4_16_9: Base, 297.0, 167.0625, "presentation-16-9" | "presentation")
+ (PAPER_A4_4_3: Base, 280.0, 210.0, "presentation-4-3")
+ (PAPER_POSTCARD: Base, 152.4, 101.6, "postcard")
+}
diff --git a/src/problem.rs b/src/problem.rs
deleted file mode 100644
index 3c2d3635..00000000
--- a/src/problem.rs
+++ /dev/null
@@ -1,94 +0,0 @@
-//! Problems (errors / warnings) in _Typst_ documents.
-//!
-//! There are no fatal errors in _Typst_. The document will always compile and
-//! yield a layout. However, this is a best effort process and bad things will
-//! still generate errors and warnings.
-
-use serde::Serialize;
-use crate::syntax::span::SpanVec;
-
-
-/// A list of spanned problems.
-pub type Problems = SpanVec<Problem>;
-
-/// A problem that arose in parsing or layouting.
-#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
-pub struct Problem {
- /// How severe / important the problem is.
- pub severity: Severity,
- /// A message describing the problem.
- pub message: String,
-}
-
-/// How severe / important a problem is.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub enum Severity {
- /// Something in the code is not good.
- Warning,
- /// Something in the code is wrong!
- Error,
-}
-
-impl Problem {
- /// Create a new problem from message and severity.
- pub fn new(message: impl Into<String>, severity: Severity) -> Self {
- Self { message: message.into(), severity }
- }
-}
-
-/// Construct a problem with `Error` severity.
-///
-/// ```
-/// # use typstc::error;
-/// # use typstc::syntax::span::Span;
-/// # use typstc::Feedback;
-/// # let span = Span::ZERO;
-/// # let mut feedback = Feedback::new();
-/// # let name = "";
-/// // Create formatted error values.
-/// let error = error!("expected {}", name);
-///
-/// // Create spanned errors.
-/// let spanned = error!(span, "there is an error here");
-///
-/// // Create an error and directly add it to existing feedback.
-/// error!(@feedback, span, "oh no!");
-/// ```
-#[macro_export]
-macro_rules! error {
- ($($tts:tt)*) => {
- $crate::__impl_problem!($crate::problem::Severity::Error; $($tts)*)
- };
-}
-
-/// Construct a problem with `Warning` severity.
-///
-/// This works exactly like `error!`. See its documentation for more
-/// information.
-#[macro_export]
-macro_rules! warning {
- ($($tts:tt)*) => {
- $crate::__impl_problem!($crate::problem::Severity::Warning; $($tts)*)
- };
-}
-
-/// Backs the `error!` and `warning!` macros.
-#[macro_export]
-#[doc(hidden)]
-macro_rules! __impl_problem {
- ($severity:expr; @$feedback:expr, $($tts:tt)*) => {
- $feedback.problems.push($crate::__impl_problem!($severity; $($tts)*));
- };
-
- ($severity:expr; $fmt:literal $($tts:tt)*) => {
- $crate::problem::Problem::new(format!($fmt $($tts)*), $severity)
- };
-
- ($severity:expr; $span:expr, $fmt:literal $($tts:tt)*) => {
- $crate::syntax::span::Spanned::new(
- $crate::__impl_problem!($severity; $fmt $($tts)*),
- $span,
- )
- };
-}
diff --git a/src/style.rs b/src/style.rs
index 075baa5a..2c74adde 100644
--- a/src/style.rs
+++ b/src/style.rs
@@ -2,8 +2,8 @@
use toddle::fallback;
use toddle::query::{FallbackTree, FontVariant, FontStyle, FontWeight};
-use crate::size::{Size, Size2D, SizeBox, ValueBox, PSize};
-
+use crate::length::{Length, Size, Margins, Value4, ScaleLength};
+use crate::paper::{Paper, PaperClass, PAPER_A4};
/// Defines properties of pages and text.
#[derive(Debug, Default, Clone, PartialEq)]
@@ -25,35 +25,35 @@ pub struct TextStyle {
/// whether the next `*` adds or removes font weight.
pub bolder: bool,
/// The base font size.
- pub base_font_size: Size,
+ pub base_font_size: Length,
/// The font scale to apply on the base font size.
- pub font_scale: f32,
+ pub font_scale: f64,
/// The word spacing (as a multiple of the font size).
- pub word_spacing_scale: f32,
+ pub word_spacing_scale: f64,
/// The line spacing (as a multiple of the font size).
- pub line_spacing_scale: f32,
+ pub line_spacing_scale: f64,
/// The paragraphs spacing (as a multiple of the font size).
- pub paragraph_spacing_scale: f32,
+ pub paragraph_spacing_scale: f64,
}
impl TextStyle {
/// The scaled font size.
- pub fn font_size(&self) -> Size {
+ pub fn font_size(&self) -> Length {
self.base_font_size * self.font_scale
}
/// The absolute word spacing.
- pub fn word_spacing(&self) -> Size {
+ pub fn word_spacing(&self) -> Length {
self.word_spacing_scale * self.font_size()
}
/// The absolute line spacing.
- pub fn line_spacing(&self) -> Size {
+ pub fn line_spacing(&self) -> Length {
(self.line_spacing_scale - 1.0) * self.font_size()
}
/// The absolute paragraph spacing.
- pub fn paragraph_spacing(&self) -> Size {
+ pub fn paragraph_spacing(&self) -> Length {
(self.paragraph_spacing_scale - 1.0) * self.font_size()
}
}
@@ -77,7 +77,7 @@ impl Default for TextStyle {
weight: FontWeight(400),
},
bolder: false,
- base_font_size: Size::pt(11.0),
+ base_font_size: Length::pt(11.0),
font_scale: 1.0,
word_spacing_scale: 0.25,
line_spacing_scale: 1.2,
@@ -92,10 +92,10 @@ pub struct PageStyle {
/// The class of this page.
pub class: PaperClass,
/// The width and height of the page.
- pub dimensions: Size2D,
+ pub dimensions: Size,
/// The amount of white space on each side. If a side is set to `None`, the
/// default for the paper class is used.
- pub margins: ValueBox<Option<PSize>>,
+ pub margins: Value4<Option<ScaleLength>>,
}
impl PageStyle {
@@ -103,17 +103,17 @@ impl PageStyle {
pub fn new(paper: Paper) -> PageStyle {
PageStyle {
class: paper.class,
- dimensions: paper.dimensions,
- margins: ValueBox::with_all(None),
+ dimensions: paper.size(),
+ margins: Value4::with_all(None),
}
}
/// The absolute margins.
- pub fn margins(&self) -> SizeBox {
+ pub fn margins(&self) -> Margins {
let dims = self.dimensions;
let default = self.class.default_margins();
- SizeBox {
+ Margins {
left: self.margins.left.unwrap_or(default.left).scaled(dims.x),
top: self.margins.top.unwrap_or(default.top).scaled(dims.y),
right: self.margins.right.unwrap_or(default.right).scaled(dims.x),
@@ -127,270 +127,3 @@ impl Default for PageStyle {
PageStyle::new(PAPER_A4)
}
}
-
-/// Details about a type of paper.
-#[derive(Debug, Copy, Clone, PartialEq)]
-pub struct Paper {
- /// The kind of paper, which defines the default margins.
- pub class: PaperClass,
- /// The size of the paper.
- pub dimensions: Size2D,
-}
-
-impl Paper {
- /// The paper with the given name.
- pub fn from_name(name: &str) -> Option<Paper> {
- parse_paper(name)
- }
-}
-
-/// Paper classes define default margins for a class of related papers.
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-#[allow(missing_docs)]
-pub enum PaperClass {
- Custom,
- Base,
- US,
- Newspaper,
- Book,
-}
-
-impl PaperClass {
- /// The default margins for this page class.
- pub fn default_margins(self) -> ValueBox<PSize> {
- use PaperClass::*;
- let values = |l, t, r, b| ValueBox::new(
- PSize::Scaled(l),
- PSize::Scaled(t),
- PSize::Scaled(r),
- PSize::Scaled(b),
- );
-
- match self {
- Custom => values(0.1190, 0.0842, 0.1190, 0.0842),
- Base => values(0.1190, 0.0842, 0.1190, 0.0842),
- US => values(0.1760, 0.1092, 0.1760, 0.0910),
- Newspaper => values(0.0455, 0.0587, 0.0455, 0.0294),
- Book => values(0.1200, 0.0852, 0.1500, 0.0965),
- }
- }
-}
-
-macro_rules! papers {
- ($(($var:ident: $class:ident, $width:expr, $height: expr, $($pats:tt)*))*) => {
- $(papers!(@$var, stringify!($($pats)*), $class, $width, $height);)*
-
- fn parse_paper(paper: &str) -> Option<Paper> {
- match paper.to_lowercase().as_str() {
- $($($pats)* => Some($var),)*
- _ => None,
- }
- }
- };
-
- (@$var:ident, $names:expr, $class:ident, $width:expr, $height:expr) => {
- #[doc = "Paper with name `"]
- #[doc = $names]
- #[doc = "`."]
- pub const $var: Paper = Paper {
- dimensions: Size2D {
- x: Size { points: 2.83465 * $width },
- y: Size { points: 2.83465 * $height },
- },
- class: PaperClass::$class,
- };
- };
-}
-
-// All paper sizes in mm.
-papers! {
- // ---------------------------------------------------------------------- //
- // ISO 216
-
- // A Series
- (PAPER_A0: Base, 841.0, 1189.0, "a0" | "poster")
- (PAPER_A1: Base, 594.0, 841.0, "a1")
- (PAPER_A2: Base, 420.0, 594.0, "a2")
- (PAPER_A3: Base, 297.0, 420.0, "a3")
- (PAPER_A4: Base, 210.0, 297.0, "a4")
- (PAPER_A5: Base, 148.0, 210.0, "a5")
- (PAPER_A6: Book, 105.0, 148.0, "a6")
- (PAPER_A7: Base, 74.0, 105.0, "a7" | "iso-7810-id-2" | "id-2" | "visa" | "flyer")
- (PAPER_A8: Base, 52.0, 74.0, "a8")
- (PAPER_A9: Base, 37.0, 52.0, "a9")
- (PAPER_A10: Base, 26.0, 37.0, "a10")
- (PAPER_A11: Base, 18.0, 26.0, "a11")
-
- // B Series
- (PAPER_B1: Base, 707.0, 1000.0, "b1" | "flipchart")
- (PAPER_B2: Base, 500.0, 707.0, "b2")
- (PAPER_B3: Base, 353.0, 500.0, "b3")
- (PAPER_B4: Base, 250.0, 353.0, "b4" | "sheet-music")
- (PAPER_B5: Book, 176.0, 250.0, "b5")
- (PAPER_B6: Book, 125.0, 176.0, "b6" | "book")
- (PAPER_B7: Base, 88.0, 125.0, "b7" | "passport" | "iso-7810-id-3" | "id-3")
- (PAPER_B8: Base, 62.0, 88.0, "b8")
-
- // C Series
- (PAPER_C3: Base, 324.0, 458.0, "c3")
- (PAPER_C4: Base, 229.0, 324.0, "c4")
- (PAPER_C5: Base, 162.0, 229.0, "c5")
- (PAPER_C6: Base, 114.0, 162.0, "c6")
- (PAPER_C7: Base, 81.0, 114.0, "c7")
- (PAPER_C8: Base, 57.0, 81.0, "c8")
-
- // D Series (DIN extension to ISO)
- (PAPER_D3: Base, 272.0, 385.0, "din-d3")
- (PAPER_D4: Base, 192.0, 272.0, "din-d4")
- (PAPER_D5: Base, 136.0, 192.0, "din-d5" | "dvd")
- (PAPER_D6: Base, 96.0, 136.0, "din-d6")
- (PAPER_D7: Base, 68.0, 96.0, "din-d7")
- (PAPER_D8: Base, 48.0, 68.0, "din-d8")
-
- // Academically relevant SIS extensions
- (PAPER_G5: Base, 169.0, 239.0, "sis-g5")
- (PAPER_E5: Base, 115.0, 220.0, "sis-e5")
-
- // ---------------------------------------------------------------------- //
- // Unites States
-
- // Customary
- (PAPER_FOLIO: US, 210.0, 330.0, "folio" | "us-folio" | "us-f4")
- (PAPER_LETTER: US, 216.0, 279.0, "letter" | "ansi-a" |
- "american-quarto" | "carta")
- (PAPER_LEGAL: US, 216.0, 356.0, "legal")
- (PAPER_TABLOID: Newspaper, 279.0, 432.0, "tabloid" | "ansi-b")
- (PAPER_LEDGER: Base, 432.0, 279.0, "ledger")
- (PAPER_JUNIOR_LEGAL: US, 127.0, 203.0, "junior-legal" | "index-card")
- (PAPER_HALF_LETTER: Base, 140.0, 216.0, "half-letter")
- (PAPER_GOVERNMENT_LETTER: US, 203.0, 267.0, "government-letter")
- (PAPER_GOVERNMENT_LEGAL: US, 216.0, 330.0, "government-legal" | "officio")
-
- // ANSI Extensions
- (PAPER_ANSI_C: Base, 432.0, 559.0, "ansi-c")
- (PAPER_ANSI_D: Base, 559.0, 864.0, "ansi-d")
- (PAPER_ANSI_E: Base, 864.0, 1118.0, "ansi-e")
- (PAPER_ENGINEERING_F: Base, 711.0, 1016.0, "engineering-f" | "engineering" |
- "navfac" | "aerospace")
-
- // Architectural Paper
- (PAPER_ARCH_A: Base, 229.0, 305.0, "arch-a" | "arch-1")
- (PAPER_ARCH_B: Base, 305.0, 457.0, "arch-b" | "arch-2" | "extra-tabloide")
- (PAPER_ARCH_C: Base, 457.0, 610.0, "arch-c" | "arch-3")
- (PAPER_ARCH_D: Base, 610.0, 914.0, "arch-d" | "arch-4")
- (PAPER_ARCH_E1: Base, 762.0, 1067.0, "arch-e1" | "arch-5")
- (PAPER_ARCH_E: Base, 914.0, 1219.0, "arch-e" | "arch-6")
-
- // ---------------------------------------------------------------------- //
- // Japan
-
- // JIS B Series
- (PAPER_JIS_B0: Base, 1030.0, 1456.0, "jis-b0" | "jb0")
- (PAPER_JIS_B1: Base, 728.0, 1030.0, "jis-b1" | "jb1")
- (PAPER_JIS_B2: Base, 515.0, 728.0, "jis-b2" | "jb2")
- (PAPER_JIS_B3: Base, 364.0, 515.0, "jis-b3" | "jb3")
- (PAPER_JIS_B4: Base, 257.0, 364.0, "jis-b4" | "jb4")
- (PAPER_JIS_B5: Base, 182.0, 257.0, "jis-b5" | "jb5")
- (PAPER_JIS_B6: Base, 128.0, 182.0, "jis-b6" | "jb6")
- (PAPER_JIS_B7: Base, 91.0, 128.0, "jis-b7" | "jb7")
- (PAPER_JIS_B8: Base, 64.0, 91.0, "jis-b8" | "jb8")
- (PAPER_JIS_B9: Base, 45.0, 64.0, "jis-b9" | "jb9")
- (PAPER_JIS_B10: Base, 32.0, 45.0, "jis-b10" | "jb10")
- (PAPER_JIS_B11: Base, 22.0, 32.0, "jis-b11" | "jb11")
-
- // Traditional
- (PAPER_SHIROKU_BAN_4: Base, 264.0, 379.0, "shiroku-ban-4")
- (PAPER_SHIROKU_BAN_5: Base, 189.0, 262.0, "shiroku-ban-5")
- (PAPER_SHIROKU_BAN_6: Base, 127.0, 188.0, "shiroku-ban-6")
- (PAPER_KIKU_4: Base, 227.0, 306.0, "kiku-4")
- (PAPER_KIKU_5: Base, 151.0, 227.0, "kiku-5")
-
- // ---------------------------------------------------------------------- //
- // China
-
- // Chinese D Series
- (PAPER_SAC_D0: Base, 764.0, 1064.0, "sac-d0" | "cn-d0")
- (PAPER_SAC_D1: Base, 532.0, 760.0, "sac-d1" | "cn-d1")
- (PAPER_SAC_D2: Base, 380.0, 528.0, "sac-d2" | "cn-d2")
- (PAPER_SAC_D3: Base, 264.0, 376.0, "sac-d3" | "cn-d3")
- (PAPER_SAC_D4: Base, 188.0, 260.0, "sac-d4" | "cn-d4")
- (PAPER_SAC_D5: Base, 130.0, 184.0, "sac-d5" | "cn-d5")
- (PAPER_SAC_D6: Base, 92.0, 126.0, "sac-d6" | "cn-d6")
-
- // ---------------------------------------------------------------------- //
- // United Kingdom Imperial (Assortment)
-
- (PAPER_MONARCH: Base, 184.0, 267.0, "monarch")
- (PAPER_QUARTO: Base, 229.0, 279.0, "quarto" | "us-quarto")
- (PAPER_UK_QUARTO: Base, 203.0, 254.0, "uk-quarto" | "imperial-quarto")
- (PAPER_UK_FOOLSCAP: Base, 343.0, 432.0, "foolscap" | "us-foolscap")
- (PAPER_FOOLSCAP: Base, 203.0, 330.0, "imperial-foolscap" | "uk-foolscap")
- (PAPER_POTT: Base, 318.0, 381.0, "pott")
- (PAPER_CROWN: Base, 318.0, 508.0, "crown")
- (PAPER_PINCHED_POST: Base, 375.0, 470.0, "pinched-post")
- (PAPER_POST: Base, 394.0, 489.0, "post")
- (PAPER_LARGE_POST: Base, 419.0, 533.0, "large-post")
- (PAPER_DEMY: Base, 445.0, 572.0, "demy")
- (PAPER_ROYAL: Base, 508.0, 635.0, "royal")
- (PAPER_DOUBLE_CROWN: Base, 508.0, 762.0, "double-crown" | "theatre")
- (PAPER_ELEPHANT: Base, 584.0, 711.0, "elephant")
- (PAPER_DOUBLE_ROYAL: Base, 635.0, 1016.0, "double-royal" | "rail")
- (PAPER_QUAD_CROWN: Base, 762.0, 1016.0, "quad-crown" | "cinema")
-
- // ---------------------------------------------------------------------- //
- // French Traditional (AFNOR)
-
- (PAPER_CLOCHE: Base, 300.0, 400.0, "cloche")
- (PAPER_POT: Base, 310.0, 400.0, "pot" | "ecolier" | "écolier")
- (PAPER_TELLIERE: Base, 340.0, 440.0, "telliere" | "tellière")
- (PAPER_COURONNE_ECRITURE: Base, 360.0, 460.0, "couronne-ecriture" |
- "couronne" | "couronne-écriture")
- (PAPER_COURONNE_EDITION: Base, 370.0, 470.0, "couronne-edition" |
- "couronne-édition")
- (PAPER_ROBERTO: Base, 390.0, 500.0, "roberto")
- (PAPER_ECU: Base, 400.0, 520.0, "ecu" | "écu")
- (PAPER_COQUILLE: Base, 440.0, 560.0, "coquille")
- (PAPER_CARRE: Base, 450.0, 560.0, "carre" | "carré")
- (PAPER_CAVALIER: Base, 460.0, 620.0, "cavalier")
- (PAPER_DEMI_RAISIN: Base, 325.0, 500.0, "demi-raisin")
- (PAPER_RAISIN: Base, 500.0, 650.0, "raisin" | "dessin")
- (PAPER_DOUBLE_RAISIN: Base, 650.0, 1000.0, "double-raisin")
- (PAPER_JESUS: Base, 560.0, 760.0, "jesus" | "jésus")
- (PAPER_SOLEIL: Base, 600.0, 800.0, "soleil")
- (PAPER_COLOMBIER_AFFICHE: Base, 600.0, 800.0, "colombier-affiche" | "affiche")
- (PAPER_COLOMBIER_COMMERCIAL: Base, 630.0, 900.0, "colombier-commercial")
- (PAPER_PETIT_AIGLE: Base, 700.0, 940.0, "petit-aigle")
- (PAPER_GRAND_AIGLE: Base, 750.0, 1060.0, "grand-aigle" | "napoleon")
- (PAPER_GRAND_MONDE: Base, 900.0, 1260.0, "grand-monde")
- (PAPER_UNIVERS: Base, 1000.0, 1300.0, "univers" | "universe")
-
- // ---------------------------------------------------------------------- //
- // Newspaper
-
- (PAPER_COMPACT: Newspaper, 280.0, 430.0, "compact")
- (PAPER_BERLINER: Newspaper, 315.0, 470.0, "berliner" | "midi")
- (PAPER_RHENISH: Newspaper, 350.0, 520.0, "rhenish")
- (PAPER_BROADSHEET: Newspaper, 381.0, 578.0, "broadsheet" | "newspaper")
- (PAPER_NEW_YORK_TIMES: Newspaper, 305.0, 559.0, "new-york-times" | "times")
-
- // ---------------------------------------------------------------------- //
- // Books
-
- (PAPER_FOLIO_BOOK: Book, 304.8, 482.6, "book-folio")
- (PAPER_QUARTO_BOOK: Book, 241.3, 304.8, "book-quarto")
- (PAPER_OCTAVO_BOOK: Book, 152.4, 228.6, "book-octavo")
- (PAPER_16_MO_BOOK: Book, 101.6, 171.45, "book-16mo")
- (PAPER_32_MO_BOOK: Book, 88.9, 139.7, "book-32mo")
-
- // ---------------------------------------------------------------------- //
- // Various
-
- (PAPER_ID_1: Base, 85.6, 53.98, "id-card" | "id-1" | "iso-7810-id-1" |
- "eu-business-card" | "business-card")
- (PAPER_US_BUSINESS_CARD: Base, 88.9, 50.8, "us-business-card")
- (PAPER_JP_BUSINESS_CARD: Base, 91.0, 55.0, "jp-business-card")
- (PAPER_CN_BUSINESS_CARD: Base, 90.0, 54.0, "cn-business-card")
- (PAPER_A4_16_9: Base, 297.0, 167.0625, "presentation-16-9" | "presentation")
- (PAPER_A4_4_3: Base, 280.0, 210.0, "presentation-4-3")
- (PAPER_POSTCARD: Base, 152.4, 101.6, "postcard")
-}
diff --git a/src/syntax/expr.rs b/src/syntax/expr.rs
index a1b3fd62..d849366c 100644
--- a/src/syntax/expr.rs
+++ b/src/syntax/expr.rs
@@ -6,13 +6,12 @@ use std::ops::Deref;
use std::str::FromStr;
use std::u8;
-use crate::problem::Problems;
-use crate::size::Size;
+use crate::diagnostic::Diagnostics;
+use crate::length::Length;
use super::func::{Key, Value};
use super::span::{Span, Spanned};
use super::tokens::is_identifier;
-
/// An argument or return value.
#[derive(Clone, PartialEq)]
pub enum Expr {
@@ -22,8 +21,8 @@ pub enum Expr {
Str(String),
/// A number: `1.2, 200%`.
Number(f64),
- /// A size: `2cm, 5.2in`.
- Size(Size),
+ /// A length: `2cm, 5.2in`.
+ Length(Length),
/// A bool: `true, false`.
Bool(bool),
/// A color value, including the alpha channel: `#f79143ff`.
@@ -32,7 +31,7 @@ pub enum Expr {
Tuple(Tuple),
/// A named tuple: `cmyk(37.7, 0, 3.9, 1.1)`.
NamedTuple(NamedTuple),
- /// An object: `{ fit: false, size: 12pt }`.
+ /// An object: `{ fit: false, width: 12pt }`.
Object(Object),
/// An operator that negates the contained expression.
Neg(Box<Spanned<Expr>>),
@@ -54,7 +53,7 @@ impl Expr {
Ident(_) => "identifier",
Str(_) => "string",
Number(_) => "number",
- Size(_) => "size",
+ Length(_) => "length",
Bool(_) => "bool",
Color(_) => "color",
Tuple(_) => "tuple",
@@ -76,7 +75,7 @@ impl Debug for Expr {
Ident(i) => i.fmt(f),
Str(s) => s.fmt(f),
Number(n) => n.fmt(f),
- Size(s) => s.fmt(f),
+ Length(s) => s.fmt(f),
Bool(b) => b.fmt(f),
Color(c) => c.fmt(f),
Tuple(t) => t.fmt(f),
@@ -128,7 +127,7 @@ impl Debug for Ident {
///
/// # Example
/// ```typst
-/// [box: background=#423abaff]
+/// [page: background=#423abaff]
/// ^^^^^^^^
/// ```
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
@@ -256,28 +255,28 @@ impl Tuple {
}
/// Extract (and remove) the first matching value and remove and generate
- /// problems for all previous items that did not match.
- pub fn get<V: Value>(&mut self, problems: &mut Problems) -> Option<V> {
+ /// diagnostics for all previous items that did not match.
+ pub fn get<V: Value>(&mut self, diagnostics: &mut Diagnostics) -> Option<V> {
while !self.items.is_empty() {
let expr = self.items.remove(0);
let span = expr.span;
match V::parse(expr) {
Ok(output) => return Some(output),
- Err(v) => problems.push(Spanned { v, span }),
+ Err(v) => diagnostics.push(Spanned { v, span }),
}
}
None
}
/// Extract and return an iterator over all values that match and generate
- /// problems for all items that do not match.
- pub fn get_all<'a, V: Value>(&'a mut self, problems: &'a mut Problems)
+ /// diagnostics for all items that do not match.
+ pub fn get_all<'a, V: Value>(&'a mut self, diagnostics: &'a mut Diagnostics)
-> impl Iterator<Item=V> + 'a {
self.items.drain(..).filter_map(move |expr| {
let span = expr.span;
match V::parse(expr) {
Ok(output) => Some(output),
- Err(v) => { problems.push(Spanned { v, span }); None }
+ Err(v) => { diagnostics.push(Spanned { v, span }); None }
}
})
}
@@ -351,13 +350,9 @@ impl Deref for NamedTuple {
/// A key-value collection of identifiers and associated expressions.
///
-/// The pairs themselves are not spanned, but the combined spans can easily be
-/// retrieved by merging the spans of key and value as happening in
-/// [`FuncArg::span`](super::func::FuncArg::span).
-///
/// # Example
/// ```typst
-/// { fit: false, size: 12cm, items: (1, 2, 3) }
+/// { fit: false, width: 12cm, items: (1, 2, 3) }
/// ```
#[derive(Default, Clone, PartialEq)]
pub struct Object {
@@ -398,9 +393,9 @@ impl Object {
///
/// Inserts an error if the value does not match. If the key is not
/// contained, no error is inserted.
- pub fn get<V: Value>(&mut self, problems: &mut Problems, key: &str) -> Option<V> {
+ pub fn get<V: Value>(&mut self, diagnostics: &mut Diagnostics, key: &str) -> Option<V> {
let index = self.pairs.iter().position(|pair| pair.v.key.v.as_str() == key)?;
- self.get_index::<V>(problems, index)
+ self.get_index::<V>(diagnostics, index)
}
/// Extract (and remove) a pair with a matching key and value.
@@ -409,12 +404,12 @@ impl Object {
/// found, no error is inserted.
pub fn get_with_key<K: Key, V: Value>(
&mut self,
- problems: &mut Problems,
+ diagnostics: &mut Diagnostics,
) -> Option<(K, V)> {
for (index, pair) in self.pairs.iter().enumerate() {
let key = Spanned { v: pair.v.key.v.as_str(), span: pair.v.key.span };
if let Some(key) = K::parse(key) {
- return self.get_index::<V>(problems, index).map(|value| (key, value));
+ return self.get_index::<V>(diagnostics, index).map(|value| (key, value));
}
}
None
@@ -425,7 +420,7 @@ impl Object {
/// Inserts errors for values that do not match.
pub fn get_all<'a, K: Key, V: Value>(
&'a mut self,
- problems: &'a mut Problems,
+ diagnostics: &'a mut Diagnostics,
) -> impl Iterator<Item=(K, V)> + 'a {
let mut index = 0;
std::iter::from_fn(move || {
@@ -434,7 +429,7 @@ impl Object {
let key = Spanned { v: key.v.as_str(), span: key.span };
Some(if let Some(key) = K::parse(key) {
- self.get_index::<V>(problems, index).map(|v| (key, v))
+ self.get_index::<V>(diagnostics, index).map(|v| (key, v))
} else {
index += 1;
None
@@ -454,20 +449,20 @@ impl Object {
/// ```
pub fn get_all_spanned<'a, K: Key + 'a, V: Value + 'a>(
&'a mut self,
- problems: &'a mut Problems,
+ diagnostics: &'a mut Diagnostics,
) -> impl Iterator<Item=Spanned<(K, V)>> + 'a {
- self.get_all::<Spanned<K>, Spanned<V>>(problems)
+ self.get_all::<Spanned<K>, Spanned<V>>(diagnostics)
.map(|(k, v)| Spanned::new((k.v, v.v), Span::merge(k.span, v.span)))
}
/// Extract the argument at the given index and insert an error if the value
/// does not match.
- fn get_index<V: Value>(&mut self, problems: &mut Problems, index: usize) -> Option<V> {
+ fn get_index<V: Value>(&mut self, diagnostics: &mut Diagnostics, index: usize) -> Option<V> {
let expr = self.pairs.remove(index).v.value;
let span = expr.span;
match V::parse(expr) {
Ok(output) => Some(output),
- Err(v) => { problems.push(Spanned { v, span }); None }
+ Err(v) => { diagnostics.push(Spanned { v, span }); None }
}
}
diff --git a/src/syntax/func/keys.rs b/src/syntax/func/keys.rs
index b8f142ee..558667dd 100644
--- a/src/syntax/func/keys.rs
+++ b/src/syntax/func/keys.rs
@@ -7,7 +7,6 @@ use super::*;
use self::AxisKey::*;
use self::PaddingKey::*;
-
/// Key types are used to extract keyword arguments from
/// [`Objects`](crate::syntax::expr::Object). They represent the key part of a
/// keyword argument.
diff --git a/src/syntax/func/maps.rs b/src/syntax/func/maps.rs
index 44d8e1aa..2ac70223 100644
--- a/src/syntax/func/maps.rs
+++ b/src/syntax/func/maps.rs
@@ -1,18 +1,17 @@
//! Deduplicating maps and keys for argument parsing.
-use crate::problem::Problems;
+use crate::diagnostic::Diagnostics;
use crate::layout::prelude::*;
-use crate::size::{PSize, ValueBox};
+use crate::length::{ScaleLength, Value4};
use crate::syntax::span::Spanned;
use super::keys::*;
use super::values::*;
use super::*;
-
/// A map which deduplicates redundant arguments.
///
/// Whenever a duplicate argument is inserted into the map, through the
-/// functions `from_iter`, `insert` or `extend` an problems is added to the error
+/// functions `from_iter`, `insert` or `extend` an diagnostics is added to the error
/// list that needs to be passed to those functions.
///
/// All entries need to have span information to enable the error reporting.
@@ -28,27 +27,27 @@ impl<K, V> DedupMap<K, V> where K: Eq {
}
/// Create a new map from an iterator of spanned keys and values.
- pub fn from_iter<I>(problems: &mut Problems, iter: I) -> DedupMap<K, V>
+ pub fn from_iter<I>(diagnostics: &mut Diagnostics, iter: I) -> DedupMap<K, V>
where I: IntoIterator<Item=Spanned<(K, V)>> {
let mut map = DedupMap::new();
- map.extend(problems, iter);
+ map.extend(diagnostics, iter);
map
}
/// Add a spanned key-value pair.
- pub fn insert(&mut self, problems: &mut Problems, entry: Spanned<(K, V)>) {
+ pub fn insert(&mut self, diagnostics: &mut Diagnostics, entry: Spanned<(K, V)>) {
if self.map.iter().any(|e| e.v.0 == entry.v.0) {
- problems.push(error!(entry.span, "duplicate argument"));
+ diagnostics.push(error!(entry.span, "duplicate argument"));
} else {
self.map.push(entry);
}
}
/// Add multiple spanned key-value pairs.
- pub fn extend<I>(&mut self, problems: &mut Problems, items: I)
+ pub fn extend<I>(&mut self, diagnostics: &mut Diagnostics, items: I)
where I: IntoIterator<Item=Spanned<(K, V)>> {
for item in items.into_iter() {
- self.insert(problems, item);
+ self.insert(diagnostics, item);
}
}
@@ -71,15 +70,15 @@ impl<K, V> DedupMap<K, V> where K: Eq {
}
/// Create a new map where keys and values are mapped to new keys and
- /// values. When the mapping introduces new duplicates, problems are
+ /// values. When the mapping introduces new duplicates, diagnostics are
/// generated.
- pub fn dedup<F, K2, V2>(&self, problems: &mut Problems, mut f: F) -> DedupMap<K2, V2>
+ pub fn dedup<F, K2, V2>(&self, diagnostics: &mut Diagnostics, mut f: F) -> DedupMap<K2, V2>
where F: FnMut(&K, &V) -> (K2, V2), K2: Eq {
let mut map = DedupMap::new();
for Spanned { v: (key, value), span } in self.map.iter() {
let (key, value) = f(key, value);
- map.insert(problems, Spanned { v: (key, value), span: *span });
+ map.insert(diagnostics, Spanned { v: (key, value), span: *span });
}
map
@@ -98,21 +97,21 @@ pub struct AxisMap<V>(DedupMap<AxisKey, V>);
impl<V: Value> AxisMap<V> {
/// Parse an axis map from the object.
pub fn parse<K>(
- problems: &mut Problems,
+ diagnostics: &mut Diagnostics,
object: &mut Object,
) -> AxisMap<V> where K: Key + Into<AxisKey> {
let values: Vec<_> = object
- .get_all_spanned::<K, V>(problems)
+ .get_all_spanned::<K, V>(diagnostics)
.map(|s| s.map(|(k, v)| (k.into(), v)))
.collect();
- AxisMap(DedupMap::from_iter(problems, values))
+ AxisMap(DedupMap::from_iter(diagnostics, values))
}
/// Deduplicate from specific or generic to just specific axes.
- pub fn dedup(&self, problems: &mut Problems, axes: LayoutAxes) -> DedupMap<SpecificAxis, V>
+ pub fn dedup(&self, diagnostics: &mut Diagnostics, axes: LayoutAxes) -> DedupMap<SpecificAxis, V>
where V: Clone {
- self.0.dedup(problems, |key, val| (key.to_specific(axes), val.clone()))
+ self.0.dedup(diagnostics, |key, val| (key.to_specific(axes), val.clone()))
}
}
@@ -124,23 +123,23 @@ pub struct PosAxisMap<V>(DedupMap<PosAxisKey, V>);
impl<V: Value> PosAxisMap<V> {
/// Parse a positional/axis map from the function arguments.
pub fn parse<K>(
- problems: &mut Problems,
+ diagnostics: &mut Diagnostics,
args: &mut FuncArgs,
) -> PosAxisMap<V> where K: Key + Into<AxisKey> {
let mut map = DedupMap::new();
for &key in &[PosAxisKey::First, PosAxisKey::Second] {
- if let Some(Spanned { v, span }) = args.pos.get::<Spanned<V>>(problems) {
- map.insert(problems, Spanned { v: (key, v), span })
+ if let Some(Spanned { v, span }) = args.pos.get::<Spanned<V>>(diagnostics) {
+ map.insert(diagnostics, Spanned { v: (key, v), span })
}
}
let keywords: Vec<_> = args.key
- .get_all_spanned::<K, V>(problems)
+ .get_all_spanned::<K, V>(diagnostics)
.map(|s| s.map(|(k, v)| (PosAxisKey::Keyword(k.into()), v)))
.collect();
- map.extend(problems, keywords);
+ map.extend(diagnostics, keywords);
PosAxisMap(map)
}
@@ -149,7 +148,7 @@ impl<V: Value> PosAxisMap<V> {
/// or specific axes to just generic axes.
pub fn dedup<F>(
&self,
- problems: &mut Problems,
+ diagnostics: &mut Diagnostics,
axes: LayoutAxes,
mut f: F,
) -> DedupMap<GenericAxis, V>
@@ -157,7 +156,7 @@ impl<V: Value> PosAxisMap<V> {
F: FnMut(&V) -> Option<GenericAxis>,
V: Clone,
{
- self.0.dedup(problems, |key, val| {
+ self.0.dedup(diagnostics, |key, val| {
(match key {
PosAxisKey::First => f(val).unwrap_or(GenericAxis::Primary),
PosAxisKey::Second => f(val).unwrap_or(GenericAxis::Secondary),
@@ -171,24 +170,24 @@ impl<V: Value> PosAxisMap<V> {
/// A map for storing padding given for a combination of all sides, opposing
/// sides or single sides.
#[derive(Debug, Clone, PartialEq)]
-pub struct PaddingMap(DedupMap<PaddingKey<AxisKey>, Option<PSize>>);
+pub struct PaddingMap(DedupMap<PaddingKey<AxisKey>, Option<ScaleLength>>);
impl PaddingMap {
/// Parse a padding map from the function arguments.
- pub fn parse(problems: &mut Problems, args: &mut FuncArgs) -> PaddingMap {
+ pub fn parse(diagnostics: &mut Diagnostics, args: &mut FuncArgs) -> PaddingMap {
let mut map = DedupMap::new();
- let all = args.pos.get::<Spanned<Defaultable<PSize>>>(problems);
+ let all = args.pos.get::<Spanned<Defaultable<ScaleLength>>>(diagnostics);
if let Some(Spanned { v, span }) = all {
- map.insert(problems, Spanned { v: (PaddingKey::All, v.into()), span });
+ map.insert(diagnostics, Spanned { v: (PaddingKey::All, v.into()), span });
}
let paddings: Vec<_> = args.key
- .get_all_spanned::<PaddingKey<AxisKey>, Defaultable<PSize>>(problems)
+ .get_all_spanned::<PaddingKey<AxisKey>, Defaultable<ScaleLength>>(diagnostics)
.map(|s| s.map(|(k, v)| (k, v.into())))
.collect();
- map.extend(problems, paddings);
+ map.extend(diagnostics, paddings);
PaddingMap(map)
}
@@ -196,13 +195,13 @@ impl PaddingMap {
/// Apply the specified padding on a value box of optional, scalable sizes.
pub fn apply(
&self,
- problems: &mut Problems,
+ diagnostics: &mut Diagnostics,
axes: LayoutAxes,
- padding: &mut ValueBox<Option<PSize>>
+ padding: &mut Value4<Option<ScaleLength>>
) {
use PaddingKey::*;
- let map = self.0.dedup(problems, |key, &val| {
+ let map = self.0.dedup(diagnostics, |key, &val| {
(match key {
All => All,
Both(axis) => Both(axis.to_specific(axes)),
diff --git a/src/syntax/func/mod.rs b/src/syntax/func/mod.rs
index 4228488d..c2631727 100644
--- a/src/syntax/func/mod.rs
+++ b/src/syntax/func/mod.rs
@@ -1,7 +1,7 @@
//! Primitives for argument parsing in library functions.
use std::iter::FromIterator;
-use crate::problem::{Problem, Problems};
+use crate::diagnostic::{Diagnostic, Diagnostics};
use super::expr::{Expr, Ident, Tuple, Object, Pair};
use super::span::{Span, Spanned};
@@ -85,13 +85,13 @@ pub enum FuncArg {
pub trait OptionExt: Sized {
/// Add an error about a missing argument `arg` with the given span if the
/// option is `None`.
- fn or_missing(self, problems: &mut Problems, span: Span, arg: &str) -> Self;
+ fn or_missing(self, diagnostics: &mut Diagnostics, span: Span, arg: &str) -> Self;
}
impl<T> OptionExt for Option<T> {
- fn or_missing(self, problems: &mut Problems, span: Span, arg: &str) -> Self {
+ fn or_missing(self, diagnostics: &mut Diagnostics, span: Span, arg: &str) -> Self {
if self.is_none() {
- problems.push(error!(span, "missing argument: {}", arg));
+ diagnostics.push(error!(span, "missing argument: {}", arg));
}
self
}
diff --git a/src/syntax/func/values.rs b/src/syntax/func/values.rs
index 7a1aa912..3269f8e9 100644
--- a/src/syntax/func/values.rs
+++ b/src/syntax/func/values.rs
@@ -4,13 +4,12 @@ use std::fmt::{self, Display, Formatter};
use toddle::query::{FontStyle, FontWeight};
use crate::layout::prelude::*;
-use crate::size::{Size, ScaleSize};
-use crate::style::Paper;
+use crate::length::{Length, ScaleLength};
+use crate::paper::Paper;
use super::*;
use self::AlignmentValue::*;
-
/// Value types are used to extract the values of positional and keyword
/// arguments from [`Tuples`](crate::syntax::expr::Tuple) and
/// [`Objects`](crate::syntax::expr::Object). They represent the value part of
@@ -24,14 +23,14 @@ use self::AlignmentValue::*;
/// An implementation for `bool` might look as follows:
/// ```
/// # use typstc::error;
-/// # use typstc::problem::Problem;
+/// # use typstc::diagnostic::Diagnostic;
/// # use typstc::syntax::expr::Expr;
/// # use typstc::syntax::func::Value;
/// # use typstc::syntax::span::Spanned;
/// # struct Bool; /*
/// impl Value for bool {
/// # */ impl Value for Bool {
-/// fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> {
+/// fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> {
/// match expr.v {
/// # /*
/// Expr::Bool(b) => Ok(b),
@@ -44,11 +43,11 @@ use self::AlignmentValue::*;
pub trait Value: Sized {
/// Parse an expression into this value or return an error if the expression
/// is valid for this value type.
- fn parse(expr: Spanned<Expr>) -> Result<Self, Problem>;
+ fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic>;
}
impl<V: Value> Value for Spanned<V> {
- fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> {
+ fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> {
let span = expr.span;
V::parse(expr).map(|v| Spanned { v, span })
}
@@ -58,7 +57,7 @@ impl<V: Value> Value for Spanned<V> {
macro_rules! value {
($type:ty, $name:expr, $($p:pat => $r:expr),* $(,)?) => {
impl Value for $type {
- fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> {
+ fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> {
#[allow(unreachable_patterns)]
match expr.v {
$($p => Ok($r)),*,
@@ -77,13 +76,13 @@ value!(Ident, "identifier", Expr::Ident(i) => i);
value!(String, "string", Expr::Str(s) => s);
value!(f64, "number", Expr::Number(n) => n);
value!(bool, "bool", Expr::Bool(b) => b);
-value!(Size, "size", Expr::Size(s) => s);
+value!(Length, "length", Expr::Length(s) => s);
value!(Tuple, "tuple", Expr::Tuple(t) => t);
value!(Object, "object", Expr::Object(o) => o);
-value!(ScaleSize, "number or size",
- Expr::Size(size) => ScaleSize::Absolute(size),
- Expr::Number(scale) => ScaleSize::Scaled(scale as f32),
+value!(ScaleLength, "number or length",
+ Expr::Length(length) => ScaleLength::Absolute(length),
+ Expr::Number(scale) => ScaleLength::Scaled(scale as f64),
);
/// A value type that matches [`Expr::Ident`] and [`Expr::Str`] and implements
@@ -108,20 +107,20 @@ impl From<StringLike> for String {
/// # Example
/// ```
/// # use typstc::syntax::func::{FuncArgs, Defaultable};
-/// # use typstc::size::Size;
+/// # use typstc::length::Length;
/// # let mut args = FuncArgs::new();
/// # let mut errors = vec![];
-/// args.key.get::<Defaultable<Size>>(&mut errors, "size");
+/// args.key.get::<Defaultable<Length>>(&mut errors, "length");
/// ```
/// This will yield.
/// ```typst
-/// [func: size=default] => None
-/// [func: size=2cm] => Some(Size::cm(2.0))
+/// [func: length=default] => None
+/// [func: length=2cm] => Some(Length::cm(2.0))
/// ```
pub struct Defaultable<V>(pub Option<V>);
impl<V: Value> Value for Defaultable<V> {
- fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> {
+ fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> {
Ok(Defaultable(match expr.v {
Expr::Ident(ident) if ident.as_str() == "default" => None,
_ => Some(V::parse(expr)?)
@@ -136,7 +135,7 @@ impl<V> From<Defaultable<V>> for Option<V> {
}
impl Value for FontStyle {
- fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> {
+ fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> {
FontStyle::from_name(Ident::parse(expr)?.as_str())
.ok_or_else(|| error!("invalid font style"))
}
@@ -145,7 +144,7 @@ impl Value for FontStyle {
/// The additional boolean specifies whether a number was clamped into the range
/// 100 - 900 to make it a valid font weight.
impl Value for (FontWeight, bool) {
- fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> {
+ fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> {
match expr.v {
Expr::Number(weight) => {
let weight = weight.round();
@@ -170,14 +169,14 @@ impl Value for (FontWeight, bool) {
}
impl Value for Paper {
- fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> {
+ fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> {
Paper::from_name(Ident::parse(expr)?.as_str())
.ok_or_else(|| error!("invalid paper type"))
}
}
impl Value for Direction {
- fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> {
+ fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> {
Ok(match Ident::parse(expr)?.as_str() {
"left-to-right" | "ltr" | "LTR" => LeftToRight,
"right-to-left" | "rtl" | "RTL" => RightToLeft,
@@ -250,7 +249,7 @@ impl AlignmentValue {
}
impl Value for AlignmentValue {
- fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> {
+ fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> {
Ok(match Ident::parse(expr)?.as_str() {
"origin" => Align(Origin),
"center" => Align(Center),
diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs
index f7321c77..b67d8cd7 100644
--- a/src/syntax/mod.rs
+++ b/src/syntax/mod.rs
@@ -20,7 +20,6 @@ pub_use_mod!(scope);
pub_use_mod!(parsing);
pub_use_mod!(tokens);
-
/// Represents a parsed piece of source that can be layouted and in the future
/// also be queried for information used for refactorings, autocomplete, etc.
#[async_trait(?Send)]
@@ -94,6 +93,9 @@ impl PartialEq for Node {
}
}
+/// A list of spanned decorations.
+pub type Decorations = SpanVec<Decoration>;
+
/// Decorations for semantic syntax highlighting.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize)]
#[serde(rename_all = "camelCase")]
@@ -110,7 +112,6 @@ pub enum Decoration {
/// ^^^^^^
/// ```
InvalidFuncName,
-
/// A key of a keyword argument:
/// ```typst
/// [box: width=5cm]
@@ -123,7 +124,6 @@ pub enum Decoration {
/// ^^^^ ^^^^^
/// ```
ObjectKey,
-
/// An italic word.
Italic,
/// A bold word.
diff --git a/src/syntax/parsing.rs b/src/syntax/parsing.rs
index a0d9c4e4..a8151125 100644
--- a/src/syntax/parsing.rs
+++ b/src/syntax/parsing.rs
@@ -4,9 +4,12 @@ use std::str::FromStr;
use super::expr::*;
use super::func::{FuncCall, FuncHeader, FuncArgs, FuncArg};
-use super::span::{Position, Span, Spanned};
+use super::span::{Pos, Span, Spanned};
use super::*;
+/// A function which parses a function call into a model.
+pub type CallParser = dyn Fn(FuncCall, &ParseState) -> Pass<Box<dyn Model>>;
+
/// The state which can influence how a string of source code is parsed.
///
/// Parsing is pure - when passed in the same state and source code, the output
@@ -22,7 +25,7 @@ pub struct ParseState {
/// `offset` position. This is used to make spans of a function body relative to
/// the start of the function as a whole as opposed to the start of the
/// function's body.
-pub fn parse(src: &str, offset: Position, state: &ParseState) -> Pass<SyntaxModel> {
+pub fn parse(src: &str, offset: Pos, state: &ParseState) -> Pass<SyntaxModel> {
let mut model = SyntaxModel::new();
let mut feedback = Feedback::new();
@@ -102,7 +105,7 @@ impl<'s> FuncParser<'s> {
state,
// Start at column 1 because the opening bracket is also part of
// the function, but not part of the `header` string.
- tokens: Tokens::new(header, Position::new(0, 1), TokenMode::Header),
+ tokens: Tokens::new(header, Pos::new(0, 1), TokenMode::Header),
peeked: None,
body,
feedback: Feedback::new(),
@@ -127,7 +130,7 @@ impl<'s> FuncParser<'s> {
}
};
- self.feedback.decos.push(Spanned::new(deco, header.name.span));
+ self.feedback.decorations.push(Spanned::new(deco, header.name.span));
(parser, header)
} else {
// Parse the body with the fallback parser even when the header is
@@ -186,7 +189,7 @@ impl<'s> FuncParser<'s> {
self.skip_white();
let key = ident;
- self.feedback.decos.push(
+ self.feedback.decorations.push(
Spanned::new(Decoration::ArgumentKey, key.span)
);
@@ -325,7 +328,7 @@ impl FuncParser<'_> {
}
Token::ExprNumber(n) => self.eat_span(Expr::Number(n)),
- Token::ExprSize(s) => self.eat_span(Expr::Size(s)),
+ Token::ExprLength(s) => self.eat_span(Expr::Length(s)),
Token::ExprBool(b) => self.eat_span(Expr::Bool(b)),
Token::ExprHex(s) => {
if let Ok(color) = RgbaColor::from_str(s) {
@@ -423,7 +426,7 @@ impl FuncParser<'_> {
continue;
}
- self.feedback.decos.push(
+ self.feedback.decorations.push(
Spanned::new(Decoration::ObjectKey, key.span)
);
@@ -464,7 +467,7 @@ impl FuncParser<'_> {
}
}
- fn expect_at(&mut self, token: Token<'_>, pos: Position) -> bool {
+ fn expect_at(&mut self, token: Token<'_>, pos: Pos) -> bool {
if self.check(token) {
self.eat();
true
@@ -485,11 +488,11 @@ impl FuncParser<'_> {
}
}
- fn expected_at(&mut self, thing: &str, pos: Position) {
+ fn expected_at(&mut self, thing: &str, pos: Pos) {
error!(@self.feedback, Span::at(pos), "expected {}", thing);
}
- fn expected_found_or_at(&mut self, thing: &str, pos: Position) {
+ fn expected_found_or_at(&mut self, thing: &str, pos: Pos) {
if self.eof() {
self.expected_at(thing, pos)
} else {
@@ -544,7 +547,7 @@ impl<'s> FuncParser<'s> {
self.peek().is_none()
}
- fn pos(&self) -> Position {
+ fn pos(&self) -> Pos {
self.peeked.flatten()
.map(|s| s.span.start)
.unwrap_or_else(|| self.tokens.pos())
@@ -604,13 +607,13 @@ fn unescape_raw(raw: &str) -> Vec<String> {
#[cfg(test)]
#[allow(non_snake_case)]
mod tests {
- use crate::size::Size;
+ use crate::length::Length;
use super::super::test::{check, DebugFn};
use super::super::func::Value;
use super::*;
use Decoration::*;
- use Expr::{Number as Num, Size as Sz, Bool};
+ use Expr::{Number as Num, Length as Len, Bool};
use Node::{
Space as S, ToggleItalic as Italic, ToggleBolder as Bold,
Parbreak, Linebreak,
@@ -625,7 +628,7 @@ mod tests {
p!($source => [$($model)*], []);
};
- ($source:expr => [$($model:tt)*], [$($problems:tt)*] $(, [$($decos:tt)*])? $(,)?) => {
+ ($source:expr => [$($model:tt)*], [$($diagnostics:tt)*] $(, [$($decos:tt)*])? $(,)?) => {
let mut scope = Scope::new::<DebugFn>();
scope.add::<DebugFn>("f");
scope.add::<DebugFn>("n");
@@ -633,25 +636,25 @@ mod tests {
scope.add::<DebugFn>("val");
let state = ParseState { scope };
- let pass = parse($source, Position::ZERO, &state);
+ let pass = parse($source, Pos::ZERO, &state);
// Test model.
let (exp, cmp) = span_vec![$($model)*];
check($source, exp, pass.output.nodes, cmp);
- // Test problems.
- let (exp, cmp) = span_vec![$($problems)*];
+ // Test diagnostics.
+ let (exp, cmp) = span_vec![$($diagnostics)*];
let exp = exp.into_iter()
.map(|s: Spanned<&str>| s.map(|e| e.to_string()))
.collect::<Vec<_>>();
- let found = pass.feedback.problems.into_iter()
+ let found = pass.feedback.diagnostics.into_iter()
.map(|s| s.map(|e| e.message))
.collect::<Vec<_>>();
check($source, exp, found, cmp);
// Test decos.
$(let (exp, cmp) = span_vec![$($decos)*];
- check($source, exp, pass.feedback.decos, cmp);)?
+ check($source, exp, pass.feedback.decorations, cmp);)?
};
}
@@ -664,7 +667,6 @@ mod tests {
fn Id(text: &str) -> Expr { Expr::Ident(Ident(text.to_string())) }
fn Str(text: &str) -> Expr { Expr::Str(text.to_string()) }
- fn Pt(points: f32) -> Expr { Expr::Size(Size::pt(points)) }
fn Color(r: u8, g: u8, b: u8, a: u8) -> Expr { Expr::Color(RgbaColor::new(r, g, b, a)) }
fn ColorStr(color: &str) -> Expr { Expr::Color(RgbaColor::from_str(color).expect("invalid test color")) }
fn ColorHealed() -> Expr { Expr::Color(RgbaColor::new_healed(0, 0, 0, 255)) }
@@ -878,8 +880,8 @@ mod tests {
pval!("name" => (Id("name")));
pval!("\"hi\"" => (Str("hi")));
pval!("3.14" => (Num(3.14)));
- pval!("4.5cm" => (Sz(Size::cm(4.5))));
- pval!("12e1pt" => (Pt(12e1)));
+ pval!("4.5cm" => (Len(Length::cm(4.5))));
+ pval!("12e1pt" => (Len(Length::pt(12e1))));
pval!("#f7a20500" => (ColorStr("f7a20500")));
pval!("\"a\n[]\\\"string\"" => (Str("a\n[]\"string")));
@@ -890,10 +892,10 @@ mod tests {
pval!("(hi)" => (Id("hi")));
// Math.
- pval!("3.2in + 6pt" => (Add(Sz(Size::inches(3.2)), Sz(Size::pt(6.0)))));
+ pval!("3.2in + 6pt" => (Add(Len(Length::inches(3.2)), Len(Length::pt(6.0)))));
pval!("5 - 0.01" => (Sub(Num(5.0), Num(0.01))));
- pval!("(3mm * 2)" => (Mul(Sz(Size::mm(3.0)), Num(2.0))));
- pval!("12e-3cm/1pt" => (Div(Sz(Size::cm(12e-3)), Sz(Size::pt(1.0)))));
+ pval!("(3mm * 2)" => (Mul(Len(Length::mm(3.0)), Num(2.0))));
+ pval!("12e-3cm/1pt" => (Div(Len(Length::cm(12e-3)), Len(Length::pt(1.0)))));
// Unclosed string.
p!("[val: \"hello]" => [func!("val": (Str("hello]")), {})], [
@@ -912,26 +914,24 @@ mod tests {
fn parse_complex_mathematical_expressions() {
// Valid expressions.
pval!("(3.2in + 6pt)*(5/2-1)" => (Mul(
- Add(Sz(Size::inches(3.2)), Sz(Size::pt(6.0))),
+ Add(Len(Length::inches(3.2)), Len(Length::pt(6.0))),
Sub(Div(Num(5.0), Num(2.0)), Num(1.0))
)));
pval!("(6.3E+2+4* - 3.2pt)/2" => (Div(
- Add(Num(6.3e2),Mul(Num(4.0), Neg(Pt(3.2)))),
+ Add(Num(6.3e2), Mul(Num(4.0), Neg(Len(Length::pt(3.2))))),
Num(2.0)
)));
// Associativity of multiplication and division.
- p!("[val: 3/4*5]" =>
- [func!("val": (Mul(Div(Num(3.0), Num(4.0)), Num(5.0))), {})]
- );
+ pval!("3/4*5" => (Mul(Div(Num(3.0), Num(4.0)), Num(5.0))));
// Invalid expressions.
- p!("[val: 4pt--]" => [func!("val": (Pt(4.0)))], [
+ p!("[val: 4pt--]" => [func!("val": (Len(Length::pt(4.0))))], [
(0:10, 0:11, "dangling minus"),
(0:6, 0:10, "missing right summand")
]);
p!("[val: 3mm+4pt*]" =>
- [func!("val": (Add(Sz(Size::mm(3.0)), Pt(4.0))))],
+ [func!("val": (Add(Len(Length::mm(3.0)), Len(Length::pt(4.0)))))],
[(0:10, 0:14, "missing right factor")],
);
}
@@ -976,7 +976,7 @@ mod tests {
// Nested tuples.
pval!("css(1pt, rgb(90, 102, 254), \"solid\")" => (named_tuple!(
"css",
- Pt(1.0),
+ Len(Length::pt(1.0)),
named_tuple!("rgb", Num(90.0), Num(102.0), Num(254.0)),
Str("solid"),
)));
@@ -1012,7 +1012,7 @@ mod tests {
// Missing key.
p!("[val: {,}]" => [val()], [(0:7, 0:8, "expected key, found comma")]);
- p!("[val: { 12pt }]" => [val()], [(0:8, 0:12, "expected key, found size")]);
+ p!("[val: { 12pt }]" => [val()], [(0:8, 0:12, "expected key, found length")]);
p!("[val: { : }]" => [val()], [(0:8, 0:9, "expected key, found colon")]);
// Missing colon.
@@ -1053,7 +1053,7 @@ mod tests {
Num(1.0),
object!(
"ab" => tuple!(),
- "d" => tuple!(Num(3.0), Pt(14.0)),
+ "d" => tuple!(Num(3.0), Len(Length::pt(14.0))),
),
),
Bool(false),
@@ -1085,7 +1085,7 @@ mod tests {
#[test]
fn parse_multiple_mixed_arguments() {
p!("[val: 12pt, key=value]" =>
- [func!("val": (Pt(12.0)), { "key" => Id("value") })], [],
+ [func!("val": (Len(Length::pt(12.0))), { "key" => Id("value") })], [],
[(0:12, 0:15, ArgumentKey), (0:1, 0:4, ValidFuncName)],
);
pval!("a , x=\"b\" , c" => (Id("a"), Id("c")), { "x" => Str("b"), });
@@ -1144,7 +1144,7 @@ mod tests {
fn parse_invalid_commas() {
// Missing commas.
p!("[val: 1pt 1]" =>
- [func!("val": (Pt(1.0), Num(1.0)), {})],
+ [func!("val": (Len(Length::pt(1.0)), Num(1.0)), {})],
[(0:9, 0:9, "expected comma")],
);
p!(r#"[val: _"s"]"# =>
diff --git a/src/syntax/scope.rs b/src/syntax/scope.rs
index 74c64280..c6350836 100644
--- a/src/syntax/scope.rs
+++ b/src/syntax/scope.rs
@@ -3,16 +3,14 @@
use std::collections::HashMap;
use std::fmt::{self, Debug, Formatter};
-use crate::Pass;
use crate::func::ParseFunc;
-use super::func::FuncCall;
-use super::parsing::ParseState;
+use super::parsing::CallParser;
use super::Model;
/// A map from identifiers to function parsers.
pub struct Scope {
- parsers: HashMap<String, Box<Parser>>,
- fallback: Box<Parser>,
+ parsers: HashMap<String, Box<CallParser>>,
+ fallback: Box<CallParser>,
}
impl Scope {
@@ -22,7 +20,7 @@ impl Scope {
where F: ParseFunc<Meta=()> + Model + 'static {
Scope {
parsers: HashMap::new(),
- fallback: parser::<F>(()),
+ fallback: make_parser::<F>(()),
}
}
@@ -43,17 +41,17 @@ impl Scope {
where F: ParseFunc + Model + 'static {
self.parsers.insert(
name.to_string(),
- parser::<F>(metadata),
+ make_parser::<F>(metadata),
);
}
/// Return the parser with the given name if there is one.
- pub fn get_parser(&self, name: &str) -> Option<&Parser> {
+ pub fn get_parser(&self, name: &str) -> Option<&CallParser> {
self.parsers.get(name).map(AsRef::as_ref)
}
/// Return the fallback parser.
- pub fn get_fallback_parser(&self) -> &Parser {
+ pub fn get_fallback_parser(&self) -> &CallParser {
&*self.fallback
}
}
@@ -66,11 +64,7 @@ impl Debug for Scope {
}
}
-/// A function which parses the source of a function into a model type which
-/// implements [`Model`].
-type Parser = dyn Fn(FuncCall, &ParseState) -> Pass<Box<dyn Model>>;
-
-fn parser<F>(metadata: <F as ParseFunc>::Meta) -> Box<Parser>
+fn make_parser<F>(metadata: <F as ParseFunc>::Meta) -> Box<CallParser>
where F: ParseFunc + Model + 'static {
Box::new(move |f, s| {
F::parse(f, s, metadata.clone())
diff --git a/src/syntax/span.rs b/src/syntax/span.rs
index c8e2cddb..19562fb1 100644
--- a/src/syntax/span.rs
+++ b/src/syntax/span.rs
@@ -4,16 +4,22 @@ use std::fmt::{self, Debug, Formatter};
use std::ops::{Add, Sub};
use serde::Serialize;
+/// Span offsetting.
+pub trait Offset {
+ /// Offset all spans contained in `Self` by the given position.
+ fn offset(self, by: Pos) -> Self;
+}
+
/// A vector of spanned values of type `T`.
pub type SpanVec<T> = Vec<Spanned<T>>;
-/// [Offset](Span::offset) all spans in a vector of spanned things by a start
-/// position.
-pub fn offset_spans<T>(
- vec: SpanVec<T>,
- start: Position,
-) -> impl Iterator<Item=Spanned<T>> {
- vec.into_iter().map(move |s| s.map_span(|span| span.offset(start)))
+impl<T> Offset for SpanVec<T> {
+ fn offset(mut self, by: Pos) -> Self {
+ for spanned in &mut self {
+ spanned.span = spanned.span.offset(by);
+ }
+ self
+ }
}
/// A value with the span it corresponds to in the source code.
@@ -53,6 +59,12 @@ impl<T> Spanned<T> {
}
}
+impl<T> Offset for Spanned<T> {
+ fn offset(self, by: Pos) -> Self {
+ self.map_span(|span| span.offset(by))
+ }
+}
+
impl<T: Debug> Debug for Spanned<T> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.v.fmt(f)?;
@@ -68,20 +80,25 @@ impl<T: Debug> Debug for Spanned<T> {
#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize)]
pub struct Span {
/// The inclusive start position.
- pub start: Position,
+ pub start: Pos,
/// The inclusive end position.
- pub end: Position,
+ pub end: Pos,
}
impl Span {
/// The zero span.
- pub const ZERO: Span = Span { start: Position::ZERO, end: Position::ZERO };
+ pub const ZERO: Span = Span { start: Pos::ZERO, end: Pos::ZERO };
/// Create a new span from start and end positions.
- pub fn new(start: Position, end: Position) -> Span {
+ pub fn new(start: Pos, end: Pos) -> Span {
Span { start, end }
}
+ /// Create a span including just a single position.
+ pub fn at(pos: Pos) -> Span {
+ Span { start: pos, end: pos }
+ }
+
/// Create a new span with the earlier start and later end position.
pub fn merge(a: Span, b: Span) -> Span {
Span {
@@ -90,24 +107,17 @@ impl Span {
}
}
- /// Create a span including just a single position.
- pub fn at(pos: Position) -> Span {
- Span { start: pos, end: pos }
- }
-
/// Expand a span by merging it with another span.
pub fn expand(&mut self, other: Span) {
*self = Span::merge(*self, other)
}
+}
- /// Offset a span by a start position.
- ///
- /// This is, for example, used to translate error spans from function local
- /// to global.
- pub fn offset(self, start: Position) -> Span {
+impl Offset for Span {
+ fn offset(self, by: Pos) -> Self {
Span {
- start: start + self.start,
- end: start + self.end,
+ start: self.start.offset(by),
+ end: self.end.offset(by),
}
}
}
@@ -120,34 +130,40 @@ impl Debug for Span {
/// Zero-indexed line-column position in source code.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize)]
-pub struct Position {
+pub struct Pos {
/// The zero-indexed line.
pub line: usize,
/// The zero-indexed column.
pub column: usize,
}
-impl Position {
+impl Pos {
/// The line 0, column 0 position.
- pub const ZERO: Position = Position { line: 0, column: 0 };
+ pub const ZERO: Pos = Pos { line: 0, column: 0 };
/// Create a new position from line and column.
- pub fn new(line: usize, column: usize) -> Position {
- Position { line, column }
+ pub fn new(line: usize, column: usize) -> Pos {
+ Pos { line, column }
+ }
+}
+
+impl Offset for Pos {
+ fn offset(self, by: Pos) -> Self {
+ by + self
}
}
-impl Add for Position {
- type Output = Position;
+impl Add for Pos {
+ type Output = Pos;
- fn add(self, rhs: Position) -> Position {
+ fn add(self, rhs: Pos) -> Pos {
if rhs.line == 0 {
- Position {
+ Pos {
line: self.line,
column: self.column + rhs.column
}
} else {
- Position {
+ Pos {
line: self.line + rhs.line,
column: rhs.column,
}
@@ -155,17 +171,17 @@ impl Add for Position {
}
}
-impl Sub for Position {
- type Output = Position;
+impl Sub for Pos {
+ type Output = Pos;
- fn sub(self, rhs: Position) -> Position {
+ fn sub(self, rhs: Pos) -> Pos {
if self.line == rhs.line {
- Position {
+ Pos {
line: 0,
column: self.column - rhs.column
}
} else {
- Position {
+ Pos {
line: self.line - rhs.line,
column: self.column,
}
@@ -173,7 +189,7 @@ impl Sub for Position {
}
}
-impl Debug for Position {
+impl Debug for Pos {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}:{}", self.line, self.column)
}
diff --git a/src/syntax/test.rs b/src/syntax/test.rs
index 7b1e0830..639fbb61 100644
--- a/src/syntax/test.rs
+++ b/src/syntax/test.rs
@@ -39,11 +39,11 @@ macro_rules! span_vec {
macro_rules! span_item {
(($sl:tt:$sc:tt, $el:tt:$ec:tt, $v:expr)) => ({
- use $crate::syntax::span::{Position, Span, Spanned};
+ use $crate::syntax::span::{Pos, Span, Spanned};
Spanned {
span: Span::new(
- Position::new($sl, $sc),
- Position::new($el, $ec)
+ Pos::new($sl, $sc),
+ Pos::new($el, $ec)
),
v: $v
}
diff --git a/src/syntax/tokens.rs b/src/syntax/tokens.rs
index 10200708..9bb95c97 100644
--- a/src/syntax/tokens.rs
+++ b/src/syntax/tokens.rs
@@ -2,8 +2,8 @@ use std::iter::Peekable;
use std::str::Chars;
use unicode_xid::UnicodeXID;
-use crate::size::Size;
-use super::span::{Position, Span, Spanned};
+use crate::length::Length;
+use super::span::{Pos, Span, Spanned};
use Token::*;
use TokenMode::*;
@@ -73,8 +73,8 @@ pub enum Token<'s> {
},
/// A number in a function header: `3.14`.
ExprNumber(f64),
- /// A size in a function header: `12pt`.
- ExprSize(Size),
+ /// A length in a function header: `12pt`.
+ ExprLength(Length),
/// A boolean in a function header: `true | false`.
ExprBool(bool),
/// A hex value in a function header: `#20d82a`.
@@ -129,7 +129,7 @@ impl<'s> Token<'s> {
ExprIdent(_) => "identifier",
ExprStr { .. } => "string",
ExprNumber(_) => "number",
- ExprSize(_) => "size",
+ ExprLength(_) => "length",
ExprBool(_) => "bool",
ExprHex(_) => "hex value",
Plus => "plus",
@@ -153,7 +153,7 @@ pub struct Tokens<'s> {
src: &'s str,
mode: TokenMode,
iter: Peekable<Chars<'s>>,
- position: Position,
+ pos: Pos,
index: usize,
}
@@ -172,12 +172,12 @@ impl<'s> Tokens<'s> {
///
/// The first token's span starts an the given `offset` position instead of
/// the zero position.
- pub fn new(src: &'s str, offset: Position, mode: TokenMode) -> Tokens<'s> {
+ pub fn new(src: &'s str, offset: Pos, mode: TokenMode) -> Tokens<'s> {
Tokens {
src,
mode,
iter: src.chars().peekable(),
- position: offset,
+ pos: offset,
index: 0,
}
}
@@ -190,8 +190,8 @@ impl<'s> Tokens<'s> {
/// The line-colunn position in the source at which the last token ends and
/// next token will start.
- pub fn pos(&self) -> Position {
- self.position
+ pub fn pos(&self) -> Pos {
+ self.pos
}
}
@@ -315,14 +315,14 @@ impl<'s> Tokens<'s> {
}, true, 0, -2).0)
}
- fn read_whitespace(&mut self, start: Position) -> Token<'s> {
+ fn read_whitespace(&mut self, start: Pos) -> Token<'s> {
self.read_string_until(|n| !n.is_whitespace(), false, 0, 0);
let end = self.pos();
Space(end.line - start.line)
}
- fn read_function(&mut self, start: Position) -> Token<'s> {
+ fn read_function(&mut self, start: Pos) -> Token<'s> {
let (header, terminated) = self.read_function_part(Header);
self.eat();
@@ -354,7 +354,7 @@ impl<'s> Tokens<'s> {
self.eat();
match n {
- '[' => { self.read_function(Position::ZERO); }
+ '[' => { self.read_function(Pos::ZERO); }
'/' if self.peek() == Some('/') => { self.read_line_comment(); }
'/' if self.peek() == Some('*') => { self.read_block_comment(); }
'"' if mode == Header => { self.read_string(); }
@@ -427,8 +427,8 @@ impl<'s> Tokens<'s> {
ExprNumber(num)
} else if let Some(num) = parse_percentage(text) {
ExprNumber(num / 100.0)
- } else if let Ok(size) = text.parse::<Size>() {
- ExprSize(size)
+ } else if let Ok(length) = text.parse::<Length>() {
+ ExprLength(length)
} else if is_identifier(text) {
ExprIdent(text)
} else {
@@ -476,10 +476,10 @@ impl<'s> Tokens<'s> {
self.index += c.len_utf8();
if is_newline_char(c) && !(c == '\r' && self.peek() == Some('\n')) {
- self.position.line += 1;
- self.position.column = 0;
+ self.pos.line += 1;
+ self.pos.column = 0;
} else {
- self.position.column += 1;
+ self.pos.column += 1;
}
Some(c)
@@ -543,7 +543,7 @@ mod tests {
LeftBrace as LB, RightBrace as RB,
ExprIdent as Id,
ExprNumber as Num,
- ExprSize as Sz,
+ ExprLength as Len,
ExprBool as Bool,
ExprHex as Hex,
Text as T,
@@ -557,7 +557,7 @@ mod tests {
macro_rules! t {
($mode:expr, $source:expr => [$($tokens:tt)*]) => {
let (exp, spans) = span_vec![$($tokens)*];
- let found = Tokens::new($source, Position::ZERO, $mode).collect::<Vec<_>>();
+ let found = Tokens::new($source, Pos::ZERO, $mode).collect::<Vec<_>>();
check($source, exp, found, spans);
}
}
@@ -640,13 +640,13 @@ mod tests {
t!(Header, "__main__" => [Id("__main__")]);
t!(Header, ".func.box" => [Id(".func.box")]);
t!(Header, "arg, _b, _1" => [Id("arg"), Comma, S(0), Id("_b"), Comma, S(0), Id("_1")]);
- t!(Header, "12_pt, 12pt" => [Invalid("12_pt"), Comma, S(0), Sz(Size::pt(12.0))]);
- t!(Header, "1e5in" => [Sz(Size::inches(100000.0))]);
- t!(Header, "2.3cm" => [Sz(Size::cm(2.3))]);
- t!(Header, "12e-3in" => [Sz(Size::inches(12e-3))]);
- t!(Header, "6.1cm + 4pt,a=1*2" => [Sz(Size::cm(6.1)), S(0), Plus, S(0), Sz(Size::pt(4.0)), Comma, Id("a"), Equals, Num(1.0), Star, Num(2.0)]);
+ t!(Header, "12_pt, 12pt" => [Invalid("12_pt"), Comma, S(0), Len(Length::pt(12.0))]);
+ t!(Header, "1e5in" => [Len(Length::inches(100000.0))]);
+ t!(Header, "2.3cm" => [Len(Length::cm(2.3))]);
+ t!(Header, "12e-3in" => [Len(Length::inches(12e-3))]);
+ t!(Header, "6.1cm + 4pt,a=1*2" => [Len(Length::cm(6.1)), S(0), Plus, S(0), Len(Length::pt(4.0)), Comma, Id("a"), Equals, Num(1.0), Star, Num(2.0)]);
t!(Header, "(5 - 1) / 2.1" => [LP, Num(5.0), S(0), Min, S(0), Num(1.0), RP, S(0), Slash, S(0), Num(2.1)]);
- t!(Header, "02.4mm" => [Sz(Size::mm(2.4))]);
+ t!(Header, "02.4mm" => [Len(Length::mm(2.4))]);
t!(Header, "2.4.cm" => [Invalid("2.4.cm")]);
t!(Header, "(1,2)" => [LP, Num(1.0), Comma, Num(2.0), RP]);
t!(Header, "{abc}" => [LB, Id("abc"), RB]);