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