mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Tidy up library functions 🧺
This commit is contained in:
parent
3cbca56a71
commit
6d7e7d945b
@ -31,12 +31,6 @@ impl Scope {
|
||||
self.functions.get(name)
|
||||
}
|
||||
|
||||
/// Return the function with the given name or the fallback if there is no
|
||||
/// such function.
|
||||
pub fn func_or_fallback(&self, name: &str) -> &FuncValue {
|
||||
self.func(name).unwrap_or_else(|| self.fallback())
|
||||
}
|
||||
|
||||
/// Return the fallback function.
|
||||
pub fn fallback(&self) -> &FuncValue {
|
||||
&self.fallback
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! A key-value map that can also model array-like structures.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::fmt::{self, Debug, Display, Formatter};
|
||||
use std::ops::Index;
|
||||
|
||||
use crate::syntax::span::{Span, Spanned};
|
||||
@ -180,25 +180,31 @@ impl<V: Debug> Debug for Table<V> {
|
||||
|
||||
let mut builder = f.debug_tuple("");
|
||||
|
||||
struct Entry<'a>(&'a dyn Debug, &'a dyn Debug);
|
||||
struct Entry<'a>(bool, &'a dyn Display, &'a dyn Debug);
|
||||
impl<'a> Debug for Entry<'a> {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
self.0.fmt(f)?;
|
||||
if self.0 {
|
||||
f.write_str("\"")?;
|
||||
}
|
||||
self.1.fmt(f)?;
|
||||
if self.0 {
|
||||
f.write_str("\"")?;
|
||||
}
|
||||
if f.alternate() {
|
||||
f.write_str(" = ")?;
|
||||
} else {
|
||||
f.write_str("=")?;
|
||||
}
|
||||
self.1.fmt(f)
|
||||
self.2.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
for (key, value) in self.nums() {
|
||||
builder.field(&Entry(&key, &value));
|
||||
builder.field(&Entry(false, &key, &value));
|
||||
}
|
||||
|
||||
for (key, value) in self.strs() {
|
||||
builder.field(&Entry(&key, &value));
|
||||
builder.field(&Entry(key.contains(' '), &key, &value));
|
||||
}
|
||||
|
||||
builder.finish()
|
||||
@ -358,21 +364,21 @@ mod tests {
|
||||
#[test]
|
||||
fn test_table_format_debug() {
|
||||
let mut table = Table::new();
|
||||
assert_eq!(format!("{:?}", table), r#"()"#);
|
||||
assert_eq!(format!("{:#?}", table), r#"()"#);
|
||||
assert_eq!(format!("{:?}", table), "()");
|
||||
assert_eq!(format!("{:#?}", table), "()");
|
||||
|
||||
table.insert(10, "hello");
|
||||
table.insert("twenty", "there");
|
||||
table.insert("sp ace", "quotes");
|
||||
assert_eq!(
|
||||
format!("{:?}", table),
|
||||
r#"(10="hello", "sp ace"="quotes", "twenty"="there")"#,
|
||||
r#"(10="hello", "sp ace"="quotes", twenty="there")"#,
|
||||
);
|
||||
assert_eq!(format!("{:#?}", table).lines().collect::<Vec<_>>(), [
|
||||
"(",
|
||||
r#" 10 = "hello","#,
|
||||
r#" "sp ace" = "quotes","#,
|
||||
r#" "twenty" = "there","#,
|
||||
r#" twenty = "there","#,
|
||||
")",
|
||||
]);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! Computational values: Syntactical expressions can be evaluated into these.
|
||||
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
use fontdock::{FontStyle, FontWeight, FontWidth};
|
||||
@ -13,7 +14,7 @@ use crate::syntax::span::{Span, Spanned};
|
||||
use crate::syntax::tree::SyntaxTree;
|
||||
use crate::syntax::Ident;
|
||||
use crate::{DynFuture, Feedback, Pass};
|
||||
use super::table::{BorrowedKey, SpannedEntry, Table};
|
||||
use super::table::{SpannedEntry, Table};
|
||||
|
||||
/// A computational value.
|
||||
#[derive(Clone)]
|
||||
@ -110,7 +111,7 @@ impl PartialEq for Value {
|
||||
///
|
||||
/// The dynamic function object is wrapped in an `Rc` to keep `Value` clonable.
|
||||
pub type FuncValue = Rc<
|
||||
dyn Fn(TableValue, LayoutContext<'_>) -> DynFuture<Pass<Value>>
|
||||
dyn Fn(Span, TableValue, LayoutContext<'_>) -> DynFuture<Pass<Value>>
|
||||
>;
|
||||
|
||||
/// A table of values.
|
||||
@ -138,13 +139,21 @@ impl TableValue {
|
||||
/// Retrieve and remove the matching value with the lowest number key,
|
||||
/// removing and generating errors for all non-matching entries with lower
|
||||
/// keys.
|
||||
pub fn expect<T: TryFromValue>(&mut self, f: &mut Feedback) -> Option<T> {
|
||||
///
|
||||
/// Generates an error at `err_span` when no matching value was found.
|
||||
pub fn expect<T: TryFromValue>(
|
||||
&mut self,
|
||||
name: &str,
|
||||
span: Span,
|
||||
f: &mut Feedback,
|
||||
) -> Option<T> {
|
||||
while let Some((num, _)) = self.first() {
|
||||
let entry = self.remove(num).unwrap();
|
||||
if let Some(val) = T::try_from_value(entry.val.as_ref(), f) {
|
||||
return Some(val);
|
||||
}
|
||||
}
|
||||
error!(@f, span, "missing argument: {}", name);
|
||||
None
|
||||
}
|
||||
|
||||
@ -152,9 +161,8 @@ impl TableValue {
|
||||
/// there is any.
|
||||
///
|
||||
/// Generates an error if the key exists but the value does not match.
|
||||
pub fn take_with_key<'a, K, T>(&mut self, key: K, f: &mut Feedback) -> Option<T>
|
||||
pub fn take_key<'a, T>(&mut self, key: &str, f: &mut Feedback) -> Option<T>
|
||||
where
|
||||
K: Into<BorrowedKey<'a>>,
|
||||
T: TryFromValue,
|
||||
{
|
||||
self.remove(key).and_then(|entry| {
|
||||
@ -312,6 +320,14 @@ impl_match!(ScaleLength, "number or length",
|
||||
/// `Into<String>`.
|
||||
pub struct StringLike(pub String);
|
||||
|
||||
impl Deref for StringLike {
|
||||
type Target = str;
|
||||
|
||||
fn deref(&self) -> &str {
|
||||
self.0.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StringLike> for String {
|
||||
fn from(like: StringLike) -> String {
|
||||
like.0
|
||||
@ -441,7 +457,10 @@ mod tests {
|
||||
table.insert(1, entry(Value::Bool(false)));
|
||||
table.insert(3, entry(Value::Str("hi".to_string())));
|
||||
table.insert(5, entry(Value::Bool(true)));
|
||||
assert_eq!(table.expect::<String>(&mut f), Some("hi".to_string()));
|
||||
assert_eq!(
|
||||
table.expect::<String>("", Span::ZERO, &mut f),
|
||||
Some("hi".to_string())
|
||||
);
|
||||
assert_eq!(f.diagnostics, [error!(Span::ZERO, "expected string, found bool")]);
|
||||
assert_eq!(table.len(), 1);
|
||||
}
|
||||
@ -452,8 +471,8 @@ mod tests {
|
||||
let mut table = Table::new();
|
||||
table.insert(1, entry(Value::Bool(false)));
|
||||
table.insert("hi", entry(Value::Bool(true)));
|
||||
assert_eq!(table.take_with_key::<_, bool>(1, &mut f), Some(false));
|
||||
assert_eq!(table.take_with_key::<_, f64>("hi", &mut f), None);
|
||||
assert_eq!(table.take::<bool>(), Some(false));
|
||||
assert_eq!(table.take_key::<f64>("hi", &mut f), None);
|
||||
assert_eq!(f.diagnostics, [error!(Span::ZERO, "expected number, found bool")]);
|
||||
assert!(table.is_empty());
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
use crate::compute::value::Value;
|
||||
use crate::style::LayoutStyle;
|
||||
use crate::syntax::decoration::Decoration;
|
||||
use crate::syntax::span::{Offset, Span, Spanned};
|
||||
use crate::syntax::span::{Span, Spanned};
|
||||
use crate::syntax::tree::{CallExpr, SyntaxNode, SyntaxTree};
|
||||
use crate::{DynFuture, Feedback, Pass};
|
||||
use super::line::{LineContext, LineLayouter};
|
||||
@ -104,7 +104,7 @@ impl<'a> TreeLayouter<'a> {
|
||||
|
||||
async fn layout_call(&mut self, call: Spanned<&CallExpr>) {
|
||||
let name = call.v.name.v.as_str();
|
||||
let span = call.v.name.span.offset(call.span.start);
|
||||
let span = call.v.name.span;
|
||||
|
||||
let (func, deco) = if let Some(func) = self.ctx.scope.func(name) {
|
||||
(func, Decoration::Resolved)
|
||||
@ -116,7 +116,7 @@ impl<'a> TreeLayouter<'a> {
|
||||
self.feedback.decorations.push(Spanned::new(deco, span));
|
||||
|
||||
let args = call.v.args.eval();
|
||||
let pass = func(args, LayoutContext {
|
||||
let pass = func(span, args, LayoutContext {
|
||||
style: &self.style,
|
||||
spaces: self.layouter.remaining(),
|
||||
root: true,
|
||||
|
@ -10,28 +10,30 @@ use super::*;
|
||||
/// - `vertical`: Any of `top`, `bottom` or `center`.
|
||||
///
|
||||
/// There may not be two alignment specifications for the same axis.
|
||||
pub async fn align(mut args: TableValue, mut ctx: LayoutContext<'_>) -> Pass<Value> {
|
||||
pub async fn align(_: Span, mut args: TableValue, mut ctx: LayoutContext<'_>) -> Pass<Value> {
|
||||
let mut f = Feedback::new();
|
||||
|
||||
let content = args.take::<SyntaxTree>();
|
||||
let aligns: Vec<_> = args.take_all_num_vals::<Spanned<SpecAlign>>().collect();
|
||||
let h = args.take_with_key::<_, Spanned<SpecAlign>>("horizontal", &mut f);
|
||||
let v = args.take_with_key::<_, Spanned<SpecAlign>>("vertical", &mut f);
|
||||
args.unexpected(&mut f);
|
||||
|
||||
ctx.base = ctx.spaces[0].size;
|
||||
|
||||
let axes = ctx.axes;
|
||||
let all = aligns.iter()
|
||||
.map(|align| {
|
||||
let spec = align.v.axis().unwrap_or(axes.primary.axis());
|
||||
(spec, align)
|
||||
})
|
||||
.chain(h.iter().map(|align| (Horizontal, align)))
|
||||
.chain(v.iter().map(|align| (Vertical, align)));
|
||||
let h = args.take_key::<Spanned<SpecAlign>>("horizontal", &mut f);
|
||||
let v = args.take_key::<Spanned<SpecAlign>>("vertical", &mut f);
|
||||
let all = args
|
||||
.take_all_num_vals::<Spanned<SpecAlign>>()
|
||||
.map(|align| (align.v.axis(), align))
|
||||
.chain(h.into_iter().map(|align| (Some(Horizontal), align)))
|
||||
.chain(v.into_iter().map(|align| (Some(Vertical), align)));
|
||||
|
||||
let mut had = [false; 2];
|
||||
for (axis, align) in all {
|
||||
let axis = axis.unwrap_or_else(|| align.v.axis().unwrap_or_else(|| {
|
||||
let primary = ctx.axes.primary.axis();
|
||||
if !had[primary as usize] {
|
||||
primary
|
||||
} else {
|
||||
ctx.axes.secondary.axis()
|
||||
}
|
||||
}));
|
||||
|
||||
if align.v.axis().map(|a| a != axis).unwrap_or(false) {
|
||||
error!(
|
||||
@f, align.span,
|
||||
@ -47,12 +49,16 @@ pub async fn align(mut args: TableValue, mut ctx: LayoutContext<'_>) -> Pass<Val
|
||||
}
|
||||
}
|
||||
|
||||
Pass::commands(match content {
|
||||
let commands = match content {
|
||||
Some(tree) => {
|
||||
ctx.base = ctx.spaces[0].size;
|
||||
let layouted = layout(&tree, ctx).await;
|
||||
f.extend(layouted.feedback);
|
||||
vec![AddMultiple(layouted.output)]
|
||||
}
|
||||
None => vec![SetAlignment(ctx.align)],
|
||||
}, f)
|
||||
};
|
||||
|
||||
args.unexpected(&mut f);
|
||||
Pass::commands(commands, f)
|
||||
}
|
||||
|
@ -6,32 +6,33 @@ use super::*;
|
||||
/// # Keyword arguments
|
||||
/// - `width`: The width of the box (length of relative to parent's width).
|
||||
/// - `height`: The height of the box (length of relative to parent's height).
|
||||
pub async fn boxed(mut args: TableValue, mut ctx: LayoutContext<'_>) -> Pass<Value> {
|
||||
pub async fn boxed(_: Span, mut args: TableValue, mut ctx: LayoutContext<'_>) -> Pass<Value> {
|
||||
let mut f = Feedback::new();
|
||||
let content = args.take::<SyntaxTree>().unwrap_or(SyntaxTree::new());
|
||||
let width = args.take_with_key::<_, ScaleLength>("width", &mut f);
|
||||
let height = args.take_with_key::<_, ScaleLength>("height", &mut f);
|
||||
args.unexpected(&mut f);
|
||||
|
||||
let content = args.take::<SyntaxTree>().unwrap_or(SyntaxTree::new());
|
||||
|
||||
ctx.base = ctx.spaces[0].size;
|
||||
ctx.spaces.truncate(1);
|
||||
ctx.repeat = false;
|
||||
|
||||
width.with(|v| {
|
||||
let length = v.raw_scaled(ctx.base.x);
|
||||
if let Some(w) = args.take_key::<ScaleLength>("width", &mut f) {
|
||||
let length = w.raw_scaled(ctx.base.x);
|
||||
ctx.base.x = length;
|
||||
ctx.spaces[0].size.x = length;
|
||||
ctx.spaces[0].expansion.horizontal = true;
|
||||
});
|
||||
}
|
||||
|
||||
height.with(|v| {
|
||||
let length = v.raw_scaled(ctx.base.y);
|
||||
if let Some(h) = args.take_key::<ScaleLength>("height", &mut f) {
|
||||
let length = h.raw_scaled(ctx.base.y);
|
||||
ctx.base.y = length;
|
||||
ctx.spaces[0].size.y = length;
|
||||
ctx.spaces[0].expansion.vertical = true;
|
||||
});
|
||||
}
|
||||
|
||||
let layouted = layout(&content, ctx).await;
|
||||
let layout = layouted.output.into_iter().next().unwrap();
|
||||
f.extend(layouted.feedback);
|
||||
|
||||
args.unexpected(&mut f);
|
||||
Pass::commands(vec![Add(layout)], f)
|
||||
}
|
||||
|
@ -18,60 +18,66 @@ use super::*;
|
||||
/// ```typst
|
||||
/// serif = ("Source Serif Pro", "Noto Serif")
|
||||
/// ```
|
||||
pub async fn font(mut args: TableValue, ctx: LayoutContext<'_>) -> Pass<Value> {
|
||||
pub async fn font(_: Span, mut args: TableValue, ctx: LayoutContext<'_>) -> Pass<Value> {
|
||||
let mut f = Feedback::new();
|
||||
let mut text = ctx.style.text.clone();
|
||||
let mut updated_fallback = false;
|
||||
|
||||
let content = args.take::<SyntaxTree>();
|
||||
let size = args.take::<ScaleLength>();
|
||||
let style = args.take_with_key::<_, FontStyle>("style", &mut f);
|
||||
let weight = args.take_with_key::<_, FontWeight>("weight", &mut f);
|
||||
let width = args.take_with_key::<_, FontWidth>("width", &mut f);
|
||||
let list: Vec<_> = args.take_all_num_vals::<StringLike>()
|
||||
.map(|s| s.0.to_lowercase())
|
||||
.collect();
|
||||
let classes: Vec<(_, Vec<_>)> = args.take_all_str::<TableValue>()
|
||||
.map(|(class, mut table)| {
|
||||
let fallback = table.take_all_num_vals::<StringLike>()
|
||||
.map(|s| s.0.to_lowercase())
|
||||
.collect();
|
||||
(class, fallback)
|
||||
})
|
||||
.collect();
|
||||
|
||||
args.unexpected(&mut f);
|
||||
|
||||
let mut text = ctx.style.text.clone();
|
||||
|
||||
size.with(|s| match s {
|
||||
ScaleLength::Absolute(length) => {
|
||||
text.base_font_size = length.as_raw();
|
||||
text.font_scale = 1.0;
|
||||
if let Some(s) = args.take::<ScaleLength>() {
|
||||
match s {
|
||||
ScaleLength::Absolute(length) => {
|
||||
text.base_font_size = length.as_raw();
|
||||
text.font_scale = 1.0;
|
||||
}
|
||||
ScaleLength::Scaled(scale) => text.font_scale = scale,
|
||||
}
|
||||
ScaleLength::Scaled(scale) => text.font_scale = scale,
|
||||
});
|
||||
}
|
||||
|
||||
style.with(|s| text.variant.style = s);
|
||||
weight.with(|w| text.variant.weight = w);
|
||||
width.with(|w| text.variant.width = w);
|
||||
let list: Vec<_> = args.take_all_num_vals::<StringLike>()
|
||||
.map(|s| s.to_lowercase())
|
||||
.collect();
|
||||
|
||||
if !list.is_empty() {
|
||||
*text.fallback.list_mut() = list.iter()
|
||||
*text.fallback.list_mut() = list;
|
||||
updated_fallback = true;
|
||||
}
|
||||
|
||||
if let Some(style) = args.take_key::<FontStyle>("style", &mut f) {
|
||||
text.variant.style = style;
|
||||
}
|
||||
|
||||
if let Some(weight) = args.take_key::<FontWeight>("weight", &mut f) {
|
||||
text.variant.weight = weight;
|
||||
}
|
||||
|
||||
if let Some(width) = args.take_key::<FontWidth>("width", &mut f) {
|
||||
text.variant.width = width;
|
||||
}
|
||||
|
||||
for (class, mut table) in args.take_all_str::<TableValue>() {
|
||||
let fallback = table.take_all_num_vals::<StringLike>()
|
||||
.map(|s| s.to_lowercase())
|
||||
.collect();
|
||||
|
||||
text.fallback.set_class_list(class, fallback);
|
||||
updated_fallback = true;
|
||||
}
|
||||
|
||||
for (class, fallback) in classes {
|
||||
text.fallback.set_class_list(class.clone(), fallback.clone());
|
||||
if updated_fallback {
|
||||
text.fallback.flatten();
|
||||
}
|
||||
|
||||
text.fallback.flatten();
|
||||
|
||||
Pass::commands(match content {
|
||||
let commands = match content {
|
||||
Some(tree) => vec![
|
||||
SetTextStyle(text),
|
||||
LayoutSyntaxTree(tree),
|
||||
SetTextStyle(ctx.style.text.clone()),
|
||||
],
|
||||
None => vec![SetTextStyle(text)],
|
||||
}, f)
|
||||
};
|
||||
|
||||
args.unexpected(&mut f);
|
||||
Pass::commands(commands, f)
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ macro_rules! std {
|
||||
|
||||
macro_rules! wrap {
|
||||
($func:expr) => {
|
||||
Rc::new(|args, ctx| Box::pin($func(args, ctx)))
|
||||
Rc::new(|name, args, ctx| Box::pin($func(name, args, ctx)))
|
||||
};
|
||||
}
|
||||
|
||||
@ -51,14 +51,16 @@ std! {
|
||||
///
|
||||
/// This is also the fallback function, which is used when a function name
|
||||
/// cannot be resolved.
|
||||
pub async fn val(mut args: TableValue, _: LayoutContext<'_>) -> Pass<Value> {
|
||||
Pass::commands(match args.take::<SyntaxTree>() {
|
||||
pub async fn val(_: Span, mut args: TableValue, _: LayoutContext<'_>) -> Pass<Value> {
|
||||
let commands = match args.take::<SyntaxTree>() {
|
||||
Some(tree) => vec![LayoutSyntaxTree(tree)],
|
||||
None => vec![],
|
||||
}, Feedback::new())
|
||||
};
|
||||
|
||||
Pass::commands(commands, Feedback::new())
|
||||
}
|
||||
|
||||
/// `dump`: Dumps its arguments.
|
||||
pub async fn dump(args: TableValue, _: LayoutContext<'_>) -> Pass<Value> {
|
||||
/// `dump`: Dumps its arguments into the document.
|
||||
pub async fn dump(_: Span, args: TableValue, _: LayoutContext<'_>) -> Pass<Value> {
|
||||
Pass::okay(Value::Table(args))
|
||||
}
|
||||
|
@ -16,45 +16,55 @@ use super::*;
|
||||
/// - `top`: The top margin (length or relative to height).
|
||||
/// - `bottom`: The bottom margin (length or relative to height).
|
||||
/// - `flip`: Flips custom or paper-defined width and height (boolean).
|
||||
pub async fn page(mut args: TableValue, ctx: LayoutContext<'_>) -> Pass<Value> {
|
||||
pub async fn page(_: Span, mut args: TableValue, ctx: LayoutContext<'_>) -> Pass<Value> {
|
||||
let mut f = Feedback::new();
|
||||
let paper = args.take::<Paper>();
|
||||
let width = args.take_with_key::<_, Length>("width", &mut f);
|
||||
let height = args.take_with_key::<_, Length>("height", &mut f);
|
||||
let margins = args.take_with_key::<_, ScaleLength>("margins", &mut f);
|
||||
let left = args.take_with_key::<_, ScaleLength>("left", &mut f);
|
||||
let right = args.take_with_key::<_, ScaleLength>("right", &mut f);
|
||||
let top = args.take_with_key::<_, ScaleLength>("top", &mut f);
|
||||
let bottom = args.take_with_key::<_, ScaleLength>("bottom", &mut f);
|
||||
let flip = args.take_with_key::<_, bool>("flip", &mut f).unwrap_or(false);
|
||||
args.unexpected(&mut f);
|
||||
|
||||
let mut style = ctx.style.page;
|
||||
|
||||
if let Some(paper) = paper {
|
||||
if let Some(paper) = args.take::<Paper>() {
|
||||
style.class = paper.class;
|
||||
style.size = paper.size();
|
||||
} else if width.is_some() || height.is_some() {
|
||||
style.class = PaperClass::Custom;
|
||||
}
|
||||
|
||||
width.with(|v| style.size.x = v.as_raw());
|
||||
height.with(|v| style.size.y = v.as_raw());
|
||||
margins.with(|v| style.margins.set_all(Some(v)));
|
||||
left.with(|v| style.margins.left = Some(v));
|
||||
right.with(|v| style.margins.right = Some(v));
|
||||
top.with(|v| style.margins.top = Some(v));
|
||||
bottom.with(|v| style.margins.bottom = Some(v));
|
||||
if let Some(width) = args.take_key::<Length>("width", &mut f) {
|
||||
style.class = PaperClass::Custom;
|
||||
style.size.x = width.as_raw();
|
||||
}
|
||||
|
||||
if flip {
|
||||
if let Some(height) = args.take_key::<Length>("height", &mut f) {
|
||||
style.class = PaperClass::Custom;
|
||||
style.size.y = height.as_raw();
|
||||
}
|
||||
|
||||
if let Some(margins) = args.take_key::<ScaleLength>("margins", &mut f) {
|
||||
style.margins.set_all(Some(margins));
|
||||
}
|
||||
|
||||
if let Some(left) = args.take_key::<ScaleLength>("left", &mut f) {
|
||||
style.margins.left = Some(left);
|
||||
}
|
||||
|
||||
if let Some(right) = args.take_key::<ScaleLength>("right", &mut f) {
|
||||
style.margins.right = Some(right);
|
||||
}
|
||||
|
||||
if let Some(top) = args.take_key::<ScaleLength>("top", &mut f) {
|
||||
style.margins.top = Some(top);
|
||||
}
|
||||
|
||||
if let Some(bottom) = args.take_key::<ScaleLength>("bottom", &mut f) {
|
||||
style.margins.bottom = Some(bottom);
|
||||
}
|
||||
|
||||
if args.take_key::<bool>("flip", &mut f).unwrap_or(false) {
|
||||
style.size.swap();
|
||||
}
|
||||
|
||||
args.unexpected(&mut f);
|
||||
Pass::commands(vec![SetPageStyle(style)], f)
|
||||
}
|
||||
|
||||
/// `pagebreak`: Ends the current page.
|
||||
pub async fn pagebreak(args: TableValue, _: LayoutContext<'_>) -> Pass<Value> {
|
||||
pub async fn pagebreak(_: Span, args: TableValue, _: LayoutContext<'_>) -> Pass<Value> {
|
||||
let mut f = Feedback::new();
|
||||
args.unexpected(&mut f);
|
||||
Pass::commands(vec![BreakPage], f)
|
||||
|
@ -6,32 +6,35 @@ use super::*;
|
||||
///
|
||||
/// # Positional arguments
|
||||
/// - The spacing (length or relative to font size).
|
||||
pub async fn h(args: TableValue, ctx: LayoutContext<'_>) -> Pass<Value> {
|
||||
spacing(args, ctx, Horizontal).await
|
||||
pub async fn h(name: Span, args: TableValue, ctx: LayoutContext<'_>) -> Pass<Value> {
|
||||
spacing(name, args, ctx, Horizontal)
|
||||
}
|
||||
|
||||
/// `v`: Add vertical spacing.
|
||||
///
|
||||
/// # Positional arguments
|
||||
/// - The spacing (length or relative to font size).
|
||||
pub async fn v(args: TableValue, ctx: LayoutContext<'_>) -> Pass<Value> {
|
||||
spacing(args, ctx, Vertical).await
|
||||
pub async fn v(name: Span, args: TableValue, ctx: LayoutContext<'_>) -> Pass<Value> {
|
||||
spacing(name, args, ctx, Vertical)
|
||||
}
|
||||
|
||||
async fn spacing(
|
||||
fn spacing(
|
||||
name: Span,
|
||||
mut args: TableValue,
|
||||
ctx: LayoutContext<'_>,
|
||||
axis: SpecAxis,
|
||||
) -> Pass<Value> {
|
||||
let mut f = Feedback::new();
|
||||
let spacing = args.expect::<ScaleLength>(&mut f).map(|s| (axis, s));
|
||||
args.unexpected(&mut f);
|
||||
|
||||
Pass::commands(if let Some((axis, spacing)) = spacing {
|
||||
let spacing = args.expect::<ScaleLength>("spacing", name, &mut f);
|
||||
let commands = if let Some(spacing) = spacing {
|
||||
let axis = axis.to_generic(ctx.axes);
|
||||
let spacing = spacing.raw_scaled(ctx.style.text.font_size());
|
||||
vec![AddSpacing(spacing, SpacingKind::Hard, axis)]
|
||||
} else {
|
||||
vec![]
|
||||
}, f)
|
||||
};
|
||||
|
||||
args.unexpected(&mut f);
|
||||
Pass::commands(commands, f)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user