mirror of
https://github.com/typst/typst
synced 2025-05-21 12:35:29 +08:00
Add Repr
trait (#2269)
This commit is contained in:
parent
57bc614cf4
commit
333e4037fc
@ -21,7 +21,7 @@ use serde::Deserialize;
|
|||||||
use serde_yaml as yaml;
|
use serde_yaml as yaml;
|
||||||
use typst::diag::{bail, StrResult};
|
use typst::diag::{bail, StrResult};
|
||||||
use typst::doc::Frame;
|
use typst::doc::Frame;
|
||||||
use typst::eval::{CastInfo, Func, Library, Module, ParamInfo, Scope, Type, Value};
|
use typst::eval::{CastInfo, Func, Library, Module, ParamInfo, Repr, Scope, Type, Value};
|
||||||
use typst::font::{Font, FontBook};
|
use typst::font::{Font, FontBook};
|
||||||
use typst::geom::{Abs, Smart};
|
use typst::geom::{Abs, Smart};
|
||||||
use typst_library::layout::{Margin, PageElem};
|
use typst_library::layout::{Margin, PageElem};
|
||||||
|
@ -6,7 +6,7 @@ use if_chain::if_chain;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use typst::doc::Frame;
|
use typst::doc::Frame;
|
||||||
use typst::eval::{
|
use typst::eval::{
|
||||||
format_str, AutoValue, CastInfo, Func, Library, NoneValue, Scope, Type, Value,
|
format_str, AutoValue, CastInfo, Func, Library, NoneValue, Repr, Scope, Type, Value,
|
||||||
};
|
};
|
||||||
use typst::geom::Color;
|
use typst::geom::Color;
|
||||||
use typst::syntax::{
|
use typst::syntax::{
|
||||||
@ -1089,14 +1089,14 @@ impl<'a> CompletionContext<'a> {
|
|||||||
docs: Option<&str>,
|
docs: Option<&str>,
|
||||||
) {
|
) {
|
||||||
let at = label.as_deref().map_or(false, |field| !is_ident(field));
|
let at = label.as_deref().map_or(false, |field| !is_ident(field));
|
||||||
let label = label.unwrap_or_else(|| value.repr().into());
|
let label = label.unwrap_or_else(|| value.repr());
|
||||||
|
|
||||||
let detail = docs.map(Into::into).or_else(|| match value {
|
let detail = docs.map(Into::into).or_else(|| match value {
|
||||||
Value::Symbol(_) => None,
|
Value::Symbol(_) => None,
|
||||||
Value::Func(func) => func.docs().map(plain_docs_sentence),
|
Value::Func(func) => func.docs().map(plain_docs_sentence),
|
||||||
v => {
|
v => {
|
||||||
let repr = v.repr();
|
let repr = v.repr();
|
||||||
(repr.as_str() != label).then(|| repr.into())
|
(repr.as_str() != label).then_some(repr)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ use std::fmt::Write;
|
|||||||
use ecow::{eco_format, EcoString};
|
use ecow::{eco_format, EcoString};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use typst::doc::Frame;
|
use typst::doc::Frame;
|
||||||
use typst::eval::{CapturesVisitor, CastInfo, Tracer, Value};
|
use typst::eval::{CapturesVisitor, CastInfo, Repr, Tracer, Value};
|
||||||
use typst::geom::{round_2, Length, Numeric};
|
use typst::geom::{round_2, Length, Numeric};
|
||||||
use typst::syntax::ast::{self, AstNode};
|
use typst::syntax::ast::{self, AstNode};
|
||||||
use typst::syntax::{LinkedNode, Source, SyntaxKind};
|
use typst::syntax::{LinkedNode, Source, SyntaxKind};
|
||||||
@ -83,7 +83,7 @@ fn expr_tooltip(world: &dyn World, leaf: &LinkedNode) -> Option<Tooltip> {
|
|||||||
write!(pieces.last_mut().unwrap(), " (x{count})").unwrap();
|
write!(pieces.last_mut().unwrap(), " (x{count})").unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pieces.push(value.repr().into());
|
pieces.push(value.repr());
|
||||||
last = Some((value, 1));
|
last = Some((value, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use typst::eval::{
|
use typst::eval::{
|
||||||
Datetime, Duration, EvalMode, Module, Never, NoneValue, Plugin, Regex, Version,
|
Datetime, Duration, EvalMode, Module, Never, NoneValue, Plugin, Regex, Repr, Version,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
@ -51,7 +51,7 @@ pub fn repr(
|
|||||||
/// The value whose string representation to produce.
|
/// The value whose string representation to produce.
|
||||||
value: Value,
|
value: Value,
|
||||||
) -> Str {
|
) -> Str {
|
||||||
value.repr()
|
value.repr().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fails with an error.
|
/// Fails with an error.
|
||||||
@ -135,7 +135,11 @@ impl assert {
|
|||||||
if let Some(message) = message {
|
if let Some(message) = message {
|
||||||
bail!("equality assertion failed: {message}");
|
bail!("equality assertion failed: {message}");
|
||||||
} else {
|
} else {
|
||||||
bail!("equality assertion failed: value {left:?} was not equal to {right:?}");
|
bail!(
|
||||||
|
"equality assertion failed: value {} was not equal to {}",
|
||||||
|
left.repr(),
|
||||||
|
right.repr()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(NoneValue)
|
Ok(NoneValue)
|
||||||
@ -165,7 +169,9 @@ impl assert {
|
|||||||
bail!("inequality assertion failed: {message}");
|
bail!("inequality assertion failed: {message}");
|
||||||
} else {
|
} else {
|
||||||
bail!(
|
bail!(
|
||||||
"inequality assertion failed: value {left:?} was equal to {right:?}"
|
"inequality assertion failed: value {} was equal to {}",
|
||||||
|
left.repr(),
|
||||||
|
right.repr()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
use std::fmt::{self, Debug, Formatter, Write};
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use ecow::{eco_vec, EcoVec};
|
use ecow::{eco_vec, EcoVec};
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use typst::eval::Tracer;
|
use typst::eval::{Repr, Tracer};
|
||||||
use typst::model::DelayedErrors;
|
use typst::model::DelayedErrors;
|
||||||
|
|
||||||
use super::{FigureElem, HeadingElem, Numbering, NumberingPattern};
|
use super::{FigureElem, HeadingElem, Numbering, NumberingPattern};
|
||||||
@ -199,7 +198,7 @@ use crate::prelude::*;
|
|||||||
/// documentation for more details on state management in Typst and why it
|
/// documentation for more details on state management in Typst and why it
|
||||||
/// doesn't just use normal variables for counters.
|
/// doesn't just use normal variables for counters.
|
||||||
#[ty(scope)]
|
#[ty(scope)]
|
||||||
#[derive(Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct Counter(CounterKey);
|
pub struct Counter(CounterKey);
|
||||||
|
|
||||||
impl Counter {
|
impl Counter {
|
||||||
@ -452,11 +451,9 @@ impl Counter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Counter {
|
impl Repr for Counter {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
f.write_str("counter(")?;
|
eco_format!("counter({})", self.0.repr())
|
||||||
self.0.fmt(f)?;
|
|
||||||
f.write_char(')')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -465,7 +462,7 @@ cast! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Identifies a counter.
|
/// Identifies a counter.
|
||||||
#[derive(Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub enum CounterKey {
|
pub enum CounterKey {
|
||||||
/// The page counter.
|
/// The page counter.
|
||||||
Page,
|
Page,
|
||||||
@ -495,19 +492,19 @@ cast! {
|
|||||||
v: LocatableSelector => Self::Selector(v.0),
|
v: LocatableSelector => Self::Selector(v.0),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for CounterKey {
|
impl Repr for CounterKey {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
match self {
|
match self {
|
||||||
Self::Page => f.pad("page"),
|
Self::Page => "page".into(),
|
||||||
Self::Selector(selector) => selector.fmt(f),
|
Self::Selector(selector) => selector.repr(),
|
||||||
Self::Str(str) => str.fmt(f),
|
Self::Str(str) => str.repr(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An update to perform on a counter.
|
/// An update to perform on a counter.
|
||||||
#[ty]
|
#[ty]
|
||||||
#[derive(Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub enum CounterUpdate {
|
pub enum CounterUpdate {
|
||||||
/// Set the counter to the specified state.
|
/// Set the counter to the specified state.
|
||||||
Set(CounterState),
|
Set(CounterState),
|
||||||
@ -517,9 +514,9 @@ pub enum CounterUpdate {
|
|||||||
Func(Func),
|
Func(Func),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for CounterUpdate {
|
impl Repr for CounterUpdate {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
f.pad("..")
|
"..".into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::fmt::{self, Debug, Formatter, Write};
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use ecow::{eco_vec, EcoVec};
|
use ecow::{eco_vec, EcoVec};
|
||||||
use typst::eval::Tracer;
|
use typst::eval::{Repr, Tracer};
|
||||||
use typst::model::DelayedErrors;
|
use typst::model::DelayedErrors;
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
@ -181,7 +181,7 @@ use crate::prelude::*;
|
|||||||
/// function to `update` that determines the value of the state based on its
|
/// function to `update` that determines the value of the state based on its
|
||||||
/// previous value.
|
/// previous value.
|
||||||
#[ty(scope)]
|
#[ty(scope)]
|
||||||
#[derive(Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
/// The key that identifies the state.
|
/// The key that identifies the state.
|
||||||
key: Str,
|
key: Str,
|
||||||
@ -335,13 +335,9 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for State {
|
impl Repr for State {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
f.write_str("state(")?;
|
eco_format!("state({}, {})", self.key.repr(), self.init.repr())
|
||||||
self.key.fmt(f)?;
|
|
||||||
f.write_str(", ")?;
|
|
||||||
self.init.fmt(f)?;
|
|
||||||
f.write_char(')')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,7 +347,7 @@ cast! {
|
|||||||
|
|
||||||
/// An update to perform on a state.
|
/// An update to perform on a state.
|
||||||
#[ty]
|
#[ty]
|
||||||
#[derive(Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub enum StateUpdate {
|
pub enum StateUpdate {
|
||||||
/// Set the state to the specified value.
|
/// Set the state to the specified value.
|
||||||
Set(Value),
|
Set(Value),
|
||||||
@ -359,9 +355,9 @@ pub enum StateUpdate {
|
|||||||
Func(Func),
|
Func(Func),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for StateUpdate {
|
impl Repr for StateUpdate {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
f.pad("..")
|
"..".into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ pub use typst::doc::*;
|
|||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use typst::eval::{
|
pub use typst::eval::{
|
||||||
array, cast, dict, format_str, func, scope, ty, Args, Array, Bytes, Cast, Dict,
|
array, cast, dict, format_str, func, scope, ty, Args, Array, Bytes, Cast, Dict,
|
||||||
FromValue, Func, IntoValue, Scope, Str, Symbol, Type, Value, Vm,
|
FromValue, Func, IntoValue, Repr, Scope, Str, Symbol, Type, Value, Vm,
|
||||||
};
|
};
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use typst::geom::*;
|
pub use typst::geom::*;
|
||||||
|
@ -346,6 +346,12 @@ impl Fold for Decoration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Repr for Decoration {
|
||||||
|
fn repr(&self) -> EcoString {
|
||||||
|
eco_format!("{self:?}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cast! {
|
cast! {
|
||||||
type Decoration,
|
type Decoration,
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,9 @@ use std::ops::Range;
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ecow::EcoString;
|
use ecow::{eco_format, EcoString};
|
||||||
|
|
||||||
use crate::eval::{cast, dict, ty, Dict, Value};
|
use crate::eval::{cast, dict, ty, Dict, Repr, Value};
|
||||||
use crate::export::PdfPageLabel;
|
use crate::export::PdfPageLabel;
|
||||||
use crate::font::Font;
|
use crate::font::Font;
|
||||||
use crate::geom::{
|
use crate::geom::{
|
||||||
@ -762,6 +762,12 @@ impl Debug for Meta {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Repr for Meta {
|
||||||
|
fn repr(&self) -> EcoString {
|
||||||
|
eco_format!("{self:?}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A link destination.
|
/// A link destination.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
pub enum Destination {
|
pub enum Destination {
|
||||||
@ -773,6 +779,12 @@ pub enum Destination {
|
|||||||
Location(Location),
|
Location(Location),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Repr for Destination {
|
||||||
|
fn repr(&self) -> EcoString {
|
||||||
|
eco_format!("{self:?}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cast! {
|
cast! {
|
||||||
Destination,
|
Destination,
|
||||||
self => match self {
|
self => match self {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
|
|
||||||
use ecow::{eco_format, EcoVec};
|
use ecow::{eco_format, EcoString, EcoVec};
|
||||||
|
|
||||||
use super::{func, scope, ty, Array, Dict, FromValue, IntoValue, Str, Value};
|
use super::{func, scope, ty, Array, Dict, FromValue, IntoValue, Repr, Str, Value};
|
||||||
use crate::diag::{bail, At, SourceDiagnostic, SourceResult};
|
use crate::diag::{bail, At, SourceDiagnostic, SourceResult};
|
||||||
use crate::syntax::{Span, Spanned};
|
use crate::syntax::{Span, Spanned};
|
||||||
use crate::util::pretty_array_like;
|
use crate::util::pretty_array_like;
|
||||||
@ -47,7 +47,7 @@ pub struct Args {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An argument to a function call: `12` or `draw: false`.
|
/// An argument to a function call: `12` or `draw: false`.
|
||||||
#[derive(Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct Arg {
|
pub struct Arg {
|
||||||
/// The span of the whole argument.
|
/// The span of the whole argument.
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
@ -252,18 +252,23 @@ impl Args {
|
|||||||
|
|
||||||
impl Debug for Args {
|
impl Debug for Args {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
let pieces: Vec<_> =
|
f.debug_list().entries(&self.items).finish()
|
||||||
self.items.iter().map(|arg| eco_format!("{arg:?}")).collect();
|
|
||||||
f.write_str(&pretty_array_like(&pieces, false))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Arg {
|
impl Repr for Args {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
if let Some(name) = &self.name {
|
let pieces = self.items.iter().map(Arg::repr).collect::<Vec<_>>();
|
||||||
f.write_str(name)?;
|
pretty_array_like(&pieces, false).into()
|
||||||
f.write_str(": ")?;
|
}
|
||||||
}
|
}
|
||||||
Debug::fmt(&self.value.v, f)
|
|
||||||
|
impl Repr for Arg {
|
||||||
|
fn repr(&self) -> EcoString {
|
||||||
|
if let Some(name) = &self.name {
|
||||||
|
eco_format!("{}: {}", name, self.value.v.repr())
|
||||||
|
} else {
|
||||||
|
self.value.v.repr()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::num::NonZeroI64;
|
use std::num::NonZeroI64;
|
||||||
use std::ops::{Add, AddAssign};
|
use std::ops::{Add, AddAssign};
|
||||||
|
|
||||||
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
cast, func, ops, scope, ty, Args, Bytes, CastInfo, FromValue, Func, IntoValue,
|
cast, func, ops, scope, ty, Args, Bytes, CastInfo, FromValue, Func, IntoValue,
|
||||||
Reflect, Value, Version, Vm,
|
Reflect, Repr, Value, Version, Vm,
|
||||||
};
|
};
|
||||||
use crate::diag::{At, SourceResult, StrResult};
|
use crate::diag::{At, SourceResult, StrResult};
|
||||||
use crate::eval::ops::{add, mul};
|
use crate::eval::ops::{add, mul};
|
||||||
@ -808,14 +808,23 @@ cast! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Array {
|
impl Debug for Array {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
|
||||||
|
f.debug_list().entries(&self.0).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Repr for Array {
|
||||||
|
fn repr(&self) -> EcoString {
|
||||||
let max = 40;
|
let max = 40;
|
||||||
let mut pieces: Vec<_> =
|
let mut pieces: Vec<_> = self
|
||||||
self.iter().take(max).map(|value| eco_format!("{value:?}")).collect();
|
.iter()
|
||||||
|
.take(max)
|
||||||
|
.map(|value| eco_format!("{}", value.repr()))
|
||||||
|
.collect();
|
||||||
if self.len() > max {
|
if self.len() > max {
|
||||||
pieces.push(eco_format!(".. ({} items omitted)", self.len() - max));
|
pieces.push(eco_format!(".. ({} items omitted)", self.len() - max));
|
||||||
}
|
}
|
||||||
f.write_str(&pretty_array_like(&pieces, self.len() == 1))
|
pretty_array_like(&pieces, self.len() == 1).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use std::fmt::{self, Debug, Formatter};
|
use ecow::EcoString;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use super::{ty, CastInfo, FromValue, IntoValue, Reflect, Type, Value};
|
use super::{ty, CastInfo, FromValue, IntoValue, Reflect, Repr, Type, Value};
|
||||||
use crate::diag::StrResult;
|
use crate::diag::StrResult;
|
||||||
|
|
||||||
/// A value that indicates a smart default.
|
/// A value that indicates a smart default.
|
||||||
@ -12,7 +13,7 @@ use crate::diag::StrResult;
|
|||||||
/// parameter. Setting it to `{auto}` lets Typst automatically determine the
|
/// parameter. Setting it to `{auto}` lets Typst automatically determine the
|
||||||
/// direction from the [text language]($text.lang).
|
/// direction from the [text language]($text.lang).
|
||||||
#[ty(name = "auto")]
|
#[ty(name = "auto")]
|
||||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub struct AutoValue;
|
pub struct AutoValue;
|
||||||
|
|
||||||
impl IntoValue for AutoValue {
|
impl IntoValue for AutoValue {
|
||||||
@ -44,8 +45,8 @@ impl Reflect for AutoValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for AutoValue {
|
impl Repr for AutoValue {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
f.pad("auto")
|
"auto".into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
use super::ty;
|
use ecow::EcoString;
|
||||||
|
|
||||||
|
use super::{ty, Repr};
|
||||||
|
|
||||||
/// A type with two states.
|
/// A type with two states.
|
||||||
///
|
///
|
||||||
@ -13,3 +15,12 @@ use super::ty;
|
|||||||
/// ```
|
/// ```
|
||||||
#[ty(title = "Boolean")]
|
#[ty(title = "Boolean")]
|
||||||
type bool;
|
type bool;
|
||||||
|
|
||||||
|
impl Repr for bool {
|
||||||
|
fn repr(&self) -> EcoString {
|
||||||
|
match self {
|
||||||
|
true => "true".into(),
|
||||||
|
false => "false".into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::Debug;
|
||||||
use std::ops::{Add, AddAssign, Deref};
|
use std::ops::{Add, AddAssign, Deref};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@ -7,7 +7,7 @@ use comemo::Prehashed;
|
|||||||
use ecow::{eco_format, EcoString};
|
use ecow::{eco_format, EcoString};
|
||||||
use serde::{Serialize, Serializer};
|
use serde::{Serialize, Serializer};
|
||||||
|
|
||||||
use super::{cast, func, scope, ty, Array, Reflect, Str, Value};
|
use super::{cast, func, scope, ty, Array, Reflect, Repr, Str, Value};
|
||||||
use crate::diag::{bail, StrResult};
|
use crate::diag::{bail, StrResult};
|
||||||
|
|
||||||
/// A sequence of bytes.
|
/// A sequence of bytes.
|
||||||
@ -38,7 +38,7 @@ use crate::diag::{bail, StrResult};
|
|||||||
/// #str(data.slice(1, 4))
|
/// #str(data.slice(1, 4))
|
||||||
/// ```
|
/// ```
|
||||||
#[ty(scope)]
|
#[ty(scope)]
|
||||||
#[derive(Clone, Hash, Eq, PartialEq)]
|
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||||
pub struct Bytes(Arc<Prehashed<Cow<'static, [u8]>>>);
|
pub struct Bytes(Arc<Prehashed<Cow<'static, [u8]>>>);
|
||||||
|
|
||||||
impl Bytes {
|
impl Bytes {
|
||||||
@ -179,9 +179,9 @@ impl AsRef<[u8]> for Bytes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Bytes {
|
impl Repr for Bytes {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
write!(f, "bytes({})", self.len())
|
eco_format!("bytes({})", self.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ use std::ops::Add;
|
|||||||
|
|
||||||
use ecow::{eco_format, EcoString};
|
use ecow::{eco_format, EcoString};
|
||||||
|
|
||||||
use super::{Type, Value};
|
use super::{Repr, Type, Value};
|
||||||
use crate::diag::{At, SourceResult, StrResult};
|
use crate::diag::{At, SourceResult, StrResult};
|
||||||
use crate::syntax::{Span, Spanned};
|
use crate::syntax::{Span, Spanned};
|
||||||
use crate::util::separated_list;
|
use crate::util::separated_list;
|
||||||
@ -239,7 +239,7 @@ impl CastInfo {
|
|||||||
self.walk(|info| match info {
|
self.walk(|info| match info {
|
||||||
CastInfo::Any => parts.push("anything".into()),
|
CastInfo::Any => parts.push("anything".into()),
|
||||||
CastInfo::Value(value, _) => {
|
CastInfo::Value(value, _) => {
|
||||||
parts.push(value.repr().into());
|
parts.push(value.repr());
|
||||||
if value.ty() == found.ty() {
|
if value.ty() == found.ty() {
|
||||||
matching_type = true;
|
matching_type = true;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt;
|
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::Debug;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::ops::{Add, Sub};
|
use std::ops::{Add, Sub};
|
||||||
|
|
||||||
@ -9,7 +9,7 @@ use time::error::{Format, InvalidFormatDescription};
|
|||||||
use time::macros::format_description;
|
use time::macros::format_description;
|
||||||
use time::{format_description, Month, PrimitiveDateTime};
|
use time::{format_description, Month, PrimitiveDateTime};
|
||||||
|
|
||||||
use super::{cast, func, scope, ty, Dict, Duration, Str, Value, Vm};
|
use super::{cast, func, scope, ty, Dict, Duration, Repr, Str, Value, Vm};
|
||||||
use crate::diag::{bail, StrResult};
|
use crate::diag::{bail, StrResult};
|
||||||
use crate::geom::Smart;
|
use crate::geom::Smart;
|
||||||
use crate::util::pretty_array_like;
|
use crate::util::pretty_array_like;
|
||||||
@ -113,7 +113,7 @@ use crate::World;
|
|||||||
/// components such as `hour` or `minute`, which would only work on datetimes
|
/// components such as `hour` or `minute`, which would only work on datetimes
|
||||||
/// that have a specified time.
|
/// that have a specified time.
|
||||||
#[ty(scope)]
|
#[ty(scope)]
|
||||||
#[derive(Clone, Copy, PartialEq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Hash)]
|
||||||
pub enum Datetime {
|
pub enum Datetime {
|
||||||
/// Representation as a date.
|
/// Representation as a date.
|
||||||
Date(time::Date),
|
Date(time::Date),
|
||||||
@ -426,20 +426,20 @@ impl Datetime {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Datetime {
|
impl Repr for Datetime {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
let year = self.year().map(|y| eco_format!("year: {y}"));
|
let year = self.year().map(|y| eco_format!("year: {}", (y as i64).repr()));
|
||||||
let month = self.month().map(|m| eco_format!("month: {m}"));
|
let month = self.month().map(|m| eco_format!("month: {}", (m as i64).repr()));
|
||||||
let day = self.day().map(|d| eco_format!("day: {d}"));
|
let day = self.day().map(|d| eco_format!("day: {}", (d as i64).repr()));
|
||||||
let hour = self.hour().map(|h| eco_format!("hour: {h}"));
|
let hour = self.hour().map(|h| eco_format!("hour: {}", (h as i64).repr()));
|
||||||
let minute = self.minute().map(|m| eco_format!("minute: {m}"));
|
let minute = self.minute().map(|m| eco_format!("minute: {}", (m as i64).repr()));
|
||||||
let second = self.second().map(|s| eco_format!("second: {s}"));
|
let second = self.second().map(|s| eco_format!("second: {}", (s as i64).repr()));
|
||||||
let filtered = [year, month, day, hour, minute, second]
|
let filtered = [year, month, day, hour, minute, second]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
.collect::<EcoVec<_>>();
|
.collect::<EcoVec<_>>();
|
||||||
|
|
||||||
write!(f, "datetime{}", &pretty_array_like(&filtered, false))
|
eco_format!("datetime{}", &pretty_array_like(&filtered, false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::ops::{Add, AddAssign};
|
use std::ops::{Add, AddAssign};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@ -7,7 +7,7 @@ use ecow::{eco_format, EcoString};
|
|||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
|
||||||
use super::{array, func, scope, ty, Array, Str, Value};
|
use super::{array, func, scope, ty, Array, Repr, Str, Value};
|
||||||
use crate::diag::StrResult;
|
use crate::diag::StrResult;
|
||||||
use crate::syntax::is_ident;
|
use crate::syntax::is_ident;
|
||||||
use crate::util::{pretty_array_like, separated_list, ArcExt};
|
use crate::util::{pretty_array_like, separated_list, ArcExt};
|
||||||
@ -117,7 +117,7 @@ impl Dict {
|
|||||||
pub fn finish(&self, expected: &[&str]) -> StrResult<()> {
|
pub fn finish(&self, expected: &[&str]) -> StrResult<()> {
|
||||||
if let Some((key, _)) = self.iter().next() {
|
if let Some((key, _)) = self.iter().next() {
|
||||||
let parts: Vec<_> = expected.iter().map(|s| eco_format!("\"{s}\"")).collect();
|
let parts: Vec<_> = expected.iter().map(|s| eco_format!("\"{s}\"")).collect();
|
||||||
let mut msg = format!("unexpected key {key:?}, valid keys are ");
|
let mut msg = format!("unexpected key {}, valid keys are ", key.repr());
|
||||||
msg.push_str(&separated_list(&parts, "and"));
|
msg.push_str(&separated_list(&parts, "and"));
|
||||||
return Err(msg.into());
|
return Err(msg.into());
|
||||||
}
|
}
|
||||||
@ -200,9 +200,15 @@ impl Dict {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Dict {
|
impl Debug for Dict {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_map().entries(self.0.iter()).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Repr for Dict {
|
||||||
|
fn repr(&self) -> EcoString {
|
||||||
if self.is_empty() {
|
if self.is_empty() {
|
||||||
return f.write_str("(:)");
|
return "(:)".into();
|
||||||
}
|
}
|
||||||
|
|
||||||
let max = 40;
|
let max = 40;
|
||||||
@ -211,9 +217,9 @@ impl Debug for Dict {
|
|||||||
.take(max)
|
.take(max)
|
||||||
.map(|(key, value)| {
|
.map(|(key, value)| {
|
||||||
if is_ident(key) {
|
if is_ident(key) {
|
||||||
eco_format!("{key}: {value:?}")
|
eco_format!("{key}: {}", value.repr())
|
||||||
} else {
|
} else {
|
||||||
eco_format!("{key:?}: {value:?}")
|
eco_format!("{}: {}", key.repr(), value.repr())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
@ -222,7 +228,7 @@ impl Debug for Dict {
|
|||||||
pieces.push(eco_format!(".. ({} pairs omitted)", self.len() - max));
|
pieces.push(eco_format!(".. ({} pairs omitted)", self.len() - max));
|
||||||
}
|
}
|
||||||
|
|
||||||
f.write_str(&pretty_array_like(&pieces, false))
|
pretty_array_like(&pieces, false).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,15 +316,15 @@ impl From<IndexMap<Str, Value>> for Dict {
|
|||||||
/// The missing key access error message.
|
/// The missing key access error message.
|
||||||
#[cold]
|
#[cold]
|
||||||
fn missing_key(key: &str) -> EcoString {
|
fn missing_key(key: &str) -> EcoString {
|
||||||
eco_format!("dictionary does not contain key {:?}", Str::from(key))
|
eco_format!("dictionary does not contain key {}", key.repr())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The missing key access error message when no default was fiven.
|
/// The missing key access error message when no default was fiven.
|
||||||
#[cold]
|
#[cold]
|
||||||
fn missing_key_no_default(key: &str) -> EcoString {
|
fn missing_key_no_default(key: &str) -> EcoString {
|
||||||
eco_format!(
|
eco_format!(
|
||||||
"dictionary does not contain key {:?} \
|
"dictionary does not contain key {} \
|
||||||
and no default value was specified",
|
and no default value was specified",
|
||||||
Str::from(key)
|
key.repr()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
use ecow::eco_format;
|
use ecow::{eco_format, EcoString};
|
||||||
use std::fmt;
|
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::Debug;
|
||||||
use std::ops::{Add, Div, Mul, Neg, Sub};
|
use std::ops::{Add, Div, Mul, Neg, Sub};
|
||||||
use time::ext::NumericalDuration;
|
use time::ext::NumericalDuration;
|
||||||
|
|
||||||
use super::{func, scope, ty};
|
use super::{func, scope, ty, Repr};
|
||||||
use crate::util::pretty_array_like;
|
use crate::util::pretty_array_like;
|
||||||
|
|
||||||
/// Represents a positive or negative span of time.
|
/// Represents a positive or negative span of time.
|
||||||
#[ty(scope)]
|
#[ty(scope)]
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub struct Duration(time::Duration);
|
pub struct Duration(time::Duration);
|
||||||
|
|
||||||
impl Duration {
|
impl Duration {
|
||||||
@ -111,41 +111,41 @@ impl Duration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Duration {
|
impl Repr for Duration {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
let mut tmp = self.0;
|
let mut tmp = self.0;
|
||||||
let mut vec = Vec::with_capacity(5);
|
let mut vec = Vec::with_capacity(5);
|
||||||
|
|
||||||
let weeks = tmp.whole_seconds() / 604_800.0 as i64;
|
let weeks = tmp.whole_seconds() / 604_800.0 as i64;
|
||||||
if weeks != 0 {
|
if weeks != 0 {
|
||||||
vec.push(eco_format!("weeks: {weeks}"));
|
vec.push(eco_format!("weeks: {}", weeks.repr()));
|
||||||
}
|
}
|
||||||
tmp -= weeks.weeks();
|
tmp -= weeks.weeks();
|
||||||
|
|
||||||
let days = tmp.whole_days();
|
let days = tmp.whole_days();
|
||||||
if days != 0 {
|
if days != 0 {
|
||||||
vec.push(eco_format!("days: {days}"));
|
vec.push(eco_format!("days: {}", days.repr()));
|
||||||
}
|
}
|
||||||
tmp -= days.days();
|
tmp -= days.days();
|
||||||
|
|
||||||
let hours = tmp.whole_hours();
|
let hours = tmp.whole_hours();
|
||||||
if hours != 0 {
|
if hours != 0 {
|
||||||
vec.push(eco_format!("hours: {hours}"));
|
vec.push(eco_format!("hours: {}", hours.repr()));
|
||||||
}
|
}
|
||||||
tmp -= hours.hours();
|
tmp -= hours.hours();
|
||||||
|
|
||||||
let minutes = tmp.whole_minutes();
|
let minutes = tmp.whole_minutes();
|
||||||
if minutes != 0 {
|
if minutes != 0 {
|
||||||
vec.push(eco_format!("minutes: {minutes}"));
|
vec.push(eco_format!("minutes: {}", minutes.repr()));
|
||||||
}
|
}
|
||||||
tmp -= minutes.minutes();
|
tmp -= minutes.minutes();
|
||||||
|
|
||||||
let seconds = tmp.whole_seconds();
|
let seconds = tmp.whole_seconds();
|
||||||
if seconds != 0 {
|
if seconds != 0 {
|
||||||
vec.push(eco_format!("seconds: {seconds}"));
|
vec.push(eco_format!("seconds: {}", seconds.repr()));
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(f, "duration{}", &pretty_array_like(&vec, false))
|
eco_format!("duration{}", &pretty_array_like(&vec, false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::Debug;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use comemo::{Prehashed, Tracked, TrackedMut};
|
use comemo::{Prehashed, Tracked, TrackedMut};
|
||||||
|
use ecow::EcoString;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
@ -118,7 +119,7 @@ pub use typst_macros::func;
|
|||||||
/// [`array.push(value)`]($array.push). These can modify the values they are
|
/// [`array.push(value)`]($array.push). These can modify the values they are
|
||||||
/// called on.
|
/// called on.
|
||||||
#[ty(scope, name = "function")]
|
#[ty(scope, name = "function")]
|
||||||
#[derive(Clone, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
#[allow(clippy::derived_hash_with_manual_eq)]
|
#[allow(clippy::derived_hash_with_manual_eq)]
|
||||||
pub struct Func {
|
pub struct Func {
|
||||||
/// The internal representation.
|
/// The internal representation.
|
||||||
@ -128,7 +129,7 @@ pub struct Func {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The different kinds of function representations.
|
/// The different kinds of function representations.
|
||||||
#[derive(Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
enum Repr {
|
enum Repr {
|
||||||
/// A native Rust function.
|
/// A native Rust function.
|
||||||
Native(Static<NativeFuncData>),
|
Native(Static<NativeFuncData>),
|
||||||
@ -363,11 +364,11 @@ impl Func {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Func {
|
impl super::Repr for Func {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
match self.name() {
|
match self.name() {
|
||||||
Some(name) => write!(f, "{name}"),
|
Some(name) => name.into(),
|
||||||
None => f.write_str("(..) => .."),
|
None => "(..) => ..".into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -412,6 +413,7 @@ pub trait NativeFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Defines a native function.
|
/// Defines a native function.
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct NativeFuncData {
|
pub struct NativeFuncData {
|
||||||
pub function: fn(&mut Vm, &mut Args) -> SourceResult<Value>,
|
pub function: fn(&mut Vm, &mut Args) -> SourceResult<Value>,
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
@ -461,7 +463,7 @@ pub struct ParamInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A user-defined closure.
|
/// A user-defined closure.
|
||||||
#[derive(Hash)]
|
#[derive(Debug, Hash)]
|
||||||
pub(super) struct Closure {
|
pub(super) struct Closure {
|
||||||
/// The closure's syntax node. Must be castable to `ast::Closure`.
|
/// The closure's syntax node. Must be castable to `ast::Closure`.
|
||||||
pub node: SyntaxNode,
|
pub node: SyntaxNode,
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use std::num::{NonZeroI64, NonZeroIsize, NonZeroU64, NonZeroUsize};
|
use std::num::{NonZeroI64, NonZeroIsize, NonZeroU64, NonZeroUsize};
|
||||||
|
|
||||||
use ecow::eco_format;
|
use ecow::{eco_format, EcoString};
|
||||||
|
|
||||||
use super::{cast, func, scope, ty, Str, Value};
|
use super::{cast, func, scope, ty, Repr, Str, Value};
|
||||||
|
|
||||||
/// A whole number.
|
/// A whole number.
|
||||||
///
|
///
|
||||||
@ -51,6 +51,18 @@ impl i64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Repr for i64 {
|
||||||
|
fn repr(&self) -> EcoString {
|
||||||
|
eco_format!("{self}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Repr for f64 {
|
||||||
|
fn repr(&self) -> EcoString {
|
||||||
|
eco_format!("{self}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A value that can be cast to an integer.
|
/// A value that can be cast to an integer.
|
||||||
pub struct ToInt(i64);
|
pub struct ToInt(i64);
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ pub use self::str::{format_str, Regex, Str};
|
|||||||
pub use self::symbol::{symbols, Symbol};
|
pub use self::symbol::{symbols, Symbol};
|
||||||
pub use self::tracer::Tracer;
|
pub use self::tracer::Tracer;
|
||||||
pub use self::ty::{scope, ty, NativeType, NativeTypeData, Type};
|
pub use self::ty::{scope, ty, NativeType, NativeTypeData, Type};
|
||||||
pub use self::value::{Dynamic, Value};
|
pub use self::value::{Dynamic, Repr, Value};
|
||||||
pub use self::version::Version;
|
pub use self::version::Version;
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::Debug;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ecow::{eco_format, EcoString};
|
use ecow::{eco_format, EcoString};
|
||||||
@ -24,7 +24,7 @@ use crate::diag::StrResult;
|
|||||||
/// >>> #(-3)
|
/// >>> #(-3)
|
||||||
/// ```
|
/// ```
|
||||||
#[ty]
|
#[ty]
|
||||||
#[derive(Clone, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
#[allow(clippy::derived_hash_with_manual_eq)]
|
#[allow(clippy::derived_hash_with_manual_eq)]
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
/// The module's name.
|
/// The module's name.
|
||||||
@ -34,7 +34,7 @@ pub struct Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The internal representation.
|
/// The internal representation.
|
||||||
#[derive(Clone, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
struct Repr {
|
struct Repr {
|
||||||
/// The top-level definitions that were bound in this module.
|
/// The top-level definitions that were bound in this module.
|
||||||
scope: Scope,
|
scope: Scope,
|
||||||
@ -100,9 +100,9 @@ impl Module {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Module {
|
impl super::Repr for Module {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
write!(f, "<module {}>", self.name())
|
eco_format!("<module {}>", self.name())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use std::fmt::{self, Debug, Formatter};
|
use ecow::EcoString;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use serde::{Serialize, Serializer};
|
use serde::{Serialize, Serializer};
|
||||||
|
|
||||||
use super::{cast, ty, CastInfo, FromValue, IntoValue, Reflect, Type, Value};
|
use super::{cast, ty, CastInfo, FromValue, IntoValue, Reflect, Repr, Type, Value};
|
||||||
use crate::diag::StrResult;
|
use crate::diag::StrResult;
|
||||||
|
|
||||||
/// A value that indicates the absence of any other value.
|
/// A value that indicates the absence of any other value.
|
||||||
@ -18,7 +19,7 @@ use crate::diag::StrResult;
|
|||||||
/// Not visible: #none
|
/// Not visible: #none
|
||||||
/// ```
|
/// ```
|
||||||
#[ty(name = "none")]
|
#[ty(name = "none")]
|
||||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub struct NoneValue;
|
pub struct NoneValue;
|
||||||
|
|
||||||
impl Reflect for NoneValue {
|
impl Reflect for NoneValue {
|
||||||
@ -50,9 +51,9 @@ impl FromValue for NoneValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for NoneValue {
|
impl Repr for NoneValue {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
f.pad("none")
|
"none".into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
//! Operations on values.
|
//! Operations on values.
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt::Debug;
|
|
||||||
|
|
||||||
use ecow::eco_format;
|
use ecow::eco_format;
|
||||||
|
|
||||||
use super::{format_str, IntoValue, Regex, Value};
|
use super::{format_str, IntoValue, Regex, Repr, Value};
|
||||||
use crate::diag::{bail, StrResult};
|
use crate::diag::{bail, StrResult};
|
||||||
use crate::geom::{Align, Length, Numeric, Rel, Smart, Stroke};
|
use crate::geom::{Align, Length, Numeric, Rel, Smart, Stroke};
|
||||||
use Value::*;
|
use Value::*;
|
||||||
@ -436,9 +435,9 @@ pub fn compare(lhs: &Value, rhs: &Value) -> StrResult<Ordering> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Try to compare two values.
|
/// Try to compare two values.
|
||||||
fn try_cmp_values<T: PartialOrd + Debug>(a: &T, b: &T) -> StrResult<Ordering> {
|
fn try_cmp_values<T: PartialOrd + Repr>(a: &T, b: &T) -> StrResult<Ordering> {
|
||||||
a.partial_cmp(b)
|
a.partial_cmp(b)
|
||||||
.ok_or_else(|| eco_format!("cannot compare {:?} with {:?}", a, b))
|
.ok_or_else(|| eco_format!("cannot compare {} with {}", a.repr(), b.repr()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to compare two datetimes.
|
/// Try to compare two datetimes.
|
||||||
|
@ -288,7 +288,13 @@ impl Plugin {
|
|||||||
|
|
||||||
impl Debug for Plugin {
|
impl Debug for Plugin {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
f.pad("plugin(..)")
|
f.pad("Plugin(..)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl super::Repr for Plugin {
|
||||||
|
fn repr(&self) -> EcoString {
|
||||||
|
"plugin(..)".into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use std::borrow::{Borrow, Cow};
|
use std::borrow::{Borrow, Cow};
|
||||||
use std::fmt::{self, Debug, Display, Formatter, Write};
|
use std::fmt::{self, Debug, Display, Formatter};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::ops::{Add, AddAssign, Deref, Range};
|
use std::ops::{Add, AddAssign, Deref, Range};
|
||||||
|
|
||||||
@ -8,13 +8,14 @@ use serde::{Deserialize, Serialize};
|
|||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
cast, dict, func, scope, ty, Args, Array, Bytes, Dict, Func, IntoValue, Type, Value,
|
cast, dict, func, scope, ty, Args, Array, Bytes, Dict, Func, IntoValue, Repr, Type,
|
||||||
Version, Vm,
|
Value, Version, Vm,
|
||||||
};
|
};
|
||||||
use crate::diag::{bail, At, SourceResult, StrResult};
|
use crate::diag::{bail, At, SourceResult, StrResult};
|
||||||
use crate::geom::Align;
|
use crate::geom::Align;
|
||||||
use crate::model::Label;
|
use crate::model::Label;
|
||||||
use crate::syntax::{Span, Spanned};
|
use crate::syntax::{Span, Spanned};
|
||||||
|
use crate::util::fmt::format_int_with_base;
|
||||||
|
|
||||||
/// Create a new [`Str`] from a format string.
|
/// Create a new [`Str`] from a format string.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
@ -68,7 +69,8 @@ pub use ecow::eco_format;
|
|||||||
/// - `[\t]` for a tab
|
/// - `[\t]` for a tab
|
||||||
/// - `[\u{1f600}]` for a hexadecimal Unicode escape sequence
|
/// - `[\u{1f600}]` for a hexadecimal Unicode escape sequence
|
||||||
#[ty(scope, title = "String")]
|
#[ty(scope, title = "String")]
|
||||||
#[derive(Default, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Default, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct Str(EcoString);
|
pub struct Str(EcoString);
|
||||||
|
|
||||||
@ -616,45 +618,6 @@ cast! {
|
|||||||
v: Str => Self::Str(v),
|
v: Str => Self::Str(v),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Format an integer in a base.
|
|
||||||
fn format_int_with_base(mut n: i64, base: i64) -> EcoString {
|
|
||||||
if n == 0 {
|
|
||||||
return "0".into();
|
|
||||||
}
|
|
||||||
|
|
||||||
// In Rust, `format!("{:x}", -14i64)` is not `-e` but `fffffffffffffff2`.
|
|
||||||
// So we can only use the built-in for decimal, not bin/oct/hex.
|
|
||||||
if base == 10 {
|
|
||||||
return eco_format!("{n}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// The largest output is `to_base(i64::MIN, 2)`, which is 65 chars long.
|
|
||||||
const SIZE: usize = 65;
|
|
||||||
let mut digits = [b'\0'; SIZE];
|
|
||||||
let mut i = SIZE;
|
|
||||||
|
|
||||||
// It's tempting to take the absolute value, but this will fail for i64::MIN.
|
|
||||||
// Instead, we turn n negative, as -i64::MAX is perfectly representable.
|
|
||||||
let negative = n < 0;
|
|
||||||
if n > 0 {
|
|
||||||
n = -n;
|
|
||||||
}
|
|
||||||
|
|
||||||
while n != 0 {
|
|
||||||
let digit = char::from_digit(-(n % base) as u32, base as u32);
|
|
||||||
i -= 1;
|
|
||||||
digits[i] = digit.unwrap_or('?') as u8;
|
|
||||||
n /= base;
|
|
||||||
}
|
|
||||||
|
|
||||||
if negative {
|
|
||||||
i -= 1;
|
|
||||||
digits[i] = b'-';
|
|
||||||
}
|
|
||||||
|
|
||||||
std::str::from_utf8(&digits[i..]).unwrap_or_default().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The out of bounds access error message.
|
/// The out of bounds access error message.
|
||||||
#[cold]
|
#[cold]
|
||||||
fn out_of_bounds(index: i64, len: usize) -> EcoString {
|
fn out_of_bounds(index: i64, len: usize) -> EcoString {
|
||||||
@ -717,18 +680,9 @@ impl Display for Str {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Str {
|
impl Repr for Str {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
f.write_char('"')?;
|
self.as_ref().repr()
|
||||||
for c in self.chars() {
|
|
||||||
match c {
|
|
||||||
'\0' => f.write_str("\\u{0}")?,
|
|
||||||
'\'' => f.write_str("'")?,
|
|
||||||
'"' => f.write_str(r#"\""#)?,
|
|
||||||
_ => Display::fmt(&c.escape_debug(), f)?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.write_char('"')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -836,6 +790,29 @@ cast! {
|
|||||||
v: Str => v.into(),
|
v: Str => v.into(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Repr for &str {
|
||||||
|
fn repr(&self) -> EcoString {
|
||||||
|
let mut r = EcoString::with_capacity(self.len() + 2);
|
||||||
|
r.push('"');
|
||||||
|
for c in self.chars() {
|
||||||
|
match c {
|
||||||
|
'\0' => r.push_str(r"\u{0}"),
|
||||||
|
'\'' => r.push('\''),
|
||||||
|
'"' => r.push_str(r#"\""#),
|
||||||
|
_ => c.escape_debug().for_each(|c| r.push(c)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r.push('"');
|
||||||
|
r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Repr for EcoString {
|
||||||
|
fn repr(&self) -> EcoString {
|
||||||
|
self.as_ref().repr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A regular expression.
|
/// A regular expression.
|
||||||
///
|
///
|
||||||
/// Can be used as a [show rule selector]($styling/#show-rules) and with
|
/// Can be used as a [show rule selector]($styling/#show-rules) and with
|
||||||
@ -856,7 +833,7 @@ cast! {
|
|||||||
/// .split(regex("[,;]")))
|
/// .split(regex("[,;]")))
|
||||||
/// ```
|
/// ```
|
||||||
#[ty(scope)]
|
#[ty(scope)]
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Regex(regex::Regex);
|
pub struct Regex(regex::Regex);
|
||||||
|
|
||||||
impl Regex {
|
impl Regex {
|
||||||
@ -895,9 +872,9 @@ impl Deref for Regex {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Regex {
|
impl Repr for Regex {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
write!(f, "regex({:?})", self.0.as_str())
|
eco_format!("regex({})", self.0.as_str().repr())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ use std::collections::BTreeSet;
|
|||||||
use std::fmt::{self, Debug, Display, Formatter, Write};
|
use std::fmt::{self, Debug, Display, Formatter, Write};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ecow::EcoString;
|
use ecow::{eco_format, EcoString};
|
||||||
use serde::{Serialize, Serializer};
|
use serde::{Serialize, Serializer};
|
||||||
|
|
||||||
use super::{cast, func, scope, ty, Array};
|
use super::{cast, func, scope, ty, Array};
|
||||||
@ -43,11 +43,11 @@ pub use typst_macros::symbols;
|
|||||||
/// $arrow.t.quad$
|
/// $arrow.t.quad$
|
||||||
/// ```
|
/// ```
|
||||||
#[ty(scope)]
|
#[ty(scope)]
|
||||||
#[derive(Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct Symbol(Repr);
|
pub struct Symbol(Repr);
|
||||||
|
|
||||||
/// The internal representation.
|
/// The internal representation.
|
||||||
#[derive(Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
enum Repr {
|
enum Repr {
|
||||||
Single(char),
|
Single(char),
|
||||||
Const(&'static [(&'static str, char)]),
|
Const(&'static [(&'static str, char)]),
|
||||||
@ -55,7 +55,7 @@ enum Repr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A collection of symbols.
|
/// A collection of symbols.
|
||||||
#[derive(Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
enum List {
|
enum List {
|
||||||
Static(&'static [(&'static str, char)]),
|
Static(&'static [(&'static str, char)]),
|
||||||
Runtime(Box<[(EcoString, char)]>),
|
Runtime(Box<[(EcoString, char)]>),
|
||||||
@ -208,15 +208,15 @@ impl Symbol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Symbol {
|
impl Display for Symbol {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
f.write_char(self.get())
|
f.write_char(self.get())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Symbol {
|
impl super::Repr for Symbol {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
f.write_char(self.get())
|
eco_format!("\"{}\"", self.get())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt::{self, Debug, Display, Formatter};
|
use std::fmt::{self, Debug, Display, Formatter};
|
||||||
|
|
||||||
use ecow::eco_format;
|
use ecow::{eco_format, EcoString};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use super::{cast, func, Func, NativeFuncData, Scope, Value};
|
use super::{cast, func, Func, NativeFuncData, Repr, Scope, Value};
|
||||||
use crate::diag::StrResult;
|
use crate::diag::StrResult;
|
||||||
use crate::util::Static;
|
use crate::util::Static;
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ pub use typst_macros::{scope, ty};
|
|||||||
/// - The `{in}` operator on a type and a dictionary will evaluate to `{true}`
|
/// - The `{in}` operator on a type and a dictionary will evaluate to `{true}`
|
||||||
/// if the dictionary has a string key matching the type's name
|
/// if the dictionary has a string key matching the type's name
|
||||||
#[ty(scope)]
|
#[ty(scope)]
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct Type(Static<NativeTypeData>);
|
pub struct Type(Static<NativeTypeData>);
|
||||||
|
|
||||||
impl Type {
|
impl Type {
|
||||||
@ -139,9 +139,9 @@ impl Type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Type {
|
impl Repr for Type {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
f.pad(self.long_name())
|
self.long_name().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,6 +180,7 @@ pub trait NativeType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Defines a native type.
|
/// Defines a native type.
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct NativeTypeData {
|
pub struct NativeTypeData {
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
pub long_name: &'static str,
|
pub long_name: &'static str,
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ecow::eco_format;
|
use ecow::{eco_format, EcoString};
|
||||||
use serde::de::value::{MapAccessDeserializer, SeqAccessDeserializer};
|
use serde::de::value::{MapAccessDeserializer, SeqAccessDeserializer};
|
||||||
use serde::de::{Error, MapAccess, SeqAccess, Visitor};
|
use serde::de::{Error, MapAccess, SeqAccess, Visitor};
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
@ -12,9 +12,9 @@ use siphasher::sip128::{Hasher128, SipHasher13};
|
|||||||
use typst::eval::Duration;
|
use typst::eval::Duration;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
fields, format_str, ops, Args, Array, AutoValue, Bytes, CastInfo, Content, Dict,
|
fields, ops, Args, Array, AutoValue, Bytes, CastInfo, Content, Dict, FromValue, Func,
|
||||||
FromValue, Func, IntoValue, Module, NativeType, NoneValue, Plugin, Reflect, Scope,
|
IntoValue, Module, NativeType, NoneValue, Plugin, Reflect, Scope, Str, Symbol, Type,
|
||||||
Str, Symbol, Type, Version,
|
Version,
|
||||||
};
|
};
|
||||||
use crate::diag::StrResult;
|
use crate::diag::StrResult;
|
||||||
use crate::eval::Datetime;
|
use crate::eval::Datetime;
|
||||||
@ -23,7 +23,7 @@ use crate::model::{Label, Styles};
|
|||||||
use crate::syntax::{ast, Span};
|
use crate::syntax::{ast, Span};
|
||||||
|
|
||||||
/// A computational value.
|
/// A computational value.
|
||||||
#[derive(Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
/// The value that indicates the absence of a meaningful value.
|
/// The value that indicates the absence of a meaningful value.
|
||||||
#[default]
|
#[default]
|
||||||
@ -90,7 +90,7 @@ impl Value {
|
|||||||
/// Create a new dynamic value.
|
/// Create a new dynamic value.
|
||||||
pub fn dynamic<T>(any: T) -> Self
|
pub fn dynamic<T>(any: T) -> Self
|
||||||
where
|
where
|
||||||
T: Debug + NativeType + PartialEq + Hash + Sync + Send + 'static,
|
T: Debug + Repr + NativeType + PartialEq + Hash + Sync + Send + 'static,
|
||||||
{
|
{
|
||||||
Self::Dyn(Dynamic::new(any))
|
Self::Dyn(Dynamic::new(any))
|
||||||
}
|
}
|
||||||
@ -194,11 +194,6 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the debug representation of the value.
|
|
||||||
pub fn repr(&self) -> Str {
|
|
||||||
format_str!("{self:?}")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the display representation of the value.
|
/// Return the display representation of the value.
|
||||||
pub fn display(self) -> Content {
|
pub fn display(self) -> Content {
|
||||||
match self {
|
match self {
|
||||||
@ -210,7 +205,7 @@ impl Value {
|
|||||||
Self::Symbol(v) => item!(text)(v.get().into()),
|
Self::Symbol(v) => item!(text)(v.get().into()),
|
||||||
Self::Content(v) => v,
|
Self::Content(v) => v,
|
||||||
Self::Module(module) => module.content(),
|
Self::Module(module) => module.content(),
|
||||||
_ => item!(raw)(self.repr().into(), Some("typc".into()), false),
|
_ => item!(raw)(self.repr(), Some("typc".into()), false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,38 +219,38 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Value {
|
impl Repr for Value {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
match self {
|
match self {
|
||||||
Self::None => Debug::fmt(&NoneValue, f),
|
Self::None => NoneValue.repr(),
|
||||||
Self::Auto => Debug::fmt(&AutoValue, f),
|
Self::Auto => AutoValue.repr(),
|
||||||
Self::Bool(v) => Debug::fmt(v, f),
|
Self::Bool(v) => v.repr(),
|
||||||
Self::Int(v) => Debug::fmt(v, f),
|
Self::Int(v) => v.repr(),
|
||||||
Self::Float(v) => Debug::fmt(v, f),
|
Self::Float(v) => v.repr(),
|
||||||
Self::Length(v) => Debug::fmt(v, f),
|
Self::Length(v) => v.repr(),
|
||||||
Self::Angle(v) => Debug::fmt(v, f),
|
Self::Angle(v) => v.repr(),
|
||||||
Self::Ratio(v) => Debug::fmt(v, f),
|
Self::Ratio(v) => v.repr(),
|
||||||
Self::Relative(v) => Debug::fmt(v, f),
|
Self::Relative(v) => v.repr(),
|
||||||
Self::Fraction(v) => Debug::fmt(v, f),
|
Self::Fraction(v) => v.repr(),
|
||||||
Self::Color(v) => Debug::fmt(v, f),
|
Self::Color(v) => v.repr(),
|
||||||
Self::Gradient(v) => Debug::fmt(v, f),
|
Self::Gradient(v) => v.repr(),
|
||||||
Self::Symbol(v) => Debug::fmt(v, f),
|
Self::Symbol(v) => v.repr(),
|
||||||
Self::Version(v) => Debug::fmt(v, f),
|
Self::Version(v) => v.repr(),
|
||||||
Self::Str(v) => Debug::fmt(v, f),
|
Self::Str(v) => v.repr(),
|
||||||
Self::Bytes(v) => Debug::fmt(v, f),
|
Self::Bytes(v) => v.repr(),
|
||||||
Self::Label(v) => Debug::fmt(v, f),
|
Self::Label(v) => v.repr(),
|
||||||
Self::Datetime(v) => Debug::fmt(v, f),
|
Self::Datetime(v) => v.repr(),
|
||||||
Self::Duration(v) => Debug::fmt(v, f),
|
Self::Duration(v) => v.repr(),
|
||||||
Self::Content(v) => Debug::fmt(v, f),
|
Self::Content(v) => v.repr(),
|
||||||
Self::Styles(v) => Debug::fmt(v, f),
|
Self::Styles(v) => v.repr(),
|
||||||
Self::Array(v) => Debug::fmt(v, f),
|
Self::Array(v) => v.repr(),
|
||||||
Self::Dict(v) => Debug::fmt(v, f),
|
Self::Dict(v) => v.repr(),
|
||||||
Self::Func(v) => Debug::fmt(v, f),
|
Self::Func(v) => v.repr(),
|
||||||
Self::Args(v) => Debug::fmt(v, f),
|
Self::Args(v) => v.repr(),
|
||||||
Self::Type(v) => Debug::fmt(v, f),
|
Self::Type(v) => v.repr(),
|
||||||
Self::Module(v) => Debug::fmt(v, f),
|
Self::Module(v) => v.repr(),
|
||||||
Self::Plugin(v) => Debug::fmt(v, f),
|
Self::Plugin(v) => v.repr(),
|
||||||
Self::Dyn(v) => Debug::fmt(v, f),
|
Self::Dyn(v) => v.repr(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -452,7 +447,7 @@ impl<'de> Visitor<'de> for ValueVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A value that is not part of the built-in enum.
|
/// A value that is not part of the built-in enum.
|
||||||
#[derive(Clone, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
#[allow(clippy::derived_hash_with_manual_eq)]
|
#[allow(clippy::derived_hash_with_manual_eq)]
|
||||||
pub struct Dynamic(Arc<dyn Bounds>);
|
pub struct Dynamic(Arc<dyn Bounds>);
|
||||||
|
|
||||||
@ -460,7 +455,7 @@ impl Dynamic {
|
|||||||
/// Create a new instance from any value that satisfies the required bounds.
|
/// Create a new instance from any value that satisfies the required bounds.
|
||||||
pub fn new<T>(any: T) -> Self
|
pub fn new<T>(any: T) -> Self
|
||||||
where
|
where
|
||||||
T: Debug + NativeType + PartialEq + Hash + Sync + Send + 'static,
|
T: Debug + Repr + NativeType + PartialEq + Hash + Sync + Send + 'static,
|
||||||
{
|
{
|
||||||
Self(Arc::new(any))
|
Self(Arc::new(any))
|
||||||
}
|
}
|
||||||
@ -481,9 +476,9 @@ impl Dynamic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Dynamic {
|
impl Repr for Dynamic {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
Debug::fmt(&self.0, f)
|
self.0.repr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,7 +488,13 @@ impl PartialEq for Dynamic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Bounds: Debug + Sync + Send + 'static {
|
/// A trait that defines the `repr` of a Typst value.
|
||||||
|
pub trait Repr {
|
||||||
|
/// Return the debug representation of the value.
|
||||||
|
fn repr(&self) -> EcoString;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Bounds: Debug + Repr + Sync + Send + 'static {
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
fn dyn_eq(&self, other: &Dynamic) -> bool;
|
fn dyn_eq(&self, other: &Dynamic) -> bool;
|
||||||
fn dyn_ty(&self) -> Type;
|
fn dyn_ty(&self) -> Type;
|
||||||
@ -502,7 +503,7 @@ trait Bounds: Debug + Sync + Send + 'static {
|
|||||||
|
|
||||||
impl<T> Bounds for T
|
impl<T> Bounds for T
|
||||||
where
|
where
|
||||||
T: Debug + NativeType + PartialEq + Hash + Sync + Send + 'static,
|
T: Debug + Repr + NativeType + PartialEq + Hash + Sync + Send + 'static,
|
||||||
{
|
{
|
||||||
fn as_any(&self) -> &dyn Any {
|
fn as_any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
@ -631,7 +632,7 @@ mod tests {
|
|||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn test(value: impl IntoValue, exp: &str) {
|
fn test(value: impl IntoValue, exp: &str) {
|
||||||
assert_eq!(format!("{:?}", value.into_value()), exp);
|
assert_eq!(value.into_value().repr(), exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt::{self, Debug, Display, Formatter, Write};
|
use std::fmt::{self, Display, Formatter, Write};
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
|
|
||||||
use ecow::{eco_format, EcoVec};
|
use ecow::{eco_format, EcoString, EcoVec};
|
||||||
|
|
||||||
use super::{cast, func, scope, ty};
|
use super::{cast, func, scope, ty, Repr};
|
||||||
use crate::diag::{bail, error, StrResult};
|
use crate::diag::{bail, error, StrResult};
|
||||||
use crate::util::pretty_array_like;
|
use crate::util::pretty_array_like;
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ use crate::util::pretty_array_like;
|
|||||||
/// The first three components have names: `major`, `minor`, `patch`. All
|
/// The first three components have names: `major`, `minor`, `patch`. All
|
||||||
/// components after that do not have names.
|
/// components after that do not have names.
|
||||||
#[ty(scope)]
|
#[ty(scope)]
|
||||||
#[derive(Default, Clone, Hash)]
|
#[derive(Debug, Default, Clone, Hash)]
|
||||||
#[allow(clippy::derived_hash_with_manual_eq)]
|
#[allow(clippy::derived_hash_with_manual_eq)]
|
||||||
pub struct Version(EcoVec<u32>);
|
pub struct Version(EcoVec<u32>);
|
||||||
|
|
||||||
@ -165,7 +165,7 @@ impl PartialEq for Version {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Version {
|
impl Display for Version {
|
||||||
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
for &v in &self.0 {
|
for &v in &self.0 {
|
||||||
if !first {
|
if !first {
|
||||||
@ -178,11 +178,10 @@ impl Display for Version {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Version {
|
impl Repr for Version {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
f.write_str("version")?;
|
|
||||||
let parts: Vec<_> = self.0.iter().map(|v| eco_format!("{v}")).collect();
|
let parts: Vec<_> = self.0.iter().map(|v| eco_format!("{v}")).collect();
|
||||||
f.write_str(&pretty_array_like(&parts, false))
|
eco_format!("version{}", &pretty_array_like(&parts, false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ use super::color::PaintEncode;
|
|||||||
use super::extg::ExternalGraphicsState;
|
use super::extg::ExternalGraphicsState;
|
||||||
use super::{deflate, AbsExt, EmExt, PdfContext, RefExt};
|
use super::{deflate, AbsExt, EmExt, PdfContext, RefExt};
|
||||||
use crate::doc::{Destination, Frame, FrameItem, GroupItem, Meta, TextItem};
|
use crate::doc::{Destination, Frame, FrameItem, GroupItem, Meta, TextItem};
|
||||||
|
use crate::eval::Repr;
|
||||||
use crate::font::Font;
|
use crate::font::Font;
|
||||||
use crate::geom::{
|
use crate::geom::{
|
||||||
self, Abs, Em, FixedStroke, Geometry, LineCap, LineJoin, Numeric, Paint, Point,
|
self, Abs, Em, FixedStroke, Geometry, LineCap, LineJoin, Numeric, Paint, Point,
|
||||||
@ -710,6 +711,12 @@ pub struct PdfPageLabel {
|
|||||||
pub offset: Option<NonZeroUsize>,
|
pub offset: Option<NonZeroUsize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Repr for PdfPageLabel {
|
||||||
|
fn repr(&self) -> EcoString {
|
||||||
|
eco_format!("{self:?}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A PDF page label number style.
|
/// A PDF page label number style.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub enum PdfPageLabelStyle {
|
pub enum PdfPageLabelStyle {
|
||||||
|
@ -133,7 +133,7 @@ impl Hash for Font {
|
|||||||
|
|
||||||
impl Debug for Font {
|
impl Debug for Font {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
write!(f, "Font({},{:?})", self.info().family, self.info().variant)
|
write!(f, "Font({}, {:?})", self.info().family, self.info().variant)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
use ecow::EcoString;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::eval::{cast, Cast, IntoValue};
|
use crate::eval::{cast, Cast, IntoValue, Repr};
|
||||||
use crate::geom::Ratio;
|
use crate::geom::Ratio;
|
||||||
|
|
||||||
/// Properties that distinguish a font from other fonts in the same family.
|
/// Properties that distinguish a font from other fonts in the same family.
|
||||||
@ -176,7 +177,7 @@ cast! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The width of a font.
|
/// The width of a font.
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct FontStretch(u16);
|
pub struct FontStretch(u16);
|
||||||
@ -247,10 +248,9 @@ impl Default for FontStretch {
|
|||||||
Self::NORMAL
|
Self::NORMAL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Repr for FontStretch {
|
||||||
impl Debug for FontStretch {
|
fn repr(&self) -> EcoString {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
self.to_ratio().repr()
|
||||||
self.to_ratio().fmt(f)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,6 +291,6 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_font_stretch_debug() {
|
fn test_font_stretch_debug() {
|
||||||
assert_eq!(format!("{:?}", FontStretch::EXPANDED), "125%")
|
assert_eq!(FontStretch::EXPANDED.repr(), "125%")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// An absolute length.
|
/// An absolute length.
|
||||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub struct Abs(Scalar);
|
pub struct Abs(Scalar);
|
||||||
|
|
||||||
impl Abs {
|
impl Abs {
|
||||||
@ -133,9 +133,9 @@ impl Numeric for Abs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Abs {
|
impl Repr for Abs {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
write!(f, "{}pt", round_2(self.to_pt()))
|
format_float(self.to_pt(), Some(2), "pt")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +220,7 @@ cast! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Different units of absolute measurement.
|
/// Different units of absolute measurement.
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub enum AbsUnit {
|
pub enum AbsUnit {
|
||||||
/// Points.
|
/// Points.
|
||||||
Pt,
|
Pt,
|
||||||
@ -244,17 +244,6 @@ impl AbsUnit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for AbsUnit {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
f.pad(match self {
|
|
||||||
AbsUnit::Mm => "mm",
|
|
||||||
AbsUnit::Pt => "pt",
|
|
||||||
AbsUnit::Cm => "cm",
|
|
||||||
AbsUnit::In => "in",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -42,7 +42,7 @@ use super::*;
|
|||||||
/// #left.y (none)
|
/// #left.y (none)
|
||||||
/// ```
|
/// ```
|
||||||
#[ty(scope, name = "alignment")]
|
#[ty(scope, name = "alignment")]
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub enum Align {
|
pub enum Align {
|
||||||
H(HAlign),
|
H(HAlign),
|
||||||
V(VAlign),
|
V(VAlign),
|
||||||
@ -149,12 +149,12 @@ impl Add for Align {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Align {
|
impl Repr for Align {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
match self {
|
match self {
|
||||||
Self::H(x) => x.fmt(f),
|
Self::H(x) => x.repr(),
|
||||||
Self::V(y) => y.fmt(f),
|
Self::V(y) => y.repr(),
|
||||||
Self::Both(x, y) => write!(f, "{x:?} + {y:?}"),
|
Self::Both(x, y) => eco_format!("{} + {}", x.repr(), y.repr()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -195,7 +195,7 @@ cast! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Where to align something horizontally.
|
/// Where to align something horizontally.
|
||||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub enum HAlign {
|
pub enum HAlign {
|
||||||
#[default]
|
#[default]
|
||||||
Start,
|
Start,
|
||||||
@ -229,15 +229,15 @@ impl HAlign {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for HAlign {
|
impl Repr for HAlign {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
f.pad(match self {
|
match self {
|
||||||
Self::Start => "start",
|
Self::Start => "start".into(),
|
||||||
Self::Left => "left",
|
Self::Left => "left".into(),
|
||||||
Self::Center => "center",
|
Self::Center => "center".into(),
|
||||||
Self::Right => "right",
|
Self::Right => "right".into(),
|
||||||
Self::End => "end",
|
Self::End => "end".into(),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,12 +268,12 @@ cast! {
|
|||||||
self => Align::H(self).into_value(),
|
self => Align::H(self).into_value(),
|
||||||
align: Align => match align {
|
align: Align => match align {
|
||||||
Align::H(v) => v,
|
Align::H(v) => v,
|
||||||
v => bail!("expected `start`, `left`, `center`, `right`, or `end`, found {v:?}"),
|
v => bail!("expected `start`, `left`, `center`, `right`, or `end`, found {}", v.repr()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Where to align something vertically.
|
/// Where to align something vertically.
|
||||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub enum VAlign {
|
pub enum VAlign {
|
||||||
#[default]
|
#[default]
|
||||||
Top,
|
Top,
|
||||||
@ -301,13 +301,13 @@ impl VAlign {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for VAlign {
|
impl Repr for VAlign {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
f.pad(match self {
|
match self {
|
||||||
Self::Top => "top",
|
Self::Top => "top".into(),
|
||||||
Self::Horizon => "horizon",
|
Self::Horizon => "horizon".into(),
|
||||||
Self::Bottom => "bottom",
|
Self::Bottom => "bottom".into(),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,7 +330,7 @@ cast! {
|
|||||||
self => Align::V(self).into_value(),
|
self => Align::V(self).into_value(),
|
||||||
align: Align => match align {
|
align: Align => match align {
|
||||||
Align::V(v) => v,
|
Align::V(v) => v,
|
||||||
v => bail!("expected `top`, `horizon`, or `bottom`, found {v:?}"),
|
v => bail!("expected `top`, `horizon`, or `bottom`, found {}", v.repr()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,7 +338,7 @@ cast! {
|
|||||||
///
|
///
|
||||||
/// For horizontal alignment, start is globally left and for vertical alignment
|
/// For horizontal alignment, start is globally left and for vertical alignment
|
||||||
/// it is globally top.
|
/// it is globally top.
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub enum FixedAlign {
|
pub enum FixedAlign {
|
||||||
Start,
|
Start,
|
||||||
Center,
|
Center,
|
||||||
@ -357,16 +357,6 @@ impl FixedAlign {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for FixedAlign {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
f.pad(match self {
|
|
||||||
Self::Start => "start",
|
|
||||||
Self::Center => "center",
|
|
||||||
Self::End => "end",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Side> for FixedAlign {
|
impl From<Side> for FixedAlign {
|
||||||
fn from(side: Side) -> Self {
|
fn from(side: Side) -> Self {
|
||||||
match side {
|
match side {
|
||||||
|
@ -12,7 +12,7 @@ use super::*;
|
|||||||
/// #rotate(10deg)[Hello there!]
|
/// #rotate(10deg)[Hello there!]
|
||||||
/// ```
|
/// ```
|
||||||
#[ty(scope)]
|
#[ty(scope)]
|
||||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub struct Angle(Scalar);
|
pub struct Angle(Scalar);
|
||||||
|
|
||||||
impl Angle {
|
impl Angle {
|
||||||
@ -119,9 +119,9 @@ impl Numeric for Angle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Angle {
|
impl Repr for Angle {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
write!(f, "{}deg", round_2(self.to_deg()))
|
format_float(self.to_deg(), Some(2), "deg")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +187,7 @@ impl Sum for Angle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Different units of angular measurement.
|
/// Different units of angular measurement.
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub enum AngleUnit {
|
pub enum AngleUnit {
|
||||||
/// Radians.
|
/// Radians.
|
||||||
Rad,
|
Rad,
|
||||||
@ -205,15 +205,6 @@ impl AngleUnit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for AngleUnit {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
f.pad(match self {
|
|
||||||
Self::Rad => "rad",
|
|
||||||
Self::Deg => "deg",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A quadrant of the Cartesian plane.
|
/// A quadrant of the Cartesian plane.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub enum Quadrant {
|
pub enum Quadrant {
|
||||||
|
@ -156,7 +156,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The two layouting axes.
|
/// The two layouting axes.
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub enum Axis {
|
pub enum Axis {
|
||||||
/// The horizontal axis.
|
/// The horizontal axis.
|
||||||
X,
|
X,
|
||||||
@ -182,27 +182,16 @@ impl Axis {
|
|||||||
Self::Y => Self::X,
|
Self::Y => Self::X,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A description of this axis' direction.
|
|
||||||
pub fn description(self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
Self::X => "horizontal",
|
|
||||||
Self::Y => "vertical",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for Axis {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
f.pad(self.description())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cast! {
|
cast! {
|
||||||
Axis,
|
Axis,
|
||||||
self => self.description().into_value(),
|
self => match self {
|
||||||
|
Self::X => "horizontal".into_value(),
|
||||||
|
Self::Y => "vertical".into_value(),
|
||||||
|
},
|
||||||
"horizontal" => Self::X,
|
"horizontal" => Self::X,
|
||||||
"vertical" => Self::X,
|
"vertical" => Self::Y,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Axes<Option<T>> {
|
impl<T> Axes<Option<T>> {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use ecow::{eco_format, EcoString, EcoVec};
|
use ecow::EcoVec;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use palette::encoding::{self, Linear};
|
use palette::encoding::{self, Linear};
|
||||||
use palette::{Darken, Desaturate, FromColor, Lighten, RgbHue, Saturate, ShiftHue};
|
use palette::{Darken, Desaturate, FromColor, Lighten, RgbHue, Saturate, ShiftHue};
|
||||||
@ -185,7 +185,7 @@ const ANGLE_EPSILON: f32 = 1e-5;
|
|||||||
///
|
///
|
||||||
/// Feel free to use or create a package with other presets useful to you!
|
/// Feel free to use or create a package with other presets useful to you!
|
||||||
#[ty(scope)]
|
#[ty(scope)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum Color {
|
pub enum Color {
|
||||||
/// A 32-bit luma color.
|
/// A 32-bit luma color.
|
||||||
Luma(Luma),
|
Luma(Luma),
|
||||||
@ -1223,106 +1223,101 @@ impl Color {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Color {
|
impl Repr for Color {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
match self {
|
match self {
|
||||||
Self::Luma(c) => write!(f, "luma({:?})", Ratio::new(c.luma as _)),
|
Self::Luma(c) => eco_format!("luma({})", Ratio::new(c.luma as _).repr()),
|
||||||
Self::Rgba(_) => write!(f, "rgb({:?})", self.to_hex()),
|
Self::Rgba(_) => eco_format!("rgb({})", self.to_hex().repr()),
|
||||||
Self::LinearRgb(c) => {
|
Self::LinearRgb(c) => {
|
||||||
if c.alpha == 1.0 {
|
if c.alpha == 1.0 {
|
||||||
write!(
|
eco_format!(
|
||||||
f,
|
"color.linear-rgb({}, {}, {})",
|
||||||
"color.linear-rgb({:?}, {:?}, {:?})",
|
Ratio::new(c.red as _).repr(),
|
||||||
Ratio::new(c.red as _),
|
Ratio::new(c.green as _).repr(),
|
||||||
Ratio::new(c.green as _),
|
Ratio::new(c.blue as _).repr(),
|
||||||
Ratio::new(c.blue as _),
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
write!(
|
eco_format!(
|
||||||
f,
|
"color.linear-rgb({}, {}, {}, {})",
|
||||||
"color.linear-rgb({:?}, {:?}, {:?}, {:?})",
|
Ratio::new(c.red as _).repr(),
|
||||||
Ratio::new(c.red as _),
|
Ratio::new(c.green as _).repr(),
|
||||||
Ratio::new(c.green as _),
|
Ratio::new(c.blue as _).repr(),
|
||||||
Ratio::new(c.blue as _),
|
Ratio::new(c.alpha as _).repr(),
|
||||||
Ratio::new(c.alpha as _),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::Cmyk(c) => {
|
Self::Cmyk(c) => {
|
||||||
write!(
|
eco_format!(
|
||||||
f,
|
"rgb({}, {}, {}, {})",
|
||||||
"rgb({:?}, {:?}, {:?}, {:?})",
|
Ratio::new(c.c as _).repr(),
|
||||||
Ratio::new(c.c as _),
|
Ratio::new(c.m as _).repr(),
|
||||||
Ratio::new(c.m as _),
|
Ratio::new(c.y as _).repr(),
|
||||||
Ratio::new(c.y as _),
|
Ratio::new(c.k as _).repr(),
|
||||||
Ratio::new(c.k as _),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Self::Oklab(c) => {
|
Self::Oklab(c) => {
|
||||||
if c.alpha == 1.0 {
|
if c.alpha == 1.0 {
|
||||||
write!(
|
eco_format!(
|
||||||
f,
|
"oklab({}, {}, {})",
|
||||||
"oklab({:?}, {:.3}, {:.3})",
|
Ratio::new(c.l as _).repr(),
|
||||||
Ratio::new(c.l as _),
|
format_float(c.a as _, Some(3), ""),
|
||||||
(c.a * 1000.0).round() / 1000.0,
|
format_float(c.b as _, Some(3), ""),
|
||||||
(c.b * 1000.0).round() / 1000.0,
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
write!(
|
eco_format!(
|
||||||
f,
|
"oklab({}, {}, {}, {})",
|
||||||
"oklab({:?}, {:?}, {:?}, {:?})",
|
Ratio::new(c.l as _).repr(),
|
||||||
Ratio::new(c.l as _),
|
format_float(c.a as _, Some(3), ""),
|
||||||
(c.a * 1000.0).round() / 1000.0,
|
format_float(c.b as _, Some(3), ""),
|
||||||
(c.b * 1000.0).round() / 1000.0,
|
Ratio::new(c.alpha as _).repr(),
|
||||||
Ratio::new(c.alpha as _),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::Hsl(c) => {
|
Self::Hsl(c) => {
|
||||||
if c.alpha == 1.0 {
|
if c.alpha == 1.0 {
|
||||||
write!(
|
eco_format!(
|
||||||
f,
|
"color.hsl({}, {}, {})",
|
||||||
"color.hsl({:?}, {:?}, {:?})",
|
|
||||||
Angle::deg(
|
Angle::deg(
|
||||||
c.hue.into_degrees().rem_euclid(360.0 + ANGLE_EPSILON) as _
|
c.hue.into_degrees().rem_euclid(360.0 + ANGLE_EPSILON) as _
|
||||||
),
|
)
|
||||||
Ratio::new(c.saturation as _),
|
.repr(),
|
||||||
Ratio::new(c.lightness as _),
|
Ratio::new(c.saturation as _).repr(),
|
||||||
|
Ratio::new(c.lightness as _).repr(),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
write!(
|
eco_format!(
|
||||||
f,
|
"color.hsl({}, {}, {}, {})",
|
||||||
"color.hsl({:?}, {:?}, {:?}, {:?})",
|
|
||||||
Angle::deg(
|
Angle::deg(
|
||||||
c.hue.into_degrees().rem_euclid(360.0 + ANGLE_EPSILON) as _
|
c.hue.into_degrees().rem_euclid(360.0 + ANGLE_EPSILON) as _
|
||||||
),
|
)
|
||||||
Ratio::new(c.saturation as _),
|
.repr(),
|
||||||
Ratio::new(c.lightness as _),
|
Ratio::new(c.saturation as _).repr(),
|
||||||
Ratio::new(c.alpha as _),
|
Ratio::new(c.lightness as _).repr(),
|
||||||
|
Ratio::new(c.alpha as _).repr(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::Hsv(c) => {
|
Self::Hsv(c) => {
|
||||||
if c.alpha == 1.0 {
|
if c.alpha == 1.0 {
|
||||||
write!(
|
eco_format!(
|
||||||
f,
|
"color.hsv({}, {}, {})",
|
||||||
"color.hsv({:?}, {:?}, {:?})",
|
|
||||||
Angle::deg(
|
Angle::deg(
|
||||||
c.hue.into_degrees().rem_euclid(360.0 + ANGLE_EPSILON) as _
|
c.hue.into_degrees().rem_euclid(360.0 + ANGLE_EPSILON) as _
|
||||||
),
|
)
|
||||||
Ratio::new(c.saturation as _),
|
.repr(),
|
||||||
Ratio::new(c.value as _),
|
Ratio::new(c.saturation as _).repr(),
|
||||||
|
Ratio::new(c.value as _).repr(),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
write!(
|
eco_format!(
|
||||||
f,
|
"color.hsv({}, {}, {}, {})",
|
||||||
"color.hsv({:?}, {:?}, {:?}, {:?})",
|
|
||||||
Angle::deg(
|
Angle::deg(
|
||||||
c.hue.into_degrees().rem_euclid(360.0 + ANGLE_EPSILON) as _
|
c.hue.into_degrees().rem_euclid(360.0 + ANGLE_EPSILON) as _
|
||||||
),
|
)
|
||||||
Ratio::new(c.saturation as _),
|
.repr(),
|
||||||
Ratio::new(c.value as _),
|
Ratio::new(c.saturation as _).repr(),
|
||||||
Ratio::new(c.alpha as _),
|
Ratio::new(c.value as _).repr(),
|
||||||
|
Ratio::new(c.alpha as _).repr(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1404,7 +1399,7 @@ impl FromStr for Color {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An 8-bit CMYK color.
|
/// An 8-bit CMYK color.
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub struct Cmyk {
|
pub struct Cmyk {
|
||||||
/// The cyan component.
|
/// The cyan component.
|
||||||
pub c: f32,
|
pub c: f32,
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use crate::eval::{CastInfo, FromValue, IntoValue, Reflect};
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::eval::{CastInfo, FromValue, IntoValue, Reflect};
|
||||||
|
|
||||||
/// A container with components for the four corners of a rectangle.
|
/// A container with components for the four corners of a rectangle.
|
||||||
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
|
@ -16,7 +16,7 @@ use super::*;
|
|||||||
/// #stack(dir: direction.rtl)[A][B][C]
|
/// #stack(dir: direction.rtl)[A][B][C]
|
||||||
/// ```
|
/// ```
|
||||||
#[ty(scope, name = "direction")]
|
#[ty(scope, name = "direction")]
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub enum Dir {
|
pub enum Dir {
|
||||||
/// Left to right.
|
/// Left to right.
|
||||||
LTR,
|
LTR,
|
||||||
@ -117,14 +117,14 @@ impl Dir {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Dir {
|
impl Repr for Dir {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
f.pad(match self {
|
match self {
|
||||||
Self::LTR => "ltr",
|
Self::LTR => "ltr".into(),
|
||||||
Self::RTL => "rtl",
|
Self::RTL => "rtl".into(),
|
||||||
Self::TTB => "ttb",
|
Self::TTB => "ttb".into(),
|
||||||
Self::BTT => "btt",
|
Self::BTT => "btt".into(),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ use super::*;
|
|||||||
/// A length that is relative to the font size.
|
/// A length that is relative to the font size.
|
||||||
///
|
///
|
||||||
/// `1em` is the same as the font size.
|
/// `1em` is the same as the font size.
|
||||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub struct Em(Scalar);
|
pub struct Em(Scalar);
|
||||||
|
|
||||||
impl Em {
|
impl Em {
|
||||||
@ -68,9 +68,9 @@ impl Numeric for Em {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Em {
|
impl Repr for Em {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
write!(f, "{}em", self.get())
|
format_float(self.get(), None, "em")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ use super::*;
|
|||||||
/// Left #h(1fr) Left-ish #h(2fr) Right
|
/// Left #h(1fr) Left-ish #h(2fr) Right
|
||||||
/// ```
|
/// ```
|
||||||
#[ty(name = "fraction")]
|
#[ty(name = "fraction")]
|
||||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub struct Fr(Scalar);
|
pub struct Fr(Scalar);
|
||||||
|
|
||||||
impl Fr {
|
impl Fr {
|
||||||
@ -63,9 +63,9 @@ impl Numeric for Fr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Fr {
|
impl Repr for Fr {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
write!(f, "{}fr", round_2(self.get()))
|
format_float(self.get(), Some(2), "fr")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,17 +1,14 @@
|
|||||||
use std::f64::consts::{FRAC_PI_2, PI, TAU};
|
use std::f64::consts::{FRAC_PI_2, PI, TAU};
|
||||||
use std::f64::{EPSILON, NEG_INFINITY};
|
use std::f64::{EPSILON, NEG_INFINITY};
|
||||||
use std::fmt::{self, Debug, Write};
|
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use typst_macros::{cast, func, scope, ty, Cast};
|
|
||||||
use typst_syntax::{Span, Spanned};
|
|
||||||
|
|
||||||
use super::color::{Hsl, Hsv};
|
use super::color::{Hsl, Hsv};
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::diag::{bail, error, SourceResult};
|
use crate::diag::{bail, error, SourceResult};
|
||||||
use crate::eval::{array, Args, Array, Func, IntoValue};
|
use crate::eval::{array, cast, func, scope, ty, Args, Array, Cast, Func, IntoValue};
|
||||||
use crate::geom::{ColorSpace, Smart};
|
use crate::geom::{ColorSpace, Smart};
|
||||||
|
use crate::syntax::{Span, Spanned};
|
||||||
|
|
||||||
/// A color gradient.
|
/// A color gradient.
|
||||||
///
|
///
|
||||||
@ -169,7 +166,7 @@ use crate::geom::{ColorSpace, Smart};
|
|||||||
/// )
|
/// )
|
||||||
/// ```
|
/// ```
|
||||||
#[ty(scope)]
|
#[ty(scope)]
|
||||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum Gradient {
|
pub enum Gradient {
|
||||||
Linear(Arc<LinearGradient>),
|
Linear(Arc<LinearGradient>),
|
||||||
}
|
}
|
||||||
@ -531,16 +528,16 @@ impl Gradient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Gradient {
|
impl Repr for Gradient {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
match self {
|
match self {
|
||||||
Self::Linear(linear) => linear.fmt(f),
|
Self::Linear(linear) => linear.repr(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A gradient that interpolates between two colors along an axis.
|
/// A gradient that interpolates between two colors along an axis.
|
||||||
#[derive(Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct LinearGradient {
|
pub struct LinearGradient {
|
||||||
/// The color stops of this gradient.
|
/// The color stops of this gradient.
|
||||||
pub stops: Vec<(Color, Ratio)>,
|
pub stops: Vec<(Color, Ratio)>,
|
||||||
@ -554,40 +551,50 @@ pub struct LinearGradient {
|
|||||||
pub anti_alias: bool,
|
pub anti_alias: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for LinearGradient {
|
impl Repr for LinearGradient {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
f.write_str("gradient.linear(")?;
|
let mut r = EcoString::from("gradient.linear(");
|
||||||
|
|
||||||
let angle = self.angle.to_rad().rem_euclid(TAU);
|
let angle = self.angle.to_rad().rem_euclid(TAU);
|
||||||
if angle.abs() < EPSILON {
|
if angle.abs() < EPSILON {
|
||||||
// Default value, do nothing
|
// Default value, do nothing
|
||||||
} else if (angle - FRAC_PI_2).abs() < EPSILON {
|
} else if (angle - FRAC_PI_2).abs() < EPSILON {
|
||||||
f.write_str("dir: rtl, ")?;
|
r.push_str("dir: rtl, ");
|
||||||
} else if (angle - PI).abs() < EPSILON {
|
} else if (angle - PI).abs() < EPSILON {
|
||||||
f.write_str("dir: ttb, ")?;
|
r.push_str("dir: ttb, ");
|
||||||
} else if (angle - 3.0 * FRAC_PI_2).abs() < EPSILON {
|
} else if (angle - 3.0 * FRAC_PI_2).abs() < EPSILON {
|
||||||
f.write_str("dir: btt, ")?;
|
r.push_str("dir: btt, ");
|
||||||
} else {
|
} else {
|
||||||
write!(f, "angle: {:?}, ", self.angle)?;
|
r.push_str("angle: ");
|
||||||
|
r.push_str(&self.angle.repr());
|
||||||
|
r.push_str(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.space != ColorSpace::Oklab {
|
if self.space != ColorSpace::Oklab {
|
||||||
write!(f, "space: {:?}, ", self.space.into_value())?;
|
r.push_str("space: ");
|
||||||
|
r.push_str(&self.space.into_value().repr());
|
||||||
|
r.push_str(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.relative.is_custom() {
|
if self.relative.is_custom() {
|
||||||
write!(f, "relative: {:?}, ", self.relative.into_value())?;
|
r.push_str("relative: ");
|
||||||
|
r.push_str(&self.relative.into_value().repr());
|
||||||
|
r.push_str(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i, (color, offset)) in self.stops.iter().enumerate() {
|
for (i, (color, offset)) in self.stops.iter().enumerate() {
|
||||||
write!(f, "({color:?}, {offset:?})")?;
|
r.push('(');
|
||||||
|
r.push_str(&color.repr());
|
||||||
|
r.push_str(", ");
|
||||||
|
r.push_str(&offset.repr());
|
||||||
|
r.push(')');
|
||||||
if i != self.stops.len() - 1 {
|
if i != self.stops.len() - 1 {
|
||||||
f.write_str(", ")?;
|
r.push_str(", ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
f.write_char(')')
|
r.push(')');
|
||||||
|
r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
use ecow::eco_format;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::diag::{At, Hint, SourceResult};
|
use crate::diag::{At, Hint, SourceResult};
|
||||||
use crate::syntax::Span;
|
use crate::syntax::Span;
|
||||||
@ -33,7 +31,7 @@ use crate::syntax::Span;
|
|||||||
/// (that is, excluding the `em` component).
|
/// (that is, excluding the `em` component).
|
||||||
/// - `em`: The amount of `em` units in this length, as a [float]($float).
|
/// - `em`: The amount of `em` units in this length, as a [float]($float).
|
||||||
#[ty(scope)]
|
#[ty(scope)]
|
||||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct Length {
|
pub struct Length {
|
||||||
/// The absolute part.
|
/// The absolute part.
|
||||||
pub abs: Abs,
|
pub abs: Abs,
|
||||||
@ -75,7 +73,8 @@ impl Length {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
Err(eco_format!(
|
Err(eco_format!(
|
||||||
"cannot convert a length with non-zero em units (`{self:?}`) to {unit}"
|
"cannot convert a length with non-zero em units (`{}`) to {unit}",
|
||||||
|
self.repr()
|
||||||
))
|
))
|
||||||
.hint(eco_format!("use `length.abs.{unit}()` instead to ignore its em component"))
|
.hint(eco_format!("use `length.abs.{unit}()` instead to ignore its em component"))
|
||||||
.at(span)
|
.at(span)
|
||||||
@ -127,12 +126,12 @@ impl Length {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Length {
|
impl Repr for Length {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
match (self.abs.is_zero(), self.em.is_zero()) {
|
match (self.abs.is_zero(), self.em.is_zero()) {
|
||||||
(false, false) => write!(f, "{:?} + {:?}", self.abs, self.em),
|
(false, false) => eco_format!("{} + {}", self.abs.repr(), self.em.repr()),
|
||||||
(true, false) => self.em.fmt(f),
|
(true, false) => self.em.repr(),
|
||||||
(_, true) => self.abs.fmt(f),
|
(_, true) => self.abs.repr(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,9 +61,12 @@ use std::hash::{Hash, Hasher};
|
|||||||
use std::iter::Sum;
|
use std::iter::Sum;
|
||||||
use std::ops::*;
|
use std::ops::*;
|
||||||
|
|
||||||
|
use ecow::{eco_format, EcoString};
|
||||||
|
|
||||||
use crate::diag::{bail, StrResult};
|
use crate::diag::{bail, StrResult};
|
||||||
use crate::eval::{array, cast, func, scope, ty, Array, Dict, Value};
|
use crate::eval::{array, cast, func, scope, ty, Array, Dict, Repr, Value};
|
||||||
use crate::model::{Fold, Resolve, StyleChain};
|
use crate::model::{Fold, Resolve, StyleChain};
|
||||||
|
use crate::util::fmt::format_float;
|
||||||
|
|
||||||
/// Generic access to a structure's components.
|
/// Generic access to a structure's components.
|
||||||
pub trait Get<Index> {
|
pub trait Get<Index> {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// How a fill or stroke should be painted.
|
/// How a fill or stroke should be painted.
|
||||||
#[derive(Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
pub enum Paint {
|
pub enum Paint {
|
||||||
/// A solid color.
|
/// A solid color.
|
||||||
Solid(Color),
|
Solid(Color),
|
||||||
@ -32,11 +32,11 @@ impl From<Gradient> for Paint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Paint {
|
impl Repr for Paint {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
match self {
|
match self {
|
||||||
Self::Solid(color) => color.fmt(f),
|
Self::Solid(color) => color.repr(),
|
||||||
Self::Gradient(gradient) => gradient.fmt(f),
|
Self::Gradient(gradient) => gradient.repr(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ use super::*;
|
|||||||
/// ]
|
/// ]
|
||||||
/// ```
|
/// ```
|
||||||
#[ty]
|
#[ty]
|
||||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub struct Ratio(Scalar);
|
pub struct Ratio(Scalar);
|
||||||
|
|
||||||
impl Ratio {
|
impl Ratio {
|
||||||
@ -62,9 +62,9 @@ impl Ratio {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Ratio {
|
impl Repr for Ratio {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
write!(f, "{}%", round_2(100.0 * self.get()))
|
format_float(self.get() * 100.0, Some(2), "%")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ use super::*;
|
|||||||
/// - `length`: Its length component.
|
/// - `length`: Its length component.
|
||||||
/// - `ratio`: Its ratio component.
|
/// - `ratio`: Its ratio component.
|
||||||
#[ty(name = "relative", title = "Relative Length")]
|
#[ty(name = "relative", title = "Relative Length")]
|
||||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct Rel<T: Numeric = Length> {
|
pub struct Rel<T: Numeric = Length> {
|
||||||
/// The relative part.
|
/// The relative part.
|
||||||
pub rel: Ratio,
|
pub rel: Ratio,
|
||||||
@ -80,12 +80,12 @@ impl Rel<Length> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Numeric> Debug for Rel<T> {
|
impl<T: Numeric + Repr> Repr for Rel<T> {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
match (self.rel.is_zero(), self.abs.is_zero()) {
|
match (self.rel.is_zero(), self.abs.is_zero()) {
|
||||||
(false, false) => write!(f, "{:?} + {:?}", self.rel, self.abs),
|
(false, false) => eco_format!("{} + {}", self.rel.repr(), self.abs.repr()),
|
||||||
(false, true) => self.rel.fmt(f),
|
(false, true) => self.rel.repr(),
|
||||||
(true, _) => self.abs.fmt(f),
|
(true, _) => self.abs.repr(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use super::*;
|
|||||||
/// A 64-bit float that implements `Eq`, `Ord` and `Hash`.
|
/// A 64-bit float that implements `Eq`, `Ord` and `Hash`.
|
||||||
///
|
///
|
||||||
/// Panics if it's `NaN` during any of those operations.
|
/// Panics if it's `NaN` during any of those operations.
|
||||||
#[derive(Default, Copy, Clone)]
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
pub struct Scalar(f64);
|
pub struct Scalar(f64);
|
||||||
|
|
||||||
// We have to detect NaNs this way since `f64::is_nan` isn’t const
|
// We have to detect NaNs this way since `f64::is_nan` isn’t const
|
||||||
@ -61,9 +61,9 @@ impl From<Scalar> for f64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Scalar {
|
impl Repr for Scalar {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
Debug::fmt(&self.0, f)
|
self.0.repr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use crate::eval::{CastInfo, FromValue, IntoValue, Reflect};
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::eval::{CastInfo, FromValue, IntoValue, Reflect};
|
||||||
|
|
||||||
/// A container with left, top, right and bottom components.
|
/// A container with left, top, right and bottom components.
|
||||||
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use crate::eval::{AutoValue, CastInfo, FromValue, IntoValue, Reflect};
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::eval::{AutoValue, CastInfo, FromValue, IntoValue, Reflect};
|
||||||
|
|
||||||
/// A value that can be automatically determined.
|
/// A value that can be automatically determined.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use crate::eval::{dict, Cast, FromValue, NoneValue};
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::eval::{dict, Cast, FromValue, NoneValue};
|
||||||
|
|
||||||
/// Defines how to draw a line.
|
/// Defines how to draw a line.
|
||||||
///
|
///
|
||||||
@ -67,7 +66,7 @@ use super::*;
|
|||||||
/// dictionary format above. For example, `{(2pt + blue).thickness}` is `{2pt}`.
|
/// dictionary format above. For example, `{(2pt + blue).thickness}` is `{2pt}`.
|
||||||
/// Meanwhile, `{(2pt + blue).cap}` is `{auto}` because it's unspecified.
|
/// Meanwhile, `{(2pt + blue).cap}` is `{auto}` because it's unspecified.
|
||||||
#[ty]
|
#[ty]
|
||||||
#[derive(Default, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct Stroke<T: Numeric = Length> {
|
pub struct Stroke<T: Numeric = Length> {
|
||||||
/// The stroke's paint.
|
/// The stroke's paint.
|
||||||
pub paint: Smart<Paint>,
|
pub paint: Smart<Paint>,
|
||||||
@ -146,8 +145,9 @@ impl Stroke<Abs> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Numeric + Debug> Debug for Stroke<T> {
|
impl<T: Numeric + Repr> Repr for Stroke<T> {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
|
let mut r = EcoString::new();
|
||||||
let Self {
|
let Self {
|
||||||
paint,
|
paint,
|
||||||
thickness,
|
thickness,
|
||||||
@ -163,46 +163,59 @@ impl<T: Numeric + Debug> Debug for Stroke<T> {
|
|||||||
{
|
{
|
||||||
match (&self.paint, &self.thickness) {
|
match (&self.paint, &self.thickness) {
|
||||||
(Smart::Custom(paint), Smart::Custom(thickness)) => {
|
(Smart::Custom(paint), Smart::Custom(thickness)) => {
|
||||||
write!(f, "{thickness:?} + {paint:?}")
|
r.push_str(&thickness.repr());
|
||||||
|
r.push_str(" + ");
|
||||||
|
r.push_str(&paint.repr());
|
||||||
}
|
}
|
||||||
(Smart::Custom(paint), Smart::Auto) => paint.fmt(f),
|
(Smart::Custom(paint), Smart::Auto) => r.push_str(&paint.repr()),
|
||||||
(Smart::Auto, Smart::Custom(thickness)) => thickness.fmt(f),
|
(Smart::Auto, Smart::Custom(thickness)) => r.push_str(&thickness.repr()),
|
||||||
(Smart::Auto, Smart::Auto) => f.pad("1pt + black"),
|
(Smart::Auto, Smart::Auto) => r.push_str("1pt + black"),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
write!(f, "(")?;
|
r.push('(');
|
||||||
let mut sep = "";
|
let mut sep = "";
|
||||||
if let Smart::Custom(paint) = &paint {
|
if let Smart::Custom(paint) = &paint {
|
||||||
write!(f, "{}paint: {:?}", sep, paint)?;
|
r.push_str(sep);
|
||||||
|
r.push_str("paint: ");
|
||||||
|
r.push_str(&paint.repr());
|
||||||
sep = ", ";
|
sep = ", ";
|
||||||
}
|
}
|
||||||
if let Smart::Custom(thickness) = &thickness {
|
if let Smart::Custom(thickness) = &thickness {
|
||||||
write!(f, "{}thickness: {:?}", sep, thickness)?;
|
r.push_str(sep);
|
||||||
|
r.push_str("thickness: ");
|
||||||
|
r.push_str(&thickness.repr());
|
||||||
sep = ", ";
|
sep = ", ";
|
||||||
}
|
}
|
||||||
if let Smart::Custom(cap) = &line_cap {
|
if let Smart::Custom(cap) = &line_cap {
|
||||||
write!(f, "{}cap: {:?}", sep, cap)?;
|
r.push_str(sep);
|
||||||
|
r.push_str("cap: ");
|
||||||
|
r.push_str(&cap.repr());
|
||||||
sep = ", ";
|
sep = ", ";
|
||||||
}
|
}
|
||||||
if let Smart::Custom(join) = &line_join {
|
if let Smart::Custom(join) = &line_join {
|
||||||
write!(f, "{}join: {:?}", sep, join)?;
|
r.push_str(sep);
|
||||||
|
r.push_str("join: ");
|
||||||
|
r.push_str(&join.repr());
|
||||||
sep = ", ";
|
sep = ", ";
|
||||||
}
|
}
|
||||||
if let Smart::Custom(dash) = &dash_pattern {
|
if let Smart::Custom(dash) = &dash_pattern {
|
||||||
write!(f, "{}dash: ", sep)?;
|
r.push_str(sep);
|
||||||
|
r.push_str("cap: ");
|
||||||
if let Some(dash) = dash {
|
if let Some(dash) = dash {
|
||||||
Debug::fmt(dash, f)?;
|
r.push_str(&dash.repr());
|
||||||
} else {
|
} else {
|
||||||
Debug::fmt(&NoneValue, f)?;
|
r.push_str(&NoneValue.repr());
|
||||||
}
|
}
|
||||||
sep = ", ";
|
sep = ", ";
|
||||||
}
|
}
|
||||||
if let Smart::Custom(miter_limit) = &miter_limit {
|
if let Smart::Custom(miter_limit) = &miter_limit {
|
||||||
write!(f, "{}miter-limit: {:?}", sep, miter_limit)?;
|
r.push_str(sep);
|
||||||
|
r.push_str("miter-limit: ");
|
||||||
|
r.push_str(&miter_limit.repr());
|
||||||
}
|
}
|
||||||
write!(f, ")")?;
|
r.push(')');
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,43 +290,43 @@ cast! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The line cap of a stroke
|
/// The line cap of a stroke
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Cast)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)]
|
||||||
pub enum LineCap {
|
pub enum LineCap {
|
||||||
Butt,
|
Butt,
|
||||||
Round,
|
Round,
|
||||||
Square,
|
Square,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for LineCap {
|
impl Repr for LineCap {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
match self {
|
match self {
|
||||||
LineCap::Butt => write!(f, "\"butt\""),
|
Self::Butt => "butt".repr(),
|
||||||
LineCap::Round => write!(f, "\"round\""),
|
Self::Round => "round".repr(),
|
||||||
LineCap::Square => write!(f, "\"square\""),
|
Self::Square => "square".repr(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The line join of a stroke
|
/// The line join of a stroke
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Cast)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)]
|
||||||
pub enum LineJoin {
|
pub enum LineJoin {
|
||||||
Miter,
|
Miter,
|
||||||
Round,
|
Round,
|
||||||
Bevel,
|
Bevel,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for LineJoin {
|
impl Repr for LineJoin {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
match self {
|
match self {
|
||||||
LineJoin::Miter => write!(f, "\"miter\""),
|
Self::Miter => "miter".repr(),
|
||||||
LineJoin::Round => write!(f, "\"round\""),
|
Self::Round => "round".repr(),
|
||||||
LineJoin::Bevel => write!(f, "\"bevel\""),
|
Self::Bevel => "bevel".repr(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A line dash pattern.
|
/// A line dash pattern.
|
||||||
#[derive(Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct DashPattern<T: Numeric = Length, DT = DashLength<T>> {
|
pub struct DashPattern<T: Numeric = Length, DT = DashLength<T>> {
|
||||||
/// The dash array.
|
/// The dash array.
|
||||||
pub array: Vec<DT>,
|
pub array: Vec<DT>,
|
||||||
@ -321,18 +334,19 @@ pub struct DashPattern<T: Numeric = Length, DT = DashLength<T>> {
|
|||||||
pub phase: T,
|
pub phase: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Numeric + Debug, DT: Debug> Debug for DashPattern<T, DT> {
|
impl<T: Numeric + Repr, DT: Repr> Repr for DashPattern<T, DT> {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
write!(f, "(array: (")?;
|
let mut r = EcoString::from("(array: (");
|
||||||
for (i, elem) in self.array.iter().enumerate() {
|
for (i, elem) in self.array.iter().enumerate() {
|
||||||
if i == 0 {
|
if i != 0 {
|
||||||
write!(f, "{:?}", elem)?;
|
r.push_str(", ")
|
||||||
} else {
|
|
||||||
write!(f, ", {:?}", elem)?;
|
|
||||||
}
|
}
|
||||||
|
r.push_str(&elem.repr())
|
||||||
}
|
}
|
||||||
write!(f, "), phase: {:?})", self.phase)?;
|
r.push_str("), phase: ");
|
||||||
Ok(())
|
r.push_str(&self.phase.repr());
|
||||||
|
r.push(')');
|
||||||
|
r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,7 +398,7 @@ cast! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The length of a dash in a line dash pattern.
|
/// The length of a dash in a line dash pattern.
|
||||||
#[derive(Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
pub enum DashLength<T: Numeric = Length> {
|
pub enum DashLength<T: Numeric = Length> {
|
||||||
LineWidth,
|
LineWidth,
|
||||||
Length(T),
|
Length(T),
|
||||||
@ -399,11 +413,11 @@ impl<T: Numeric> DashLength<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Numeric + Debug> Debug for DashLength<T> {
|
impl<T: Numeric + Repr> Repr for DashLength<T> {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
match self {
|
match self {
|
||||||
Self::LineWidth => write!(f, "\"dot\""),
|
Self::LineWidth => "dot".repr(),
|
||||||
Self::Length(v) => Debug::fmt(v, f),
|
Self::Length(v) => v.repr(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
use std::fmt::{self, Debug, Formatter, Write};
|
use std::fmt::Debug;
|
||||||
use std::iter::{self, Sum};
|
use std::iter::{self, Sum};
|
||||||
use std::ops::{Add, AddAssign};
|
use std::ops::{Add, AddAssign};
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ use super::{
|
|||||||
};
|
};
|
||||||
use crate::diag::{SourceResult, StrResult};
|
use crate::diag::{SourceResult, StrResult};
|
||||||
use crate::doc::Meta;
|
use crate::doc::Meta;
|
||||||
use crate::eval::{func, scope, ty, Dict, FromValue, IntoValue, Str, Value, Vm};
|
use crate::eval::{func, scope, ty, Dict, FromValue, IntoValue, Repr, Str, Value, Vm};
|
||||||
use crate::syntax::Span;
|
use crate::syntax::Span;
|
||||||
use crate::util::pretty_array_like;
|
use crate::util::pretty_array_like;
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ use crate::util::pretty_array_like;
|
|||||||
/// elements the content is composed of and what fields they have.
|
/// elements the content is composed of and what fields they have.
|
||||||
/// Alternatively, you can inspect the output of the [`repr`]($repr) function.
|
/// Alternatively, you can inspect the output of the [`repr`]($repr) function.
|
||||||
#[ty(scope)]
|
#[ty(scope)]
|
||||||
#[derive(Clone, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
#[allow(clippy::derived_hash_with_manual_eq)]
|
#[allow(clippy::derived_hash_with_manual_eq)]
|
||||||
pub struct Content {
|
pub struct Content {
|
||||||
elem: Element,
|
elem: Element,
|
||||||
@ -528,30 +528,26 @@ impl Content {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Content {
|
impl Repr for Content {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
let name = self.elem.name();
|
let name = self.elem.name();
|
||||||
if let Some(text) = item!(text_str)(self) {
|
if let Some(text) = item!(text_str)(self) {
|
||||||
f.write_char('[')?;
|
return eco_format!("[{}]", text);
|
||||||
f.write_str(&text)?;
|
|
||||||
f.write_char(']')?;
|
|
||||||
return Ok(());
|
|
||||||
} else if name == "space" {
|
} else if name == "space" {
|
||||||
return f.write_str("[ ]");
|
return ("[ ]").into();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut pieces: Vec<_> = self
|
let mut pieces: Vec<_> = self
|
||||||
.fields()
|
.fields()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(name, value)| eco_format!("{name}: {value:?}"))
|
.map(|(name, value)| eco_format!("{}: {}", name, value.repr()))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if self.is::<StyledElem>() {
|
if self.is::<StyledElem>() {
|
||||||
pieces.push(EcoString::from(".."));
|
pieces.push(EcoString::from(".."));
|
||||||
}
|
}
|
||||||
|
|
||||||
f.write_str(name)?;
|
eco_format!("{}{}", name, pretty_array_like(&pieces, false))
|
||||||
f.write_str(&pretty_array_like(&pieces, false))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -696,15 +692,15 @@ pub trait PlainText {
|
|||||||
/// The missing field access error message.
|
/// The missing field access error message.
|
||||||
#[cold]
|
#[cold]
|
||||||
fn missing_field(field: &str) -> EcoString {
|
fn missing_field(field: &str) -> EcoString {
|
||||||
eco_format!("content does not contain field {:?}", Str::from(field))
|
eco_format!("content does not contain field {}", field.repr())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The missing field access error message when no default value was given.
|
/// The missing field access error message when no default value was given.
|
||||||
#[cold]
|
#[cold]
|
||||||
fn missing_field_no_default(field: &str) -> EcoString {
|
fn missing_field_no_default(field: &str) -> EcoString {
|
||||||
eco_format!(
|
eco_format!(
|
||||||
"content does not contain field {:?} and \
|
"content does not contain field {} and \
|
||||||
no default value was specified",
|
no default value was specified",
|
||||||
Str::from(field)
|
field.repr()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
|
use ecow::EcoString;
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use super::{Content, Selector, Styles};
|
use super::{Content, Selector, Styles};
|
||||||
use crate::diag::SourceResult;
|
use crate::diag::SourceResult;
|
||||||
use crate::eval::{cast, Args, Dict, Func, ParamInfo, Scope, Value, Vm};
|
use crate::eval::{cast, Args, Dict, Func, ParamInfo, Repr, Scope, Value, Vm};
|
||||||
use crate::util::Static;
|
use crate::util::Static;
|
||||||
|
|
||||||
/// A document element.
|
/// A document element.
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct Element(Static<NativeElementData>);
|
pub struct Element(Static<NativeElementData>);
|
||||||
|
|
||||||
impl Element {
|
impl Element {
|
||||||
@ -93,9 +94,9 @@ impl Element {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Element {
|
impl Repr for Element {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
f.pad(self.name())
|
self.name().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,6 +151,7 @@ pub trait Set {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Defines a native element.
|
/// Defines a native element.
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct NativeElementData {
|
pub struct NativeElementData {
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
pub title: &'static str,
|
pub title: &'static str,
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::{BTreeSet, HashMap};
|
use std::collections::{BTreeSet, HashMap};
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::Debug;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
|
|
||||||
use comemo::{Prehashed, Track, Tracked, Validate};
|
use comemo::{Prehashed, Track, Tracked, Validate};
|
||||||
use ecow::EcoVec;
|
use ecow::{EcoString, EcoVec};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
use super::{Content, Selector};
|
use super::{Content, Selector};
|
||||||
use crate::diag::{bail, StrResult};
|
use crate::diag::{bail, StrResult};
|
||||||
use crate::doc::{Frame, FrameItem, Meta, Position};
|
use crate::doc::{Frame, FrameItem, Meta, Position};
|
||||||
use crate::eval::{cast, func, scope, ty, Dict, Value, Vm};
|
use crate::eval::{cast, func, scope, ty, Dict, Repr, Value, Vm};
|
||||||
use crate::geom::{Point, Transform};
|
use crate::geom::{Point, Transform};
|
||||||
use crate::model::Label;
|
use crate::model::Label;
|
||||||
use crate::util::NonZeroExt;
|
use crate::util::NonZeroExt;
|
||||||
@ -24,7 +24,7 @@ use crate::util::NonZeroExt;
|
|||||||
/// or shown element with the [`location()`]($content.location) method on
|
/// or shown element with the [`location()`]($content.location) method on
|
||||||
/// content.
|
/// content.
|
||||||
#[ty(scope)]
|
#[ty(scope)]
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct Location {
|
pub struct Location {
|
||||||
/// The hash of the element.
|
/// The hash of the element.
|
||||||
hash: u128,
|
hash: u128,
|
||||||
@ -83,9 +83,9 @@ impl Location {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Location {
|
impl Repr for Location {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
f.pad("..")
|
"..".into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use ecow::EcoString;
|
use ecow::{eco_format, EcoString};
|
||||||
|
|
||||||
use crate::eval::{func, scope, ty};
|
use crate::eval::{func, scope, ty, Repr};
|
||||||
|
|
||||||
/// A label for an element.
|
/// A label for an element.
|
||||||
///
|
///
|
||||||
@ -23,7 +23,7 @@ use crate::eval::{func, scope, ty};
|
|||||||
/// This function also has dedicated syntax: You can create a label by enclosing
|
/// This function also has dedicated syntax: You can create a label by enclosing
|
||||||
/// its name in angle brackets. This works both in markup and code.
|
/// its name in angle brackets. This works both in markup and code.
|
||||||
#[ty(scope)]
|
#[ty(scope)]
|
||||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub struct Label(pub EcoString);
|
pub struct Label(pub EcoString);
|
||||||
|
|
||||||
#[scope]
|
#[scope]
|
||||||
@ -38,9 +38,9 @@ impl Label {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Label {
|
impl Repr for Label {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
write!(f, "<{}>", self.0)
|
eco_format!("<{}>", self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use std::any::{Any, TypeId};
|
use std::any::{Any, TypeId};
|
||||||
use std::fmt::{self, Debug, Formatter, Write};
|
use std::fmt::Debug;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ecow::{eco_format, EcoString, EcoVec};
|
use ecow::{eco_format, EcoString, EcoVec};
|
||||||
@ -7,8 +7,8 @@ use ecow::{eco_format, EcoString, EcoVec};
|
|||||||
use super::{Content, Element, Label, Locatable, Location};
|
use super::{Content, Element, Label, Locatable, Location};
|
||||||
use crate::diag::{bail, StrResult};
|
use crate::diag::{bail, StrResult};
|
||||||
use crate::eval::{
|
use crate::eval::{
|
||||||
cast, func, scope, ty, CastInfo, Dict, FromValue, Func, Reflect, Regex, Str, Symbol,
|
cast, func, scope, ty, CastInfo, Dict, FromValue, Func, Reflect, Regex, Repr, Str,
|
||||||
Type, Value,
|
Symbol, Type, Value,
|
||||||
};
|
};
|
||||||
use crate::util::pretty_array_like;
|
use crate::util::pretty_array_like;
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ use crate::util::pretty_array_like;
|
|||||||
/// === But this will not.
|
/// === But this will not.
|
||||||
/// ```
|
/// ```
|
||||||
#[ty(scope)]
|
#[ty(scope)]
|
||||||
#[derive(Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub enum Selector {
|
pub enum Selector {
|
||||||
/// Matches a specific type of element.
|
/// Matches a specific type of element.
|
||||||
///
|
///
|
||||||
@ -209,42 +209,37 @@ impl From<Location> for Selector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Selector {
|
impl Repr for Selector {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
match self {
|
match self {
|
||||||
Self::Elem(elem, dict) => {
|
Self::Elem(elem, dict) => {
|
||||||
f.write_str(elem.name())?;
|
|
||||||
if let Some(dict) = dict {
|
if let Some(dict) = dict {
|
||||||
f.write_str(".where")?;
|
eco_format!("{}.where{}", elem.name(), dict.repr())
|
||||||
dict.fmt(f)?;
|
} else {
|
||||||
|
elem.name().into()
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
Self::Label(label) => label.fmt(f),
|
Self::Label(label) => label.repr(),
|
||||||
Self::Regex(regex) => regex.fmt(f),
|
Self::Regex(regex) => regex.repr(),
|
||||||
Self::Can(cap) => cap.fmt(f),
|
Self::Can(cap) => eco_format!("{cap:?}"),
|
||||||
Self::Or(selectors) | Self::And(selectors) => {
|
Self::Or(selectors) | Self::And(selectors) => {
|
||||||
f.write_str(if matches!(self, Self::Or(_)) { "or" } else { "and" })?;
|
let function = if matches!(self, Self::Or(_)) { "or" } else { "and" };
|
||||||
let pieces: Vec<_> =
|
let pieces: Vec<_> = selectors.iter().map(Selector::repr).collect();
|
||||||
selectors.iter().map(|sel| eco_format!("{sel:?}")).collect();
|
eco_format!("{}{}", function, pretty_array_like(&pieces, false))
|
||||||
f.write_str(&pretty_array_like(&pieces, false))
|
|
||||||
}
|
}
|
||||||
Self::Location(loc) => loc.fmt(f),
|
Self::Location(loc) => loc.repr(),
|
||||||
Self::Before { selector, end: split, inclusive }
|
Self::Before { selector, end: split, inclusive }
|
||||||
| Self::After { selector, start: split, inclusive } => {
|
| Self::After { selector, start: split, inclusive } => {
|
||||||
selector.fmt(f)?;
|
let method =
|
||||||
|
if matches!(self, Self::Before { .. }) { "before" } else { "after" };
|
||||||
if matches!(self, Self::Before { .. }) {
|
let inclusive_arg = if !*inclusive { ", inclusive: false" } else { "" };
|
||||||
f.write_str(".before(")?;
|
eco_format!(
|
||||||
} else {
|
"{}.{}({}{})",
|
||||||
f.write_str(".after(")?;
|
selector.repr(),
|
||||||
}
|
method,
|
||||||
|
split.repr(),
|
||||||
split.fmt(f)?;
|
inclusive_arg
|
||||||
if !*inclusive {
|
)
|
||||||
f.write_str(", inclusive: false")?;
|
|
||||||
}
|
|
||||||
f.write_char(')')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,12 @@ use ecow::{eco_vec, EcoString, EcoVec};
|
|||||||
|
|
||||||
use super::{Content, Element, NativeElement, Selector, Vt};
|
use super::{Content, Element, NativeElement, Selector, Vt};
|
||||||
use crate::diag::{SourceResult, Trace, Tracepoint};
|
use crate::diag::{SourceResult, Trace, Tracepoint};
|
||||||
use crate::eval::{cast, ty, Args, FromValue, Func, IntoValue, Value, Vm};
|
use crate::eval::{cast, ty, Args, FromValue, Func, IntoValue, Repr, Value, Vm};
|
||||||
use crate::syntax::Span;
|
use crate::syntax::Span;
|
||||||
|
|
||||||
/// A list of style properties.
|
/// A list of style properties.
|
||||||
#[ty]
|
#[ty]
|
||||||
#[derive(Default, PartialEq, Clone, Hash)]
|
#[derive(Debug, Default, PartialEq, Clone, Hash)]
|
||||||
pub struct Styles(EcoVec<Prehashed<Style>>);
|
pub struct Styles(EcoVec<Prehashed<Style>>);
|
||||||
|
|
||||||
impl Styles {
|
impl Styles {
|
||||||
@ -86,9 +86,9 @@ impl From<Style> for Styles {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Styles {
|
impl Repr for Styles {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn repr(&self) -> EcoString {
|
||||||
f.pad("..")
|
"..".into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,54 @@
|
|||||||
|
use ecow::{eco_format, EcoString};
|
||||||
|
|
||||||
|
/// Format an integer in a base.
|
||||||
|
pub fn format_int_with_base(mut n: i64, base: i64) -> EcoString {
|
||||||
|
if n == 0 {
|
||||||
|
return "0".into();
|
||||||
|
}
|
||||||
|
|
||||||
|
// In Rust, `format!("{:x}", -14i64)` is not `-e` but `fffffffffffffff2`.
|
||||||
|
// So we can only use the built-in for decimal, not bin/oct/hex.
|
||||||
|
if base == 10 {
|
||||||
|
return eco_format!("{n}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// The largest output is `to_base(i64::MIN, 2)`, which is 65 chars long.
|
||||||
|
const SIZE: usize = 65;
|
||||||
|
let mut digits = [b'\0'; SIZE];
|
||||||
|
let mut i = SIZE;
|
||||||
|
|
||||||
|
// It's tempting to take the absolute value, but this will fail for i64::MIN.
|
||||||
|
// Instead, we turn n negative, as -i64::MAX is perfectly representable.
|
||||||
|
let negative = n < 0;
|
||||||
|
if n > 0 {
|
||||||
|
n = -n;
|
||||||
|
}
|
||||||
|
|
||||||
|
while n != 0 {
|
||||||
|
let digit = char::from_digit(-(n % base) as u32, base as u32);
|
||||||
|
i -= 1;
|
||||||
|
digits[i] = digit.unwrap_or('?') as u8;
|
||||||
|
n /= base;
|
||||||
|
}
|
||||||
|
|
||||||
|
if negative {
|
||||||
|
i -= 1;
|
||||||
|
digits[i] = b'-';
|
||||||
|
}
|
||||||
|
|
||||||
|
std::str::from_utf8(&digits[i..]).unwrap_or_default().into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts a float to a string representation with a specific precision and a
|
||||||
|
/// suffix, all with a single allocation.
|
||||||
|
pub fn format_float(mut value: f64, precision: Option<u8>, suffix: &str) -> EcoString {
|
||||||
|
if let Some(p) = precision {
|
||||||
|
let offset = 10_f64.powi(p as i32);
|
||||||
|
value = (value * offset).round() / offset;
|
||||||
|
}
|
||||||
|
eco_format!("{}{}", value, suffix)
|
||||||
|
}
|
||||||
|
|
||||||
/// Format pieces separated with commas and a final "and" or "or".
|
/// Format pieces separated with commas and a final "and" or "or".
|
||||||
pub fn separated_list(pieces: &[impl AsRef<str>], last: &str) -> String {
|
pub fn separated_list(pieces: &[impl AsRef<str>], last: &str) -> String {
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! Utilities.
|
//! Utilities.
|
||||||
|
|
||||||
pub mod fat;
|
pub mod fat;
|
||||||
mod fmt;
|
pub mod fmt;
|
||||||
|
|
||||||
pub use self::fmt::{pretty_array_like, pretty_comma_list, separated_list};
|
pub use self::fmt::{pretty_array_like, pretty_comma_list, separated_list};
|
||||||
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 53 KiB |
@ -22,7 +22,9 @@ use walkdir::WalkDir;
|
|||||||
|
|
||||||
use typst::diag::{bail, FileError, FileResult, Severity, StrResult};
|
use typst::diag::{bail, FileError, FileResult, Severity, StrResult};
|
||||||
use typst::doc::{Document, Frame, FrameItem, Meta};
|
use typst::doc::{Document, Frame, FrameItem, Meta};
|
||||||
use typst::eval::{eco_format, func, Bytes, Datetime, Library, NoneValue, Tracer, Value};
|
use typst::eval::{
|
||||||
|
eco_format, func, Bytes, Datetime, Library, NoneValue, Repr, Tracer, Value,
|
||||||
|
};
|
||||||
use typst::font::{Font, FontBook};
|
use typst::font::{Font, FontBook};
|
||||||
use typst::geom::{Abs, Color, Smart};
|
use typst::geom::{Abs, Color, Smart};
|
||||||
use typst::syntax::{FileId, PackageVersion, Source, SyntaxNode, VirtualPath};
|
use typst::syntax::{FileId, PackageVersion, Source, SyntaxNode, VirtualPath};
|
||||||
@ -154,7 +156,7 @@ fn library() -> Library {
|
|||||||
#[func]
|
#[func]
|
||||||
fn test(lhs: Value, rhs: Value) -> StrResult<NoneValue> {
|
fn test(lhs: Value, rhs: Value) -> StrResult<NoneValue> {
|
||||||
if lhs != rhs {
|
if lhs != rhs {
|
||||||
bail!("Assertion failed: {lhs:?} != {rhs:?}");
|
bail!("Assertion failed: {} != {}", lhs.repr(), rhs.repr());
|
||||||
}
|
}
|
||||||
Ok(NoneValue)
|
Ok(NoneValue)
|
||||||
}
|
}
|
||||||
@ -162,7 +164,7 @@ fn library() -> Library {
|
|||||||
#[func]
|
#[func]
|
||||||
fn test_repr(lhs: Value, rhs: Value) -> StrResult<NoneValue> {
|
fn test_repr(lhs: Value, rhs: Value) -> StrResult<NoneValue> {
|
||||||
if lhs.repr() != rhs.repr() {
|
if lhs.repr() != rhs.repr() {
|
||||||
bail!("Assertion failed: {lhs:?} != {rhs:?}");
|
bail!("Assertion failed: {} != {}", lhs.repr(), rhs.repr());
|
||||||
}
|
}
|
||||||
Ok(NoneValue)
|
Ok(NoneValue)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user