mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Small improvements 🍪
This commit is contained in:
parent
605ab104c5
commit
335fa2d118
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use super::*;
|
use super::{Convert, RefKey, ValueDict};
|
||||||
|
use crate::layout::LayoutContext;
|
||||||
|
use crate::syntax::{SpanWith, Spanned};
|
||||||
|
|
||||||
/// A wrapper around a dictionary value that simplifies argument parsing in
|
/// A wrapper around a dictionary value that simplifies argument parsing in
|
||||||
/// functions.
|
/// functions.
|
||||||
@ -21,14 +23,44 @@ impl Args {
|
|||||||
{
|
{
|
||||||
self.0.v.remove(key).and_then(|entry| {
|
self.0.v.remove(key).and_then(|entry| {
|
||||||
let span = entry.value.span;
|
let span = entry.value.span;
|
||||||
let (t, diag) = T::convert(entry.value);
|
let (result, diag) = T::convert(entry.value);
|
||||||
if let Some(diag) = diag {
|
if let Some(diag) = diag {
|
||||||
ctx.f.diags.push(diag.span_with(span))
|
ctx.f.diags.push(diag.span_with(span))
|
||||||
}
|
}
|
||||||
t.ok()
|
result.ok()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This is the same as [`get`], except that it generates an error about a
|
||||||
|
/// missing argument with the given `name` if the key does not exist.
|
||||||
|
///
|
||||||
|
/// [`get`]: #method.get
|
||||||
|
pub fn need<'a, K, T>(
|
||||||
|
&mut self,
|
||||||
|
ctx: &mut LayoutContext,
|
||||||
|
key: K,
|
||||||
|
name: &str,
|
||||||
|
) -> Option<T>
|
||||||
|
where
|
||||||
|
K: Into<RefKey<'a>>,
|
||||||
|
T: Convert,
|
||||||
|
{
|
||||||
|
match self.0.v.remove(key) {
|
||||||
|
Some(entry) => {
|
||||||
|
let span = entry.value.span;
|
||||||
|
let (result, diag) = T::convert(entry.value);
|
||||||
|
if let Some(diag) = diag {
|
||||||
|
ctx.f.diags.push(diag.span_with(span))
|
||||||
|
}
|
||||||
|
result.ok()
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
ctx.f.diags.push(error!(self.0.span, "missing argument: {}", name));
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Retrieve and remove the first matching positional argument.
|
/// Retrieve and remove the first matching positional argument.
|
||||||
pub fn find<T>(&mut self) -> Option<T>
|
pub fn find<T>(&mut self) -> Option<T>
|
||||||
where
|
where
|
||||||
@ -104,6 +136,7 @@ impl Args {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use super::super::{Dict, SpannedEntry, Value};
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn entry(value: Value) -> SpannedEntry<Value> {
|
fn entry(value: Value) -> SpannedEntry<Value> {
|
||||||
|
@ -4,11 +4,12 @@ use std::ops::Deref;
|
|||||||
|
|
||||||
use fontdock::{FontStretch, FontStyle, FontWeight};
|
use fontdock::{FontStretch, FontStyle, FontWeight};
|
||||||
|
|
||||||
use super::*;
|
use super::{Value, ValueDict, ValueFunc};
|
||||||
use crate::diag::Diag;
|
use crate::diag::Diag;
|
||||||
use crate::geom::Linear;
|
use crate::geom::Linear;
|
||||||
use crate::layout::{Dir, SpecAlign};
|
use crate::layout::{Dir, SpecAlign};
|
||||||
use crate::paper::Paper;
|
use crate::paper::Paper;
|
||||||
|
use crate::syntax::{Ident, SpanWith, Spanned, SynTree};
|
||||||
|
|
||||||
/// Types that values can be converted into.
|
/// Types that values can be converted into.
|
||||||
pub trait Convert: Sized {
|
pub trait Convert: Sized {
|
||||||
@ -96,9 +97,9 @@ macro_rules! impl_match {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl_match!(Value, "value", v => v);
|
impl_match!(Value, "value", v => v);
|
||||||
impl_match!(Ident, "ident", Value::Ident(v) => v);
|
impl_match!(Ident, "identifier", Value::Ident(v) => v);
|
||||||
impl_match!(bool, "bool", Value::Bool(v) => v);
|
impl_match!(bool, "bool", Value::Bool(v) => v);
|
||||||
impl_match!(i64, "int", Value::Int(v) => v);
|
impl_match!(i64, "integer", Value::Int(v) => v);
|
||||||
impl_match!(f64, "float",
|
impl_match!(f64, "float",
|
||||||
Value::Int(v) => v as f64,
|
Value::Int(v) => v as f64,
|
||||||
Value::Float(v) => v,
|
Value::Float(v) => v,
|
||||||
@ -112,9 +113,9 @@ impl_match!(Linear, "linear",
|
|||||||
);
|
);
|
||||||
impl_match!(String, "string", Value::Str(v) => v);
|
impl_match!(String, "string", Value::Str(v) => v);
|
||||||
impl_match!(SynTree, "tree", Value::Content(v) => v);
|
impl_match!(SynTree, "tree", Value::Content(v) => v);
|
||||||
impl_match!(ValueDict, "dict", Value::Dict(v) => v);
|
impl_match!(ValueDict, "dictionary", Value::Dict(v) => v);
|
||||||
impl_match!(ValueFunc, "function", Value::Func(v) => v);
|
impl_match!(ValueFunc, "function", Value::Func(v) => v);
|
||||||
impl_match!(StringLike, "ident or string",
|
impl_match!(StringLike, "identifier or string",
|
||||||
Value::Ident(Ident(v)) => StringLike(v),
|
Value::Ident(Ident(v)) => StringLike(v),
|
||||||
Value::Str(v) => StringLike(v),
|
Value::Str(v) => StringLike(v),
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//! State.
|
//! Evaluation state.
|
||||||
|
|
||||||
use fontdock::{fallback, FallbackTree, FontStretch, FontStyle, FontVariant, FontWeight};
|
use fontdock::{fallback, FallbackTree, FontStretch, FontStyle, FontVariant, FontWeight};
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//! Computational values: Syntactical expressions can be evaluated into these.
|
//! Computational values.
|
||||||
|
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
@ -57,9 +57,9 @@ impl Value {
|
|||||||
pub fn ty(&self) -> &'static str {
|
pub fn ty(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::None => "none",
|
Self::None => "none",
|
||||||
Self::Ident(_) => "ident",
|
Self::Ident(_) => "identifier",
|
||||||
Self::Bool(_) => "bool",
|
Self::Bool(_) => "bool",
|
||||||
Self::Int(_) => "int",
|
Self::Int(_) => "integer",
|
||||||
Self::Float(_) => "float",
|
Self::Float(_) => "float",
|
||||||
Self::Relative(_) => "relative",
|
Self::Relative(_) => "relative",
|
||||||
Self::Length(_) => "length",
|
Self::Length(_) => "length",
|
||||||
@ -88,6 +88,9 @@ impl Spanned<Value> {
|
|||||||
/// the value is represented as layoutable content in a reasonable way.
|
/// the value is represented as layoutable content in a reasonable way.
|
||||||
pub fn into_commands(self) -> Vec<Command> {
|
pub fn into_commands(self) -> Vec<Command> {
|
||||||
match self.v {
|
match self.v {
|
||||||
|
// Don't print out none values.
|
||||||
|
Value::None => vec![],
|
||||||
|
|
||||||
// Pass-through.
|
// Pass-through.
|
||||||
Value::Commands(commands) => commands,
|
Value::Commands(commands) => commands,
|
||||||
Value::Content(tree) => vec![Command::LayoutSyntaxTree(tree)],
|
Value::Content(tree) => vec![Command::LayoutSyntaxTree(tree)],
|
||||||
@ -109,9 +112,6 @@ impl Spanned<Value> {
|
|||||||
commands
|
commands
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't print out none values.
|
|
||||||
Value::None => vec![],
|
|
||||||
|
|
||||||
// Format with debug.
|
// Format with debug.
|
||||||
val => {
|
val => {
|
||||||
let fmt = format!("{:?}", val);
|
let fmt = format!("{:?}", val);
|
||||||
@ -144,6 +144,14 @@ impl Debug for Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A dictionary of values.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```typst
|
||||||
|
/// (false, 12cm, greeting="hi")
|
||||||
|
/// ```
|
||||||
|
pub type ValueDict = Dict<SpannedEntry<Value>>;
|
||||||
|
|
||||||
/// An wrapper around a reference-counted executable function value.
|
/// An wrapper around a reference-counted executable function value.
|
||||||
///
|
///
|
||||||
/// The dynamic function object is wrapped in an `Rc` to keep [`Value`]
|
/// The dynamic function object is wrapped in an `Rc` to keep [`Value`]
|
||||||
@ -192,11 +200,3 @@ impl Debug for ValueFunc {
|
|||||||
f.pad("<function>")
|
f.pad("<function>")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A dictionary of values.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
/// ```typst
|
|
||||||
/// (false, 12cm, greeting="hi")
|
|
||||||
/// ```
|
|
||||||
pub type ValueDict = Dict<SpannedEntry<Value>>;
|
|
||||||
|
@ -26,11 +26,11 @@ use crate::length::Length;
|
|||||||
/// The raw _PDF_ is written into the `target` writable, returning the number of
|
/// The raw _PDF_ is written into the `target` writable, returning the number of
|
||||||
/// bytes written.
|
/// bytes written.
|
||||||
pub fn export<W: Write>(
|
pub fn export<W: Write>(
|
||||||
layout: &[BoxLayout],
|
layouts: &[BoxLayout],
|
||||||
loader: &FontLoader,
|
loader: &FontLoader,
|
||||||
target: W,
|
target: W,
|
||||||
) -> io::Result<usize> {
|
) -> io::Result<usize> {
|
||||||
PdfExporter::new(layout, loader, target)?.write()
|
PdfExporter::new(layouts, loader, target)?.write()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PdfExporter<'a, W: Write> {
|
struct PdfExporter<'a, W: Write> {
|
||||||
@ -42,7 +42,7 @@ struct PdfExporter<'a, W: Write> {
|
|||||||
/// tree and so on. These offsets are computed in the beginning and stored
|
/// tree and so on. These offsets are computed in the beginning and stored
|
||||||
/// here.
|
/// here.
|
||||||
offsets: Offsets,
|
offsets: Offsets,
|
||||||
// Font remapping, see below at `remap_fonts`.
|
// Font remapping, for more information see `remap_fonts`.
|
||||||
to_pdf: HashMap<FaceId, usize>,
|
to_pdf: HashMap<FaceId, usize>,
|
||||||
to_layout: Vec<FaceId>,
|
to_layout: Vec<FaceId>,
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,9 @@ use super::*;
|
|||||||
|
|
||||||
/// Performs the line layouting.
|
/// Performs the line layouting.
|
||||||
pub struct LineLayouter {
|
pub struct LineLayouter {
|
||||||
|
/// The context used for line layouting.
|
||||||
ctx: LineContext,
|
ctx: LineContext,
|
||||||
|
/// The underlying layouter that stacks the finished lines.
|
||||||
stack: StackLayouter,
|
stack: StackLayouter,
|
||||||
/// The in-progress line.
|
/// The in-progress line.
|
||||||
run: LineRun,
|
run: LineRun,
|
||||||
@ -36,27 +38,6 @@ pub struct LineContext {
|
|||||||
pub line_spacing: f64,
|
pub line_spacing: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A sequence of boxes with the same alignment. A real line can consist of
|
|
||||||
/// multiple runs with different alignments.
|
|
||||||
struct LineRun {
|
|
||||||
/// The so-far accumulated items of the run.
|
|
||||||
layouts: Vec<(f64, BoxLayout)>,
|
|
||||||
/// The summed width and maximal height of the run.
|
|
||||||
size: Size,
|
|
||||||
/// The alignment of all layouts in the line.
|
|
||||||
///
|
|
||||||
/// When a new run is created the alignment is yet to be determined and
|
|
||||||
/// `None` as such. Once a layout is added, its alignment decides the
|
|
||||||
/// alignment for the whole run.
|
|
||||||
align: Option<LayoutAlign>,
|
|
||||||
/// The amount of space left by another run on the same line or `None` if
|
|
||||||
/// this is the only run so far.
|
|
||||||
usable: Option<f64>,
|
|
||||||
/// The spacing state. This influences how new spacing is handled, e.g. hard
|
|
||||||
/// spacing may override soft spacing.
|
|
||||||
last_spacing: LastSpacing,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LineLayouter {
|
impl LineLayouter {
|
||||||
/// Create a new line layouter.
|
/// Create a new line layouter.
|
||||||
pub fn new(ctx: LineContext) -> Self {
|
pub fn new(ctx: LineContext) -> Self {
|
||||||
@ -259,6 +240,27 @@ impl LineLayouter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A sequence of boxes with the same alignment. A real line can consist of
|
||||||
|
/// multiple runs with different alignments.
|
||||||
|
struct LineRun {
|
||||||
|
/// The so-far accumulated items of the run.
|
||||||
|
layouts: Vec<(f64, BoxLayout)>,
|
||||||
|
/// The summed width and maximal height of the run.
|
||||||
|
size: Size,
|
||||||
|
/// The alignment of all layouts in the line.
|
||||||
|
///
|
||||||
|
/// When a new run is created the alignment is yet to be determined and
|
||||||
|
/// `None` as such. Once a layout is added, its alignment decides the
|
||||||
|
/// alignment for the whole run.
|
||||||
|
align: Option<LayoutAlign>,
|
||||||
|
/// The amount of space left by another run on the same line or `None` if
|
||||||
|
/// this is the only run so far.
|
||||||
|
usable: Option<f64>,
|
||||||
|
/// The spacing state. This influences how new spacing is handled, e.g. hard
|
||||||
|
/// spacing may override soft spacing.
|
||||||
|
last_spacing: LastSpacing,
|
||||||
|
}
|
||||||
|
|
||||||
impl LineRun {
|
impl LineRun {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -46,7 +46,6 @@ pub async fn layout(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let layouts = layout_tree(&tree, &mut ctx).await;
|
let layouts = layout_tree(&tree, &mut ctx).await;
|
||||||
|
|
||||||
Pass::new(layouts, ctx.f)
|
Pass::new(layouts, ctx.f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,12 +176,11 @@ pub enum Command {
|
|||||||
SetTextState(TextState),
|
SetTextState(TextState),
|
||||||
/// Update the page style.
|
/// Update the page style.
|
||||||
SetPageState(PageState),
|
SetPageState(PageState),
|
||||||
|
|
||||||
/// Update the alignment for future boxes added to this layouting process.
|
|
||||||
SetAlignment(LayoutAlign),
|
|
||||||
/// Update the layouting system along which future boxes will be laid
|
/// Update the layouting system along which future boxes will be laid
|
||||||
/// out. This ends the current line.
|
/// out. This ends the current line.
|
||||||
SetSystem(LayoutSystem),
|
SetSystem(LayoutSystem),
|
||||||
|
/// Update the alignment for future boxes added to this layouting process.
|
||||||
|
SetAlignment(LayoutAlign),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Defines how spacing interacts with surrounding spacing.
|
/// Defines how spacing interacts with surrounding spacing.
|
||||||
@ -211,26 +209,3 @@ impl SpacingKind {
|
|||||||
/// The standard spacing kind used for word spacing.
|
/// The standard spacing kind used for word spacing.
|
||||||
pub const WORD: Self = Self::Soft(1);
|
pub const WORD: Self = Self::Soft(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The spacing kind of the most recently inserted item in a layouting process.
|
|
||||||
///
|
|
||||||
/// Since the last inserted item may not be spacing at all, this can be `None`.
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
|
||||||
enum LastSpacing {
|
|
||||||
/// The last item was hard spacing.
|
|
||||||
Hard,
|
|
||||||
/// The last item was soft spacing with the given width and level.
|
|
||||||
Soft(f64, u32),
|
|
||||||
/// The last item wasn't spacing.
|
|
||||||
None,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LastSpacing {
|
|
||||||
/// The width of the soft space if this is a soft space or zero otherwise.
|
|
||||||
fn soft_or_zero(self) -> f64 {
|
|
||||||
match self {
|
|
||||||
LastSpacing::Soft(space, _) => space,
|
|
||||||
_ => 0.0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -23,7 +23,9 @@ use super::*;
|
|||||||
|
|
||||||
/// Performs the stack layouting.
|
/// Performs the stack layouting.
|
||||||
pub struct StackLayouter {
|
pub struct StackLayouter {
|
||||||
|
/// The context used for stack layouting.
|
||||||
ctx: StackContext,
|
ctx: StackContext,
|
||||||
|
/// The finished layouts.
|
||||||
layouts: Vec<BoxLayout>,
|
layouts: Vec<BoxLayout>,
|
||||||
/// The in-progress space.
|
/// The in-progress space.
|
||||||
space: Space,
|
space: Space,
|
||||||
@ -45,30 +47,6 @@ pub struct StackContext {
|
|||||||
pub repeat: bool,
|
pub repeat: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A layout space composed of subspaces which can have different systems and
|
|
||||||
/// alignments.
|
|
||||||
struct Space {
|
|
||||||
/// The index of this space in `ctx.spaces`.
|
|
||||||
index: usize,
|
|
||||||
/// Whether to include a layout for this space even if it would be empty.
|
|
||||||
hard: bool,
|
|
||||||
/// The so-far accumulated layouts.
|
|
||||||
layouts: Vec<(LayoutSystem, BoxLayout)>,
|
|
||||||
/// The specialized size of this space.
|
|
||||||
size: Size,
|
|
||||||
/// The specialized remaining space.
|
|
||||||
usable: Size,
|
|
||||||
/// The specialized extra-needed size to affect the size at all.
|
|
||||||
extra: Size,
|
|
||||||
/// Dictate which alignments for new boxes are still allowed and which
|
|
||||||
/// require a new space to be started. For example, after an `End`-aligned
|
|
||||||
/// item, no `Start`-aligned one can follow.
|
|
||||||
rulers: Sides<GenAlign>,
|
|
||||||
/// The spacing state. This influences how new spacing is handled, e.g. hard
|
|
||||||
/// spacing may override soft spacing.
|
|
||||||
last_spacing: LastSpacing,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StackLayouter {
|
impl StackLayouter {
|
||||||
/// Create a new stack layouter.
|
/// Create a new stack layouter.
|
||||||
pub fn new(ctx: StackContext) -> Self {
|
pub fn new(ctx: StackContext) -> Self {
|
||||||
@ -387,6 +365,30 @@ impl StackLayouter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A layout space composed of subspaces which can have different systems and
|
||||||
|
/// alignments.
|
||||||
|
struct Space {
|
||||||
|
/// The index of this space in `ctx.spaces`.
|
||||||
|
index: usize,
|
||||||
|
/// Whether to include a layout for this space even if it would be empty.
|
||||||
|
hard: bool,
|
||||||
|
/// The so-far accumulated layouts.
|
||||||
|
layouts: Vec<(LayoutSystem, BoxLayout)>,
|
||||||
|
/// The specialized size of this space.
|
||||||
|
size: Size,
|
||||||
|
/// The specialized remaining space.
|
||||||
|
usable: Size,
|
||||||
|
/// The specialized extra-needed size to affect the size at all.
|
||||||
|
extra: Size,
|
||||||
|
/// Dictate which alignments for new boxes are still allowed and which
|
||||||
|
/// require a new space to be started. For example, after an `End`-aligned
|
||||||
|
/// item, no `Start`-aligned one can follow.
|
||||||
|
rulers: Sides<GenAlign>,
|
||||||
|
/// The spacing state. This influences how new spacing is handled, e.g. hard
|
||||||
|
/// spacing may override soft spacing.
|
||||||
|
last_spacing: LastSpacing,
|
||||||
|
}
|
||||||
|
|
||||||
impl Space {
|
impl Space {
|
||||||
fn new(index: usize, hard: bool, usable: Size) -> Self {
|
fn new(index: usize, hard: bool, usable: Size) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -401,3 +403,26 @@ impl Space {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The spacing kind of the most recently inserted item in a layouting process.
|
||||||
|
///
|
||||||
|
/// Since the last inserted item may not be spacing at all, this can be `None`.
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
pub(crate) enum LastSpacing {
|
||||||
|
/// The last item was hard spacing.
|
||||||
|
Hard,
|
||||||
|
/// The last item was soft spacing with the given width and level.
|
||||||
|
Soft(f64, u32),
|
||||||
|
/// The last item wasn't spacing.
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LastSpacing {
|
||||||
|
/// The width of the soft space if this is a soft space or zero otherwise.
|
||||||
|
fn soft_or_zero(self) -> f64 {
|
||||||
|
match self {
|
||||||
|
LastSpacing::Soft(space, _) => space,
|
||||||
|
_ => 0.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -3,9 +3,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::eval::Eval;
|
use crate::eval::Eval;
|
||||||
use crate::shaping;
|
use crate::shaping;
|
||||||
use crate::syntax::{
|
use crate::syntax::*;
|
||||||
Deco, Expr, NodeHeading, NodeRaw, Span, SpanWith, Spanned, SynNode, SynTree,
|
|
||||||
};
|
|
||||||
use crate::DynFuture;
|
use crate::DynFuture;
|
||||||
|
|
||||||
/// Layout a syntax tree in a given context.
|
/// Layout a syntax tree in a given context.
|
||||||
|
29
src/lib.rs
29
src/lib.rs
@ -2,24 +2,25 @@
|
|||||||
//!
|
//!
|
||||||
//! # Steps
|
//! # Steps
|
||||||
//! - **Parsing:** The parsing step first transforms a plain string into an
|
//! - **Parsing:** The parsing step first transforms a plain string into an
|
||||||
//! [iterator of tokens][tokens]. Then, a [parser] constructs a syntax tree
|
//! [iterator of tokens][tokens]. This token stream is [parsed] into a [syntax
|
||||||
//! from the token stream. The structures describing the tree can be found in
|
//! tree]. The structures describing the tree can be found in the [ast]
|
||||||
//! the [syntax] module.
|
//! module.
|
||||||
//! - **Layouting:** The next step is to transform the syntax tree into a
|
//! - **Layouting:** The next step is to transform the syntax tree into a
|
||||||
//! portable representation of the typesetted document. Types for these can be
|
//! portable representation of the typesetted document. The final output
|
||||||
//! found in the [layout] module. A finished layout ready for exporting is a
|
//! consists of a vector of [`BoxLayouts`] (corresponding to pages), ready for
|
||||||
//! [`MultiLayout`] consisting of multiple boxes (or pages).
|
//! exporting.
|
||||||
//! - **Exporting:** The finished layout can then be exported into a supported
|
//! - **Exporting:** The finished layout can then be exported into a supported
|
||||||
//! format. Submodules for these formats are located in the [export] module.
|
//! format. Submodules for these formats are located in the [export] module.
|
||||||
//! Currently, the only supported output format is [_PDF_].
|
//! Currently, the only supported output format is [_PDF_].
|
||||||
//!
|
//!
|
||||||
//! [tokens]: parse/struct.Tokens.html
|
//! [tokens]: parsing/struct.Tokens.html
|
||||||
//! [parser]: parse/fn.parse.html
|
//! [parsed]: parsing/fn.parse.html
|
||||||
//! [syntax]: syntax/index.html
|
//! [syntax tree]: syntax/ast/type.SynTree.html
|
||||||
|
//! [ast]: syntax/ast/index.html
|
||||||
//! [layout]: layout/index.html
|
//! [layout]: layout/index.html
|
||||||
|
//! [`BoxLayouts`]: layout/struct.BoxLayout.html
|
||||||
//! [export]: export/index.html
|
//! [export]: export/index.html
|
||||||
//! [_PDF_]: export/pdf/index.html
|
//! [_PDF_]: export/pdf/index.html
|
||||||
//! [`MultiLayout`]: layout/type.MultiLayout.html
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod diag;
|
pub mod diag;
|
||||||
@ -56,7 +57,7 @@ pub async fn typeset(
|
|||||||
) -> Pass<Vec<BoxLayout>> {
|
) -> Pass<Vec<BoxLayout>> {
|
||||||
let parsed = parse::parse(src);
|
let parsed = parse::parse(src);
|
||||||
let layouted = layout::layout(&parsed.output, state, loader).await;
|
let layouted = layout::layout(&parsed.output, state, loader).await;
|
||||||
let feedback = Feedback::merge(parsed.feedback, layouted.feedback);
|
let feedback = Feedback::join(parsed.feedback, layouted.feedback);
|
||||||
Pass::new(layouted.output, feedback)
|
Pass::new(layouted.output, feedback)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,8 +109,8 @@ impl Feedback {
|
|||||||
Self { diags: vec![], decos: vec![] }
|
Self { diags: vec![], decos: vec![] }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Merged two feedbacks into one.
|
/// Merge two feedbacks into one.
|
||||||
pub fn merge(mut a: Self, b: Self) -> Self {
|
pub fn join(mut a: Self, b: Self) -> Self {
|
||||||
a.extend(b);
|
a.extend(b);
|
||||||
a
|
a
|
||||||
}
|
}
|
||||||
@ -120,7 +121,7 @@ impl Feedback {
|
|||||||
self.decos.extend(more.decos);
|
self.decos.extend(more.decos);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add more feedback whose spans are local and need to be offset by an
|
/// Add more feedback whose spans are local and need to be translated by an
|
||||||
/// `offset` to be correct in this feedback's context.
|
/// `offset` to be correct in this feedback's context.
|
||||||
pub fn extend_offset(&mut self, more: Self, offset: Pos) {
|
pub fn extend_offset(&mut self, more: Self, offset: Pos) {
|
||||||
self.diags.extend(more.diags.offset(offset));
|
self.diags.extend(more.diags.offset(offset));
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
/// `align`: Align content along the layouting axes.
|
/// `align`: Align content along the layouting axes.
|
||||||
///
|
///
|
||||||
@ -16,7 +16,6 @@ use super::*;
|
|||||||
/// There may not be two alignment specifications for the same axis.
|
/// There may not be two alignment specifications for the same axis.
|
||||||
pub async fn align(mut args: Args, ctx: &mut LayoutContext) -> Value {
|
pub async fn align(mut args: Args, ctx: &mut LayoutContext) -> Value {
|
||||||
let body = args.find::<SynTree>();
|
let body = args.find::<SynTree>();
|
||||||
|
|
||||||
let h = args.get::<_, Spanned<SpecAlign>>(ctx, "horizontal");
|
let h = args.get::<_, Spanned<SpecAlign>>(ctx, "horizontal");
|
||||||
let v = args.get::<_, Spanned<SpecAlign>>(ctx, "vertical");
|
let v = args.get::<_, Spanned<SpecAlign>>(ctx, "vertical");
|
||||||
let pos = args.find_all::<Spanned<SpecAlign>>();
|
let pos = args.find_all::<Spanned<SpecAlign>>();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use super::*;
|
|
||||||
use crate::geom::Linear;
|
use crate::geom::Linear;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
/// `box`: Layouts its contents into a box.
|
/// `box`: Layouts its contents into a box.
|
||||||
///
|
///
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use super::*;
|
|
||||||
use crate::color::RgbaColor;
|
use crate::color::RgbaColor;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
/// `rgb`: Create an RGB(A) color.
|
/// `rgb`: Create an RGB(A) color.
|
||||||
pub async fn rgb(mut args: Args, ctx: &mut LayoutContext) -> Value {
|
pub async fn rgb(mut args: Args, ctx: &mut LayoutContext) -> Value {
|
||||||
let r = args.get::<_, Spanned<i64>>(ctx, 0);
|
let r = args.need::<_, Spanned<i64>>(ctx, 0, "red value");
|
||||||
let g = args.get::<_, Spanned<i64>>(ctx, 1);
|
let g = args.need::<_, Spanned<i64>>(ctx, 1, "green value");
|
||||||
let b = args.get::<_, Spanned<i64>>(ctx, 2);
|
let b = args.need::<_, Spanned<i64>>(ctx, 2, "blue value");
|
||||||
let a = args.get::<_, Spanned<i64>>(ctx, 3);
|
let a = args.get::<_, Spanned<i64>>(ctx, 3);
|
||||||
args.done(ctx);
|
args.done(ctx);
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use fontdock::{FontStretch, FontStyle, FontWeight};
|
use fontdock::{FontStretch, FontStyle, FontWeight};
|
||||||
|
|
||||||
use super::*;
|
|
||||||
use crate::eval::StringLike;
|
use crate::eval::StringLike;
|
||||||
use crate::geom::Linear;
|
use crate::geom::Linear;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
/// `font`: Configure the font.
|
/// `font`: Configure the font.
|
||||||
///
|
///
|
||||||
|
@ -15,7 +15,6 @@ pub use page::*;
|
|||||||
pub use spacing::*;
|
pub use spacing::*;
|
||||||
|
|
||||||
use crate::eval::{Scope, ValueFunc};
|
use crate::eval::{Scope, ValueFunc};
|
||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
macro_rules! std {
|
macro_rules! std {
|
||||||
($($name:literal => $func:expr),* $(,)?) => {
|
($($name:literal => $func:expr),* $(,)?) => {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use super::*;
|
|
||||||
use crate::eval::Absolute;
|
use crate::eval::Absolute;
|
||||||
use crate::geom::{Linear, Sides};
|
use crate::geom::{Linear, Sides};
|
||||||
use crate::paper::{Paper, PaperClass};
|
use crate::paper::{Paper, PaperClass};
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
/// `page`: Configure pages.
|
/// `page`: Configure pages.
|
||||||
///
|
///
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use super::*;
|
|
||||||
use crate::geom::Linear;
|
use crate::geom::Linear;
|
||||||
use crate::layout::SpacingKind;
|
use crate::layout::SpacingKind;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
/// `h`: Add horizontal spacing.
|
/// `h`: Add horizontal spacing.
|
||||||
///
|
///
|
||||||
@ -19,7 +19,7 @@ pub async fn v(args: Args, ctx: &mut LayoutContext) -> Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn spacing(mut args: Args, ctx: &mut LayoutContext, axis: SpecAxis) -> Value {
|
fn spacing(mut args: Args, ctx: &mut LayoutContext, axis: SpecAxis) -> Value {
|
||||||
let spacing = args.get::<_, Linear>(ctx, 0);
|
let spacing = args.need::<_, Linear>(ctx, 0, "spacing");
|
||||||
args.done(ctx);
|
args.done(ctx);
|
||||||
|
|
||||||
Value::Commands(if let Some(spacing) = spacing {
|
Value::Commands(if let Some(spacing) = spacing {
|
||||||
|
@ -37,7 +37,7 @@ pub enum PaperClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PaperClass {
|
impl PaperClass {
|
||||||
/// The default margin ratios for this page class.
|
/// The default margins for this page class.
|
||||||
pub fn default_margins(self) -> Sides<Linear> {
|
pub fn default_margins(self) -> Sides<Linear> {
|
||||||
let f = Linear::rel;
|
let f = Linear::rel;
|
||||||
let s = |l, r, t, b| Sides::new(f(l), f(r), f(t), f(b));
|
let s = |l, r, t, b| Sides::new(f(l), f(r), f(t), f(b));
|
||||||
|
@ -89,6 +89,7 @@ macro_rules! Call {
|
|||||||
}};
|
}};
|
||||||
($($tts:tt)*) => { Expr::Call(Call![@$($tts)*]) };
|
($($tts:tt)*) => { Expr::Call(Call![@$($tts)*]) };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Unary(op: impl Into<Spanned<UnOp>>, expr: impl Into<Spanned<Expr>>) -> Expr {
|
fn Unary(op: impl Into<Spanned<UnOp>>, expr: impl Into<Spanned<Expr>>) -> Expr {
|
||||||
Expr::Unary(ExprUnary {
|
Expr::Unary(ExprUnary {
|
||||||
op: op.into(),
|
op: op.into(),
|
||||||
|
@ -21,6 +21,9 @@ pub struct ExprCall {
|
|||||||
/// The name of the function.
|
/// The name of the function.
|
||||||
pub name: Spanned<Ident>,
|
pub name: Spanned<Ident>,
|
||||||
/// The arguments to the function.
|
/// The arguments to the function.
|
||||||
|
///
|
||||||
|
/// In case of a bracketed invocation with a body, the body is _not_
|
||||||
|
/// included in the span for the sake of clearer error messages.
|
||||||
pub args: Spanned<LitDict>,
|
pub args: Spanned<LitDict>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,4 +8,4 @@ pub use expr::*;
|
|||||||
pub use lit::*;
|
pub use lit::*;
|
||||||
pub use tree::*;
|
pub use tree::*;
|
||||||
|
|
||||||
use super::*;
|
use super::{Ident, SpanVec, Spanned};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user