mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Scheduled maintenance 🔨
- New naming scheme - TextNode instead of NodeText - CallExpr instead of ExprCall - ... - Less glob imports - Removes Value::Args variant - Removes prelude - Renames Layouted to Fragment - Moves font into env - Moves shaping into layout - Moves frame into separate module
This commit is contained in:
parent
ca3df70e2a
commit
264a7dedd4
@ -1,11 +1,10 @@
|
|||||||
use criterion::{criterion_group, criterion_main, Criterion};
|
use criterion::{criterion_group, criterion_main, Criterion};
|
||||||
use fontdock::fs::FsIndex;
|
use fontdock::fs::FsIndex;
|
||||||
|
|
||||||
use typst::env::{Env, ResourceLoader};
|
use typst::env::{Env, FsIndexExt, ResourceLoader};
|
||||||
use typst::eval::eval;
|
use typst::eval::eval;
|
||||||
use typst::exec::{exec, State};
|
use typst::exec::{exec, State};
|
||||||
use typst::export::pdf;
|
use typst::export::pdf;
|
||||||
use typst::font::FsIndexExt;
|
|
||||||
use typst::layout::layout;
|
use typst::layout::layout;
|
||||||
use typst::library;
|
use typst::library;
|
||||||
use typst::parse::parse;
|
use typst::parse::parse;
|
||||||
|
79
src/env.rs
79
src/env.rs
@ -7,11 +7,13 @@ use std::fs;
|
|||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use fontdock::fs::FsSource;
|
use fontdock::{ContainsChar, FaceFromVec, FaceId, FontSource};
|
||||||
use image::io::Reader as ImageReader;
|
use image::io::Reader as ImageReader;
|
||||||
use image::{DynamicImage, GenericImageView, ImageFormat};
|
use image::{DynamicImage, GenericImageView, ImageFormat};
|
||||||
|
use ttf_parser::Face;
|
||||||
|
|
||||||
use crate::font::FontLoader;
|
#[cfg(feature = "fs")]
|
||||||
|
use fontdock::fs::{FsIndex, FsSource};
|
||||||
|
|
||||||
/// Encapsulates all environment dependencies (fonts, resources).
|
/// Encapsulates all environment dependencies (fonts, resources).
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -25,13 +27,84 @@ pub struct Env {
|
|||||||
impl Env {
|
impl Env {
|
||||||
/// Create an empty environment for testing purposes.
|
/// Create an empty environment for testing purposes.
|
||||||
pub fn blank() -> Self {
|
pub fn blank() -> Self {
|
||||||
|
struct BlankSource;
|
||||||
|
|
||||||
|
impl FontSource for BlankSource {
|
||||||
|
type Face = FaceBuf;
|
||||||
|
|
||||||
|
fn load(&self, _: FaceId) -> Option<Self::Face> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
fonts: FontLoader::new(Box::new(FsSource::new(vec![])), vec![]),
|
fonts: FontLoader::new(Box::new(BlankSource), vec![]),
|
||||||
resources: ResourceLoader::new(),
|
resources: ResourceLoader::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A font loader that is backed by a dynamic source.
|
||||||
|
pub type FontLoader = fontdock::FontLoader<Box<dyn FontSource<Face = FaceBuf>>>;
|
||||||
|
|
||||||
|
/// An owned font face.
|
||||||
|
pub struct FaceBuf {
|
||||||
|
data: Box<[u8]>,
|
||||||
|
face: Face<'static>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FaceBuf {
|
||||||
|
/// Get a reference to the underlying face.
|
||||||
|
pub fn get(&self) -> &Face<'_> {
|
||||||
|
// We can't implement Deref because that would leak the internal 'static
|
||||||
|
// lifetime.
|
||||||
|
&self.face
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The raw face data.
|
||||||
|
pub fn data(&self) -> &[u8] {
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FaceFromVec for FaceBuf {
|
||||||
|
fn from_vec(vec: Vec<u8>, i: u32) -> Option<Self> {
|
||||||
|
let data = vec.into_boxed_slice();
|
||||||
|
|
||||||
|
// SAFETY: The slices's location is stable in memory since we don't
|
||||||
|
// touch it and it can't be touched from outside this type.
|
||||||
|
let slice: &'static [u8] =
|
||||||
|
unsafe { std::slice::from_raw_parts(data.as_ptr(), data.len()) };
|
||||||
|
|
||||||
|
Some(Self {
|
||||||
|
data,
|
||||||
|
face: Face::from_slice(slice, i).ok()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ContainsChar for FaceBuf {
|
||||||
|
fn contains_char(&self, c: char) -> bool {
|
||||||
|
self.get().glyph_index(c).is_some()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Simplify font loader construction from an [`FsIndex`].
|
||||||
|
#[cfg(feature = "fs")]
|
||||||
|
pub trait FsIndexExt {
|
||||||
|
/// Create a font loader backed by a boxed [`FsSource`] which serves all
|
||||||
|
/// indexed font faces.
|
||||||
|
fn into_dynamic_loader(self) -> FontLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "fs")]
|
||||||
|
impl FsIndexExt for FsIndex {
|
||||||
|
fn into_dynamic_loader(self) -> FontLoader {
|
||||||
|
let (files, descriptors) = self.into_vecs();
|
||||||
|
FontLoader::new(Box::new(FsSource::new(files)), descriptors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Loads resource from the file system.
|
/// Loads resource from the file system.
|
||||||
pub struct ResourceLoader {
|
pub struct ResourceLoader {
|
||||||
paths: HashMap<PathBuf, ResourceId>,
|
paths: HashMap<PathBuf, ResourceId>,
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use super::*;
|
use super::{Scope, Scopes, Value};
|
||||||
use crate::syntax::visit::*;
|
use crate::syntax::visit::{visit_expr, Visit};
|
||||||
|
use crate::syntax::{Expr, Ident};
|
||||||
|
|
||||||
/// A visitor that captures variable slots.
|
/// A visitor that captures variable slots.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -13,9 +13,9 @@ pub use value::*;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use super::*;
|
|
||||||
use crate::color::Color;
|
use crate::color::Color;
|
||||||
use crate::diag::{Diag, DiagSet};
|
use crate::diag::{Diag, DiagSet, Pass};
|
||||||
|
use crate::env::Env;
|
||||||
use crate::geom::{Angle, Length, Relative};
|
use crate::geom::{Angle, Length, Relative};
|
||||||
use crate::syntax::visit::Visit;
|
use crate::syntax::visit::Visit;
|
||||||
use crate::syntax::*;
|
use crate::syntax::*;
|
||||||
@ -143,16 +143,16 @@ impl Eval for Lit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for ExprArray {
|
impl Eval for ArrayExpr {
|
||||||
type Output = ValueArray;
|
type Output = ArrayValue;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||||
self.items.iter().map(|expr| expr.eval(ctx)).collect()
|
self.items.iter().map(|expr| expr.eval(ctx)).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for ExprDict {
|
impl Eval for DictExpr {
|
||||||
type Output = ValueDict;
|
type Output = DictValue;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||||
self.items
|
self.items
|
||||||
@ -162,7 +162,7 @@ impl Eval for ExprDict {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for ExprTemplate {
|
impl Eval for TemplateExpr {
|
||||||
type Output = TemplateNode;
|
type Output = TemplateNode;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||||
@ -172,7 +172,7 @@ impl Eval for ExprTemplate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for ExprGroup {
|
impl Eval for GroupExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||||
@ -180,7 +180,7 @@ impl Eval for ExprGroup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for ExprBlock {
|
impl Eval for BlockExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||||
@ -201,7 +201,7 @@ impl Eval for ExprBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for ExprUnary {
|
impl Eval for UnaryExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||||
@ -230,7 +230,7 @@ impl Eval for ExprUnary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for ExprBinary {
|
impl Eval for BinaryExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||||
@ -256,7 +256,7 @@ impl Eval for ExprBinary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExprBinary {
|
impl BinaryExpr {
|
||||||
/// Apply a basic binary operation.
|
/// Apply a basic binary operation.
|
||||||
fn apply<F>(&self, ctx: &mut EvalContext, op: F) -> Value
|
fn apply<F>(&self, ctx: &mut EvalContext, op: F) -> Value
|
||||||
where
|
where
|
||||||
@ -335,7 +335,7 @@ impl ExprBinary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for ExprCall {
|
impl Eval for CallExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||||
@ -361,25 +361,25 @@ impl Eval for ExprCall {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for ExprArgs {
|
impl Eval for CallArgs {
|
||||||
type Output = ValueArgs;
|
type Output = FuncArgs;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||||
let items = self.items.iter().map(|arg| arg.eval(ctx)).collect();
|
let items = self.items.iter().map(|arg| arg.eval(ctx)).collect();
|
||||||
ValueArgs { span: self.span, items }
|
FuncArgs { span: self.span, items }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for ExprArg {
|
impl Eval for CallArg {
|
||||||
type Output = ValueArg;
|
type Output = FuncArg;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||||
match self {
|
match self {
|
||||||
Self::Pos(expr) => ValueArg {
|
Self::Pos(expr) => FuncArg {
|
||||||
name: None,
|
name: None,
|
||||||
value: Spanned::new(expr.eval(ctx), expr.span()),
|
value: Spanned::new(expr.eval(ctx), expr.span()),
|
||||||
},
|
},
|
||||||
Self::Named(Named { name, expr }) => ValueArg {
|
Self::Named(Named { name, expr }) => FuncArg {
|
||||||
name: Some(Spanned::new(name.string.clone(), name.span)),
|
name: Some(Spanned::new(name.string.clone(), name.span)),
|
||||||
value: Spanned::new(expr.eval(ctx), expr.span()),
|
value: Spanned::new(expr.eval(ctx), expr.span()),
|
||||||
},
|
},
|
||||||
@ -387,7 +387,7 @@ impl Eval for ExprArg {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for ExprClosure {
|
impl Eval for ClosureExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||||
@ -402,7 +402,7 @@ impl Eval for ExprClosure {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let name = self.name.as_ref().map(|id| id.to_string());
|
let name = self.name.as_ref().map(|id| id.to_string());
|
||||||
Value::Func(ValueFunc::new(name, move |ctx, args| {
|
Value::Func(FuncValue::new(name, move |ctx, args| {
|
||||||
// Don't leak the scopes from the call site. Instead, we use the
|
// Don't leak the scopes from the call site. Instead, we use the
|
||||||
// scope of captured variables we collected earlier.
|
// scope of captured variables we collected earlier.
|
||||||
let prev = std::mem::take(&mut ctx.scopes);
|
let prev = std::mem::take(&mut ctx.scopes);
|
||||||
@ -422,7 +422,7 @@ impl Eval for ExprClosure {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for ExprLet {
|
impl Eval for LetExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||||
@ -435,7 +435,7 @@ impl Eval for ExprLet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for ExprIf {
|
impl Eval for IfExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||||
@ -461,7 +461,7 @@ impl Eval for ExprIf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for ExprWhile {
|
impl Eval for WhileExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||||
@ -493,7 +493,7 @@ impl Eval for ExprWhile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for ExprFor {
|
impl Eval for ForExpr {
|
||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use super::*;
|
use super::{ArrayValue, DictValue, TemplateNode, Value};
|
||||||
|
use crate::syntax::Span;
|
||||||
use Value::*;
|
use Value::*;
|
||||||
|
|
||||||
/// Apply the plus operator to a value.
|
/// Apply the plus operator to a value.
|
||||||
@ -189,12 +190,12 @@ fn value_eq(lhs: &Value, rhs: &Value) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Compute whether two arrays are equal.
|
/// Compute whether two arrays are equal.
|
||||||
fn array_eq(a: &ValueArray, b: &ValueArray) -> bool {
|
fn array_eq(a: &ArrayValue, b: &ArrayValue) -> bool {
|
||||||
a.len() == b.len() && a.iter().zip(b).all(|(x, y)| value_eq(x, y))
|
a.len() == b.len() && a.iter().zip(b).all(|(x, y)| value_eq(x, y))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute whether two dictionaries are equal.
|
/// Compute whether two dictionaries are equal.
|
||||||
fn dict_eq(a: &ValueDict, b: &ValueDict) -> bool {
|
fn dict_eq(a: &DictValue, b: &DictValue) -> bool {
|
||||||
a.len() == b.len()
|
a.len() == b.len()
|
||||||
&& a.iter().all(|(k, x)| b.get(k).map_or(false, |y| value_eq(x, y)))
|
&& a.iter().all(|(k, x)| b.get(k).map_or(false, |y| value_eq(x, y)))
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,12 @@ use std::fmt::{self, Debug, Display, Formatter};
|
|||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use super::*;
|
use super::{EvalContext, ExprMap};
|
||||||
use crate::color::Color;
|
use crate::color::Color;
|
||||||
|
use crate::diag::DiagSet;
|
||||||
use crate::exec::ExecContext;
|
use crate::exec::ExecContext;
|
||||||
use crate::geom::{Angle, Length, Linear, Relative};
|
use crate::geom::{Angle, Length, Linear, Relative};
|
||||||
use crate::syntax::Tree;
|
use crate::syntax::{Span, Spanned, Tree};
|
||||||
|
|
||||||
/// A computational value.
|
/// A computational value.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
@ -34,17 +35,15 @@ pub enum Value {
|
|||||||
/// A string: `"string"`.
|
/// A string: `"string"`.
|
||||||
Str(String),
|
Str(String),
|
||||||
/// An array value: `(1, "hi", 12cm)`.
|
/// An array value: `(1, "hi", 12cm)`.
|
||||||
Array(ValueArray),
|
Array(ArrayValue),
|
||||||
/// A dictionary value: `(color: #f79143, pattern: dashed)`.
|
/// A dictionary value: `(color: #f79143, pattern: dashed)`.
|
||||||
Dict(ValueDict),
|
Dict(DictValue),
|
||||||
/// A template value: `[*Hi* there]`.
|
/// A template value: `[*Hi* there]`.
|
||||||
Template(ValueTemplate),
|
Template(TemplateValue),
|
||||||
/// An executable function.
|
/// An executable function.
|
||||||
Func(ValueFunc),
|
Func(FuncValue),
|
||||||
/// Arguments to a function.
|
|
||||||
Args(ValueArgs),
|
|
||||||
/// Any object.
|
/// Any object.
|
||||||
Any(ValueAny),
|
Any(AnyValue),
|
||||||
/// The result of invalid operations.
|
/// The result of invalid operations.
|
||||||
Error,
|
Error,
|
||||||
}
|
}
|
||||||
@ -71,11 +70,10 @@ impl Value {
|
|||||||
Self::Linear(_) => Linear::TYPE_NAME,
|
Self::Linear(_) => Linear::TYPE_NAME,
|
||||||
Self::Color(_) => Color::TYPE_NAME,
|
Self::Color(_) => Color::TYPE_NAME,
|
||||||
Self::Str(_) => String::TYPE_NAME,
|
Self::Str(_) => String::TYPE_NAME,
|
||||||
Self::Array(_) => ValueArray::TYPE_NAME,
|
Self::Array(_) => ArrayValue::TYPE_NAME,
|
||||||
Self::Dict(_) => ValueDict::TYPE_NAME,
|
Self::Dict(_) => DictValue::TYPE_NAME,
|
||||||
Self::Template(_) => ValueTemplate::TYPE_NAME,
|
Self::Template(_) => TemplateValue::TYPE_NAME,
|
||||||
Self::Func(_) => ValueFunc::TYPE_NAME,
|
Self::Func(_) => FuncValue::TYPE_NAME,
|
||||||
Self::Args(_) => ValueArgs::TYPE_NAME,
|
|
||||||
Self::Any(v) => v.type_name(),
|
Self::Any(v) => v.type_name(),
|
||||||
Self::Error => "error",
|
Self::Error => "error",
|
||||||
}
|
}
|
||||||
@ -97,13 +95,13 @@ impl Default for Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An array value: `(1, "hi", 12cm)`.
|
/// An array value: `(1, "hi", 12cm)`.
|
||||||
pub type ValueArray = Vec<Value>;
|
pub type ArrayValue = Vec<Value>;
|
||||||
|
|
||||||
/// A dictionary value: `(color: #f79143, pattern: dashed)`.
|
/// A dictionary value: `(color: #f79143, pattern: dashed)`.
|
||||||
pub type ValueDict = BTreeMap<String, Value>;
|
pub type DictValue = BTreeMap<String, Value>;
|
||||||
|
|
||||||
/// A template value: `[*Hi* there]`.
|
/// A template value: `[*Hi* there]`.
|
||||||
pub type ValueTemplate = Vec<TemplateNode>;
|
pub type TemplateValue = Vec<TemplateNode>;
|
||||||
|
|
||||||
/// One chunk of a template.
|
/// One chunk of a template.
|
||||||
///
|
///
|
||||||
@ -171,16 +169,16 @@ impl Debug for TemplateFunc {
|
|||||||
|
|
||||||
/// A wrapper around a reference-counted executable function.
|
/// A wrapper around a reference-counted executable function.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ValueFunc {
|
pub struct FuncValue {
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
f: Rc<dyn Fn(&mut EvalContext, &mut ValueArgs) -> Value>,
|
f: Rc<dyn Fn(&mut EvalContext, &mut FuncArgs) -> Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ValueFunc {
|
impl FuncValue {
|
||||||
/// Create a new function value from a rust function or closure.
|
/// Create a new function value from a rust function or closure.
|
||||||
pub fn new<F>(name: Option<String>, f: F) -> Self
|
pub fn new<F>(name: Option<String>, f: F) -> Self
|
||||||
where
|
where
|
||||||
F: Fn(&mut EvalContext, &mut ValueArgs) -> Value + 'static,
|
F: Fn(&mut EvalContext, &mut FuncArgs) -> Value + 'static,
|
||||||
{
|
{
|
||||||
Self { name, f: Rc::new(f) }
|
Self { name, f: Rc::new(f) }
|
||||||
}
|
}
|
||||||
@ -191,22 +189,22 @@ impl ValueFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for ValueFunc {
|
impl PartialEq for FuncValue {
|
||||||
fn eq(&self, _: &Self) -> bool {
|
fn eq(&self, _: &Self) -> bool {
|
||||||
// TODO: Figure out what we want here.
|
// TODO: Figure out what we want here.
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for ValueFunc {
|
impl Deref for FuncValue {
|
||||||
type Target = dyn Fn(&mut EvalContext, &mut ValueArgs) -> Value;
|
type Target = dyn Fn(&mut EvalContext, &mut FuncArgs) -> Value;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
self.f.as_ref()
|
self.f.as_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for ValueFunc {
|
impl Debug for FuncValue {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
f.debug_struct("ValueFunc").field("name", &self.name).finish()
|
f.debug_struct("ValueFunc").field("name", &self.name).finish()
|
||||||
}
|
}
|
||||||
@ -214,14 +212,14 @@ impl Debug for ValueFunc {
|
|||||||
|
|
||||||
/// Evaluated arguments to a function.
|
/// Evaluated arguments to a function.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ValueArgs {
|
pub struct FuncArgs {
|
||||||
/// The span of the whole argument list.
|
/// The span of the whole argument list.
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
/// The arguments.
|
/// The arguments.
|
||||||
pub items: Vec<ValueArg>,
|
pub items: Vec<FuncArg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ValueArgs {
|
impl FuncArgs {
|
||||||
/// Find and remove the first convertible positional argument.
|
/// Find and remove the first convertible positional argument.
|
||||||
pub fn find<T>(&mut self, ctx: &mut EvalContext) -> Option<T>
|
pub fn find<T>(&mut self, ctx: &mut EvalContext) -> Option<T>
|
||||||
where
|
where
|
||||||
@ -345,14 +343,14 @@ impl ValueArgs {
|
|||||||
|
|
||||||
/// An argument to a function call: `12` or `draw: false`.
|
/// An argument to a function call: `12` or `draw: false`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ValueArg {
|
pub struct FuncArg {
|
||||||
/// The name of the argument (`None` for positional arguments).
|
/// The name of the argument (`None` for positional arguments).
|
||||||
pub name: Option<Spanned<String>>,
|
pub name: Option<Spanned<String>>,
|
||||||
/// The value of the argument.
|
/// The value of the argument.
|
||||||
pub value: Spanned<Value>,
|
pub value: Spanned<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ValueArg {
|
impl FuncArg {
|
||||||
/// The source code location.
|
/// The source code location.
|
||||||
pub fn span(&self) -> Span {
|
pub fn span(&self) -> Span {
|
||||||
match &self.name {
|
match &self.name {
|
||||||
@ -363,9 +361,9 @@ impl ValueArg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A wrapper around a dynamic value.
|
/// A wrapper around a dynamic value.
|
||||||
pub struct ValueAny(Box<dyn Bounds>);
|
pub struct AnyValue(Box<dyn Bounds>);
|
||||||
|
|
||||||
impl ValueAny {
|
impl AnyValue {
|
||||||
/// Create a new instance from any value that satisifies the required bounds.
|
/// Create a new instance from any value that satisifies the required bounds.
|
||||||
pub fn new<T>(any: T) -> Self
|
pub fn new<T>(any: T) -> Self
|
||||||
where
|
where
|
||||||
@ -399,25 +397,25 @@ impl ValueAny {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for ValueAny {
|
impl Clone for AnyValue {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self(self.0.dyn_clone())
|
Self(self.0.dyn_clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for ValueAny {
|
impl PartialEq for AnyValue {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.0.dyn_eq(other)
|
self.0.dyn_eq(other)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for ValueAny {
|
impl Debug for AnyValue {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
f.debug_tuple("ValueAny").field(&self.0).finish()
|
f.debug_tuple("ValueAny").field(&self.0).finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for ValueAny {
|
impl Display for AnyValue {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
Display::fmt(&self.0, f)
|
Display::fmt(&self.0, f)
|
||||||
}
|
}
|
||||||
@ -426,7 +424,7 @@ impl Display for ValueAny {
|
|||||||
trait Bounds: Debug + Display + 'static {
|
trait Bounds: Debug + Display + 'static {
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
fn into_any(self: Box<Self>) -> Box<dyn Any>;
|
fn into_any(self: Box<Self>) -> Box<dyn Any>;
|
||||||
fn dyn_eq(&self, other: &ValueAny) -> bool;
|
fn dyn_eq(&self, other: &AnyValue) -> bool;
|
||||||
fn dyn_clone(&self) -> Box<dyn Bounds>;
|
fn dyn_clone(&self) -> Box<dyn Bounds>;
|
||||||
fn dyn_type_name(&self) -> &'static str;
|
fn dyn_type_name(&self) -> &'static str;
|
||||||
}
|
}
|
||||||
@ -443,7 +441,7 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dyn_eq(&self, other: &ValueAny) -> bool {
|
fn dyn_eq(&self, other: &AnyValue) -> bool {
|
||||||
if let Some(other) = other.downcast_ref::<Self>() {
|
if let Some(other) = other.downcast_ref::<Self>() {
|
||||||
self == other
|
self == other
|
||||||
} else {
|
} else {
|
||||||
@ -584,15 +582,14 @@ primitive! {
|
|||||||
}
|
}
|
||||||
primitive! { Color: "color", Value::Color }
|
primitive! { Color: "color", Value::Color }
|
||||||
primitive! { String: "string", Value::Str }
|
primitive! { String: "string", Value::Str }
|
||||||
primitive! { ValueArray: "array", Value::Array }
|
primitive! { ArrayValue: "array", Value::Array }
|
||||||
primitive! { ValueDict: "dictionary", Value::Dict }
|
primitive! { DictValue: "dictionary", Value::Dict }
|
||||||
primitive! {
|
primitive! {
|
||||||
ValueTemplate: "template",
|
TemplateValue: "template",
|
||||||
Value::Template,
|
Value::Template,
|
||||||
Value::Str(v) => vec![TemplateNode::Str(v)],
|
Value::Str(v) => vec![TemplateNode::Str(v)],
|
||||||
}
|
}
|
||||||
primitive! { ValueFunc: "function", Value::Func }
|
primitive! { FuncValue: "function", Value::Func }
|
||||||
primitive! { ValueArgs: "arguments", Value::Args }
|
|
||||||
|
|
||||||
impl From<usize> for Value {
|
impl From<usize> for Value {
|
||||||
fn from(v: usize) -> Self {
|
fn from(v: usize) -> Self {
|
||||||
@ -606,8 +603,8 @@ impl From<&str> for Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ValueAny> for Value {
|
impl From<AnyValue> for Value {
|
||||||
fn from(v: ValueAny) -> Self {
|
fn from(v: AnyValue) -> Self {
|
||||||
Self::Any(v)
|
Self::Any(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,16 @@ use std::rc::Rc;
|
|||||||
|
|
||||||
use fontdock::FontStyle;
|
use fontdock::FontStyle;
|
||||||
|
|
||||||
use super::*;
|
use super::{Exec, State};
|
||||||
use crate::diag::{Diag, DiagSet};
|
use crate::diag::{Diag, DiagSet, Pass};
|
||||||
|
use crate::env::Env;
|
||||||
|
use crate::eval::TemplateValue;
|
||||||
use crate::geom::{Dir, Gen, Linear, Sides, Size};
|
use crate::geom::{Dir, Gen, Linear, Sides, Size};
|
||||||
use crate::layout::{
|
use crate::layout::{
|
||||||
Node, NodePad, NodePages, NodePar, NodeSpacing, NodeStack, NodeText, Tree,
|
Node, PadNode, PageRun, ParNode, SpacingNode, StackNode, TextNode, Tree,
|
||||||
};
|
};
|
||||||
use crate::parse::is_newline;
|
use crate::parse::is_newline;
|
||||||
|
use crate::syntax::{Span, Spanned};
|
||||||
|
|
||||||
/// The context for execution.
|
/// The context for execution.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -26,9 +29,9 @@ pub struct ExecContext<'a> {
|
|||||||
page: Option<PageInfo>,
|
page: Option<PageInfo>,
|
||||||
/// The content of the active stack. This may be the top-level stack for the
|
/// The content of the active stack. This may be the top-level stack for the
|
||||||
/// page or a lower one created by [`exec`](Self::exec).
|
/// page or a lower one created by [`exec`](Self::exec).
|
||||||
stack: NodeStack,
|
stack: StackNode,
|
||||||
/// The content of the active paragraph.
|
/// The content of the active paragraph.
|
||||||
par: NodePar,
|
par: ParNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ExecContext<'a> {
|
impl<'a> ExecContext<'a> {
|
||||||
@ -39,8 +42,8 @@ impl<'a> ExecContext<'a> {
|
|||||||
diags: DiagSet::new(),
|
diags: DiagSet::new(),
|
||||||
tree: Tree { runs: vec![] },
|
tree: Tree { runs: vec![] },
|
||||||
page: Some(PageInfo::new(&state, true)),
|
page: Some(PageInfo::new(&state, true)),
|
||||||
stack: NodeStack::new(&state),
|
stack: StackNode::new(&state),
|
||||||
par: NodePar::new(&state),
|
par: ParNode::new(&state),
|
||||||
state,
|
state,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,7 +81,7 @@ impl<'a> ExecContext<'a> {
|
|||||||
/// Push a layout node into the active paragraph.
|
/// Push a layout node into the active paragraph.
|
||||||
///
|
///
|
||||||
/// Spacing nodes will be handled according to their
|
/// Spacing nodes will be handled according to their
|
||||||
/// [`softness`](NodeSpacing::softness).
|
/// [`softness`](SpacingNode::softness).
|
||||||
pub fn push(&mut self, node: impl Into<Node>) {
|
pub fn push(&mut self, node: impl Into<Node>) {
|
||||||
push(&mut self.par.children, node.into());
|
push(&mut self.par.children, node.into());
|
||||||
}
|
}
|
||||||
@ -86,7 +89,7 @@ impl<'a> ExecContext<'a> {
|
|||||||
/// Push a word space into the active paragraph.
|
/// Push a word space into the active paragraph.
|
||||||
pub fn push_space(&mut self) {
|
pub fn push_space(&mut self) {
|
||||||
let em = self.state.font.font_size();
|
let em = self.state.font.font_size();
|
||||||
self.push(NodeSpacing {
|
self.push(SpacingNode {
|
||||||
amount: self.state.par.word_spacing.resolve(em),
|
amount: self.state.par.word_spacing.resolve(em),
|
||||||
softness: 1,
|
softness: 1,
|
||||||
});
|
});
|
||||||
@ -111,7 +114,7 @@ impl<'a> ExecContext<'a> {
|
|||||||
/// Apply a forced line break.
|
/// Apply a forced line break.
|
||||||
pub fn push_linebreak(&mut self) {
|
pub fn push_linebreak(&mut self) {
|
||||||
let em = self.state.font.font_size();
|
let em = self.state.font.font_size();
|
||||||
self.push_into_stack(NodeSpacing {
|
self.push_into_stack(SpacingNode {
|
||||||
amount: self.state.par.leading.resolve(em),
|
amount: self.state.par.leading.resolve(em),
|
||||||
softness: 2,
|
softness: 2,
|
||||||
});
|
});
|
||||||
@ -120,7 +123,7 @@ impl<'a> ExecContext<'a> {
|
|||||||
/// Apply a forced paragraph break.
|
/// Apply a forced paragraph break.
|
||||||
pub fn push_parbreak(&mut self) {
|
pub fn push_parbreak(&mut self) {
|
||||||
let em = self.state.font.font_size();
|
let em = self.state.font.font_size();
|
||||||
self.push_into_stack(NodeSpacing {
|
self.push_into_stack(SpacingNode {
|
||||||
amount: self.state.par.spacing.resolve(em),
|
amount: self.state.par.spacing.resolve(em),
|
||||||
softness: 1,
|
softness: 1,
|
||||||
});
|
});
|
||||||
@ -134,10 +137,10 @@ impl<'a> ExecContext<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Execute a template and return the result as a stack node.
|
/// Execute a template and return the result as a stack node.
|
||||||
pub fn exec(&mut self, template: &ValueTemplate) -> NodeStack {
|
pub fn exec(&mut self, template: &TemplateValue) -> StackNode {
|
||||||
let page = self.page.take();
|
let page = self.page.take();
|
||||||
let stack = mem::replace(&mut self.stack, NodeStack::new(&self.state));
|
let stack = mem::replace(&mut self.stack, StackNode::new(&self.state));
|
||||||
let par = mem::replace(&mut self.par, NodePar::new(&self.state));
|
let par = mem::replace(&mut self.par, ParNode::new(&self.state));
|
||||||
|
|
||||||
template.exec(self);
|
template.exec(self);
|
||||||
let result = self.finish_stack();
|
let result = self.finish_stack();
|
||||||
@ -151,7 +154,7 @@ impl<'a> ExecContext<'a> {
|
|||||||
|
|
||||||
/// Construct a text node from the given string based on the active text
|
/// Construct a text node from the given string based on the active text
|
||||||
/// state.
|
/// state.
|
||||||
pub fn make_text_node(&self, text: String) -> NodeText {
|
pub fn make_text_node(&self, text: String) -> TextNode {
|
||||||
let mut variant = self.state.font.variant;
|
let mut variant = self.state.font.variant;
|
||||||
|
|
||||||
if self.state.font.strong {
|
if self.state.font.strong {
|
||||||
@ -166,7 +169,7 @@ impl<'a> ExecContext<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeText {
|
TextNode {
|
||||||
text,
|
text,
|
||||||
dir: self.state.dirs.cross,
|
dir: self.state.dirs.cross,
|
||||||
aligns: self.state.aligns,
|
aligns: self.state.aligns,
|
||||||
@ -180,7 +183,7 @@ impl<'a> ExecContext<'a> {
|
|||||||
|
|
||||||
/// Finish the active paragraph.
|
/// Finish the active paragraph.
|
||||||
fn finish_par(&mut self) {
|
fn finish_par(&mut self) {
|
||||||
let mut par = mem::replace(&mut self.par, NodePar::new(&self.state));
|
let mut par = mem::replace(&mut self.par, ParNode::new(&self.state));
|
||||||
trim(&mut par.children);
|
trim(&mut par.children);
|
||||||
|
|
||||||
if !par.children.is_empty() {
|
if !par.children.is_empty() {
|
||||||
@ -189,10 +192,10 @@ impl<'a> ExecContext<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Finish the active stack.
|
/// Finish the active stack.
|
||||||
fn finish_stack(&mut self) -> NodeStack {
|
fn finish_stack(&mut self) -> StackNode {
|
||||||
self.finish_par();
|
self.finish_par();
|
||||||
|
|
||||||
let mut stack = mem::replace(&mut self.stack, NodeStack::new(&self.state));
|
let mut stack = mem::replace(&mut self.stack, StackNode::new(&self.state));
|
||||||
trim(&mut stack.children);
|
trim(&mut stack.children);
|
||||||
|
|
||||||
stack
|
stack
|
||||||
@ -205,9 +208,9 @@ impl<'a> ExecContext<'a> {
|
|||||||
let stack = self.finish_stack();
|
let stack = self.finish_stack();
|
||||||
|
|
||||||
if !stack.children.is_empty() || (keep && info.hard) {
|
if !stack.children.is_empty() || (keep && info.hard) {
|
||||||
self.tree.runs.push(NodePages {
|
self.tree.runs.push(PageRun {
|
||||||
size: info.size,
|
size: info.size,
|
||||||
child: NodePad {
|
child: PadNode {
|
||||||
padding: info.padding,
|
padding: info.padding,
|
||||||
child: stack.into(),
|
child: stack.into(),
|
||||||
}
|
}
|
||||||
@ -274,7 +277,7 @@ impl PageInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodeStack {
|
impl StackNode {
|
||||||
fn new(state: &State) -> Self {
|
fn new(state: &State) -> Self {
|
||||||
Self {
|
Self {
|
||||||
dirs: state.dirs,
|
dirs: state.dirs,
|
||||||
@ -284,7 +287,7 @@ impl NodeStack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodePar {
|
impl ParNode {
|
||||||
fn new(state: &State) -> Self {
|
fn new(state: &State) -> Self {
|
||||||
let em = state.font.font_size();
|
let em = state.font.font_size();
|
||||||
Self {
|
Self {
|
||||||
|
@ -10,8 +10,8 @@ use std::rc::Rc;
|
|||||||
|
|
||||||
use crate::diag::Pass;
|
use crate::diag::Pass;
|
||||||
use crate::env::Env;
|
use crate::env::Env;
|
||||||
use crate::eval::{ExprMap, TemplateFunc, TemplateNode, Value, ValueTemplate};
|
use crate::eval::{ExprMap, TemplateFunc, TemplateNode, TemplateValue, Value};
|
||||||
use crate::layout::{self, NodeFixed, NodeSpacing, NodeStack};
|
use crate::layout::{self, FixedNode, SpacingNode, StackNode};
|
||||||
use crate::pretty::pretty;
|
use crate::pretty::pretty;
|
||||||
use crate::syntax::*;
|
use crate::syntax::*;
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ impl ExecWithMap for Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExecWithMap for NodeHeading {
|
impl ExecWithMap for HeadingNode {
|
||||||
fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap) {
|
fn exec_with_map(&self, ctx: &mut ExecContext, map: &ExprMap) {
|
||||||
let prev = ctx.state.clone();
|
let prev = ctx.state.clone();
|
||||||
let upscale = 1.5 - 0.1 * self.level as f64;
|
let upscale = 1.5 - 0.1 * self.level as f64;
|
||||||
@ -91,7 +91,7 @@ impl ExecWithMap for NodeHeading {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Exec for NodeRaw {
|
impl Exec for RawNode {
|
||||||
fn exec(&self, ctx: &mut ExecContext) {
|
fn exec(&self, ctx: &mut ExecContext) {
|
||||||
let prev = Rc::clone(&ctx.state.font.families);
|
let prev = Rc::clone(&ctx.state.font.families);
|
||||||
ctx.set_monospace();
|
ctx.set_monospace();
|
||||||
@ -103,7 +103,7 @@ impl Exec for NodeRaw {
|
|||||||
let mut newline = false;
|
let mut newline = false;
|
||||||
for line in &self.lines {
|
for line in &self.lines {
|
||||||
if newline {
|
if newline {
|
||||||
children.push(layout::Node::Spacing(NodeSpacing {
|
children.push(layout::Node::Spacing(SpacingNode {
|
||||||
amount: leading,
|
amount: leading,
|
||||||
softness: 2,
|
softness: 2,
|
||||||
}));
|
}));
|
||||||
@ -119,10 +119,10 @@ impl Exec for NodeRaw {
|
|||||||
|
|
||||||
// This is wrapped in a fixed node to make sure the stack fits to its
|
// This is wrapped in a fixed node to make sure the stack fits to its
|
||||||
// content instead of filling the available area.
|
// content instead of filling the available area.
|
||||||
ctx.push(NodeFixed {
|
ctx.push(FixedNode {
|
||||||
width: None,
|
width: None,
|
||||||
height: None,
|
height: None,
|
||||||
child: NodeStack {
|
child: StackNode {
|
||||||
dirs: ctx.state.dirs,
|
dirs: ctx.state.dirs,
|
||||||
aligns: ctx.state.aligns,
|
aligns: ctx.state.aligns,
|
||||||
children,
|
children,
|
||||||
@ -159,7 +159,7 @@ impl Exec for Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Exec for ValueTemplate {
|
impl Exec for TemplateValue {
|
||||||
fn exec(&self, ctx: &mut ExecContext) {
|
fn exec(&self, ctx: &mut ExecContext) {
|
||||||
for node in self {
|
for node in self {
|
||||||
node.exec(ctx);
|
node.exec(ctx);
|
||||||
|
@ -3,8 +3,8 @@ use std::rc::Rc;
|
|||||||
use fontdock::{fallback, FallbackTree, FontStretch, FontStyle, FontVariant, FontWeight};
|
use fontdock::{fallback, FallbackTree, FontStretch, FontStyle, FontVariant, FontWeight};
|
||||||
|
|
||||||
use crate::geom::*;
|
use crate::geom::*;
|
||||||
|
use crate::layout::VerticalFontMetric;
|
||||||
use crate::paper::{Paper, PaperClass, PAPER_A4};
|
use crate::paper::{Paper, PaperClass, PAPER_A4};
|
||||||
use crate::shaping::VerticalFontMetric;
|
|
||||||
|
|
||||||
/// The evaluation state.
|
/// The evaluation state.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
68
src/font.rs
68
src/font.rs
@ -1,68 +0,0 @@
|
|||||||
//! Font handling.
|
|
||||||
|
|
||||||
use fontdock::{ContainsChar, FaceFromVec, FontSource};
|
|
||||||
use ttf_parser::Face;
|
|
||||||
|
|
||||||
#[cfg(feature = "fs")]
|
|
||||||
use fontdock::fs::{FsIndex, FsSource};
|
|
||||||
|
|
||||||
/// A font loader that is backed by a dynamic source.
|
|
||||||
pub type FontLoader = fontdock::FontLoader<Box<dyn FontSource<Face = FaceBuf>>>;
|
|
||||||
|
|
||||||
/// An owned font face.
|
|
||||||
pub struct FaceBuf {
|
|
||||||
data: Box<[u8]>,
|
|
||||||
face: Face<'static>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FaceBuf {
|
|
||||||
/// Get a reference to the underlying face.
|
|
||||||
pub fn get(&self) -> &Face<'_> {
|
|
||||||
// We can't implement Deref because that would leak the internal 'static
|
|
||||||
// lifetime.
|
|
||||||
&self.face
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The raw face data.
|
|
||||||
pub fn data(&self) -> &[u8] {
|
|
||||||
&self.data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FaceFromVec for FaceBuf {
|
|
||||||
fn from_vec(vec: Vec<u8>, i: u32) -> Option<Self> {
|
|
||||||
let data = vec.into_boxed_slice();
|
|
||||||
|
|
||||||
// SAFETY: The slices's location is stable in memory since we don't
|
|
||||||
// touch it and it can't be touched from outside this type.
|
|
||||||
let slice: &'static [u8] =
|
|
||||||
unsafe { std::slice::from_raw_parts(data.as_ptr(), data.len()) };
|
|
||||||
|
|
||||||
Some(Self {
|
|
||||||
data,
|
|
||||||
face: Face::from_slice(slice, i).ok()?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ContainsChar for FaceBuf {
|
|
||||||
fn contains_char(&self, c: char) -> bool {
|
|
||||||
self.get().glyph_index(c).is_some()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Simplify font loader construction from an [`FsIndex`].
|
|
||||||
#[cfg(feature = "fs")]
|
|
||||||
pub trait FsIndexExt {
|
|
||||||
/// Create a font loader backed by a boxed [`FsSource`] which serves all
|
|
||||||
/// indexed font faces.
|
|
||||||
fn into_dynamic_loader(self) -> FontLoader;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "fs")]
|
|
||||||
impl FsIndexExt for FsIndex {
|
|
||||||
fn into_dynamic_loader(self) -> FontLoader {
|
|
||||||
let (files, descriptors) = self.into_vecs();
|
|
||||||
FontLoader::new(Box::new(FsSource::new(files)), descriptors)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,3 @@
|
|||||||
use std::f64::consts::PI;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// An angle.
|
/// An angle.
|
||||||
|
@ -26,6 +26,7 @@ pub use sides::*;
|
|||||||
pub use size::*;
|
pub use size::*;
|
||||||
pub use spec::*;
|
pub use spec::*;
|
||||||
|
|
||||||
|
use std::f64::consts::PI;
|
||||||
use std::fmt::{self, Debug, Display, Formatter};
|
use std::fmt::{self, Debug, Display, Formatter};
|
||||||
use std::iter::Sum;
|
use std::iter::Sum;
|
||||||
use std::ops::*;
|
use std::ops::*;
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A node that places a rectangular filled background behind another node.
|
/// A node that places a rectangular filled background behind its child.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct NodeBackground {
|
pub struct BackgroundNode {
|
||||||
/// The background fill.
|
/// The background fill.
|
||||||
pub fill: Fill,
|
pub fill: Fill,
|
||||||
/// The child node to be filled.
|
/// The child node to be filled.
|
||||||
pub child: Node,
|
pub child: Node,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Layout for NodeBackground {
|
impl Layout for BackgroundNode {
|
||||||
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Layouted {
|
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Fragment {
|
||||||
let mut layouted = self.child.layout(ctx, areas);
|
let mut layouted = self.child.layout(ctx, areas);
|
||||||
|
|
||||||
for frame in layouted.frames_mut() {
|
for frame in layouted.frames_mut() {
|
||||||
@ -25,8 +25,8 @@ impl Layout for NodeBackground {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<NodeBackground> for NodeAny {
|
impl From<BackgroundNode> for AnyNode {
|
||||||
fn from(background: NodeBackground) -> Self {
|
fn from(background: BackgroundNode) -> Self {
|
||||||
Self::new(background)
|
Self::new(background)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::geom::Linear;
|
|
||||||
|
|
||||||
/// A node that can fix its child's width and height.
|
/// A node that can fix its child's width and height.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct NodeFixed {
|
pub struct FixedNode {
|
||||||
/// The fixed width, if any.
|
/// The fixed width, if any.
|
||||||
pub width: Option<Linear>,
|
pub width: Option<Linear>,
|
||||||
/// The fixed height, if any.
|
/// The fixed height, if any.
|
||||||
@ -12,8 +11,8 @@ pub struct NodeFixed {
|
|||||||
pub child: Node,
|
pub child: Node,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Layout for NodeFixed {
|
impl Layout for FixedNode {
|
||||||
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Layouted {
|
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Fragment {
|
||||||
let Areas { current, full, .. } = areas;
|
let Areas { current, full, .. } = areas;
|
||||||
let size = Size::new(
|
let size = Size::new(
|
||||||
self.width.map(|w| w.resolve(full.width)).unwrap_or(current.width),
|
self.width.map(|w| w.resolve(full.width)).unwrap_or(current.width),
|
||||||
@ -31,8 +30,8 @@ impl Layout for NodeFixed {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<NodeFixed> for NodeAny {
|
impl From<FixedNode> for AnyNode {
|
||||||
fn from(fixed: NodeFixed) -> Self {
|
fn from(fixed: FixedNode) -> Self {
|
||||||
Self::new(fixed)
|
Self::new(fixed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
82
src/layout/frame.rs
Normal file
82
src/layout/frame.rs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
use super::Shaped;
|
||||||
|
use crate::color::Color;
|
||||||
|
use crate::env::ResourceId;
|
||||||
|
use crate::geom::{Point, Size};
|
||||||
|
|
||||||
|
/// A finished layout with elements at fixed positions.
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct Frame {
|
||||||
|
/// The size of the frame.
|
||||||
|
pub size: Size,
|
||||||
|
/// The elements composing this layout.
|
||||||
|
pub elements: Vec<(Point, Element)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frame {
|
||||||
|
/// Create a new, empty frame.
|
||||||
|
pub fn new(size: Size) -> Self {
|
||||||
|
Self { size, elements: vec![] }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add an element at a position.
|
||||||
|
pub fn push(&mut self, pos: Point, element: Element) {
|
||||||
|
self.elements.push((pos, element));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add all elements of another frame, placing them relative to the given
|
||||||
|
/// position.
|
||||||
|
pub fn push_frame(&mut self, pos: Point, subframe: Self) {
|
||||||
|
for (subpos, element) in subframe.elements {
|
||||||
|
self.push(pos + subpos, element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The building block frames are composed of.
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum Element {
|
||||||
|
/// Shaped text.
|
||||||
|
Text(Shaped),
|
||||||
|
/// A geometric shape.
|
||||||
|
Geometry(Geometry),
|
||||||
|
/// A raster image.
|
||||||
|
Image(Image),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A shape with some kind of fill.
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct Geometry {
|
||||||
|
/// The shape to draw.
|
||||||
|
pub shape: Shape,
|
||||||
|
/// How the shape looks on the inside.
|
||||||
|
//
|
||||||
|
// TODO: This could be made into a Vec<Fill> or something such that
|
||||||
|
// the user can compose multiple fills with alpha values less
|
||||||
|
// than one to achieve cool effects.
|
||||||
|
pub fill: Fill,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Some shape.
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum Shape {
|
||||||
|
/// A rectangle.
|
||||||
|
Rect(Size),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The kind of graphic fill to be applied to a [`Shape`].
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
pub enum Fill {
|
||||||
|
/// The fill is a color.
|
||||||
|
Color(Color),
|
||||||
|
/// The fill is an image.
|
||||||
|
Image(Image),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An image element.
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
pub struct Image {
|
||||||
|
/// The image resource.
|
||||||
|
pub res: ResourceId,
|
||||||
|
/// The size of the image in the document.
|
||||||
|
pub size: Size,
|
||||||
|
}
|
@ -2,27 +2,29 @@
|
|||||||
|
|
||||||
mod background;
|
mod background;
|
||||||
mod fixed;
|
mod fixed;
|
||||||
|
mod frame;
|
||||||
mod node;
|
mod node;
|
||||||
mod pad;
|
mod pad;
|
||||||
mod par;
|
mod par;
|
||||||
|
mod shaping;
|
||||||
mod spacing;
|
mod spacing;
|
||||||
mod stack;
|
mod stack;
|
||||||
mod text;
|
mod text;
|
||||||
|
|
||||||
use crate::color::Color;
|
|
||||||
use crate::env::{Env, ResourceId};
|
|
||||||
use crate::geom::*;
|
|
||||||
use crate::shaping::Shaped;
|
|
||||||
|
|
||||||
pub use background::*;
|
pub use background::*;
|
||||||
pub use fixed::*;
|
pub use fixed::*;
|
||||||
|
pub use frame::*;
|
||||||
pub use node::*;
|
pub use node::*;
|
||||||
pub use pad::*;
|
pub use pad::*;
|
||||||
pub use par::*;
|
pub use par::*;
|
||||||
|
pub use shaping::*;
|
||||||
pub use spacing::*;
|
pub use spacing::*;
|
||||||
pub use stack::*;
|
pub use stack::*;
|
||||||
pub use text::*;
|
pub use text::*;
|
||||||
|
|
||||||
|
use crate::env::Env;
|
||||||
|
use crate::geom::*;
|
||||||
|
|
||||||
/// Layout a tree into a collection of frames.
|
/// Layout a tree into a collection of frames.
|
||||||
pub fn layout(env: &mut Env, tree: &Tree) -> Vec<Frame> {
|
pub fn layout(env: &mut Env, tree: &Tree) -> Vec<Frame> {
|
||||||
tree.layout(&mut LayoutContext { env })
|
tree.layout(&mut LayoutContext { env })
|
||||||
@ -32,7 +34,7 @@ pub fn layout(env: &mut Env, tree: &Tree) -> Vec<Frame> {
|
|||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Tree {
|
pub struct Tree {
|
||||||
/// Runs of pages with the same properties.
|
/// Runs of pages with the same properties.
|
||||||
pub runs: Vec<NodePages>,
|
pub runs: Vec<PageRun>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tree {
|
impl Tree {
|
||||||
@ -44,15 +46,15 @@ impl Tree {
|
|||||||
|
|
||||||
/// A run of pages that all have the same properties.
|
/// A run of pages that all have the same properties.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct NodePages {
|
pub struct PageRun {
|
||||||
/// The size of each page.
|
/// The size of each page.
|
||||||
pub size: Size,
|
pub size: Size,
|
||||||
/// The layout node that produces the actual pages (typically a
|
/// The layout node that produces the actual pages (typically a
|
||||||
/// [`NodeStack`]).
|
/// [`StackNode`]).
|
||||||
pub child: Node,
|
pub child: Node,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodePages {
|
impl PageRun {
|
||||||
/// Layout the page run.
|
/// Layout the page run.
|
||||||
pub fn layout(&self, ctx: &mut LayoutContext) -> Vec<Frame> {
|
pub fn layout(&self, ctx: &mut LayoutContext) -> Vec<Frame> {
|
||||||
let areas = Areas::repeat(self.size, Spec::uniform(Expand::Fill));
|
let areas = Areas::repeat(self.size, Spec::uniform(Expand::Fill));
|
||||||
@ -64,7 +66,7 @@ impl NodePages {
|
|||||||
/// Layout a node.
|
/// Layout a node.
|
||||||
pub trait Layout {
|
pub trait Layout {
|
||||||
/// Layout the node into the given areas.
|
/// Layout the node into the given areas.
|
||||||
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Layouted;
|
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The context for layouting.
|
/// The context for layouting.
|
||||||
@ -74,7 +76,7 @@ pub struct LayoutContext<'a> {
|
|||||||
pub env: &'a mut Env,
|
pub env: &'a mut Env,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A collection of areas to layout into.
|
/// A sequence of areas to layout into.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Areas {
|
pub struct Areas {
|
||||||
/// The remaining size of the current area.
|
/// The remaining size of the current area.
|
||||||
@ -155,7 +157,7 @@ impl Expand {
|
|||||||
|
|
||||||
/// The result of layouting a node.
|
/// The result of layouting a node.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Layouted {
|
pub enum Fragment {
|
||||||
/// Spacing that should be added to the parent.
|
/// Spacing that should be added to the parent.
|
||||||
Spacing(Length),
|
Spacing(Length),
|
||||||
/// A layout that should be added to and aligned in the parent.
|
/// A layout that should be added to and aligned in the parent.
|
||||||
@ -164,7 +166,7 @@ pub enum Layouted {
|
|||||||
Frames(Vec<Frame>, LayoutAligns),
|
Frames(Vec<Frame>, LayoutAligns),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Layouted {
|
impl Fragment {
|
||||||
/// Return a reference to all frames contained in this variant (zero, one or
|
/// Return a reference to all frames contained in this variant (zero, one or
|
||||||
/// arbitrarily many).
|
/// arbitrarily many).
|
||||||
pub fn frames(&self) -> &[Frame] {
|
pub fn frames(&self) -> &[Frame] {
|
||||||
@ -193,81 +195,3 @@ impl Layouted {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A finished layout with elements at fixed positions.
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct Frame {
|
|
||||||
/// The size of the frame.
|
|
||||||
pub size: Size,
|
|
||||||
/// The elements composing this layout.
|
|
||||||
pub elements: Vec<(Point, Element)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Frame {
|
|
||||||
/// Create a new, empty frame.
|
|
||||||
pub fn new(size: Size) -> Self {
|
|
||||||
Self { size, elements: vec![] }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add an element at a position.
|
|
||||||
pub fn push(&mut self, pos: Point, element: Element) {
|
|
||||||
self.elements.push((pos, element));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add all elements of another frame, placing them relative to the given
|
|
||||||
/// position.
|
|
||||||
pub fn push_frame(&mut self, pos: Point, subframe: Self) {
|
|
||||||
for (subpos, element) in subframe.elements {
|
|
||||||
self.push(pos + subpos, element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The building block frames are composed of.
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub enum Element {
|
|
||||||
/// Shaped text.
|
|
||||||
Text(Shaped),
|
|
||||||
/// An image.
|
|
||||||
Image(Image),
|
|
||||||
/// Some shape that could hold another frame.
|
|
||||||
Geometry(Geometry),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A shape with some kind of fill.
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct Geometry {
|
|
||||||
/// The shape to draw.
|
|
||||||
pub shape: Shape,
|
|
||||||
/// How the shape looks on the inside.
|
|
||||||
//
|
|
||||||
// TODO: This could be made into a Vec<Fill> or something such that
|
|
||||||
// the user can compose multiple fills with alpha values less
|
|
||||||
// than one to achieve cool effects.
|
|
||||||
pub fill: Fill,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Some shape.
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub enum Shape {
|
|
||||||
/// A rectangle.
|
|
||||||
Rect(Size),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The kind of graphic fill to be applied to a [`Shape`].
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
|
||||||
pub enum Fill {
|
|
||||||
/// The fill is a color.
|
|
||||||
Color(Color),
|
|
||||||
/// The fill is an image.
|
|
||||||
Image(Image),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An image element.
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
|
||||||
pub struct Image {
|
|
||||||
/// The image resource.
|
|
||||||
pub res: ResourceId,
|
|
||||||
/// The size of the image in the document.
|
|
||||||
pub size: Size,
|
|
||||||
}
|
|
||||||
|
@ -7,15 +7,15 @@ use super::*;
|
|||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub enum Node {
|
pub enum Node {
|
||||||
/// A text node.
|
/// A text node.
|
||||||
Text(NodeText),
|
Text(TextNode),
|
||||||
/// A spacing node.
|
/// A spacing node.
|
||||||
Spacing(NodeSpacing),
|
Spacing(SpacingNode),
|
||||||
/// A dynamic node that can implement custom layouting behaviour.
|
/// A dynamic node that can implement custom layouting behaviour.
|
||||||
Any(NodeAny),
|
Any(AnyNode),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Layout for Node {
|
impl Layout for Node {
|
||||||
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Layouted {
|
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Fragment {
|
||||||
match self {
|
match self {
|
||||||
Self::Spacing(spacing) => spacing.layout(ctx, areas),
|
Self::Spacing(spacing) => spacing.layout(ctx, areas),
|
||||||
Self::Text(text) => text.layout(ctx, areas),
|
Self::Text(text) => text.layout(ctx, areas),
|
||||||
@ -35,9 +35,9 @@ impl Debug for Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A wrapper around a dynamic layouting node.
|
/// A wrapper around a dynamic layouting node.
|
||||||
pub struct NodeAny(Box<dyn Bounds>);
|
pub struct AnyNode(Box<dyn Bounds>);
|
||||||
|
|
||||||
impl NodeAny {
|
impl AnyNode {
|
||||||
/// Create a new instance from any node that satisifies the required bounds.
|
/// Create a new instance from any node that satisifies the required bounds.
|
||||||
pub fn new<T>(any: T) -> Self
|
pub fn new<T>(any: T) -> Self
|
||||||
where
|
where
|
||||||
@ -47,25 +47,25 @@ impl NodeAny {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Layout for NodeAny {
|
impl Layout for AnyNode {
|
||||||
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Layouted {
|
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Fragment {
|
||||||
self.0.layout(ctx, areas)
|
self.0.layout(ctx, areas)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for NodeAny {
|
impl Clone for AnyNode {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self(self.0.dyn_clone())
|
Self(self.0.dyn_clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for NodeAny {
|
impl PartialEq for AnyNode {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.0.dyn_eq(other.0.as_ref())
|
self.0.dyn_eq(other.0.as_ref())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for NodeAny {
|
impl Debug for AnyNode {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
self.0.fmt(f)
|
self.0.fmt(f)
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ impl Debug for NodeAny {
|
|||||||
|
|
||||||
impl<T> From<T> for Node
|
impl<T> From<T> for Node
|
||||||
where
|
where
|
||||||
T: Into<NodeAny>,
|
T: Into<AnyNode>,
|
||||||
{
|
{
|
||||||
fn from(t: T) -> Self {
|
fn from(t: T) -> Self {
|
||||||
Self::Any(t.into())
|
Self::Any(t.into())
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::geom::Linear;
|
|
||||||
|
|
||||||
/// A node that adds padding to its child.
|
/// A node that adds padding to its child.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct NodePad {
|
pub struct PadNode {
|
||||||
/// The amount of padding.
|
/// The amount of padding.
|
||||||
pub padding: Sides<Linear>,
|
pub padding: Sides<Linear>,
|
||||||
/// The child node whose sides to pad.
|
/// The child node whose sides to pad.
|
||||||
pub child: Node,
|
pub child: Node,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Layout for NodePad {
|
impl Layout for PadNode {
|
||||||
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Layouted {
|
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Fragment {
|
||||||
let areas = shrink(areas, self.padding);
|
let areas = shrink(areas, self.padding);
|
||||||
|
|
||||||
let mut layouted = self.child.layout(ctx, &areas);
|
let mut layouted = self.child.layout(ctx, &areas);
|
||||||
@ -23,8 +22,8 @@ impl Layout for NodePad {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<NodePad> for NodeAny {
|
impl From<PadNode> for AnyNode {
|
||||||
fn from(pad: NodePad) -> Self {
|
fn from(pad: PadNode) -> Self {
|
||||||
Self::new(pad)
|
Self::new(pad)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use super::*;
|
|||||||
|
|
||||||
/// A node that arranges its children into a paragraph.
|
/// A node that arranges its children into a paragraph.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct NodePar {
|
pub struct ParNode {
|
||||||
/// The `main` and `cross` directions of this paragraph.
|
/// The `main` and `cross` directions of this paragraph.
|
||||||
///
|
///
|
||||||
/// The children are placed in lines along the `cross` direction. The lines
|
/// The children are placed in lines along the `cross` direction. The lines
|
||||||
@ -16,28 +16,28 @@ pub struct NodePar {
|
|||||||
pub children: Vec<Node>,
|
pub children: Vec<Node>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Layout for NodePar {
|
impl Layout for ParNode {
|
||||||
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Layouted {
|
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Fragment {
|
||||||
let mut layouter = ParLayouter::new(self, areas.clone());
|
let mut layouter = ParLayouter::new(self, areas.clone());
|
||||||
for child in &self.children {
|
for child in &self.children {
|
||||||
match child.layout(ctx, &layouter.areas) {
|
match child.layout(ctx, &layouter.areas) {
|
||||||
Layouted::Spacing(spacing) => layouter.push_spacing(spacing),
|
Fragment::Spacing(spacing) => layouter.push_spacing(spacing),
|
||||||
Layouted::Frame(frame, aligns) => {
|
Fragment::Frame(frame, aligns) => {
|
||||||
layouter.push_frame(frame, aligns.cross)
|
layouter.push_frame(frame, aligns.cross)
|
||||||
}
|
}
|
||||||
Layouted::Frames(frames, aligns) => {
|
Fragment::Frames(frames, aligns) => {
|
||||||
for frame in frames {
|
for frame in frames {
|
||||||
layouter.push_frame(frame, aligns.cross);
|
layouter.push_frame(frame, aligns.cross);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Layouted::Frames(layouter.finish(), self.aligns)
|
Fragment::Frames(layouter.finish(), self.aligns)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<NodePar> for NodeAny {
|
impl From<ParNode> for AnyNode {
|
||||||
fn from(par: NodePar) -> Self {
|
fn from(par: ParNode) -> Self {
|
||||||
Self::new(par)
|
Self::new(par)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,7 +57,7 @@ struct ParLayouter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ParLayouter {
|
impl ParLayouter {
|
||||||
fn new(par: &NodePar, areas: Areas) -> Self {
|
fn new(par: &ParNode, areas: Areas) -> Self {
|
||||||
Self {
|
Self {
|
||||||
main: par.dirs.main.axis(),
|
main: par.dirs.main.axis(),
|
||||||
cross: par.dirs.cross.axis(),
|
cross: par.dirs.cross.axis(),
|
||||||
|
@ -9,7 +9,7 @@ use std::fmt::{self, Debug, Display, Formatter};
|
|||||||
use fontdock::{FaceId, FaceQuery, FallbackTree, FontVariant};
|
use fontdock::{FaceId, FaceQuery, FallbackTree, FontVariant};
|
||||||
use ttf_parser::{Face, GlyphId};
|
use ttf_parser::{Face, GlyphId};
|
||||||
|
|
||||||
use crate::font::FontLoader;
|
use crate::env::FontLoader;
|
||||||
use crate::geom::{Dir, Length, Point, Size};
|
use crate::geom::{Dir, Length, Point, Size};
|
||||||
use crate::layout::{Element, Frame};
|
use crate::layout::{Element, Frame};
|
||||||
|
|
@ -2,9 +2,9 @@ use std::fmt::{self, Debug, Formatter};
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A spacing node.
|
/// A node that adds spacing to its parent.
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub struct NodeSpacing {
|
pub struct SpacingNode {
|
||||||
/// The amount of spacing to insert.
|
/// The amount of spacing to insert.
|
||||||
pub amount: Length,
|
pub amount: Length,
|
||||||
/// Defines how spacing interacts with surrounding spacing.
|
/// Defines how spacing interacts with surrounding spacing.
|
||||||
@ -16,20 +16,20 @@ pub struct NodeSpacing {
|
|||||||
pub softness: u8,
|
pub softness: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Layout for NodeSpacing {
|
impl Layout for SpacingNode {
|
||||||
fn layout(&self, _: &mut LayoutContext, _: &Areas) -> Layouted {
|
fn layout(&self, _: &mut LayoutContext, _: &Areas) -> Fragment {
|
||||||
Layouted::Spacing(self.amount)
|
Fragment::Spacing(self.amount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for NodeSpacing {
|
impl Debug for SpacingNode {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
write!(f, "Spacing({}, {})", self.amount, self.softness)
|
write!(f, "Spacing({}, {})", self.amount, self.softness)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<NodeSpacing> for Node {
|
impl From<SpacingNode> for Node {
|
||||||
fn from(spacing: NodeSpacing) -> Self {
|
fn from(spacing: SpacingNode) -> Self {
|
||||||
Self::Spacing(spacing)
|
Self::Spacing(spacing)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use super::*;
|
|||||||
|
|
||||||
/// A node that stacks its children.
|
/// A node that stacks its children.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct NodeStack {
|
pub struct StackNode {
|
||||||
/// The `main` and `cross` directions of this stack.
|
/// The `main` and `cross` directions of this stack.
|
||||||
///
|
///
|
||||||
/// The children are stacked along the `main` direction. The `cross`
|
/// The children are stacked along the `main` direction. The `cross`
|
||||||
@ -14,26 +14,26 @@ pub struct NodeStack {
|
|||||||
pub children: Vec<Node>,
|
pub children: Vec<Node>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Layout for NodeStack {
|
impl Layout for StackNode {
|
||||||
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Layouted {
|
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Fragment {
|
||||||
let mut layouter = StackLayouter::new(self, areas.clone());
|
let mut layouter = StackLayouter::new(self, areas.clone());
|
||||||
for child in &self.children {
|
for child in &self.children {
|
||||||
match child.layout(ctx, &layouter.areas) {
|
match child.layout(ctx, &layouter.areas) {
|
||||||
Layouted::Spacing(spacing) => layouter.push_spacing(spacing),
|
Fragment::Spacing(spacing) => layouter.push_spacing(spacing),
|
||||||
Layouted::Frame(frame, aligns) => layouter.push_frame(frame, aligns),
|
Fragment::Frame(frame, aligns) => layouter.push_frame(frame, aligns),
|
||||||
Layouted::Frames(frames, aligns) => {
|
Fragment::Frames(frames, aligns) => {
|
||||||
for frame in frames {
|
for frame in frames {
|
||||||
layouter.push_frame(frame, aligns);
|
layouter.push_frame(frame, aligns);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Layouted::Frames(layouter.finish(), self.aligns)
|
Fragment::Frames(layouter.finish(), self.aligns)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<NodeStack> for NodeAny {
|
impl From<StackNode> for AnyNode {
|
||||||
fn from(stack: NodeStack) -> Self {
|
fn from(stack: StackNode) -> Self {
|
||||||
Self::new(stack)
|
Self::new(stack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,7 +49,7 @@ struct StackLayouter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StackLayouter {
|
impl StackLayouter {
|
||||||
fn new(stack: &NodeStack, areas: Areas) -> Self {
|
fn new(stack: &StackNode, areas: Areas) -> Self {
|
||||||
Self {
|
Self {
|
||||||
main: stack.dirs.main.axis(),
|
main: stack.dirs.main.axis(),
|
||||||
dirs: stack.dirs,
|
dirs: stack.dirs,
|
||||||
|
@ -4,11 +4,10 @@ use std::rc::Rc;
|
|||||||
use fontdock::{FallbackTree, FontVariant};
|
use fontdock::{FallbackTree, FontVariant};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::shaping::{shape, VerticalFontMetric};
|
|
||||||
|
|
||||||
/// A text node.
|
/// A consecutive, styled run of text.
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub struct NodeText {
|
pub struct TextNode {
|
||||||
/// The text.
|
/// The text.
|
||||||
pub text: String,
|
pub text: String,
|
||||||
/// The text direction.
|
/// The text direction.
|
||||||
@ -27,9 +26,9 @@ pub struct NodeText {
|
|||||||
pub bottom_edge: VerticalFontMetric,
|
pub bottom_edge: VerticalFontMetric,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Layout for NodeText {
|
impl Layout for TextNode {
|
||||||
fn layout(&self, ctx: &mut LayoutContext, _: &Areas) -> Layouted {
|
fn layout(&self, ctx: &mut LayoutContext, _: &Areas) -> Fragment {
|
||||||
Layouted::Frame(
|
Fragment::Frame(
|
||||||
shape(
|
shape(
|
||||||
&self.text,
|
&self.text,
|
||||||
self.dir,
|
self.dir,
|
||||||
@ -45,14 +44,14 @@ impl Layout for NodeText {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for NodeText {
|
impl Debug for TextNode {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
write!(f, "Text({})", self.text)
|
write!(f, "Text({})", self.text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<NodeText> for Node {
|
impl From<TextNode> for Node {
|
||||||
fn from(text: NodeText) -> Self {
|
fn from(text: TextNode) -> Self {
|
||||||
Self::Text(text)
|
Self::Text(text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
14
src/lib.rs
14
src/lib.rs
@ -9,12 +9,13 @@
|
|||||||
//! computes the value of each expression in document and stores them in a map
|
//! computes the value of each expression in document and stores them in a map
|
||||||
//! from expression-pointers to values.
|
//! from expression-pointers to values.
|
||||||
//! - **Execution:** Now, we can [execute] the parsed and evaluated "script".
|
//! - **Execution:** Now, we can [execute] the parsed and evaluated "script".
|
||||||
//! This produces a [layout tree], a high-level, fully styled representation.
|
//! This produces a [layout tree], a high-level, fully styled representation
|
||||||
//! The nodes of this tree are self-contained and order-independent and thus
|
//! of the document. The nodes of this tree are self-contained and
|
||||||
//! much better suited for layouting than the syntax tree.
|
//! order-independent and thus much better suited for layouting than the
|
||||||
|
//! syntax tree.
|
||||||
//! - **Layouting:** Next, the tree is [layouted] into a portable version of the
|
//! - **Layouting:** Next, the tree is [layouted] into a portable version of the
|
||||||
//! typeset document. The output of this is a vector of [`Frame`]s
|
//! typeset document. The output of this is a collection of [`Frame`]s (one
|
||||||
//! (corresponding to pages), ready for exporting.
|
//! per page), ready for exporting.
|
||||||
//! - **Exporting:** The finished layout can be exported into a supported
|
//! - **Exporting:** The finished layout can 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_].
|
||||||
@ -36,15 +37,12 @@ pub mod color;
|
|||||||
pub mod env;
|
pub mod env;
|
||||||
pub mod exec;
|
pub mod exec;
|
||||||
pub mod export;
|
pub mod export;
|
||||||
pub mod font;
|
|
||||||
pub mod geom;
|
pub mod geom;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
pub mod library;
|
pub mod library;
|
||||||
pub mod paper;
|
pub mod paper;
|
||||||
pub mod parse;
|
pub mod parse;
|
||||||
pub mod prelude;
|
|
||||||
pub mod pretty;
|
pub mod pretty;
|
||||||
pub mod shaping;
|
|
||||||
pub mod syntax;
|
pub mod syntax;
|
||||||
|
|
||||||
use crate::diag::Pass;
|
use crate::diag::Pass;
|
||||||
|
@ -26,12 +26,12 @@ use super::*;
|
|||||||
/// - `top`
|
/// - `top`
|
||||||
/// - `bottom`
|
/// - `bottom`
|
||||||
/// - `center`
|
/// - `center`
|
||||||
pub fn align(ctx: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
pub fn align(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||||
let first = args.find(ctx);
|
let first = args.find(ctx);
|
||||||
let second = args.find(ctx);
|
let second = args.find(ctx);
|
||||||
let hor = args.get(ctx, "horizontal");
|
let hor = args.get(ctx, "horizontal");
|
||||||
let ver = args.get(ctx, "vertical");
|
let ver = args.get(ctx, "vertical");
|
||||||
let body = args.find::<ValueTemplate>(ctx);
|
let body = args.find::<TemplateValue>(ctx);
|
||||||
|
|
||||||
Value::template("align", move |ctx| {
|
Value::template("align", move |ctx| {
|
||||||
let snapshot = ctx.state.clone();
|
let snapshot = ctx.state.clone();
|
||||||
|
@ -10,7 +10,7 @@ use super::*;
|
|||||||
///
|
///
|
||||||
/// # Return value
|
/// # Return value
|
||||||
/// The string representation of the value.
|
/// The string representation of the value.
|
||||||
pub fn repr(ctx: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
pub fn repr(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||||
match args.require::<Value>(ctx, "value") {
|
match args.require::<Value>(ctx, "value") {
|
||||||
Some(value) => pretty(&value).into(),
|
Some(value) => pretty(&value).into(),
|
||||||
None => Value::Error,
|
None => Value::Error,
|
||||||
@ -27,7 +27,7 @@ pub fn repr(ctx: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
|||||||
///
|
///
|
||||||
/// # Return value
|
/// # Return value
|
||||||
/// The color with the given components.
|
/// The color with the given components.
|
||||||
pub fn rgb(ctx: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
pub fn rgb(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||||
let r = args.require(ctx, "red component");
|
let r = args.require(ctx, "red component");
|
||||||
let g = args.require(ctx, "green component");
|
let g = args.require(ctx, "green component");
|
||||||
let b = args.require(ctx, "blue component");
|
let b = args.require(ctx, "blue component");
|
||||||
@ -57,7 +57,7 @@ pub fn rgb(ctx: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
|||||||
///
|
///
|
||||||
/// # Return value
|
/// # Return value
|
||||||
/// The name of the value's type as a string.
|
/// The name of the value's type as a string.
|
||||||
pub fn type_(ctx: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
pub fn type_(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||||
match args.require::<Value>(ctx, "value") {
|
match args.require::<Value>(ctx, "value") {
|
||||||
Some(value) => value.type_name().into(),
|
Some(value) => value.type_name().into(),
|
||||||
None => Value::Error,
|
None => Value::Error,
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use fontdock::{FontStretch, FontStyle, FontWeight};
|
use fontdock::{FontStretch, FontStyle, FontWeight};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::shaping::VerticalFontMetric;
|
|
||||||
|
|
||||||
/// `font`: Configure the font.
|
/// `font`: Configure the font.
|
||||||
///
|
///
|
||||||
@ -55,7 +54,7 @@ use crate::shaping::VerticalFontMetric;
|
|||||||
/// - `x-height`
|
/// - `x-height`
|
||||||
/// - `baseline`
|
/// - `baseline`
|
||||||
/// - `descender`
|
/// - `descender`
|
||||||
pub fn font(ctx: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
pub fn font(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||||
let size = args.find::<Linear>(ctx);
|
let size = args.find::<Linear>(ctx);
|
||||||
let list: Vec<_> = args.filter::<FontFamily>(ctx).map(|f| f.to_string()).collect();
|
let list: Vec<_> = args.filter::<FontFamily>(ctx).map(|f| f.to_string()).collect();
|
||||||
let style = args.get(ctx, "style");
|
let style = args.get(ctx, "style");
|
||||||
@ -66,7 +65,7 @@ pub fn font(ctx: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
|||||||
let serif = args.get(ctx, "serif");
|
let serif = args.get(ctx, "serif");
|
||||||
let sans_serif = args.get(ctx, "sans-serif");
|
let sans_serif = args.get(ctx, "sans-serif");
|
||||||
let monospace = args.get(ctx, "monospace");
|
let monospace = args.get(ctx, "monospace");
|
||||||
let body = args.find::<ValueTemplate>(ctx);
|
let body = args.find::<TemplateValue>(ctx);
|
||||||
|
|
||||||
Value::template("font", move |ctx| {
|
Value::template("font", move |ctx| {
|
||||||
let snapshot = ctx.state.clone();
|
let snapshot = ctx.state.clone();
|
||||||
|
@ -2,7 +2,9 @@ use ::image::GenericImageView;
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::env::{ImageResource, ResourceId};
|
use crate::env::{ImageResource, ResourceId};
|
||||||
use crate::layout::*;
|
use crate::layout::{
|
||||||
|
AnyNode, Areas, Element, Fragment, Frame, Image, Layout, LayoutContext,
|
||||||
|
};
|
||||||
|
|
||||||
/// `image`: Insert an image.
|
/// `image`: Insert an image.
|
||||||
///
|
///
|
||||||
@ -13,7 +15,7 @@ use crate::layout::*;
|
|||||||
///
|
///
|
||||||
/// # Return value
|
/// # Return value
|
||||||
/// A template that inserts an image.
|
/// A template that inserts an image.
|
||||||
pub fn image(ctx: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
pub fn image(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||||
let path = args.require::<Spanned<String>>(ctx, "path to image file");
|
let path = args.require::<Spanned<String>>(ctx, "path to image file");
|
||||||
let width = args.get(ctx, "width");
|
let width = args.get(ctx, "width");
|
||||||
let height = args.get(ctx, "height");
|
let height = args.get(ctx, "height");
|
||||||
@ -53,7 +55,7 @@ struct NodeImage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Layout for NodeImage {
|
impl Layout for NodeImage {
|
||||||
fn layout(&self, _: &mut LayoutContext, areas: &Areas) -> Layouted {
|
fn layout(&self, _: &mut LayoutContext, areas: &Areas) -> Fragment {
|
||||||
let Areas { current, full, .. } = areas;
|
let Areas { current, full, .. } = areas;
|
||||||
|
|
||||||
let pixel_width = self.dimensions.0 as f64;
|
let pixel_width = self.dimensions.0 as f64;
|
||||||
@ -84,11 +86,11 @@ impl Layout for NodeImage {
|
|||||||
let mut frame = Frame::new(size);
|
let mut frame = Frame::new(size);
|
||||||
frame.push(Point::ZERO, Element::Image(Image { res: self.res, size }));
|
frame.push(Point::ZERO, Element::Image(Image { res: self.res, size }));
|
||||||
|
|
||||||
Layouted::Frame(frame, self.aligns)
|
Fragment::Frame(frame, self.aligns)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<NodeImage> for NodeAny {
|
impl From<NodeImage> for AnyNode {
|
||||||
fn from(image: NodeImage) -> Self {
|
fn from(image: NodeImage) -> Self {
|
||||||
Self::new(image)
|
Self::new(image)
|
||||||
}
|
}
|
||||||
|
@ -27,68 +27,72 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
|
|
||||||
use fontdock::{FontStyle, FontWeight};
|
use fontdock::{FontStyle, FontWeight};
|
||||||
|
|
||||||
use crate::eval::{Scope, ValueAny, ValueFunc};
|
use crate::eval::{AnyValue, FuncValue, Scope};
|
||||||
use crate::layout::*;
|
use crate::eval::{EvalContext, FuncArgs, TemplateValue, Value};
|
||||||
use crate::prelude::*;
|
use crate::exec::{Exec, ExecContext};
|
||||||
use crate::shaping::VerticalFontMetric;
|
use crate::geom::*;
|
||||||
|
use crate::layout::VerticalFontMetric;
|
||||||
|
use crate::syntax::Spanned;
|
||||||
|
|
||||||
/// Construct a scope containing all standard library definitions.
|
/// Construct a scope containing all standard library definitions.
|
||||||
pub fn new() -> Scope {
|
pub fn new() -> Scope {
|
||||||
let mut std = Scope::new();
|
let mut std = Scope::new();
|
||||||
macro_rules! set {
|
|
||||||
(func: $name:expr, $func:expr) => {
|
macro_rules! func {
|
||||||
std.def_const($name, ValueFunc::new(Some($name.into()), $func))
|
($name:expr, $func:expr) => {
|
||||||
};
|
std.def_const($name, FuncValue::new(Some($name.into()), $func))
|
||||||
(any: $var:expr, $any:expr) => {
|
|
||||||
std.def_const($var, ValueAny::new($any))
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Functions.
|
macro_rules! constant {
|
||||||
set!(func: "align", align);
|
($var:expr, $any:expr) => {
|
||||||
set!(func: "font", font);
|
std.def_const($var, AnyValue::new($any))
|
||||||
set!(func: "h", h);
|
};
|
||||||
set!(func: "image", image);
|
}
|
||||||
set!(func: "pad", pad);
|
|
||||||
set!(func: "page", page);
|
|
||||||
set!(func: "pagebreak", pagebreak);
|
|
||||||
set!(func: "paragraph", paragraph);
|
|
||||||
set!(func: "rect", rect);
|
|
||||||
set!(func: "repr", repr);
|
|
||||||
set!(func: "rgb", rgb);
|
|
||||||
set!(func: "type", type_);
|
|
||||||
set!(func: "v", v);
|
|
||||||
|
|
||||||
// Constants.
|
func!("align", align);
|
||||||
set!(any: "left", AlignValue::Left);
|
func!("font", font);
|
||||||
set!(any: "center", AlignValue::Center);
|
func!("h", h);
|
||||||
set!(any: "right", AlignValue::Right);
|
func!("image", image);
|
||||||
set!(any: "top", AlignValue::Top);
|
func!("pad", pad);
|
||||||
set!(any: "bottom", AlignValue::Bottom);
|
func!("page", page);
|
||||||
set!(any: "ltr", Dir::LTR);
|
func!("pagebreak", pagebreak);
|
||||||
set!(any: "rtl", Dir::RTL);
|
func!("paragraph", par);
|
||||||
set!(any: "ttb", Dir::TTB);
|
func!("rect", rect);
|
||||||
set!(any: "btt", Dir::BTT);
|
func!("repr", repr);
|
||||||
set!(any: "serif", FontFamily::Serif);
|
func!("rgb", rgb);
|
||||||
set!(any: "sans-serif", FontFamily::SansSerif);
|
func!("type", type_);
|
||||||
set!(any: "monospace", FontFamily::Monospace);
|
func!("v", v);
|
||||||
set!(any: "normal", FontStyle::Normal);
|
|
||||||
set!(any: "italic", FontStyle::Italic);
|
constant!("left", AlignValue::Left);
|
||||||
set!(any: "oblique", FontStyle::Oblique);
|
constant!("center", AlignValue::Center);
|
||||||
set!(any: "thin", FontWeight::THIN);
|
constant!("right", AlignValue::Right);
|
||||||
set!(any: "extralight", FontWeight::EXTRALIGHT);
|
constant!("top", AlignValue::Top);
|
||||||
set!(any: "light", FontWeight::LIGHT);
|
constant!("bottom", AlignValue::Bottom);
|
||||||
set!(any: "regular", FontWeight::REGULAR);
|
constant!("ltr", Dir::LTR);
|
||||||
set!(any: "medium", FontWeight::MEDIUM);
|
constant!("rtl", Dir::RTL);
|
||||||
set!(any: "semibold", FontWeight::SEMIBOLD);
|
constant!("ttb", Dir::TTB);
|
||||||
set!(any: "bold", FontWeight::BOLD);
|
constant!("btt", Dir::BTT);
|
||||||
set!(any: "extrabold", FontWeight::EXTRABOLD);
|
constant!("serif", FontFamily::Serif);
|
||||||
set!(any: "black", FontWeight::BLACK);
|
constant!("sans-serif", FontFamily::SansSerif);
|
||||||
set!(any: "ascender", VerticalFontMetric::Ascender);
|
constant!("monospace", FontFamily::Monospace);
|
||||||
set!(any: "cap-height", VerticalFontMetric::CapHeight);
|
constant!("normal", FontStyle::Normal);
|
||||||
set!(any: "x-height", VerticalFontMetric::XHeight);
|
constant!("italic", FontStyle::Italic);
|
||||||
set!(any: "baseline", VerticalFontMetric::Baseline);
|
constant!("oblique", FontStyle::Oblique);
|
||||||
set!(any: "descender", VerticalFontMetric::Descender);
|
constant!("thin", FontWeight::THIN);
|
||||||
|
constant!("extralight", FontWeight::EXTRALIGHT);
|
||||||
|
constant!("light", FontWeight::LIGHT);
|
||||||
|
constant!("regular", FontWeight::REGULAR);
|
||||||
|
constant!("medium", FontWeight::MEDIUM);
|
||||||
|
constant!("semibold", FontWeight::SEMIBOLD);
|
||||||
|
constant!("bold", FontWeight::BOLD);
|
||||||
|
constant!("extrabold", FontWeight::EXTRABOLD);
|
||||||
|
constant!("black", FontWeight::BLACK);
|
||||||
|
constant!("ascender", VerticalFontMetric::Ascender);
|
||||||
|
constant!("cap-height", VerticalFontMetric::CapHeight);
|
||||||
|
constant!("x-height", VerticalFontMetric::XHeight);
|
||||||
|
constant!("baseline", VerticalFontMetric::Baseline);
|
||||||
|
constant!("descender", VerticalFontMetric::Descender);
|
||||||
|
|
||||||
std
|
std
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::layout::PadNode;
|
||||||
|
|
||||||
/// `pad`: Pad content at the sides.
|
/// `pad`: Pad content at the sides.
|
||||||
///
|
///
|
||||||
@ -14,13 +15,13 @@ use super::*;
|
|||||||
///
|
///
|
||||||
/// # Return value
|
/// # Return value
|
||||||
/// A template that pads the body at the sides.
|
/// A template that pads the body at the sides.
|
||||||
pub fn pad(ctx: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
pub fn pad(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||||
let all = args.find(ctx);
|
let all = args.find(ctx);
|
||||||
let left = args.get(ctx, "left");
|
let left = args.get(ctx, "left");
|
||||||
let top = args.get(ctx, "top");
|
let top = args.get(ctx, "top");
|
||||||
let right = args.get(ctx, "right");
|
let right = args.get(ctx, "right");
|
||||||
let bottom = args.get(ctx, "bottom");
|
let bottom = args.get(ctx, "bottom");
|
||||||
let body = args.require::<ValueTemplate>(ctx, "body").unwrap_or_default();
|
let body = args.require::<TemplateValue>(ctx, "body").unwrap_or_default();
|
||||||
|
|
||||||
let padding = Sides::new(
|
let padding = Sides::new(
|
||||||
left.or(all).unwrap_or_default(),
|
left.or(all).unwrap_or_default(),
|
||||||
@ -31,10 +32,8 @@ pub fn pad(ctx: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
|||||||
|
|
||||||
Value::template("pad", move |ctx| {
|
Value::template("pad", move |ctx| {
|
||||||
let snapshot = ctx.state.clone();
|
let snapshot = ctx.state.clone();
|
||||||
|
|
||||||
let child = ctx.exec(&body).into();
|
let child = ctx.exec(&body).into();
|
||||||
ctx.push(NodePad { padding, child });
|
ctx.push(PadNode { padding, child });
|
||||||
|
|
||||||
ctx.state = snapshot;
|
ctx.state = snapshot;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ use crate::paper::{Paper, PaperClass};
|
|||||||
/// - `rtl` (right to left)
|
/// - `rtl` (right to left)
|
||||||
/// - `ttb` (top to bottom)
|
/// - `ttb` (top to bottom)
|
||||||
/// - `btt` (bottom to top)
|
/// - `btt` (bottom to top)
|
||||||
pub fn page(ctx: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
pub fn page(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||||
let paper = args.find::<Spanned<String>>(ctx).and_then(|name| {
|
let paper = args.find::<Spanned<String>>(ctx).and_then(|name| {
|
||||||
Paper::from_name(&name.v).or_else(|| {
|
Paper::from_name(&name.v).or_else(|| {
|
||||||
ctx.diag(error!(name.span, "invalid paper name"));
|
ctx.diag(error!(name.span, "invalid paper name"));
|
||||||
@ -48,7 +48,7 @@ pub fn page(ctx: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
|||||||
let flip = args.get(ctx, "flip");
|
let flip = args.get(ctx, "flip");
|
||||||
let main = args.get(ctx, "main-dir");
|
let main = args.get(ctx, "main-dir");
|
||||||
let cross = args.get(ctx, "cross-dir");
|
let cross = args.get(ctx, "cross-dir");
|
||||||
let body = args.find::<ValueTemplate>(ctx);
|
let body = args.find::<TemplateValue>(ctx);
|
||||||
let span = args.span;
|
let span = args.span;
|
||||||
|
|
||||||
Value::template("page", move |ctx| {
|
Value::template("page", move |ctx| {
|
||||||
@ -110,7 +110,7 @@ pub fn page(ctx: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
|||||||
///
|
///
|
||||||
/// # Return value
|
/// # Return value
|
||||||
/// A template that starts a new page.
|
/// A template that starts a new page.
|
||||||
pub fn pagebreak(_: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
pub fn pagebreak(_: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||||
let span = args.span;
|
let span = args.span;
|
||||||
Value::template("pagebreak", move |ctx| {
|
Value::template("pagebreak", move |ctx| {
|
||||||
ctx.finish_page(true, true, span);
|
ctx.finish_page(true, true, span);
|
||||||
|
@ -2,6 +2,9 @@ use super::*;
|
|||||||
|
|
||||||
/// `paragraph`: Configure paragraphs.
|
/// `paragraph`: Configure paragraphs.
|
||||||
///
|
///
|
||||||
|
/// # Positional parameters
|
||||||
|
/// - Body: optional, of type `template`.
|
||||||
|
///
|
||||||
/// # Named parameters
|
/// # Named parameters
|
||||||
/// - Paragraph spacing: `spacing`, of type `linear` relative to current font size.
|
/// - Paragraph spacing: `spacing`, of type `linear` relative to current font size.
|
||||||
/// - Line leading: `leading`, of type `linear` relative to current font size.
|
/// - Line leading: `leading`, of type `linear` relative to current font size.
|
||||||
@ -10,11 +13,11 @@ use super::*;
|
|||||||
/// # Return value
|
/// # Return value
|
||||||
/// A template that configures paragraph properties. The effect is scoped to the
|
/// A template that configures paragraph properties. The effect is scoped to the
|
||||||
/// body if present.
|
/// body if present.
|
||||||
pub fn paragraph(ctx: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
pub fn par(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||||
let spacing = args.get(ctx, "spacing");
|
let spacing = args.get(ctx, "spacing");
|
||||||
let leading = args.get(ctx, "leading");
|
let leading = args.get(ctx, "leading");
|
||||||
let word_spacing = args.get(ctx, "word-spacing");
|
let word_spacing = args.get(ctx, "word-spacing");
|
||||||
let body = args.find::<ValueTemplate>(ctx);
|
let body = args.find::<TemplateValue>(ctx);
|
||||||
|
|
||||||
Value::template("paragraph", move |ctx| {
|
Value::template("paragraph", move |ctx| {
|
||||||
let snapshot = ctx.state.clone();
|
let snapshot = ctx.state.clone();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::layout::{BackgroundNode, Fill, FixedNode};
|
||||||
|
|
||||||
/// `rect`: Create a rectangular box.
|
/// `rect`: Create a rectangular box.
|
||||||
///
|
///
|
||||||
@ -21,13 +22,13 @@ use super::*;
|
|||||||
/// - `rtl` (right to left)
|
/// - `rtl` (right to left)
|
||||||
/// - `ttb` (top to bottom)
|
/// - `ttb` (top to bottom)
|
||||||
/// - `btt` (bottom to top)
|
/// - `btt` (bottom to top)
|
||||||
pub fn rect(ctx: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
pub fn rect(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||||
let width = args.get(ctx, "width");
|
let width = args.get(ctx, "width");
|
||||||
let height = args.get(ctx, "height");
|
let height = args.get(ctx, "height");
|
||||||
let main = args.get(ctx, "main-dir");
|
let main = args.get(ctx, "main-dir");
|
||||||
let cross = args.get(ctx, "cross-dir");
|
let cross = args.get(ctx, "cross-dir");
|
||||||
let fill = args.get(ctx, "fill");
|
let fill = args.get(ctx, "fill");
|
||||||
let body = args.find::<ValueTemplate>(ctx).unwrap_or_default();
|
let body = args.find::<TemplateValue>(ctx).unwrap_or_default();
|
||||||
|
|
||||||
Value::template("box", move |ctx| {
|
Value::template("box", move |ctx| {
|
||||||
let snapshot = ctx.state.clone();
|
let snapshot = ctx.state.clone();
|
||||||
@ -35,9 +36,9 @@ pub fn rect(ctx: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
|||||||
ctx.set_dirs(Gen::new(main, cross));
|
ctx.set_dirs(Gen::new(main, cross));
|
||||||
|
|
||||||
let child = ctx.exec(&body).into();
|
let child = ctx.exec(&body).into();
|
||||||
let fixed = NodeFixed { width, height, child };
|
let fixed = FixedNode { width, height, child };
|
||||||
if let Some(color) = fill {
|
if let Some(color) = fill {
|
||||||
ctx.push(NodeBackground {
|
ctx.push(BackgroundNode {
|
||||||
fill: Fill::Color(color),
|
fill: Fill::Color(color),
|
||||||
child: fixed.into(),
|
child: fixed.into(),
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::layout::SpacingNode;
|
||||||
|
|
||||||
/// `h`: Add horizontal spacing.
|
/// `h`: Add horizontal spacing.
|
||||||
///
|
///
|
||||||
@ -7,7 +8,7 @@ use super::*;
|
|||||||
///
|
///
|
||||||
/// # Return value
|
/// # Return value
|
||||||
/// A template that adds horizontal spacing.
|
/// A template that adds horizontal spacing.
|
||||||
pub fn h(ctx: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
pub fn h(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||||
spacing(ctx, args, SpecAxis::Horizontal)
|
spacing(ctx, args, SpecAxis::Horizontal)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,17 +19,17 @@ pub fn h(ctx: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
|||||||
///
|
///
|
||||||
/// # Return value
|
/// # Return value
|
||||||
/// A template that adds vertical spacing.
|
/// A template that adds vertical spacing.
|
||||||
pub fn v(ctx: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
pub fn v(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||||
spacing(ctx, args, SpecAxis::Vertical)
|
spacing(ctx, args, SpecAxis::Vertical)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply spacing along a specific axis.
|
/// Apply spacing along a specific axis.
|
||||||
fn spacing(ctx: &mut EvalContext, args: &mut ValueArgs, axis: SpecAxis) -> Value {
|
fn spacing(ctx: &mut EvalContext, args: &mut FuncArgs, axis: SpecAxis) -> Value {
|
||||||
let spacing: Option<Linear> = args.require(ctx, "spacing");
|
let spacing: Option<Linear> = args.require(ctx, "spacing");
|
||||||
Value::template("spacing", move |ctx| {
|
Value::template("spacing", move |ctx| {
|
||||||
if let Some(linear) = spacing {
|
if let Some(linear) = spacing {
|
||||||
let amount = linear.resolve(ctx.state.font.font_size());
|
let amount = linear.resolve(ctx.state.font.font_size());
|
||||||
let spacing = NodeSpacing { amount, softness: 0 };
|
let spacing = SpacingNode { amount, softness: 0 };
|
||||||
if axis == ctx.state.dirs.main.axis() {
|
if axis == ctx.state.dirs.main.axis() {
|
||||||
ctx.push_into_stack(spacing);
|
ctx.push_into_stack(spacing);
|
||||||
} else {
|
} else {
|
||||||
|
@ -5,10 +5,9 @@ use anyhow::{anyhow, bail, Context};
|
|||||||
use fontdock::fs::FsIndex;
|
use fontdock::fs::FsIndex;
|
||||||
|
|
||||||
use typst::diag::Pass;
|
use typst::diag::Pass;
|
||||||
use typst::env::{Env, ResourceLoader};
|
use typst::env::{Env, FsIndexExt, ResourceLoader};
|
||||||
use typst::exec::State;
|
use typst::exec::State;
|
||||||
use typst::export::pdf;
|
use typst::export::pdf;
|
||||||
use typst::font::FsIndexExt;
|
|
||||||
use typst::library;
|
use typst::library;
|
||||||
use typst::parse::LineMap;
|
use typst::parse::LineMap;
|
||||||
use typst::typeset;
|
use typst::typeset;
|
||||||
|
@ -136,11 +136,11 @@ fn heading(p: &mut Parser) -> Node {
|
|||||||
contents.extend(node(p, &mut false));
|
contents.extend(node(p, &mut false));
|
||||||
}
|
}
|
||||||
|
|
||||||
Node::Heading(NodeHeading { level, contents })
|
Node::Heading(HeadingNode { level, contents })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle a raw block.
|
/// Handle a raw block.
|
||||||
fn raw(p: &mut Parser, token: TokenRaw) -> Node {
|
fn raw(p: &mut Parser, token: RawToken) -> Node {
|
||||||
let raw = resolve::resolve_raw(token.text, token.backticks, p.start());
|
let raw = resolve::resolve_raw(token.text, token.backticks, p.start());
|
||||||
if !token.terminated {
|
if !token.terminated {
|
||||||
p.diag(error!(p.peek_span().end, "expected backtick(s)"));
|
p.diag(error!(p.peek_span().end, "expected backtick(s)"));
|
||||||
@ -149,7 +149,7 @@ fn raw(p: &mut Parser, token: TokenRaw) -> Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Handle a unicode escape sequence.
|
/// Handle a unicode escape sequence.
|
||||||
fn unicode_escape(p: &mut Parser, token: TokenUnicodeEscape) -> String {
|
fn unicode_escape(p: &mut Parser, token: UnicodeEscapeToken) -> String {
|
||||||
let span = p.peek_span();
|
let span = p.peek_span();
|
||||||
let text = if let Some(c) = resolve::resolve_hex(token.sequence) {
|
let text = if let Some(c) = resolve::resolve_hex(token.sequence) {
|
||||||
c.to_string()
|
c.to_string()
|
||||||
@ -184,7 +184,7 @@ fn expr_with(p: &mut Parser, atomic: bool, min_prec: usize) -> Option<Expr> {
|
|||||||
Some(op) => {
|
Some(op) => {
|
||||||
let prec = op.precedence();
|
let prec = op.precedence();
|
||||||
let expr = Box::new(expr_with(p, atomic, prec)?);
|
let expr = Box::new(expr_with(p, atomic, prec)?);
|
||||||
Expr::Unary(ExprUnary { span: p.span(start), op, expr })
|
Expr::Unary(UnaryExpr { span: p.span(start), op, expr })
|
||||||
}
|
}
|
||||||
None => primary(p, atomic)?,
|
None => primary(p, atomic)?,
|
||||||
};
|
};
|
||||||
@ -225,7 +225,7 @@ fn expr_with(p: &mut Parser, atomic: bool, min_prec: usize) -> Option<Expr> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let span = lhs.span().join(rhs.span());
|
let span = lhs.span().join(rhs.span());
|
||||||
lhs = Expr::Binary(ExprBinary { span, lhs: Box::new(lhs), op, rhs });
|
lhs = Expr::Binary(BinaryExpr { span, lhs: Box::new(lhs), op, rhs });
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(lhs)
|
Some(lhs)
|
||||||
@ -248,7 +248,7 @@ fn primary(p: &mut Parser, atomic: bool) -> Option<Expr> {
|
|||||||
// Arrow means this is a closure's lone parameter.
|
// Arrow means this is a closure's lone parameter.
|
||||||
Some(if !atomic && p.eat_if(Token::Arrow) {
|
Some(if !atomic && p.eat_if(Token::Arrow) {
|
||||||
let body = expr(p)?;
|
let body = expr(p)?;
|
||||||
Expr::Closure(ExprClosure {
|
Expr::Closure(ClosureExpr {
|
||||||
span: id.span.join(body.span()),
|
span: id.span.join(body.span()),
|
||||||
name: None,
|
name: None,
|
||||||
params: Rc::new(vec![id]),
|
params: Rc::new(vec![id]),
|
||||||
@ -306,7 +306,7 @@ fn literal(p: &mut Parser) -> Option<Expr> {
|
|||||||
/// - Dictionary literal
|
/// - Dictionary literal
|
||||||
/// - Parenthesized expression
|
/// - Parenthesized expression
|
||||||
/// - Parameter list of closure expression
|
/// - Parameter list of closure expression
|
||||||
pub fn parenthesized(p: &mut Parser) -> Option<Expr> {
|
fn parenthesized(p: &mut Parser) -> Option<Expr> {
|
||||||
p.start_group(Group::Paren, TokenMode::Code);
|
p.start_group(Group::Paren, TokenMode::Code);
|
||||||
let colon = p.eat_if(Token::Colon);
|
let colon = p.eat_if(Token::Colon);
|
||||||
let (items, has_comma) = collection(p);
|
let (items, has_comma) = collection(p);
|
||||||
@ -321,7 +321,7 @@ pub fn parenthesized(p: &mut Parser) -> Option<Expr> {
|
|||||||
if p.eat_if(Token::Arrow) {
|
if p.eat_if(Token::Arrow) {
|
||||||
let params = params(p, items);
|
let params = params(p, items);
|
||||||
let body = expr(p)?;
|
let body = expr(p)?;
|
||||||
return Some(Expr::Closure(ExprClosure {
|
return Some(Expr::Closure(ClosureExpr {
|
||||||
span: span.join(body.span()),
|
span: span.join(body.span()),
|
||||||
name: None,
|
name: None,
|
||||||
params: Rc::new(params),
|
params: Rc::new(params),
|
||||||
@ -332,21 +332,21 @@ pub fn parenthesized(p: &mut Parser) -> Option<Expr> {
|
|||||||
// Find out which kind of collection this is.
|
// Find out which kind of collection this is.
|
||||||
Some(match items.as_slice() {
|
Some(match items.as_slice() {
|
||||||
[] => array(p, items, span),
|
[] => array(p, items, span),
|
||||||
[ExprArg::Pos(_)] if !has_comma => match items.into_iter().next() {
|
[CallArg::Pos(_)] if !has_comma => match items.into_iter().next() {
|
||||||
Some(ExprArg::Pos(expr)) => {
|
Some(CallArg::Pos(expr)) => {
|
||||||
Expr::Group(ExprGroup { span, expr: Box::new(expr) })
|
Expr::Group(GroupExpr { span, expr: Box::new(expr) })
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
[ExprArg::Pos(_), ..] => array(p, items, span),
|
[CallArg::Pos(_), ..] => array(p, items, span),
|
||||||
[ExprArg::Named(_), ..] => dict(p, items, span),
|
[CallArg::Named(_), ..] => dict(p, items, span),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a collection.
|
/// Parse a collection.
|
||||||
///
|
///
|
||||||
/// Returns whether the literal contained any commas.
|
/// Returns whether the literal contained any commas.
|
||||||
fn collection(p: &mut Parser) -> (Vec<ExprArg>, bool) {
|
fn collection(p: &mut Parser) -> (Vec<CallArg>, bool) {
|
||||||
let mut items = vec![];
|
let mut items = vec![];
|
||||||
let mut has_comma = false;
|
let mut has_comma = false;
|
||||||
let mut missing_coma = None;
|
let mut missing_coma = None;
|
||||||
@ -376,52 +376,52 @@ fn collection(p: &mut Parser) -> (Vec<ExprArg>, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parse an expression or a named pair.
|
/// Parse an expression or a named pair.
|
||||||
fn item(p: &mut Parser) -> Option<ExprArg> {
|
fn item(p: &mut Parser) -> Option<CallArg> {
|
||||||
let first = expr(p)?;
|
let first = expr(p)?;
|
||||||
if p.eat_if(Token::Colon) {
|
if p.eat_if(Token::Colon) {
|
||||||
if let Expr::Ident(name) = first {
|
if let Expr::Ident(name) = first {
|
||||||
Some(ExprArg::Named(Named { name, expr: expr(p)? }))
|
Some(CallArg::Named(Named { name, expr: expr(p)? }))
|
||||||
} else {
|
} else {
|
||||||
p.diag(error!(first.span(), "expected identifier"));
|
p.diag(error!(first.span(), "expected identifier"));
|
||||||
expr(p);
|
expr(p);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Some(ExprArg::Pos(first))
|
Some(CallArg::Pos(first))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a collection into an array, producing errors for named items.
|
/// Convert a collection into an array, producing errors for named items.
|
||||||
fn array(p: &mut Parser, items: Vec<ExprArg>, span: Span) -> Expr {
|
fn array(p: &mut Parser, items: Vec<CallArg>, span: Span) -> Expr {
|
||||||
let items = items.into_iter().filter_map(|item| match item {
|
let items = items.into_iter().filter_map(|item| match item {
|
||||||
ExprArg::Pos(expr) => Some(expr),
|
CallArg::Pos(expr) => Some(expr),
|
||||||
ExprArg::Named(_) => {
|
CallArg::Named(_) => {
|
||||||
p.diag(error!(item.span(), "expected expression, found named pair"));
|
p.diag(error!(item.span(), "expected expression, found named pair"));
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Expr::Array(ExprArray { span, items: items.collect() })
|
Expr::Array(ArrayExpr { span, items: items.collect() })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a collection into a dictionary, producing errors for expressions.
|
/// Convert a collection into a dictionary, producing errors for expressions.
|
||||||
fn dict(p: &mut Parser, items: Vec<ExprArg>, span: Span) -> Expr {
|
fn dict(p: &mut Parser, items: Vec<CallArg>, span: Span) -> Expr {
|
||||||
let items = items.into_iter().filter_map(|item| match item {
|
let items = items.into_iter().filter_map(|item| match item {
|
||||||
ExprArg::Named(named) => Some(named),
|
CallArg::Named(named) => Some(named),
|
||||||
ExprArg::Pos(_) => {
|
CallArg::Pos(_) => {
|
||||||
p.diag(error!(item.span(), "expected named pair, found expression"));
|
p.diag(error!(item.span(), "expected named pair, found expression"));
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Expr::Dict(ExprDict { span, items: items.collect() })
|
Expr::Dict(DictExpr { span, items: items.collect() })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a collection into a parameter list, producing errors for anything
|
/// Convert a collection into a parameter list, producing errors for anything
|
||||||
/// other than identifiers.
|
/// other than identifiers.
|
||||||
fn params(p: &mut Parser, items: Vec<ExprArg>) -> Vec<Ident> {
|
fn params(p: &mut Parser, items: Vec<CallArg>) -> Vec<Ident> {
|
||||||
let items = items.into_iter().filter_map(|item| match item {
|
let items = items.into_iter().filter_map(|item| match item {
|
||||||
ExprArg::Pos(Expr::Ident(id)) => Some(id),
|
CallArg::Pos(Expr::Ident(id)) => Some(id),
|
||||||
_ => {
|
_ => {
|
||||||
p.diag(error!(item.span(), "expected identifier"));
|
p.diag(error!(item.span(), "expected identifier"));
|
||||||
None
|
None
|
||||||
@ -435,7 +435,7 @@ fn template(p: &mut Parser) -> Expr {
|
|||||||
p.start_group(Group::Bracket, TokenMode::Markup);
|
p.start_group(Group::Bracket, TokenMode::Markup);
|
||||||
let tree = Rc::new(tree(p));
|
let tree = Rc::new(tree(p));
|
||||||
let span = p.end_group();
|
let span = p.end_group();
|
||||||
Expr::Template(ExprTemplate { span, tree })
|
Expr::Template(TemplateExpr { span, tree })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a block expression: `{...}`.
|
/// Parse a block expression: `{...}`.
|
||||||
@ -454,7 +454,7 @@ fn block(p: &mut Parser, scoping: bool) -> Expr {
|
|||||||
p.skip_white();
|
p.skip_white();
|
||||||
}
|
}
|
||||||
let span = p.end_group();
|
let span = p.end_group();
|
||||||
Expr::Block(ExprBlock { span, exprs, scoping })
|
Expr::Block(BlockExpr { span, exprs, scoping })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a function call.
|
/// Parse a function call.
|
||||||
@ -466,7 +466,7 @@ fn call(p: &mut Parser, callee: Expr) -> Expr {
|
|||||||
p.end_group();
|
p.end_group();
|
||||||
args
|
args
|
||||||
}
|
}
|
||||||
_ => ExprArgs {
|
_ => CallArgs {
|
||||||
span: Span::at(callee.span().end),
|
span: Span::at(callee.span().end),
|
||||||
items: vec![],
|
items: vec![],
|
||||||
},
|
},
|
||||||
@ -474,10 +474,10 @@ fn call(p: &mut Parser, callee: Expr) -> Expr {
|
|||||||
|
|
||||||
if p.peek_direct() == Some(Token::LeftBracket) {
|
if p.peek_direct() == Some(Token::LeftBracket) {
|
||||||
let body = template(p);
|
let body = template(p);
|
||||||
args.items.push(ExprArg::Pos(body));
|
args.items.push(CallArg::Pos(body));
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::Call(ExprCall {
|
Expr::Call(CallExpr {
|
||||||
span: p.span(callee.span().start),
|
span: p.span(callee.span().start),
|
||||||
callee: Box::new(callee),
|
callee: Box::new(callee),
|
||||||
args,
|
args,
|
||||||
@ -485,10 +485,10 @@ fn call(p: &mut Parser, callee: Expr) -> Expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parse the arguments to a function call.
|
/// Parse the arguments to a function call.
|
||||||
fn args(p: &mut Parser) -> ExprArgs {
|
fn args(p: &mut Parser) -> CallArgs {
|
||||||
let start = p.start();
|
let start = p.start();
|
||||||
let items = collection(p).0;
|
let items = collection(p).0;
|
||||||
ExprArgs { span: p.span(start), items }
|
CallArgs { span: p.span(start), items }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a let expression.
|
/// Parse a let expression.
|
||||||
@ -518,7 +518,7 @@ fn expr_let(p: &mut Parser) -> Option<Expr> {
|
|||||||
// Rewrite into a closure expression if it's a function definition.
|
// Rewrite into a closure expression if it's a function definition.
|
||||||
if let Some(params) = parameters {
|
if let Some(params) = parameters {
|
||||||
let body = init?;
|
let body = init?;
|
||||||
init = Some(Expr::Closure(ExprClosure {
|
init = Some(Expr::Closure(ClosureExpr {
|
||||||
span: binding.span.join(body.span()),
|
span: binding.span.join(body.span()),
|
||||||
name: Some(binding.clone()),
|
name: Some(binding.clone()),
|
||||||
params: Rc::new(params),
|
params: Rc::new(params),
|
||||||
@ -526,7 +526,7 @@ fn expr_let(p: &mut Parser) -> Option<Expr> {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
expr_let = Some(Expr::Let(ExprLet {
|
expr_let = Some(Expr::Let(LetExpr {
|
||||||
span: p.span(start),
|
span: p.span(start),
|
||||||
binding,
|
binding,
|
||||||
init: init.map(Box::new),
|
init: init.map(Box::new),
|
||||||
@ -555,7 +555,7 @@ fn expr_if(p: &mut Parser) -> Option<Expr> {
|
|||||||
else_body = body(p);
|
else_body = body(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
expr_if = Some(Expr::If(ExprIf {
|
expr_if = Some(Expr::If(IfExpr {
|
||||||
span: p.span(start),
|
span: p.span(start),
|
||||||
condition: Box::new(condition),
|
condition: Box::new(condition),
|
||||||
if_body: Box::new(if_body),
|
if_body: Box::new(if_body),
|
||||||
@ -575,7 +575,7 @@ fn expr_while(p: &mut Parser) -> Option<Expr> {
|
|||||||
let mut expr_while = None;
|
let mut expr_while = None;
|
||||||
if let Some(condition) = expr(p) {
|
if let Some(condition) = expr(p) {
|
||||||
if let Some(body) = body(p) {
|
if let Some(body) = body(p) {
|
||||||
expr_while = Some(Expr::While(ExprWhile {
|
expr_while = Some(Expr::While(WhileExpr {
|
||||||
span: p.span(start),
|
span: p.span(start),
|
||||||
condition: Box::new(condition),
|
condition: Box::new(condition),
|
||||||
body: Box::new(body),
|
body: Box::new(body),
|
||||||
@ -596,7 +596,7 @@ fn expr_for(p: &mut Parser) -> Option<Expr> {
|
|||||||
if p.expect(Token::In) {
|
if p.expect(Token::In) {
|
||||||
if let Some(iter) = expr(p) {
|
if let Some(iter) = expr(p) {
|
||||||
if let Some(body) = body(p) {
|
if let Some(body) = body(p) {
|
||||||
expr_for = Some(Expr::For(ExprFor {
|
expr_for = Some(Expr::For(ForExpr {
|
||||||
span: p.span(start),
|
span: p.span(start),
|
||||||
pattern,
|
pattern,
|
||||||
iter: Box::new(iter),
|
iter: Box::new(iter),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use super::{is_newline, Scanner};
|
use super::{is_newline, Scanner};
|
||||||
use crate::syntax::{Ident, NodeRaw, Pos};
|
use crate::syntax::{Ident, Pos, RawNode};
|
||||||
|
|
||||||
/// Resolve all escape sequences in a string.
|
/// Resolve all escape sequences in a string.
|
||||||
pub fn resolve_string(string: &str) -> String {
|
pub fn resolve_string(string: &str) -> String {
|
||||||
@ -47,17 +47,17 @@ pub fn resolve_hex(sequence: &str) -> Option<char> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve the language tag and trims the raw text.
|
/// Resolve the language tag and trims the raw text.
|
||||||
pub fn resolve_raw(text: &str, backticks: usize, start: Pos) -> NodeRaw {
|
pub fn resolve_raw(text: &str, backticks: usize, start: Pos) -> RawNode {
|
||||||
if backticks > 1 {
|
if backticks > 1 {
|
||||||
let (tag, inner) = split_at_lang_tag(text);
|
let (tag, inner) = split_at_lang_tag(text);
|
||||||
let (lines, had_newline) = trim_and_split_raw(inner);
|
let (lines, had_newline) = trim_and_split_raw(inner);
|
||||||
NodeRaw {
|
RawNode {
|
||||||
lang: Ident::new(tag, start .. start + tag.len()),
|
lang: Ident::new(tag, start .. start + tag.len()),
|
||||||
lines,
|
lines,
|
||||||
block: had_newline,
|
block: had_newline,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
NodeRaw {
|
RawNode {
|
||||||
lang: None,
|
lang: None,
|
||||||
lines: split_lines(text),
|
lines: split_lines(text),
|
||||||
block: false,
|
block: false,
|
||||||
@ -105,7 +105,7 @@ fn trim_and_split_raw(mut raw: &str) -> (Vec<String>, bool) {
|
|||||||
|
|
||||||
/// Split a string into a vector of lines
|
/// Split a string into a vector of lines
|
||||||
/// (respecting Unicode, Unix, Mac and Windows line breaks).
|
/// (respecting Unicode, Unix, Mac and Windows line breaks).
|
||||||
pub fn split_lines(text: &str) -> Vec<String> {
|
fn split_lines(text: &str) -> Vec<String> {
|
||||||
let mut s = Scanner::new(text);
|
let mut s = Scanner::new(text);
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
let mut lines = Vec::new();
|
let mut lines = Vec::new();
|
||||||
@ -174,7 +174,7 @@ mod tests {
|
|||||||
lines: &[&str],
|
lines: &[&str],
|
||||||
block: bool,
|
block: bool,
|
||||||
) {
|
) {
|
||||||
Span::without_cmp(|| assert_eq!(resolve_raw(raw, backticks, Pos(0)), NodeRaw {
|
Span::without_cmp(|| assert_eq!(resolve_raw(raw, backticks, Pos(0)), RawNode {
|
||||||
lang: lang.and_then(|id| Ident::new(id, 0)),
|
lang: lang.and_then(|id| Ident::new(id, 0)),
|
||||||
lines: lines.iter().map(ToString::to_string).collect(),
|
lines: lines.iter().map(ToString::to_string).collect(),
|
||||||
block,
|
block,
|
||||||
|
@ -232,7 +232,7 @@ impl<'s> Tokens<'s> {
|
|||||||
|
|
||||||
// Special case for empty inline block.
|
// Special case for empty inline block.
|
||||||
if backticks == 2 {
|
if backticks == 2 {
|
||||||
return Token::Raw(TokenRaw { text: "", backticks: 1, terminated: true });
|
return Token::Raw(RawToken { text: "", backticks: 1, terminated: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
let start = self.s.index();
|
let start = self.s.index();
|
||||||
@ -249,7 +249,7 @@ impl<'s> Tokens<'s> {
|
|||||||
let terminated = found == backticks;
|
let terminated = found == backticks;
|
||||||
let end = self.s.index() - if terminated { found } else { 0 };
|
let end = self.s.index() - if terminated { found } else { 0 };
|
||||||
|
|
||||||
Token::Raw(TokenRaw {
|
Token::Raw(RawToken {
|
||||||
text: self.s.get(start .. end),
|
text: self.s.get(start .. end),
|
||||||
backticks,
|
backticks,
|
||||||
terminated,
|
terminated,
|
||||||
@ -286,7 +286,7 @@ impl<'s> Tokens<'s> {
|
|||||||
(true, true) => 2,
|
(true, true) => 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
Token::Math(TokenMath {
|
Token::Math(MathToken {
|
||||||
formula: self.s.get(start .. end),
|
formula: self.s.get(start .. end),
|
||||||
display,
|
display,
|
||||||
terminated,
|
terminated,
|
||||||
@ -309,7 +309,7 @@ impl<'s> Tokens<'s> {
|
|||||||
'u' if self.s.peek_nth(1) == Some('{') => {
|
'u' if self.s.peek_nth(1) == Some('{') => {
|
||||||
self.s.eat_assert('u');
|
self.s.eat_assert('u');
|
||||||
self.s.eat_assert('{');
|
self.s.eat_assert('{');
|
||||||
Token::UnicodeEscape(TokenUnicodeEscape {
|
Token::UnicodeEscape(UnicodeEscapeToken {
|
||||||
// Allow more than `ascii_hexdigit` for better error recovery.
|
// Allow more than `ascii_hexdigit` for better error recovery.
|
||||||
sequence: self.s.eat_while(|c| c.is_ascii_alphanumeric()),
|
sequence: self.s.eat_while(|c| c.is_ascii_alphanumeric()),
|
||||||
terminated: self.s.eat_if('}'),
|
terminated: self.s.eat_if('}'),
|
||||||
@ -391,7 +391,7 @@ impl<'s> Tokens<'s> {
|
|||||||
|
|
||||||
fn string(&mut self) -> Token<'s> {
|
fn string(&mut self) -> Token<'s> {
|
||||||
let mut escaped = false;
|
let mut escaped = false;
|
||||||
Token::Str(TokenStr {
|
Token::Str(StrToken {
|
||||||
string: self.s.eat_until(|c| {
|
string: self.s.eat_until(|c| {
|
||||||
if c == '"' && !escaped {
|
if c == '"' && !escaped {
|
||||||
true
|
true
|
||||||
@ -470,19 +470,19 @@ mod tests {
|
|||||||
use TokenMode::{Code, Markup};
|
use TokenMode::{Code, Markup};
|
||||||
|
|
||||||
const fn Raw(text: &str, backticks: usize, terminated: bool) -> Token {
|
const fn Raw(text: &str, backticks: usize, terminated: bool) -> Token {
|
||||||
Token::Raw(TokenRaw { text, backticks, terminated })
|
Token::Raw(RawToken { text, backticks, terminated })
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn Math(formula: &str, display: bool, terminated: bool) -> Token {
|
const fn Math(formula: &str, display: bool, terminated: bool) -> Token {
|
||||||
Token::Math(TokenMath { formula, display, terminated })
|
Token::Math(MathToken { formula, display, terminated })
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn UnicodeEscape(sequence: &str, terminated: bool) -> Token {
|
const fn UnicodeEscape(sequence: &str, terminated: bool) -> Token {
|
||||||
Token::UnicodeEscape(TokenUnicodeEscape { sequence, terminated })
|
Token::UnicodeEscape(UnicodeEscapeToken { sequence, terminated })
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn Str(string: &str, terminated: bool) -> Token {
|
const fn Str(string: &str, terminated: bool) -> Token {
|
||||||
Token::Str(TokenStr { string, terminated })
|
Token::Str(StrToken { string, terminated })
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn Color(r: u8, g: u8, b: u8, a: u8) -> Token<'static> {
|
const fn Color(r: u8, g: u8, b: u8, a: u8) -> Token<'static> {
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
//! A prelude for building custom functions.
|
|
||||||
|
|
||||||
pub use crate::diag::{Diag, Pass};
|
|
||||||
#[doc(no_inline)]
|
|
||||||
pub use crate::eval::{
|
|
||||||
CastResult, Eval, EvalContext, TemplateFunc, TemplateNode, Value, ValueAny,
|
|
||||||
ValueArgs, ValueArray, ValueDict, ValueTemplate,
|
|
||||||
};
|
|
||||||
#[doc(no_inline)]
|
|
||||||
pub use crate::exec::{Exec, ExecContext};
|
|
||||||
pub use crate::geom::*;
|
|
||||||
#[doc(no_inline)]
|
|
||||||
pub use crate::layout::Node;
|
|
||||||
#[doc(no_inline)]
|
|
||||||
pub use crate::syntax::{Span, Spanned};
|
|
||||||
pub use crate::{error, typify, warning};
|
|
100
src/pretty.rs
100
src/pretty.rs
@ -138,7 +138,7 @@ impl PrettyWithMap for Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrettyWithMap for NodeHeading {
|
impl PrettyWithMap for HeadingNode {
|
||||||
fn pretty_with_map(&self, p: &mut Printer, map: Option<&ExprMap>) {
|
fn pretty_with_map(&self, p: &mut Printer, map: Option<&ExprMap>) {
|
||||||
for _ in 0 ..= self.level {
|
for _ in 0 ..= self.level {
|
||||||
p.push('=');
|
p.push('=');
|
||||||
@ -147,7 +147,7 @@ impl PrettyWithMap for NodeHeading {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for NodeRaw {
|
impl Pretty for RawNode {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
// Find out how many backticks we need.
|
// Find out how many backticks we need.
|
||||||
let mut backticks = 1;
|
let mut backticks = 1;
|
||||||
@ -250,7 +250,7 @@ impl Pretty for LitKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for ExprArray {
|
impl Pretty for ArrayExpr {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
p.push('(');
|
p.push('(');
|
||||||
p.join(&self.items, ", ", |item, p| item.pretty(p));
|
p.join(&self.items, ", ", |item, p| item.pretty(p));
|
||||||
@ -261,7 +261,7 @@ impl Pretty for ExprArray {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for ExprDict {
|
impl Pretty for DictExpr {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
p.push('(');
|
p.push('(');
|
||||||
if self.items.is_empty() {
|
if self.items.is_empty() {
|
||||||
@ -281,7 +281,7 @@ impl Pretty for Named {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for ExprTemplate {
|
impl Pretty for TemplateExpr {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
p.push('[');
|
p.push('[');
|
||||||
self.tree.pretty_with_map(p, None);
|
self.tree.pretty_with_map(p, None);
|
||||||
@ -289,7 +289,7 @@ impl Pretty for ExprTemplate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for ExprGroup {
|
impl Pretty for GroupExpr {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
p.push('(');
|
p.push('(');
|
||||||
self.expr.pretty(p);
|
self.expr.pretty(p);
|
||||||
@ -297,7 +297,7 @@ impl Pretty for ExprGroup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for ExprBlock {
|
impl Pretty for BlockExpr {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
p.push('{');
|
p.push('{');
|
||||||
if self.exprs.len() > 1 {
|
if self.exprs.len() > 1 {
|
||||||
@ -311,7 +311,7 @@ impl Pretty for ExprBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for ExprUnary {
|
impl Pretty for UnaryExpr {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
self.op.pretty(p);
|
self.op.pretty(p);
|
||||||
if self.op == UnOp::Not {
|
if self.op == UnOp::Not {
|
||||||
@ -327,7 +327,7 @@ impl Pretty for UnOp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for ExprBinary {
|
impl Pretty for BinaryExpr {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
self.lhs.pretty(p);
|
self.lhs.pretty(p);
|
||||||
p.push(' ');
|
p.push(' ');
|
||||||
@ -343,11 +343,11 @@ impl Pretty for BinOp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for ExprCall {
|
impl Pretty for CallExpr {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
self.callee.pretty(p);
|
self.callee.pretty(p);
|
||||||
|
|
||||||
let mut write_args = |items: &[ExprArg]| {
|
let mut write_args = |items: &[CallArg]| {
|
||||||
p.push('(');
|
p.push('(');
|
||||||
p.join(items, ", ", |item, p| item.pretty(p));
|
p.join(items, ", ", |item, p| item.pretty(p));
|
||||||
p.push(')');
|
p.push(')');
|
||||||
@ -357,7 +357,7 @@ impl Pretty for ExprCall {
|
|||||||
// This can be moved behind the arguments.
|
// This can be moved behind the arguments.
|
||||||
//
|
//
|
||||||
// Example: Transforms "#v(a, [b])" => "#v(a)[b]".
|
// Example: Transforms "#v(a, [b])" => "#v(a)[b]".
|
||||||
[head @ .., ExprArg::Pos(Expr::Template(template))] => {
|
[head @ .., CallArg::Pos(Expr::Template(template))] => {
|
||||||
if !head.is_empty() {
|
if !head.is_empty() {
|
||||||
write_args(head);
|
write_args(head);
|
||||||
}
|
}
|
||||||
@ -369,13 +369,13 @@ impl Pretty for ExprCall {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for ExprArgs {
|
impl Pretty for CallArgs {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
p.join(&self.items, ", ", |item, p| item.pretty(p));
|
p.join(&self.items, ", ", |item, p| item.pretty(p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for ExprArg {
|
impl Pretty for CallArg {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
match self {
|
match self {
|
||||||
Self::Pos(expr) => expr.pretty(p),
|
Self::Pos(expr) => expr.pretty(p),
|
||||||
@ -384,7 +384,7 @@ impl Pretty for ExprArg {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for ExprClosure {
|
impl Pretty for ClosureExpr {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
p.push('(');
|
p.push('(');
|
||||||
p.join(self.params.iter(), ", ", |item, p| item.pretty(p));
|
p.join(self.params.iter(), ", ", |item, p| item.pretty(p));
|
||||||
@ -393,7 +393,7 @@ impl Pretty for ExprClosure {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for ExprLet {
|
impl Pretty for LetExpr {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
p.push_str("let ");
|
p.push_str("let ");
|
||||||
self.binding.pretty(p);
|
self.binding.pretty(p);
|
||||||
@ -404,7 +404,7 @@ impl Pretty for ExprLet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for ExprIf {
|
impl Pretty for IfExpr {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
p.push_str("if ");
|
p.push_str("if ");
|
||||||
self.condition.pretty(p);
|
self.condition.pretty(p);
|
||||||
@ -418,7 +418,7 @@ impl Pretty for ExprIf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for ExprWhile {
|
impl Pretty for WhileExpr {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
p.push_str("while ");
|
p.push_str("while ");
|
||||||
self.condition.pretty(p);
|
self.condition.pretty(p);
|
||||||
@ -427,7 +427,7 @@ impl Pretty for ExprWhile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for ExprFor {
|
impl Pretty for ForExpr {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
p.push_str("for ");
|
p.push_str("for ");
|
||||||
self.pattern.pretty(p);
|
self.pattern.pretty(p);
|
||||||
@ -475,14 +475,13 @@ impl Pretty for Value {
|
|||||||
Value::Dict(v) => v.pretty(p),
|
Value::Dict(v) => v.pretty(p),
|
||||||
Value::Template(v) => v.pretty(p),
|
Value::Template(v) => v.pretty(p),
|
||||||
Value::Func(v) => v.pretty(p),
|
Value::Func(v) => v.pretty(p),
|
||||||
Value::Args(v) => v.pretty(p),
|
|
||||||
Value::Any(v) => v.pretty(p),
|
Value::Any(v) => v.pretty(p),
|
||||||
Value::Error => p.push_str("<error>"),
|
Value::Error => p.push_str("<error>"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for ValueArray {
|
impl Pretty for ArrayValue {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
p.push('(');
|
p.push('(');
|
||||||
p.join(self, ", ", |item, p| item.pretty(p));
|
p.join(self, ", ", |item, p| item.pretty(p));
|
||||||
@ -493,7 +492,7 @@ impl Pretty for ValueArray {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for ValueDict {
|
impl Pretty for DictValue {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
p.push('(');
|
p.push('(');
|
||||||
if self.is_empty() {
|
if self.is_empty() {
|
||||||
@ -509,7 +508,7 @@ impl Pretty for ValueDict {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for ValueTemplate {
|
impl Pretty for TemplateValue {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
p.push('[');
|
p.push('[');
|
||||||
for part in self {
|
for part in self {
|
||||||
@ -537,7 +536,7 @@ impl Pretty for TemplateFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for ValueFunc {
|
impl Pretty for FuncValue {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
p.push_str("<function");
|
p.push_str("<function");
|
||||||
if let Some(name) = self.name() {
|
if let Some(name) = self.name() {
|
||||||
@ -548,7 +547,7 @@ impl Pretty for ValueFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for ValueArgs {
|
impl Pretty for FuncArgs {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
p.push('(');
|
p.push('(');
|
||||||
p.join(&self.items, ", ", |item, p| item.pretty(p));
|
p.join(&self.items, ", ", |item, p| item.pretty(p));
|
||||||
@ -556,7 +555,7 @@ impl Pretty for ValueArgs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for ValueArg {
|
impl Pretty for FuncArg {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
if let Some(name) = &self.name {
|
if let Some(name) = &self.name {
|
||||||
p.push_str(&name.v);
|
p.push_str(&name.v);
|
||||||
@ -613,7 +612,7 @@ pretty_display! {
|
|||||||
Linear,
|
Linear,
|
||||||
RgbaColor,
|
RgbaColor,
|
||||||
Color,
|
Color,
|
||||||
ValueAny,
|
AnyValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -622,9 +621,7 @@ mod tests {
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::color::RgbaColor;
|
|
||||||
use crate::env::Env;
|
use crate::env::Env;
|
||||||
use crate::eval::eval;
|
|
||||||
use crate::parse::parse;
|
use crate::parse::parse;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
@ -796,34 +793,37 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Function.
|
// Function.
|
||||||
test_value(ValueFunc::new(None, |_, _| Value::None), "<function>");
|
test_value(FuncValue::new(None, |_, _| Value::None), "<function>");
|
||||||
test_value(
|
test_value(
|
||||||
ValueFunc::new(Some("nil".into()), |_, _| Value::None),
|
FuncValue::new(Some("nil".into()), |_, _| Value::None),
|
||||||
"<function nil>",
|
"<function nil>",
|
||||||
);
|
);
|
||||||
|
|
||||||
// Arguments.
|
|
||||||
test_value(
|
|
||||||
ValueArgs {
|
|
||||||
span: Span::ZERO,
|
|
||||||
items: vec![
|
|
||||||
ValueArg {
|
|
||||||
name: Some(Spanned::zero("a".into())),
|
|
||||||
value: Spanned::zero(Value::Int(1)),
|
|
||||||
},
|
|
||||||
ValueArg {
|
|
||||||
name: None,
|
|
||||||
value: Spanned::zero(Value::Int(2)),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"(a: 1, 2)",
|
|
||||||
);
|
|
||||||
|
|
||||||
// Any.
|
// Any.
|
||||||
test_value(ValueAny::new(1), "1");
|
test_value(AnyValue::new(1), "1");
|
||||||
|
|
||||||
// Error.
|
// Error.
|
||||||
test_value(Value::Error, "<error>");
|
test_value(Value::Error, "<error>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_pretty_print_args() {
|
||||||
|
// Arguments.
|
||||||
|
assert_eq!(
|
||||||
|
pretty(&FuncArgs {
|
||||||
|
span: Span::ZERO,
|
||||||
|
items: vec![
|
||||||
|
FuncArg {
|
||||||
|
name: Some(Spanned::zero("a".into())),
|
||||||
|
value: Spanned::zero(Value::Int(1)),
|
||||||
|
},
|
||||||
|
FuncArg {
|
||||||
|
name: None,
|
||||||
|
value: Spanned::zero(Value::Int(2)),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
"(a: 1, 2)",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,36 +7,36 @@ use crate::geom::{AngularUnit, LengthUnit};
|
|||||||
/// An expression.
|
/// An expression.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
/// A literal.
|
/// A literal, like `11pt` or `"hi"`.
|
||||||
Lit(Lit),
|
Lit(Lit),
|
||||||
/// An identifier: `left`.
|
/// An identifier: `left`.
|
||||||
Ident(Ident),
|
Ident(Ident),
|
||||||
/// An array expression: `(1, "hi", 12cm)`.
|
/// An array expression: `(1, "hi", 12cm)`.
|
||||||
Array(ExprArray),
|
Array(ArrayExpr),
|
||||||
/// A dictionary expression: `(color: #f79143, pattern: dashed)`.
|
/// A dictionary expression: `(color: #f79143, pattern: dashed)`.
|
||||||
Dict(ExprDict),
|
Dict(DictExpr),
|
||||||
/// A template expression: `[*Hi* there!]`.
|
/// A template expression: `[*Hi* there!]`.
|
||||||
Template(ExprTemplate),
|
Template(TemplateExpr),
|
||||||
/// A grouped expression: `(1 + 2)`.
|
/// A grouped expression: `(1 + 2)`.
|
||||||
Group(ExprGroup),
|
Group(GroupExpr),
|
||||||
/// A block expression: `{ let x = 1; x + 2 }`.
|
/// A block expression: `{ let x = 1; x + 2 }`.
|
||||||
Block(ExprBlock),
|
Block(BlockExpr),
|
||||||
/// A unary operation: `-x`.
|
/// A unary operation: `-x`.
|
||||||
Unary(ExprUnary),
|
Unary(UnaryExpr),
|
||||||
/// A binary operation: `a + b`.
|
/// A binary operation: `a + b`.
|
||||||
Binary(ExprBinary),
|
Binary(BinaryExpr),
|
||||||
/// An invocation of a function: `f(x, y)`.
|
/// An invocation of a function: `f(x, y)`.
|
||||||
Call(ExprCall),
|
Call(CallExpr),
|
||||||
/// A closure expression: `(x, y) => z`.
|
/// A closure expression: `(x, y) => z`.
|
||||||
Closure(ExprClosure),
|
Closure(ClosureExpr),
|
||||||
/// A let expression: `let x = 1`.
|
/// A let expression: `let x = 1`.
|
||||||
Let(ExprLet),
|
Let(LetExpr),
|
||||||
/// An if expression: `if x { y } else { z }`.
|
/// An if-else expression: `if x { y } else { z }`.
|
||||||
If(ExprIf),
|
If(IfExpr),
|
||||||
/// A while expression: `while x { y }`.
|
/// A while loop expression: `while x { y }`.
|
||||||
While(ExprWhile),
|
While(WhileExpr),
|
||||||
/// A for expression: `for x in y { z }`.
|
/// A for loop expression: `for x in y { z }`.
|
||||||
For(ExprFor),
|
For(ForExpr),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expr {
|
impl Expr {
|
||||||
@ -74,7 +74,7 @@ impl Expr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A literal.
|
/// A literal, like `11pt` or `"hi"`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Lit {
|
pub struct Lit {
|
||||||
/// The source code location.
|
/// The source code location.
|
||||||
@ -111,7 +111,7 @@ pub enum LitKind {
|
|||||||
|
|
||||||
/// An array expression: `(1, "hi", 12cm)`.
|
/// An array expression: `(1, "hi", 12cm)`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ExprArray {
|
pub struct ArrayExpr {
|
||||||
/// The source code location.
|
/// The source code location.
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
/// The entries of the array.
|
/// The entries of the array.
|
||||||
@ -120,7 +120,7 @@ pub struct ExprArray {
|
|||||||
|
|
||||||
/// A dictionary expression: `(color: #f79143, pattern: dashed)`.
|
/// A dictionary expression: `(color: #f79143, pattern: dashed)`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ExprDict {
|
pub struct DictExpr {
|
||||||
/// The source code location.
|
/// The source code location.
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
/// The named dictionary entries.
|
/// The named dictionary entries.
|
||||||
@ -145,7 +145,7 @@ impl Named {
|
|||||||
|
|
||||||
/// A template expression: `[*Hi* there!]`.
|
/// A template expression: `[*Hi* there!]`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ExprTemplate {
|
pub struct TemplateExpr {
|
||||||
/// The source code location.
|
/// The source code location.
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
/// The contents of the template.
|
/// The contents of the template.
|
||||||
@ -154,7 +154,7 @@ pub struct ExprTemplate {
|
|||||||
|
|
||||||
/// A grouped expression: `(1 + 2)`.
|
/// A grouped expression: `(1 + 2)`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ExprGroup {
|
pub struct GroupExpr {
|
||||||
/// The source code location.
|
/// The source code location.
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
/// The wrapped expression.
|
/// The wrapped expression.
|
||||||
@ -163,7 +163,7 @@ pub struct ExprGroup {
|
|||||||
|
|
||||||
/// A block expression: `{ let x = 1; x + 2 }`.
|
/// A block expression: `{ let x = 1; x + 2 }`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ExprBlock {
|
pub struct BlockExpr {
|
||||||
/// The source code location.
|
/// The source code location.
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
/// The list of expressions contained in the block.
|
/// The list of expressions contained in the block.
|
||||||
@ -174,7 +174,7 @@ pub struct ExprBlock {
|
|||||||
|
|
||||||
/// A unary operation: `-x`.
|
/// A unary operation: `-x`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ExprUnary {
|
pub struct UnaryExpr {
|
||||||
/// The source code location.
|
/// The source code location.
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
/// The operator: `-`.
|
/// The operator: `-`.
|
||||||
@ -225,7 +225,7 @@ impl UnOp {
|
|||||||
|
|
||||||
/// A binary operation: `a + b`.
|
/// A binary operation: `a + b`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ExprBinary {
|
pub struct BinaryExpr {
|
||||||
/// The source code location.
|
/// The source code location.
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
/// The left-hand side of the operation: `a`.
|
/// The left-hand side of the operation: `a`.
|
||||||
@ -374,13 +374,13 @@ pub enum Associativity {
|
|||||||
|
|
||||||
/// An invocation of a function: `foo(...)`.
|
/// An invocation of a function: `foo(...)`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ExprCall {
|
pub struct CallExpr {
|
||||||
/// The source code location.
|
/// The source code location.
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
/// The callee of the function.
|
/// The callee of the function.
|
||||||
pub callee: Box<Expr>,
|
pub callee: Box<Expr>,
|
||||||
/// The arguments to the function.
|
/// The arguments to the function.
|
||||||
pub args: ExprArgs,
|
pub args: CallArgs,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The arguments to a function: `12, draw: false`.
|
/// The arguments to a function: `12, draw: false`.
|
||||||
@ -388,23 +388,23 @@ pub struct ExprCall {
|
|||||||
/// In case of a bracketed invocation with a body, the body is _not_
|
/// In case of a bracketed invocation with a body, the body is _not_
|
||||||
/// included in the span for the sake of clearer error messages.
|
/// included in the span for the sake of clearer error messages.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ExprArgs {
|
pub struct CallArgs {
|
||||||
/// The source code location.
|
/// The source code location.
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
/// The positional and named arguments.
|
/// The positional and named arguments.
|
||||||
pub items: Vec<ExprArg>,
|
pub items: Vec<CallArg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An argument to a function call: `12` or `draw: false`.
|
/// An argument to a function call: `12` or `draw: false`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum ExprArg {
|
pub enum CallArg {
|
||||||
/// A positional argument.
|
/// A positional argument.
|
||||||
Pos(Expr),
|
Pos(Expr),
|
||||||
/// A named argument.
|
/// A named argument.
|
||||||
Named(Named),
|
Named(Named),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExprArg {
|
impl CallArg {
|
||||||
/// The source code location.
|
/// The source code location.
|
||||||
pub fn span(&self) -> Span {
|
pub fn span(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
@ -416,7 +416,7 @@ impl ExprArg {
|
|||||||
|
|
||||||
/// A closure expression: `(x, y) => z`.
|
/// A closure expression: `(x, y) => z`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ExprClosure {
|
pub struct ClosureExpr {
|
||||||
/// The source code location.
|
/// The source code location.
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
/// The name of the closure.
|
/// The name of the closure.
|
||||||
@ -431,7 +431,7 @@ pub struct ExprClosure {
|
|||||||
|
|
||||||
/// A let expression: `let x = 1`.
|
/// A let expression: `let x = 1`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ExprLet {
|
pub struct LetExpr {
|
||||||
/// The source code location.
|
/// The source code location.
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
/// The binding to assign to.
|
/// The binding to assign to.
|
||||||
@ -440,9 +440,9 @@ pub struct ExprLet {
|
|||||||
pub init: Option<Box<Expr>>,
|
pub init: Option<Box<Expr>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An if expression: `if x { y } else { z }`.
|
/// An if-else expression: `if x { y } else { z }`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ExprIf {
|
pub struct IfExpr {
|
||||||
/// The source code location.
|
/// The source code location.
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
/// The condition which selects the body to evaluate.
|
/// The condition which selects the body to evaluate.
|
||||||
@ -453,9 +453,9 @@ pub struct ExprIf {
|
|||||||
pub else_body: Option<Box<Expr>>,
|
pub else_body: Option<Box<Expr>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A while expression: `while x { y }`.
|
/// A while loop expression: `while x { y }`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ExprWhile {
|
pub struct WhileExpr {
|
||||||
/// The source code location.
|
/// The source code location.
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
/// The condition which selects whether to evaluate the body.
|
/// The condition which selects whether to evaluate the body.
|
||||||
@ -464,9 +464,9 @@ pub struct ExprWhile {
|
|||||||
pub body: Box<Expr>,
|
pub body: Box<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A for expression: `for x in y { z }`.
|
/// A for loop expression: `for x in y { z }`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ExprFor {
|
pub struct ForExpr {
|
||||||
/// The source code location.
|
/// The source code location.
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
/// The pattern to assign to.
|
/// The pattern to assign to.
|
||||||
|
@ -4,7 +4,7 @@ use unicode_xid::UnicodeXID;
|
|||||||
|
|
||||||
use super::Span;
|
use super::Span;
|
||||||
|
|
||||||
/// An Unicode identifier with a few extra permissible characters.
|
/// An unicode identifier with a few extra permissible characters.
|
||||||
///
|
///
|
||||||
/// In addition to what is specified in the [Unicode Standard][uax31], we allow:
|
/// In addition to what is specified in the [Unicode Standard][uax31], we allow:
|
||||||
/// - `_` as a starting character,
|
/// - `_` as a starting character,
|
||||||
|
@ -14,4 +14,6 @@ pub use span::*;
|
|||||||
pub use token::*;
|
pub use token::*;
|
||||||
|
|
||||||
/// The abstract syntax tree.
|
/// The abstract syntax tree.
|
||||||
|
///
|
||||||
|
/// This type can represent a full parsed document.
|
||||||
pub type Tree = Vec<Node>;
|
pub type Tree = Vec<Node>;
|
||||||
|
@ -16,23 +16,23 @@ pub enum Node {
|
|||||||
/// Plain text.
|
/// Plain text.
|
||||||
Text(String),
|
Text(String),
|
||||||
/// A section heading.
|
/// A section heading.
|
||||||
Heading(NodeHeading),
|
Heading(HeadingNode),
|
||||||
/// An optionally syntax-highlighted raw block.
|
/// An optionally syntax-highlighted raw block.
|
||||||
Raw(NodeRaw),
|
Raw(RawNode),
|
||||||
/// An expression.
|
/// An expression.
|
||||||
Expr(Expr),
|
Expr(Expr),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A section heading: `= Introduction`.
|
/// A section heading: `= Introduction`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct NodeHeading {
|
pub struct HeadingNode {
|
||||||
/// The section depth (numer of equals signs minus 1).
|
/// The section depth (numer of equals signs minus 1).
|
||||||
pub level: usize,
|
pub level: usize,
|
||||||
/// The contents of the heading.
|
/// The contents of the heading.
|
||||||
pub contents: Tree,
|
pub contents: Tree,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A raw block with optional syntax highlighting: `` `raw` ``.
|
/// A raw block with optional syntax highlighting: `` `...` ``.
|
||||||
///
|
///
|
||||||
/// Raw blocks start with 1 or 3+ backticks and end with the same number of
|
/// Raw blocks start with 1 or 3+ backticks and end with the same number of
|
||||||
/// backticks.
|
/// backticks.
|
||||||
@ -96,7 +96,7 @@ pub struct NodeHeading {
|
|||||||
/// Note that with these rules you can always force leading or trailing
|
/// Note that with these rules you can always force leading or trailing
|
||||||
/// whitespace simply by adding more spaces.
|
/// whitespace simply by adding more spaces.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct NodeRaw {
|
pub struct RawNode {
|
||||||
/// An optional identifier specifying the language to syntax-highlight in.
|
/// An optional identifier specifying the language to syntax-highlight in.
|
||||||
pub lang: Option<Ident>,
|
pub lang: Option<Ident>,
|
||||||
/// The lines of raw text, determined as the raw string between the
|
/// The lines of raw text, determined as the raw string between the
|
||||||
|
@ -32,7 +32,7 @@ impl<T> Spanned<T> {
|
|||||||
Spanned { v: &self.v, span: self.span }
|
Spanned { v: &self.v, span: self.span }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Map the value using a function while keeping the span.
|
/// Map the value using a function keeping the span.
|
||||||
pub fn map<F, U>(self, f: F) -> Spanned<U>
|
pub fn map<F, U>(self, f: F) -> Spanned<U>
|
||||||
where
|
where
|
||||||
F: FnOnce(T) -> U,
|
F: FnOnce(T) -> U,
|
||||||
|
@ -99,13 +99,13 @@ pub enum Token<'s> {
|
|||||||
Text(&'s str),
|
Text(&'s str),
|
||||||
/// An arbitrary number of backticks followed by inner contents, terminated
|
/// An arbitrary number of backticks followed by inner contents, terminated
|
||||||
/// with the same number of backticks: `` `...` ``.
|
/// with the same number of backticks: `` `...` ``.
|
||||||
Raw(TokenRaw<'s>),
|
Raw(RawToken<'s>),
|
||||||
/// One or two dollar signs followed by inner contents, terminated with the
|
/// One or two dollar signs followed by inner contents, terminated with the
|
||||||
/// same number of dollar signs.
|
/// same number of dollar signs.
|
||||||
Math(TokenMath<'s>),
|
Math(MathToken<'s>),
|
||||||
/// A slash and the letter "u" followed by a hexadecimal unicode entity
|
/// A slash and the letter "u" followed by a hexadecimal unicode entity
|
||||||
/// enclosed in curly braces: `\u{1F5FA}`.
|
/// enclosed in curly braces: `\u{1F5FA}`.
|
||||||
UnicodeEscape(TokenUnicodeEscape<'s>),
|
UnicodeEscape(UnicodeEscapeToken<'s>),
|
||||||
/// An identifier: `center`.
|
/// An identifier: `center`.
|
||||||
Ident(&'s str),
|
Ident(&'s str),
|
||||||
/// A boolean: `true`, `false`.
|
/// A boolean: `true`, `false`.
|
||||||
@ -126,7 +126,7 @@ pub enum Token<'s> {
|
|||||||
/// A color value: `#20d82a`.
|
/// A color value: `#20d82a`.
|
||||||
Color(RgbaColor),
|
Color(RgbaColor),
|
||||||
/// A quoted string: `"..."`.
|
/// A quoted string: `"..."`.
|
||||||
Str(TokenStr<'s>),
|
Str(StrToken<'s>),
|
||||||
/// Two slashes followed by inner contents, terminated with a newline:
|
/// Two slashes followed by inner contents, terminated with a newline:
|
||||||
/// `//<str>\n`.
|
/// `//<str>\n`.
|
||||||
LineComment(&'s str),
|
LineComment(&'s str),
|
||||||
@ -139,9 +139,9 @@ pub enum Token<'s> {
|
|||||||
Invalid(&'s str),
|
Invalid(&'s str),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A quoted string: `"..."`.
|
/// A quoted string token: `"..."`.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub struct TokenStr<'s> {
|
pub struct StrToken<'s> {
|
||||||
/// The string inside the quotes.
|
/// The string inside the quotes.
|
||||||
///
|
///
|
||||||
/// _Note_: If the string contains escape sequences these are not yet
|
/// _Note_: If the string contains escape sequences these are not yet
|
||||||
@ -152,9 +152,9 @@ pub struct TokenStr<'s> {
|
|||||||
pub terminated: bool,
|
pub terminated: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A raw block: `` `...` ``.
|
/// A raw block token: `` `...` ``.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub struct TokenRaw<'s> {
|
pub struct RawToken<'s> {
|
||||||
/// The raw text between the backticks.
|
/// The raw text between the backticks.
|
||||||
pub text: &'s str,
|
pub text: &'s str,
|
||||||
/// The number of opening backticks.
|
/// The number of opening backticks.
|
||||||
@ -163,9 +163,9 @@ pub struct TokenRaw<'s> {
|
|||||||
pub terminated: bool,
|
pub terminated: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A math formula: `$2pi + x$`, `$$f'(x) = x^2$$`.
|
/// A math formula token: `$2pi + x$` or `$[f'(x) = x^2]$`.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub struct TokenMath<'s> {
|
pub struct MathToken<'s> {
|
||||||
/// The formula between the dollars.
|
/// The formula between the dollars.
|
||||||
pub formula: &'s str,
|
pub formula: &'s str,
|
||||||
/// Whether the formula is display-level, that is, it is surrounded by
|
/// Whether the formula is display-level, that is, it is surrounded by
|
||||||
@ -175,9 +175,9 @@ pub struct TokenMath<'s> {
|
|||||||
pub terminated: bool,
|
pub terminated: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A unicode escape sequence: `\u{1F5FA}`.
|
/// A unicode escape sequence token: `\u{1F5FA}`.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub struct TokenUnicodeEscape<'s> {
|
pub struct UnicodeEscapeToken<'s> {
|
||||||
/// The escape sequence between the braces.
|
/// The escape sequence between the braces.
|
||||||
pub sequence: &'s str,
|
pub sequence: &'s str,
|
||||||
/// Whether the closing brace was present.
|
/// Whether the closing brace was present.
|
||||||
|
@ -82,29 +82,29 @@ visit! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_array(v, node: &ExprArray) {
|
fn visit_array(v, node: &ArrayExpr) {
|
||||||
for expr in &node.items {
|
for expr in &node.items {
|
||||||
v.visit_expr(&expr);
|
v.visit_expr(&expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_dict(v, node: &ExprDict) {
|
fn visit_dict(v, node: &DictExpr) {
|
||||||
for named in &node.items {
|
for named in &node.items {
|
||||||
v.visit_expr(&named.expr);
|
v.visit_expr(&named.expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_template(v, node: &ExprTemplate) {
|
fn visit_template(v, node: &TemplateExpr) {
|
||||||
v.visit_enter();
|
v.visit_enter();
|
||||||
v.visit_tree(&node.tree);
|
v.visit_tree(&node.tree);
|
||||||
v.visit_exit();
|
v.visit_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_group(v, node: &ExprGroup) {
|
fn visit_group(v, node: &GroupExpr) {
|
||||||
v.visit_expr(&node.expr);
|
v.visit_expr(&node.expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_block(v, node: &ExprBlock) {
|
fn visit_block(v, node: &BlockExpr) {
|
||||||
if node.scoping {
|
if node.scoping {
|
||||||
v.visit_enter();
|
v.visit_enter();
|
||||||
}
|
}
|
||||||
@ -116,48 +116,48 @@ visit! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_binary(v, node: &ExprBinary) {
|
fn visit_binary(v, node: &BinaryExpr) {
|
||||||
v.visit_expr(&node.lhs);
|
v.visit_expr(&node.lhs);
|
||||||
v.visit_expr(&node.rhs);
|
v.visit_expr(&node.rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_unary(v, node: &ExprUnary) {
|
fn visit_unary(v, node: &UnaryExpr) {
|
||||||
v.visit_expr(&node.expr);
|
v.visit_expr(&node.expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_call(v, node: &ExprCall) {
|
fn visit_call(v, node: &CallExpr) {
|
||||||
v.visit_expr(&node.callee);
|
v.visit_expr(&node.callee);
|
||||||
v.visit_args(&node.args);
|
v.visit_args(&node.args);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_closure(v, node: &ExprClosure) {
|
fn visit_closure(v, node: &ClosureExpr) {
|
||||||
for param in node.params.iter() {
|
for param in node.params.iter() {
|
||||||
v.visit_binding(param);
|
v.visit_binding(param);
|
||||||
}
|
}
|
||||||
v.visit_expr(&node.body);
|
v.visit_expr(&node.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_args(v, node: &ExprArgs) {
|
fn visit_args(v, node: &CallArgs) {
|
||||||
for arg in &node.items {
|
for arg in &node.items {
|
||||||
v.visit_arg(arg);
|
v.visit_arg(arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_arg(v, node: &ExprArg) {
|
fn visit_arg(v, node: &CallArg) {
|
||||||
match node {
|
match node {
|
||||||
ExprArg::Pos(expr) => v.visit_expr(&expr),
|
CallArg::Pos(expr) => v.visit_expr(&expr),
|
||||||
ExprArg::Named(named) => v.visit_expr(&named.expr),
|
CallArg::Named(named) => v.visit_expr(&named.expr),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_let(v, node: &ExprLet) {
|
fn visit_let(v, node: &LetExpr) {
|
||||||
v.visit_binding(&node.binding);
|
v.visit_binding(&node.binding);
|
||||||
if let Some(init) = &node.init {
|
if let Some(init) = &node.init {
|
||||||
v.visit_expr(&init);
|
v.visit_expr(&init);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_if(v, node: &ExprIf) {
|
fn visit_if(v, node: &IfExpr) {
|
||||||
v.visit_expr(&node.condition);
|
v.visit_expr(&node.condition);
|
||||||
v.visit_expr(&node.if_body);
|
v.visit_expr(&node.if_body);
|
||||||
if let Some(body) = &node.else_body {
|
if let Some(body) = &node.else_body {
|
||||||
@ -165,12 +165,12 @@ visit! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_while(v, node: &ExprWhile) {
|
fn visit_while(v, node: &WhileExpr) {
|
||||||
v.visit_expr(&node.condition);
|
v.visit_expr(&node.condition);
|
||||||
v.visit_expr(&node.body);
|
v.visit_expr(&node.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_for(v, node: &ExprFor) {
|
fn visit_for(v, node: &ForExpr) {
|
||||||
match &node.pattern {
|
match &node.pattern {
|
||||||
ForPattern::Value(value) => v.visit_binding(value),
|
ForPattern::Value(value) => v.visit_binding(value),
|
||||||
ForPattern::KeyValue(key, value) => {
|
ForPattern::KeyValue(key, value) => {
|
||||||
|
@ -3,29 +3,35 @@
|
|||||||
## Directory structure
|
## Directory structure
|
||||||
Top level directory structure:
|
Top level directory structure:
|
||||||
- `typ`: Input files.
|
- `typ`: Input files.
|
||||||
|
- `res`: Resource files used by tests.
|
||||||
- `ref`: Reference images which the output is compared with to determine whether
|
- `ref`: Reference images which the output is compared with to determine whether
|
||||||
a test passed or failed.
|
a test passed or failed.
|
||||||
- `png`: PNG files produced by tests.
|
- `png`: PNG files produced by tests.
|
||||||
- `pdf`: PDF files produced by tests.
|
- `pdf`: PDF files produced by tests.
|
||||||
- `res`: Resource files used by tests.
|
|
||||||
|
|
||||||
## Running the tests
|
## Running the tests
|
||||||
|
Running the integration tests (the tests in this directory).
|
||||||
```bash
|
```bash
|
||||||
# Run all tests
|
|
||||||
cargo test
|
|
||||||
|
|
||||||
# Run unit tests
|
|
||||||
cargo test --lib
|
|
||||||
|
|
||||||
# Run integration tests (the tests in this directory)
|
|
||||||
cargo test --test typeset
|
cargo test --test typeset
|
||||||
|
```
|
||||||
|
|
||||||
# Run all tests whose names contain the word `filter`
|
Running all tests whose names contain the word `filter`.
|
||||||
|
```bash
|
||||||
cargo test --test typeset filter
|
cargo test --test typeset filter
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To make the integration tests go faster they don't generate PDFs by default.
|
||||||
|
Pass the `--pdf` flag to generate those. Mind that PDFs are not tested
|
||||||
|
automatically at the moment, so you should always check the output manually when
|
||||||
|
making changes.
|
||||||
|
```bash
|
||||||
|
cargo test --test typeset -- --pdf
|
||||||
|
```
|
||||||
|
|
||||||
## Creating new tests
|
## Creating new tests
|
||||||
To keep things small, please optimize reference images before committing them:
|
To keep things small, please optimize reference images before committing them.
|
||||||
|
When you use the approve buttom from the Test Helper (see the `tools` folder)
|
||||||
|
this happens automatically if you have `oxipng` installed.
|
||||||
```bash
|
```bash
|
||||||
# One image
|
# One image
|
||||||
oxipng -o max path/to/image.png
|
oxipng -o max path/to/image.png
|
||||||
|
@ -15,16 +15,15 @@ use ttf_parser::OutlineBuilder;
|
|||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
use typst::diag::{Diag, DiagSet, Level, Pass};
|
use typst::diag::{Diag, DiagSet, Level, Pass};
|
||||||
use typst::env::{Env, ImageResource, ResourceLoader};
|
use typst::env::{Env, FsIndexExt, ImageResource, ResourceLoader};
|
||||||
use typst::eval::{EvalContext, Scope, Value, ValueArgs, ValueFunc};
|
use typst::eval::{EvalContext, FuncArgs, FuncValue, Scope, Value};
|
||||||
use typst::exec::State;
|
use typst::exec::State;
|
||||||
use typst::export::pdf;
|
use typst::export::pdf;
|
||||||
use typst::font::FsIndexExt;
|
|
||||||
use typst::geom::{Length, Point, Sides, Size};
|
use typst::geom::{Length, Point, Sides, Size};
|
||||||
use typst::layout::{Element, Fill, Frame, Geometry, Image, Shape};
|
use typst::layout::{Element, Fill, Frame, Geometry, Image, Shape, Shaped};
|
||||||
use typst::library;
|
use typst::library;
|
||||||
use typst::parse::{LineMap, Scanner};
|
use typst::parse::{LineMap, Scanner};
|
||||||
use typst::shaping::Shaped;
|
use typst::pretty::pretty;
|
||||||
use typst::syntax::{Location, Pos};
|
use typst::syntax::{Location, Pos};
|
||||||
use typst::typeset;
|
use typst::typeset;
|
||||||
|
|
||||||
@ -313,13 +312,18 @@ struct Panic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn register_helpers(scope: &mut Scope, panics: Rc<RefCell<Vec<Panic>>>) {
|
fn register_helpers(scope: &mut Scope, panics: Rc<RefCell<Vec<Panic>>>) {
|
||||||
pub fn args(_: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
pub fn args(_: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||||
let value = args.clone().into();
|
let repr = pretty(args);
|
||||||
args.items.clear();
|
args.items.clear();
|
||||||
value
|
Value::template("args", move |ctx| {
|
||||||
|
let snapshot = ctx.state.clone();
|
||||||
|
ctx.set_monospace();
|
||||||
|
ctx.push_text(&repr);
|
||||||
|
ctx.state = snapshot;
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let test = move |ctx: &mut EvalContext, args: &mut ValueArgs| -> Value {
|
let test = move |ctx: &mut EvalContext, args: &mut FuncArgs| -> Value {
|
||||||
let lhs = args.require::<Value>(ctx, "left-hand side");
|
let lhs = args.require::<Value>(ctx, "left-hand side");
|
||||||
let rhs = args.require::<Value>(ctx, "right-hand side");
|
let rhs = args.require::<Value>(ctx, "right-hand side");
|
||||||
if lhs != rhs {
|
if lhs != rhs {
|
||||||
@ -331,8 +335,8 @@ fn register_helpers(scope: &mut Scope, panics: Rc<RefCell<Vec<Panic>>>) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
scope.def_const("error", Value::Error);
|
scope.def_const("error", Value::Error);
|
||||||
scope.def_const("args", ValueFunc::new(Some("args".into()), args));
|
scope.def_const("args", FuncValue::new(Some("args".into()), args));
|
||||||
scope.def_const("test", ValueFunc::new(Some("test".into()), test));
|
scope.def_const("test", FuncValue::new(Some("test".into()), test));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_diag(diag: &Diag, map: &LineMap, lines: u32) {
|
fn print_diag(diag: &Diag, map: &LineMap, lines: u32) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user