summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMALO <57839069+MDLC01@users.noreply.github.com>2023-10-04 12:08:56 +0200
committerGitHub <noreply@github.com>2023-10-04 12:08:56 +0200
commit333e4037fcfc806137867e592c124811059e5c3d (patch)
tree4e254fb6fa94d4c83a0ef90450bf17454e9aad8f
parent57bc614cf472c080800afff6df74b354375be4b4 (diff)
Add `Repr` trait (#2269)
-rw-r--r--crates/typst-docs/src/lib.rs2
-rw-r--r--crates/typst-ide/src/complete.rs6
-rw-r--r--crates/typst-ide/src/tooltip.rs4
-rw-r--r--crates/typst-library/src/compute/foundations.rs14
-rw-r--r--crates/typst-library/src/meta/counter.rs33
-rw-r--r--crates/typst-library/src/meta/state.rs24
-rw-r--r--crates/typst-library/src/prelude.rs2
-rw-r--r--crates/typst-library/src/text/deco.rs6
-rw-r--r--crates/typst/src/doc.rs16
-rw-r--r--crates/typst/src/eval/args.rs27
-rw-r--r--crates/typst/src/eval/array.rs21
-rw-r--r--crates/typst/src/eval/auto.rs13
-rw-r--r--crates/typst/src/eval/bool.rs13
-rw-r--r--crates/typst/src/eval/bytes.rs12
-rw-r--r--crates/typst/src/eval/cast.rs4
-rw-r--r--crates/typst/src/eval/datetime.rs26
-rw-r--r--crates/typst/src/eval/dict.rs28
-rw-r--r--crates/typst/src/eval/duration.rs26
-rw-r--r--crates/typst/src/eval/func.rs18
-rw-r--r--crates/typst/src/eval/int.rs16
-rw-r--r--crates/typst/src/eval/mod.rs2
-rw-r--r--crates/typst/src/eval/module.rs12
-rw-r--r--crates/typst/src/eval/none.rs13
-rw-r--r--crates/typst/src/eval/ops.rs7
-rw-r--r--crates/typst/src/eval/plugin.rs8
-rw-r--r--crates/typst/src/eval/str.rs95
-rw-r--r--crates/typst/src/eval/symbol.rs16
-rw-r--r--crates/typst/src/eval/ty.rs13
-rw-r--r--crates/typst/src/eval/value.rs105
-rw-r--r--crates/typst/src/eval/version.rs17
-rw-r--r--crates/typst/src/export/pdf/page.rs7
-rw-r--r--crates/typst/src/font/mod.rs2
-rw-r--r--crates/typst/src/font/variant.rs14
-rw-r--r--crates/typst/src/geom/abs.rs21
-rw-r--r--crates/typst/src/geom/align.rs64
-rw-r--r--crates/typst/src/geom/angle.rs19
-rw-r--r--crates/typst/src/geom/axes.rs23
-rw-r--r--crates/typst/src/geom/color.rs127
-rw-r--r--crates/typst/src/geom/corners.rs3
-rw-r--r--crates/typst/src/geom/dir.rs18
-rw-r--r--crates/typst/src/geom/em.rs8
-rw-r--r--crates/typst/src/geom/fr.rs8
-rw-r--r--crates/typst/src/geom/gradient.rs53
-rw-r--r--crates/typst/src/geom/length.rs17
-rw-r--r--crates/typst/src/geom/mod.rs5
-rw-r--r--crates/typst/src/geom/paint.rs10
-rw-r--r--crates/typst/src/geom/ratio.rs8
-rw-r--r--crates/typst/src/geom/rel.rs12
-rw-r--r--crates/typst/src/geom/scalar.rs8
-rw-r--r--crates/typst/src/geom/sides.rs3
-rw-r--r--crates/typst/src/geom/smart.rs3
-rw-r--r--crates/typst/src/geom/stroke.rs108
-rw-r--r--crates/typst/src/model/content.rs28
-rw-r--r--crates/typst/src/model/element.rs14
-rw-r--r--crates/typst/src/model/introspect.rs14
-rw-r--r--crates/typst/src/model/label.rs14
-rw-r--r--crates/typst/src/model/selector.rs57
-rw-r--r--crates/typst/src/model/styles.rs10
-rw-r--r--crates/typst/src/util/fmt.rs51
-rw-r--r--crates/typst/src/util/mod.rs2
-rw-r--r--tests/ref/compiler/repr-color-gradient.pngbin102476 -> 53933 bytes
-rw-r--r--tests/src/tests.rs8
62 files changed, 706 insertions, 632 deletions
diff --git a/crates/typst-docs/src/lib.rs b/crates/typst-docs/src/lib.rs
index 8f7c8ff8..30ba4ebb 100644
--- a/crates/typst-docs/src/lib.rs
+++ b/crates/typst-docs/src/lib.rs
@@ -21,7 +21,7 @@ use serde::Deserialize;
use serde_yaml as yaml;
use typst::diag::{bail, StrResult};
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::geom::{Abs, Smart};
use typst_library::layout::{Margin, PageElem};
diff --git a/crates/typst-ide/src/complete.rs b/crates/typst-ide/src/complete.rs
index 83e339f9..bb17dd37 100644
--- a/crates/typst-ide/src/complete.rs
+++ b/crates/typst-ide/src/complete.rs
@@ -6,7 +6,7 @@ use if_chain::if_chain;
use serde::{Deserialize, Serialize};
use typst::doc::Frame;
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::syntax::{
@@ -1089,14 +1089,14 @@ impl<'a> CompletionContext<'a> {
docs: Option<&str>,
) {
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 {
Value::Symbol(_) => None,
Value::Func(func) => func.docs().map(plain_docs_sentence),
v => {
let repr = v.repr();
- (repr.as_str() != label).then(|| repr.into())
+ (repr.as_str() != label).then_some(repr)
}
});
diff --git a/crates/typst-ide/src/tooltip.rs b/crates/typst-ide/src/tooltip.rs
index 8a418e0e..37f32e22 100644
--- a/crates/typst-ide/src/tooltip.rs
+++ b/crates/typst-ide/src/tooltip.rs
@@ -3,7 +3,7 @@ use std::fmt::Write;
use ecow::{eco_format, EcoString};
use if_chain::if_chain;
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::syntax::ast::{self, AstNode};
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();
}
}
- pieces.push(value.repr().into());
+ pieces.push(value.repr());
last = Some((value, 1));
}
diff --git a/crates/typst-library/src/compute/foundations.rs b/crates/typst-library/src/compute/foundations.rs
index 250a9f57..b02f9793 100644
--- a/crates/typst-library/src/compute/foundations.rs
+++ b/crates/typst-library/src/compute/foundations.rs
@@ -1,5 +1,5 @@
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::*;
@@ -51,7 +51,7 @@ pub fn repr(
/// The value whose string representation to produce.
value: Value,
) -> Str {
- value.repr()
+ value.repr().into()
}
/// Fails with an error.
@@ -135,7 +135,11 @@ impl assert {
if let Some(message) = message {
bail!("equality assertion failed: {message}");
} 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)
@@ -165,7 +169,9 @@ impl assert {
bail!("inequality assertion failed: {message}");
} else {
bail!(
- "inequality assertion failed: value {left:?} was equal to {right:?}"
+ "inequality assertion failed: value {} was equal to {}",
+ left.repr(),
+ right.repr()
);
}
}
diff --git a/crates/typst-library/src/meta/counter.rs b/crates/typst-library/src/meta/counter.rs
index 88bc82bd..1ad0bff1 100644
--- a/crates/typst-library/src/meta/counter.rs
+++ b/crates/typst-library/src/meta/counter.rs
@@ -1,9 +1,8 @@
-use std::fmt::{self, Debug, Formatter, Write};
use std::str::FromStr;
use ecow::{eco_vec, EcoVec};
use smallvec::{smallvec, SmallVec};
-use typst::eval::Tracer;
+use typst::eval::{Repr, Tracer};
use typst::model::DelayedErrors;
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
/// doesn't just use normal variables for counters.
#[ty(scope)]
-#[derive(Clone, PartialEq, Hash)]
+#[derive(Debug, Clone, PartialEq, Hash)]
pub struct Counter(CounterKey);
impl Counter {
@@ -452,11 +451,9 @@ impl Counter {
}
}
-impl Debug for Counter {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.write_str("counter(")?;
- self.0.fmt(f)?;
- f.write_char(')')
+impl Repr for Counter {
+ fn repr(&self) -> EcoString {
+ eco_format!("counter({})", self.0.repr())
}
}
@@ -465,7 +462,7 @@ cast! {
}
/// Identifies a counter.
-#[derive(Clone, PartialEq, Hash)]
+#[derive(Debug, Clone, PartialEq, Hash)]
pub enum CounterKey {
/// The page counter.
Page,
@@ -495,19 +492,19 @@ cast! {
v: LocatableSelector => Self::Selector(v.0),
}
-impl Debug for CounterKey {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+impl Repr for CounterKey {
+ fn repr(&self) -> EcoString {
match self {
- Self::Page => f.pad("page"),
- Self::Selector(selector) => selector.fmt(f),
- Self::Str(str) => str.fmt(f),
+ Self::Page => "page".into(),
+ Self::Selector(selector) => selector.repr(),
+ Self::Str(str) => str.repr(),
}
}
}
/// An update to perform on a counter.
#[ty]
-#[derive(Clone, PartialEq, Hash)]
+#[derive(Debug, Clone, PartialEq, Hash)]
pub enum CounterUpdate {
/// Set the counter to the specified state.
Set(CounterState),
@@ -517,9 +514,9 @@ pub enum CounterUpdate {
Func(Func),
}
-impl Debug for CounterUpdate {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.pad("..")
+impl Repr for CounterUpdate {
+ fn repr(&self) -> EcoString {
+ "..".into()
}
}
diff --git a/crates/typst-library/src/meta/state.rs b/crates/typst-library/src/meta/state.rs
index f7b5eb77..137b754e 100644
--- a/crates/typst-library/src/meta/state.rs
+++ b/crates/typst-library/src/meta/state.rs
@@ -1,7 +1,7 @@
-use std::fmt::{self, Debug, Formatter, Write};
+use std::fmt::Debug;
use ecow::{eco_vec, EcoVec};
-use typst::eval::Tracer;
+use typst::eval::{Repr, Tracer};
use typst::model::DelayedErrors;
use crate::prelude::*;
@@ -181,7 +181,7 @@ use crate::prelude::*;
/// function to `update` that determines the value of the state based on its
/// previous value.
#[ty(scope)]
-#[derive(Clone, PartialEq, Hash)]
+#[derive(Debug, Clone, PartialEq, Hash)]
pub struct State {
/// The key that identifies the state.
key: Str,
@@ -335,13 +335,9 @@ impl State {
}
}
-impl Debug for State {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.write_str("state(")?;
- self.key.fmt(f)?;
- f.write_str(", ")?;
- self.init.fmt(f)?;
- f.write_char(')')
+impl Repr for State {
+ fn repr(&self) -> EcoString {
+ eco_format!("state({}, {})", self.key.repr(), self.init.repr())
}
}
@@ -351,7 +347,7 @@ cast! {
/// An update to perform on a state.
#[ty]
-#[derive(Clone, PartialEq, Hash)]
+#[derive(Debug, Clone, PartialEq, Hash)]
pub enum StateUpdate {
/// Set the state to the specified value.
Set(Value),
@@ -359,9 +355,9 @@ pub enum StateUpdate {
Func(Func),
}
-impl Debug for StateUpdate {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.pad("..")
+impl Repr for StateUpdate {
+ fn repr(&self) -> EcoString {
+ "..".into()
}
}
diff --git a/crates/typst-library/src/prelude.rs b/crates/typst-library/src/prelude.rs
index aca5a064..329cbf61 100644
--- a/crates/typst-library/src/prelude.rs
+++ b/crates/typst-library/src/prelude.rs
@@ -16,7 +16,7 @@ pub use typst::doc::*;
#[doc(no_inline)]
pub use typst::eval::{
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)]
pub use typst::geom::*;
diff --git a/crates/typst-library/src/text/deco.rs b/crates/typst-library/src/text/deco.rs
index 6a6b8477..20323207 100644
--- a/crates/typst-library/src/text/deco.rs
+++ b/crates/typst-library/src/text/deco.rs
@@ -346,6 +346,12 @@ impl Fold for Decoration {
}
}
+impl Repr for Decoration {
+ fn repr(&self) -> EcoString {
+ eco_format!("{self:?}")
+ }
+}
+
cast! {
type Decoration,
}
diff --git a/crates/typst/src/doc.rs b/crates/typst/src/doc.rs
index ffd9d4aa..dd206044 100644
--- a/crates/typst/src/doc.rs
+++ b/crates/typst/src/doc.rs
@@ -6,9 +6,9 @@ use std::ops::Range;
use std::str::FromStr;
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::font::Font;
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.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Destination {
@@ -773,6 +779,12 @@ pub enum Destination {
Location(Location),
}
+impl Repr for Destination {
+ fn repr(&self) -> EcoString {
+ eco_format!("{self:?}")
+ }
+}
+
cast! {
Destination,
self => match self {
diff --git a/crates/typst/src/eval/args.rs b/crates/typst/src/eval/args.rs
index ac403eef..aad9fda6 100644
--- a/crates/typst/src/eval/args.rs
+++ b/crates/typst/src/eval/args.rs
@@ -1,8 +1,8 @@
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::syntax::{Span, Spanned};
use crate::util::pretty_array_like;
@@ -47,7 +47,7 @@ pub struct Args {
}
/// An argument to a function call: `12` or `draw: false`.
-#[derive(Clone, PartialEq, Hash)]
+#[derive(Debug, Clone, PartialEq, Hash)]
pub struct Arg {
/// The span of the whole argument.
pub span: Span,
@@ -252,18 +252,23 @@ impl Args {
impl Debug for Args {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- let pieces: Vec<_> =
- self.items.iter().map(|arg| eco_format!("{arg:?}")).collect();
- f.write_str(&pretty_array_like(&pieces, false))
+ f.debug_list().entries(&self.items).finish()
}
}
-impl Debug for Arg {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+impl Repr for Args {
+ fn repr(&self) -> EcoString {
+ let pieces = self.items.iter().map(Arg::repr).collect::<Vec<_>>();
+ pretty_array_like(&pieces, false).into()
+ }
+}
+
+impl Repr for Arg {
+ fn repr(&self) -> EcoString {
if let Some(name) = &self.name {
- f.write_str(name)?;
- f.write_str(": ")?;
+ eco_format!("{}: {}", name, self.value.v.repr())
+ } else {
+ self.value.v.repr()
}
- Debug::fmt(&self.value.v, f)
}
}
diff --git a/crates/typst/src/eval/array.rs b/crates/typst/src/eval/array.rs
index 3da7c0b0..92642702 100644
--- a/crates/typst/src/eval/array.rs
+++ b/crates/typst/src/eval/array.rs
@@ -1,5 +1,5 @@
use std::cmp::Ordering;
-use std::fmt::{self, Debug, Formatter};
+use std::fmt::{Debug, Formatter};
use std::num::NonZeroI64;
use std::ops::{Add, AddAssign};
@@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
use super::{
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::eval::ops::{add, mul};
@@ -808,14 +808,23 @@ cast! {
}
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 mut pieces: Vec<_> =
- self.iter().take(max).map(|value| eco_format!("{value:?}")).collect();
+ let mut pieces: Vec<_> = self
+ .iter()
+ .take(max)
+ .map(|value| eco_format!("{}", value.repr()))
+ .collect();
if 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()
}
}
diff --git a/crates/typst/src/eval/auto.rs b/crates/typst/src/eval/auto.rs
index a9d8fc9e..24254a0f 100644
--- a/crates/typst/src/eval/auto.rs
+++ b/crates/typst/src/eval/auto.rs
@@ -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;
/// 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
/// direction from the [text language]($text.lang).
#[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;
impl IntoValue for AutoValue {
@@ -44,8 +45,8 @@ impl Reflect for AutoValue {
}
}
-impl Debug for AutoValue {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.pad("auto")
+impl Repr for AutoValue {
+ fn repr(&self) -> EcoString {
+ "auto".into()
}
}
diff --git a/crates/typst/src/eval/bool.rs b/crates/typst/src/eval/bool.rs
index dcc73e66..1dca260c 100644
--- a/crates/typst/src/eval/bool.rs
+++ b/crates/typst/src/eval/bool.rs
@@ -1,4 +1,6 @@
-use super::ty;
+use ecow::EcoString;
+
+use super::{ty, Repr};
/// A type with two states.
///
@@ -13,3 +15,12 @@ use super::ty;
/// ```
#[ty(title = "Boolean")]
type bool;
+
+impl Repr for bool {
+ fn repr(&self) -> EcoString {
+ match self {
+ true => "true".into(),
+ false => "false".into(),
+ }
+ }
+}
diff --git a/crates/typst/src/eval/bytes.rs b/crates/typst/src/eval/bytes.rs
index 12f9bcf1..69116000 100644
--- a/crates/typst/src/eval/bytes.rs
+++ b/crates/typst/src/eval/bytes.rs
@@ -1,5 +1,5 @@
use std::borrow::Cow;
-use std::fmt::{self, Debug, Formatter};
+use std::fmt::Debug;
use std::ops::{Add, AddAssign, Deref};
use std::sync::Arc;
@@ -7,7 +7,7 @@ use comemo::Prehashed;
use ecow::{eco_format, EcoString};
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};
/// A sequence of bytes.
@@ -38,7 +38,7 @@ use crate::diag::{bail, StrResult};
/// #str(data.slice(1, 4))
/// ```
#[ty(scope)]
-#[derive(Clone, Hash, Eq, PartialEq)]
+#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct Bytes(Arc<Prehashed<Cow<'static, [u8]>>>);
impl Bytes {
@@ -179,9 +179,9 @@ impl AsRef<[u8]> for Bytes {
}
}
-impl Debug for Bytes {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- write!(f, "bytes({})", self.len())
+impl Repr for Bytes {
+ fn repr(&self) -> EcoString {
+ eco_format!("bytes({})", self.len())
}
}
diff --git a/crates/typst/src/eval/cast.rs b/crates/typst/src/eval/cast.rs
index f457d4d1..0965c8fa 100644
--- a/crates/typst/src/eval/cast.rs
+++ b/crates/typst/src/eval/cast.rs
@@ -6,7 +6,7 @@ use std::ops::Add;
use ecow::{eco_format, EcoString};
-use super::{Type, Value};
+use super::{Repr, Type, Value};
use crate::diag::{At, SourceResult, StrResult};
use crate::syntax::{Span, Spanned};
use crate::util::separated_list;
@@ -239,7 +239,7 @@ impl CastInfo {
self.walk(|info| match info {
CastInfo::Any => parts.push("anything".into()),
CastInfo::Value(value, _) => {
- parts.push(value.repr().into());
+ parts.push(value.repr());
if value.ty() == found.ty() {
matching_type = true;
}
diff --git a/crates/typst/src/eval/datetime.rs b/crates/typst/src/eval/datetime.rs
index 6b340a8e..c76a59bd 100644
--- a/crates/typst/src/eval/datetime.rs
+++ b/crates/typst/src/eval/datetime.rs
@@ -1,6 +1,6 @@
use std::cmp::Ordering;
-use std::fmt;
-use std::fmt::{Debug, Formatter};
+
+use std::fmt::Debug;
use std::hash::Hash;
use std::ops::{Add, Sub};
@@ -9,7 +9,7 @@ use time::error::{Format, InvalidFormatDescription};
use time::macros::format_description;
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::geom::Smart;
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
/// that have a specified time.
#[ty(scope)]
-#[derive(Clone, Copy, PartialEq, Hash)]
+#[derive(Debug, Clone, Copy, PartialEq, Hash)]
pub enum Datetime {
/// Representation as a date.
Date(time::Date),
@@ -426,20 +426,20 @@ impl Datetime {
}
}
-impl Debug for Datetime {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- let year = self.year().map(|y| eco_format!("year: {y}"));
- let month = self.month().map(|m| eco_format!("month: {m}"));
- let day = self.day().map(|d| eco_format!("day: {d}"));
- let hour = self.hour().map(|h| eco_format!("hour: {h}"));
- let minute = self.minute().map(|m| eco_format!("minute: {m}"));
- let second = self.second().map(|s| eco_format!("second: {s}"));
+impl Repr for Datetime {
+ fn repr(&self) -> EcoString {
+ let year = self.year().map(|y| eco_format!("year: {}", (y as i64).repr()));
+ let month = self.month().map(|m| eco_format!("month: {}", (m as i64).repr()));
+ let day = self.day().map(|d| eco_format!("day: {}", (d as i64).repr()));
+ let hour = self.hour().map(|h| eco_format!("hour: {}", (h as i64).repr()));
+ let minute = self.minute().map(|m| eco_format!("minute: {}", (m as i64).repr()));
+ let second = self.second().map(|s| eco_format!("second: {}", (s as i64).repr()));
let filtered = [year, month, day, hour, minute, second]
.into_iter()
.flatten()
.collect::<EcoVec<_>>();
- write!(f, "datetime{}", &pretty_array_like(&filtered, false))
+ eco_format!("datetime{}", &pretty_array_like(&filtered, false))
}
}
diff --git a/crates/typst/src/eval/dict.rs b/crates/typst/src/eval/dict.rs
index 4ac68587..c5da7c15 100644
--- a/crates/typst/src/eval/dict.rs
+++ b/crates/typst/src/eval/dict.rs
@@ -1,4 +1,4 @@
-use std::fmt::{self, Debug, Formatter};
+use std::fmt::{Debug, Formatter};
use std::hash::{Hash, Hasher};
use std::ops::{Add, AddAssign};
use std::sync::Arc;
@@ -7,7 +7,7 @@ use ecow::{eco_format, EcoString};
use indexmap::IndexMap;
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::syntax::is_ident;
use crate::util::{pretty_array_like, separated_list, ArcExt};
@@ -117,7 +117,7 @@ impl Dict {
pub fn finish(&self, expected: &[&str]) -> StrResult<()> {
if let Some((key, _)) = self.iter().next() {
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"));
return Err(msg.into());
}
@@ -200,9 +200,15 @@ impl 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() {
- return f.write_str("(:)");
+ return "(:)".into();
}
let max = 40;
@@ -211,9 +217,9 @@ impl Debug for Dict {
.take(max)
.map(|(key, value)| {
if is_ident(key) {
- eco_format!("{key}: {value:?}")
+ eco_format!("{key}: {}", value.repr())
} else {
- eco_format!("{key:?}: {value:?}")
+ eco_format!("{}: {}", key.repr(), value.repr())
}
})
.collect();
@@ -222,7 +228,7 @@ impl Debug for Dict {
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.
#[cold]
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.
#[cold]
fn missing_key_no_default(key: &str) -> EcoString {
eco_format!(
- "dictionary does not contain key {:?} \
+ "dictionary does not contain key {} \
and no default value was specified",
- Str::from(key)
+ key.repr()
)
}
diff --git a/crates/typst/src/eval/duration.rs b/crates/typst/src/eval/duration.rs
index 1bbf8492..e1e6ee57 100644
--- a/crates/typst/src/eval/duration.rs
+++ b/crates/typst/src/eval/duration.rs
@@ -1,15 +1,15 @@
-use ecow::eco_format;
-use std::fmt;
-use std::fmt::{Debug, Formatter};
+use ecow::{eco_format, EcoString};
+
+use std::fmt::Debug;
use std::ops::{Add, Div, Mul, Neg, Sub};
use time::ext::NumericalDuration;
-use super::{func, scope, ty};
+use super::{func, scope, ty, Repr};
use crate::util::pretty_array_like;
/// Represents a positive or negative span of time.
#[ty(scope)]
-#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Duration(time::Duration);
impl Duration {
@@ -111,41 +111,41 @@ impl Duration {
}
}
-impl Debug for Duration {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+impl Repr for Duration {
+ fn repr(&self) -> EcoString {
let mut tmp = self.0;
let mut vec = Vec::with_capacity(5);
let weeks = tmp.whole_seconds() / 604_800.0 as i64;
if weeks != 0 {
- vec.push(eco_format!("weeks: {weeks}"));
+ vec.push(eco_format!("weeks: {}", weeks.repr()));
}
tmp -= weeks.weeks();
let days = tmp.whole_days();
if days != 0 {
- vec.push(eco_format!("days: {days}"));
+ vec.push(eco_format!("days: {}", days.repr()));
}
tmp -= days.days();
let hours = tmp.whole_hours();
if hours != 0 {
- vec.push(eco_format!("hours: {hours}"));
+ vec.push(eco_format!("hours: {}", hours.repr()));
}
tmp -= hours.hours();
let minutes = tmp.whole_minutes();
if minutes != 0 {
- vec.push(eco_format!("minutes: {minutes}"));
+ vec.push(eco_format!("minutes: {}", minutes.repr()));
}
tmp -= minutes.minutes();
let seconds = tmp.whole_seconds();
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))
}
}
diff --git a/crates/typst/src/eval/func.rs b/crates/typst/src/eval/func.rs
index d8a2c3e8..d9003850 100644
--- a/crates/typst/src/eval/func.rs
+++ b/crates/typst/src/eval/func.rs
@@ -1,7 +1,8 @@
-use std::fmt::{self, Debug, Formatter};
+use std::fmt::Debug;
use std::sync::Arc;
use comemo::{Prehashed, Tracked, TrackedMut};
+use ecow::EcoString;
use once_cell::sync::Lazy;
use super::{
@@ -118,7 +119,7 @@ pub use typst_macros::func;
/// [`array.push(value)`]($array.push). These can modify the values they are
/// called on.
#[ty(scope, name = "function")]
-#[derive(Clone, Hash)]
+#[derive(Debug, Clone, Hash)]
#[allow(clippy::derived_hash_with_manual_eq)]
pub struct Func {
/// The internal representation.
@@ -128,7 +129,7 @@ pub struct Func {
}
/// The different kinds of function representations.
-#[derive(Clone, PartialEq, Hash)]
+#[derive(Debug, Clone, PartialEq, Hash)]
enum Repr {
/// A native Rust function.
Native(Static<NativeFuncData>),
@@ -363,11 +364,11 @@ impl Func {
}
}
-impl Debug for Func {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+impl super::Repr for Func {
+ fn repr(&self) -> EcoString {
match self.name() {
- Some(name) => write!(f, "{name}"),
- None => f.write_str("(..) => .."),
+ Some(name) => name.into(),
+ None => "(..) => ..".into(),
}
}
}
@@ -412,6 +413,7 @@ pub trait NativeFunc {
}
/// Defines a native function.
+#[derive(Debug)]
pub struct NativeFuncData {
pub function: fn(&mut Vm, &mut Args) -> SourceResult<Value>,
pub name: &'static str,
@@ -461,7 +463,7 @@ pub struct ParamInfo {
}
/// A user-defined closure.
-#[derive(Hash)]
+#[derive(Debug, Hash)]
pub(super) struct Closure {
/// The closure's syntax node. Must be castable to `ast::Closure`.
pub node: SyntaxNode,
diff --git a/crates/typst/src/eval/int.rs b/crates/typst/src/eval/int.rs
index 55c709c0..b2b76f30 100644
--- a/crates/typst/src/eval/int.rs
+++ b/crates/typst/src/eval/int.rs
@@ -1,8 +1,8 @@
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.
///
@@ -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.
pub struct ToInt(i64);
diff --git a/crates/typst/src/eval/mod.rs b/crates/typst/src/eval/mod.rs
index f0d1be20..8627b489 100644
--- a/crates/typst/src/eval/mod.rs
+++ b/crates/typst/src/eval/mod.rs
@@ -65,7 +65,7 @@ pub use self::str::{format_str, Regex, Str};
pub use self::symbol::{symbols, Symbol};
pub use self::tracer::Tracer;
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;
use std::collections::HashSet;
diff --git a/crates/typst/src/eval/module.rs b/crates/typst/src/eval/module.rs
index 9ae4b0f9..9169c6d2 100644
--- a/crates/typst/src/eval/module.rs
+++ b/crates/typst/src/eval/module.rs
@@ -1,4 +1,4 @@
-use std::fmt::{self, Debug, Formatter};
+use std::fmt::Debug;
use std::sync::Arc;
use ecow::{eco_format, EcoString};
@@ -24,7 +24,7 @@ use crate::diag::StrResult;
/// >>> #(-3)
/// ```
#[ty]
-#[derive(Clone, Hash)]
+#[derive(Debug, Clone, Hash)]
#[allow(clippy::derived_hash_with_manual_eq)]
pub struct Module {
/// The module's name.
@@ -34,7 +34,7 @@ pub struct Module {
}
/// The internal representation.
-#[derive(Clone, Hash)]
+#[derive(Debug, Clone, Hash)]
struct Repr {
/// The top-level definitions that were bound in this module.
scope: Scope,
@@ -100,9 +100,9 @@ impl Module {
}
}
-impl Debug for Module {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- write!(f, "<module {}>", self.name())
+impl super::Repr for Module {
+ fn repr(&self) -> EcoString {
+ eco_format!("<module {}>", self.name())
}
}
diff --git a/crates/typst/src/eval/none.rs b/crates/typst/src/eval/none.rs
index 5262301f..90cd0ff9 100644
--- a/crates/typst/src/eval/none.rs
+++ b/crates/typst/src/eval/none.rs
@@ -1,8 +1,9 @@
-use std::fmt::{self, Debug, Formatter};
+use ecow::EcoString;
+use std::fmt::Debug;
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;
/// A value that indicates the absence of any other value.
@@ -18,7 +19,7 @@ use crate::diag::StrResult;
/// Not visible: #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;
impl Reflect for NoneValue {
@@ -50,9 +51,9 @@ impl FromValue for NoneValue {
}
}
-impl Debug for NoneValue {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.pad("none")
+impl Repr for NoneValue {
+ fn repr(&self) -> EcoString {
+ "none".into()
}
}
diff --git a/crates/typst/src/eval/ops.rs b/crates/typst/src/eval/ops.rs
index 5581e79e..4a64cfed 100644
--- a/crates/typst/src/eval/ops.rs
+++ b/crates/typst/src/eval/ops.rs
@@ -1,11 +1,10 @@
//! Operations on values.
use std::cmp::Ordering;
-use std::fmt::Debug;
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::geom::{Align, Length, Numeric, Rel, Smart, Stroke};
use Value::*;
@@ -436,9 +435,9 @@ pub fn compare(lhs: &Value, rhs: &Value) -> StrResult<Ordering> {
}
/// 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)
- .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.
diff --git a/crates/typst/src/eval/plugin.rs b/crates/typst/src/eval/plugin.rs
index ee64ec5f..af781089 100644
--- a/crates/typst/src/eval/plugin.rs
+++ b/crates/typst/src/eval/plugin.rs
@@ -288,7 +288,13 @@ impl Plugin {
impl Debug for Plugin {
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()
}
}
diff --git a/crates/typst/src/eval/str.rs b/crates/typst/src/eval/str.rs
index 3a8d4730..e7df00e1 100644
--- a/crates/typst/src/eval/str.rs
+++ b/crates/typst/src/eval/str.rs
@@ -1,5 +1,5 @@
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::ops::{Add, AddAssign, Deref, Range};
@@ -8,13 +8,14 @@ use serde::{Deserialize, Serialize};
use unicode_segmentation::UnicodeSegmentation;
use super::{
- cast, dict, func, scope, ty, Args, Array, Bytes, Dict, Func, IntoValue, Type, Value,
- Version, Vm,
+ cast, dict, func, scope, ty, Args, Array, Bytes, Dict, Func, IntoValue, Repr, Type,
+ Value, Version, Vm,
};
use crate::diag::{bail, At, SourceResult, StrResult};
use crate::geom::Align;
use crate::model::Label;
use crate::syntax::{Span, Spanned};
+use crate::util::fmt::format_int_with_base;
/// Create a new [`Str`] from a format string.
#[macro_export]
@@ -68,7 +69,8 @@ pub use ecow::eco_format;
/// - `[\t]` for a tab
/// - `[\u{1f600}]` for a hexadecimal Unicode escape sequence
#[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)]
pub struct Str(EcoString);
@@ -616,45 +618,6 @@ cast! {
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.
#[cold]
fn out_of_bounds(index: i64, len: usize) -> EcoString {
@@ -717,18 +680,9 @@ impl Display for Str {
}
}
-impl Debug for Str {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.write_char('"')?;
- 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('"')
+impl Repr for Str {
+ fn repr(&self) -> EcoString {
+ self.as_ref().repr()
}
}
@@ -836,6 +790,29 @@ cast! {
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.
///
/// Can be used as a [show rule selector]($styling/#show-rules) and with
@@ -856,7 +833,7 @@ cast! {
/// .split(regex("[,;]")))
/// ```
#[ty(scope)]
-#[derive(Clone)]
+#[derive(Debug, Clone)]
pub struct Regex(regex::Regex);
impl Regex {
@@ -895,9 +872,9 @@ impl Deref for Regex {
}
}
-impl Debug for Regex {
- fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
- write!(f, "regex({:?})", self.0.as_str())
+impl Repr for Regex {
+ fn repr(&self) -> EcoString {
+ eco_format!("regex({})", self.0.as_str().repr())
}
}
diff --git a/crates/typst/src/eval/symbol.rs b/crates/typst/src/eval/symbol.rs
index e74bec3f..679835d0 100644
--- a/crates/typst/src/eval/symbol.rs
+++ b/crates/typst/src/eval/symbol.rs
@@ -3,7 +3,7 @@ use std::collections::BTreeSet;
use std::fmt::{self, Debug, Display, Formatter, Write};
use std::sync::Arc;
-use ecow::EcoString;
+use ecow::{eco_format, EcoString};
use serde::{Serialize, Serializer};
use super::{cast, func, scope, ty, Array};
@@ -43,11 +43,11 @@ pub use typst_macros::symbols;
/// $arrow.t.quad$
/// ```
#[ty(scope)]
-#[derive(Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Symbol(Repr);
/// The internal representation.
-#[derive(Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
enum Repr {
Single(char),
Const(&'static [(&'static str, char)]),
@@ -55,7 +55,7 @@ enum Repr {
}
/// A collection of symbols.
-#[derive(Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
enum List {
Static(&'static [(&'static str, 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 {
f.write_char(self.get())
}
}
-impl Display for Symbol {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.write_char(self.get())
+impl super::Repr for Symbol {
+ fn repr(&self) -> EcoString {
+ eco_format!("\"{}\"", self.get())
}
}
diff --git a/crates/typst/src/eval/ty.rs b/crates/typst/src/eval/ty.rs
index 5a2457e6..82e895fa 100644
--- a/crates/typst/src/eval/ty.rs
+++ b/crates/typst/src/eval/ty.rs
@@ -1,10 +1,10 @@
use std::cmp::Ordering;
use std::fmt::{self, Debug, Display, Formatter};
-use ecow::eco_format;
+use ecow::{eco_format, EcoString};
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::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}`
/// if the dictionary has a string key matching the type's name
#[ty(scope)]
-#[derive(Copy, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Type(Static<NativeTypeData>);
impl Type {
@@ -139,9 +139,9 @@ impl Type {
}
}
-impl Debug for Type {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.pad(self.long_name())
+impl Repr for Type {
+ fn repr(&self) -> EcoString {
+ self.long_name().into()
}
}
@@ -180,6 +180,7 @@ pub trait NativeType {
}
/// Defines a native type.
+#[derive(Debug)]
pub struct NativeTypeData {
pub name: &'static str,
pub long_name: &'static str,
diff --git a/crates/typst/src/eval/value.rs b/crates/typst/src/eval/value.rs
index 901bc278..901d3819 100644
--- a/crates/typst/src/eval/value.rs
+++ b/crates/typst/src/eval/value.rs
@@ -1,10 +1,10 @@
use std::any::Any;
use std::cmp::Ordering;
-use std::fmt::{self, Debug, Formatter};
+use std::fmt::{self, Debug};
use std::hash::{Hash, Hasher};
use std::sync::Arc;
-use ecow::eco_format;
+use ecow::{eco_format, EcoString};
use serde::de::value::{MapAccessDeserializer, SeqAccessDeserializer};
use serde::de::{Error, MapAccess, SeqAccess, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
@@ -12,9 +12,9 @@ use siphasher::sip128::{Hasher128, SipHasher13};
use typst::eval::Duration;
use super::{
- fields, format_str, ops, Args, Array, AutoValue, Bytes, CastInfo, Content, Dict,
- FromValue, Func, IntoValue, Module, NativeType, NoneValue, Plugin, Reflect, Scope,
- Str, Symbol, Type, Version,
+ fields, ops, Args, Array, AutoValue, Bytes, CastInfo, Content, Dict, FromValue, Func,
+ IntoValue, Module, NativeType, NoneValue, Plugin, Reflect, Scope, Str, Symbol, Type,
+ Version,
};
use crate::diag::StrResult;
use crate::eval::Datetime;
@@ -23,7 +23,7 @@ use crate::model::{Label, Styles};
use crate::syntax::{ast, Span};
/// A computational value.
-#[derive(Default, Clone)]
+#[derive(Debug, Default, Clone)]
pub enum Value {
/// The value that indicates the absence of a meaningful value.
#[default]
@@ -90,7 +90,7 @@ impl Value {
/// Create a new dynamic value.
pub fn dynamic<T>(any: T) -> Self
where
- T: Debug + NativeType + PartialEq + Hash + Sync + Send + 'static,
+ T: Debug + Repr + NativeType + PartialEq + Hash + Sync + Send + 'static,
{
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.
pub fn display(self) -> Content {
match self {
@@ -210,7 +205,7 @@ impl Value {
Self::Symbol(v) => item!(text)(v.get().into()),
Self::Content(v) => v,
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 {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+impl Repr for Value {
+ fn repr(&self) -> EcoString {
match self {
- Self::None => Debug::fmt(&NoneValue, f),
- Self::Auto => Debug::fmt(&AutoValue, f),
- Self::Bool(v) => Debug::fmt(v, f),
- Self::Int(v) => Debug::fmt(v, f),
- Self::Float(v) => Debug::fmt(v, f),
- Self::Length(v) => Debug::fmt(v, f),
- Self::Angle(v) => Debug::fmt(v, f),
- Self::Ratio(v) => Debug::fmt(v, f),
- Self::Relative(v) => Debug::fmt(v, f),
- Self::Fraction(v) => Debug::fmt(v, f),
- Self::Color(v) => Debug::fmt(v, f),
- Self::Gradient(v) => Debug::fmt(v, f),
- Self::Symbol(v) => Debug::fmt(v, f),
- Self::Version(v) => Debug::fmt(v, f),
- Self::Str(v) => Debug::fmt(v, f),
- Self::Bytes(v) => Debug::fmt(v, f),
- Self::Label(v) => Debug::fmt(v, f),
- Self::Datetime(v) => Debug::fmt(v, f),
- Self::Duration(v) => Debug::fmt(v, f),
- Self::Content(v) => Debug::fmt(v, f),
- Self::Styles(v) => Debug::fmt(v, f),
- Self::Array(v) => Debug::fmt(v, f),
- Self::Dict(v) => Debug::fmt(v, f),
- Self::Func(v) => Debug::fmt(v, f),
- Self::Args(v) => Debug::fmt(v, f),
- Self::Type(v) => Debug::fmt(v, f),
- Self::Module(v) => Debug::fmt(v, f),
- Self::Plugin(v) => Debug::fmt(v, f),
- Self::Dyn(v) => Debug::fmt(v, f),
+ Self::None => NoneValue.repr(),
+ Self::Auto => AutoValue.repr(),
+ Self::Bool(v) => v.repr(),
+ Self::Int(v) => v.repr(),
+ Self::Float(v) => v.repr(),
+ Self::Length(v) => v.repr(),
+ Self::Angle(v) => v.repr(),
+ Self::Ratio(v) => v.repr(),
+ Self::Relative(v) => v.repr(),
+ Self::Fraction(v) => v.repr(),
+ Self::Color(v) => v.repr(),
+ Self::Gradient(v) => v.repr(),
+ Self::Symbol(v) => v.repr(),
+ Self::Version(v) => v.repr(),
+ Self::Str(v) => v.repr(),
+ Self::Bytes(v) => v.repr(),
+ Self::Label(v) => v.repr(),
+ Self::Datetime(v) => v.repr(),
+ Self::Duration(v) => v.repr(),
+ Self::Content(v) => v.repr(),
+ Self::Styles(v) => v.repr(),
+ Self::Array(v) => v.repr(),
+ Self::Dict(v) => v.repr(),
+ Self::Func(v) => v.repr(),
+ Self::Args(v) => v.repr(),
+ Self::Type(v) => v.repr(),
+ Self::Module(v) => v.repr(),
+ Self::Plugin(v) => v.repr(),
+ 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.
-#[derive(Clone, Hash)]
+#[derive(Debug, Clone, Hash)]
#[allow(clippy::derived_hash_with_manual_eq)]
pub struct Dynamic(Arc<dyn Bounds>);
@@ -460,7 +455,7 @@ impl Dynamic {
/// Create a new instance from any value that satisfies the required bounds.
pub fn new<T>(any: T) -> Self
where
- T: Debug + NativeType + PartialEq + Hash + Sync + Send + 'static,
+ T: Debug + Repr + NativeType + PartialEq + Hash + Sync + Send + 'static,
{
Self(Arc::new(any))
}
@@ -481,9 +476,9 @@ impl Dynamic {
}
}
-impl Debug for Dynamic {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- Debug::fmt(&self.0, f)
+impl Repr for Dynamic {
+ fn repr(&self) -> EcoString {
+ 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 dyn_eq(&self, other: &Dynamic) -> bool;
fn dyn_ty(&self) -> Type;
@@ -502,7 +503,7 @@ trait Bounds: Debug + Sync + Send + 'static {
impl<T> Bounds for T
where
- T: Debug + NativeType + PartialEq + Hash + Sync + Send + 'static,
+ T: Debug + Repr + NativeType + PartialEq + Hash + Sync + Send + 'static,
{
fn as_any(&self) -> &dyn Any {
self
@@ -631,7 +632,7 @@ mod tests {
#[track_caller]
fn test(value: impl IntoValue, exp: &str) {
- assert_eq!(format!("{:?}", value.into_value()), exp);
+ assert_eq!(value.into_value().repr(), exp);
}
#[test]
diff --git a/crates/typst/src/eval/version.rs b/crates/typst/src/eval/version.rs
index 6ba0dff4..e2b4ac52 100644
--- a/crates/typst/src/eval/version.rs
+++ b/crates/typst/src/eval/version.rs
@@ -1,11 +1,11 @@
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::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::util::pretty_array_like;
@@ -19,7 +19,7 @@ use crate::util::pretty_array_like;
/// The first three components have names: `major`, `minor`, `patch`. All
/// components after that do not have names.
#[ty(scope)]
-#[derive(Default, Clone, Hash)]
+#[derive(Debug, Default, Clone, Hash)]
#[allow(clippy::derived_hash_with_manual_eq)]
pub struct Version(EcoVec<u32>);
@@ -165,7 +165,7 @@ impl PartialEq 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;
for &v in &self.0 {
if !first {
@@ -178,11 +178,10 @@ impl Display for Version {
}
}
-impl Debug for Version {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.write_str("version")?;
+impl Repr for Version {
+ fn repr(&self) -> EcoString {
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))
}
}
diff --git a/crates/typst/src/export/pdf/page.rs b/crates/typst/src/export/pdf/page.rs
index e74f6322..ec247b25 100644
--- a/crates/typst/src/export/pdf/page.rs
+++ b/crates/typst/src/export/pdf/page.rs
@@ -11,6 +11,7 @@ use super::color::PaintEncode;
use super::extg::ExternalGraphicsState;
use super::{deflate, AbsExt, EmExt, PdfContext, RefExt};
use crate::doc::{Destination, Frame, FrameItem, GroupItem, Meta, TextItem};
+use crate::eval::Repr;
use crate::font::Font;
use crate::geom::{
self, Abs, Em, FixedStroke, Geometry, LineCap, LineJoin, Numeric, Paint, Point,
@@ -710,6 +711,12 @@ pub struct PdfPageLabel {
pub offset: Option<NonZeroUsize>,
}
+impl Repr for PdfPageLabel {
+ fn repr(&self) -> EcoString {
+ eco_format!("{self:?}")
+ }
+}
+
/// A PDF page label number style.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum PdfPageLabelStyle {
diff --git a/crates/typst/src/font/mod.rs b/crates/typst/src/font/mod.rs
index 2dd1ad32..953a5122 100644
--- a/crates/typst/src/font/mod.rs
+++ b/crates/typst/src/font/mod.rs
@@ -133,7 +133,7 @@ impl Hash for Font {
impl Debug for Font {
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)
}
}
diff --git a/crates/typst/src/font/variant.rs b/crates/typst/src/font/variant.rs
index 74053e34..d3c1f953 100644
--- a/crates/typst/src/font/variant.rs
+++ b/crates/typst/src/font/variant.rs
@@ -1,8 +1,9 @@
+use ecow::EcoString;
use std::fmt::{self, Debug, Formatter};
use serde::{Deserialize, Serialize};
-use crate::eval::{cast, Cast, IntoValue};
+use crate::eval::{cast, Cast, IntoValue, Repr};
use crate::geom::Ratio;
/// Properties that distinguish a font from other fonts in the same family.
@@ -176,7 +177,7 @@ cast! {
}
/// 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)]
#[serde(transparent)]
pub struct FontStretch(u16);
@@ -247,10 +248,9 @@ impl Default for FontStretch {
Self::NORMAL
}
}
-
-impl Debug for FontStretch {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- self.to_ratio().fmt(f)
+impl Repr for FontStretch {
+ fn repr(&self) -> EcoString {
+ self.to_ratio().repr()
}
}
@@ -291,6 +291,6 @@ mod tests {
#[test]
fn test_font_stretch_debug() {
- assert_eq!(format!("{:?}", FontStretch::EXPANDED), "125%")
+ assert_eq!(FontStretch::EXPANDED.repr(), "125%")
}
}
diff --git a/crates/typst/src/geom/abs.rs b/crates/typst/src/geom/abs.rs
index d177a304..3b56f5f2 100644
--- a/crates/typst/src/geom/abs.rs
+++ b/crates/typst/src/geom/abs.rs
@@ -1,7 +1,7 @@
use super::*;
/// 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);
impl Abs {
@@ -133,9 +133,9 @@ impl Numeric for Abs {
}
}
-impl Debug for Abs {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- write!(f, "{}pt", round_2(self.to_pt()))
+impl Repr for Abs {
+ fn repr(&self) -> EcoString {
+ format_float(self.to_pt(), Some(2), "pt")
}
}
@@ -220,7 +220,7 @@ cast! {
}
/// Different units of absolute measurement.
-#[derive(Copy, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum AbsUnit {
/// Points.
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)]
mod tests {
use super::*;
diff --git a/crates/typst/src/geom/align.rs b/crates/typst/src/geom/align.rs
index bfe377fb..59e608b1 100644
--- a/crates/typst/src/geom/align.rs
+++ b/crates/typst/src/geom/align.rs
@@ -42,7 +42,7 @@ use super::*;
/// #left.y (none)
/// ```
#[ty(scope, name = "alignment")]
-#[derive(Copy, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum Align {
H(HAlign),
V(VAlign),
@@ -149,12 +149,12 @@ impl Add for Align {
}
}
-impl Debug for Align {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+impl Repr for Align {
+ fn repr(&self) -> EcoString {
match self {
- Self::H(x) => x.fmt(f),
- Self::V(y) => y.fmt(f),
- Self::Both(x, y) => write!(f, "{x:?} + {y:?}"),
+ Self::H(x) => x.repr(),
+ Self::V(y) => y.repr(),
+ Self::Both(x, y) => eco_format!("{} + {}", x.repr(), y.repr()),
}
}
}
@@ -195,7 +195,7 @@ cast! {
}
/// Where to align something horizontally.
-#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
pub enum HAlign {
#[default]
Start,
@@ -229,15 +229,15 @@ impl HAlign {
}
}
-impl Debug for HAlign {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.pad(match self {
- Self::Start => "start",
- Self::Left => "left",
- Self::Center => "center",
- Self::Right => "right",
- Self::End => "end",
- })
+impl Repr for HAlign {
+ fn repr(&self) -> EcoString {
+ match self {
+ Self::Start => "start".into(),
+ Self::Left => "left".into(),
+ Self::Center => "center".into(),
+ Self::Right => "right".into(),
+ Self::End => "end".into(),
+ }
}
}
@@ -268,12 +268,12 @@ cast! {
self => Align::H(self).into_value(),
align: Align => match align {
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.
-#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum VAlign {
#[default]
Top,
@@ -301,13 +301,13 @@ impl VAlign {
}
}
-impl Debug for VAlign {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.pad(match self {
- Self::Top => "top",
- Self::Horizon => "horizon",
- Self::Bottom => "bottom",
- })
+impl Repr for VAlign {
+ fn repr(&self) -> EcoString {
+ match self {
+ Self::Top => "top".into(),
+ Self::Horizon => "horizon".into(),
+ Self::Bottom => "bottom".into(),
+ }
}
}
@@ -330,7 +330,7 @@ cast! {
self => Align::V(self).into_value(),
align: Align => match align {
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
/// it is globally top.
-#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum FixedAlign {
Start,
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 {
fn from(side: Side) -> Self {
match side {
diff --git a/crates/typst/src/geom/angle.rs b/crates/typst/src/geom/angle.rs
index 3f187ffe..2c379f26 100644
--- a/crates/typst/src/geom/angle.rs
+++ b/crates/typst/src/geom/angle.rs
@@ -12,7 +12,7 @@ use super::*;
/// #rotate(10deg)[Hello there!]
/// ```
#[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);
impl Angle {
@@ -119,9 +119,9 @@ impl Numeric for Angle {
}
}
-impl Debug for Angle {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- write!(f, "{}deg", round_2(self.to_deg()))
+impl Repr for Angle {
+ fn repr(&self) -> EcoString {
+ format_float(self.to_deg(), Some(2), "deg")
}
}
@@ -187,7 +187,7 @@ impl Sum for Angle {
}
/// Different units of angular measurement.
-#[derive(Copy, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum AngleUnit {
/// Radians.
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.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Quadrant {
diff --git a/crates/typst/src/geom/axes.rs b/crates/typst/src/geom/axes.rs
index 9384b799..14875553 100644
--- a/crates/typst/src/geom/axes.rs
+++ b/crates/typst/src/geom/axes.rs
@@ -156,7 +156,7 @@ where
}
/// The two layouting axes.
-#[derive(Copy, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum Axis {
/// The horizontal axis.
X,
@@ -182,27 +182,16 @@ impl Axis {
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! {
Axis,
- self => self.description().into_value(),
+ self => match self {
+ Self::X => "horizontal".into_value(),
+ Self::Y => "vertical".into_value(),
+ },
"horizontal" => Self::X,
- "vertical" => Self::X,
+ "vertical" => Self::Y,
}
impl<T> Axes<Option<T>> {
diff --git a/crates/typst/src/geom/color.rs b/crates/typst/src/geom/color.rs
index fdeb664f..a5b90aa3 100644
--- a/crates/typst/src/geom/color.rs
+++ b/crates/typst/src/geom/color.rs
@@ -1,6 +1,6 @@
use std::str::FromStr;
-use ecow::{eco_format, EcoString, EcoVec};
+use ecow::EcoVec;
use once_cell::sync::Lazy;
use palette::encoding::{self, Linear};
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!
#[ty(scope)]
-#[derive(Copy, Clone)]
+#[derive(Debug, Copy, Clone)]
pub enum Color {
/// A 32-bit luma color.
Luma(Luma),
@@ -1223,106 +1223,101 @@ impl Color {
}
}
-impl Debug for Color {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+impl Repr for Color {
+ fn repr(&self) -> EcoString {
match self {
- Self::Luma(c) => write!(f, "luma({:?})", Ratio::new(c.luma as _)),
- Self::Rgba(_) => write!(f, "rgb({:?})", self.to_hex()),
+ Self::Luma(c) => eco_format!("luma({})", Ratio::new(c.luma as _).repr()),
+ Self::Rgba(_) => eco_format!("rgb({})", self.to_hex().repr()),
Self::LinearRgb(c) => {
if c.alpha == 1.0 {
- write!(
- f,
- "color.linear-rgb({:?}, {:?}, {:?})",
- Ratio::new(c.red as _),
- Ratio::new(c.green as _),
- Ratio::new(c.blue as _),
+ eco_format!(
+ "color.linear-rgb({}, {}, {})",
+ Ratio::new(c.red as _).repr(),
+ Ratio::new(c.green as _).repr(),
+ Ratio::new(c.blue as _).repr(),
)
} else {
- write!(
- f,
- "color.linear-rgb({:?}, {:?}, {:?}, {:?})",
- Ratio::new(c.red as _),
- Ratio::new(c.green as _),
- Ratio::new(c.blue as _),
- Ratio::new(c.alpha as _),
+ eco_format!(
+ "color.linear-rgb({}, {}, {}, {})",
+ Ratio::new(c.red as _).repr(),
+ Ratio::new(c.green as _).repr(),
+ Ratio::new(c.blue as _).repr(),
+ Ratio::new(c.alpha as _).repr(),
)
}
}
Self::Cmyk(c) => {
- write!(
- f,
- "rgb({:?}, {:?}, {:?}, {:?})",
- Ratio::new(c.c as _),
- Ratio::new(c.m as _),
- Ratio::new(c.y as _),
- Ratio::new(c.k as _),
+ eco_format!(
+ "rgb({}, {}, {}, {})",
+ Ratio::new(c.c as _).repr(),
+ Ratio::new(c.m as _).repr(),
+ Ratio::new(c.y as _).repr(),
+ Ratio::new(c.k as _).repr(),
)
}
Self::Oklab(c) => {
if c.alpha == 1.0 {
- write!(
- f,
- "oklab({:?}, {:.3}, {:.3})",
- Ratio::new(c.l as _),
- (c.a * 1000.0).round() / 1000.0,
- (c.b * 1000.0).round() / 1000.0,
+ eco_format!(
+ "oklab({}, {}, {})",
+ Ratio::new(c.l as _).repr(),
+ format_float(c.a as _, Some(3), ""),
+ format_float(c.b as _, Some(3), ""),
)
} else {
- write!(
- f,
- "oklab({:?}, {:?}, {:?}, {:?})",
- Ratio::new(c.l as _),
- (c.a * 1000.0).round() / 1000.0,
- (c.b * 1000.0).round() / 1000.0,
- Ratio::new(c.alpha as _),
+ eco_format!(
+ "oklab({}, {}, {}, {})",
+ Ratio::new(c.l as _).repr(),
+ format_float(c.a as _, Some(3), ""),
+ format_float(c.b as _, Some(3), ""),
+ Ratio::new(c.alpha as _).repr(),
)
}
}
Self::Hsl(c) => {
if c.alpha == 1.0 {
- write!(
- f,
- "color.hsl({:?}, {:?}, {:?})",
+ eco_format!(
+ "color.hsl({}, {}, {})",
Angle::deg(
c.hue.into_degrees().rem_euclid(360.0 + ANGLE_EPSILON) as _
- ),
- Ratio::new(c.saturation as _),
- Ratio::new(c.lightness as _),
+ )
+ .repr(),
+ Ratio::new(c.saturation as _).repr(),
+ Ratio::new(c.lightness as _).repr(),
)
} else {
- write!(
- f,
- "color.hsl({:?}, {:?}, {:?}, {:?})",
+ eco_format!(
+ "color.hsl({}, {}, {}, {})",
Angle::deg(
c.hue.into_degrees().rem_euclid(360.0 + ANGLE_EPSILON) as _
- ),
- Ratio::new(c.saturation as _),
- Ratio::new(c.lightness as _),
- Ratio::new(c.alpha as _),
+ )
+ .repr(),
+ Ratio::new(c.saturation as _).repr(),
+ Ratio::new(c.lightness as _).repr(),
+ Ratio::new(c.alpha as _).repr(),
)
}
}
Self::Hsv(c) => {
if c.alpha == 1.0 {
- write!(
- f,
- "color.hsv({:?}, {:?}, {:?})",
+ eco_format!(
+ "color.hsv({}, {}, {})",
Angle::deg(
c.hue.into_degrees().rem_euclid(360.0 + ANGLE_EPSILON) as _
- ),
- Ratio::new(c.saturation as _),
- Ratio::new(c.value as _),
+ )
+ .repr(),
+ Ratio::new(c.saturation as _).repr(),
+ Ratio::new(c.value as _).repr(),
)
} else {
- write!(
- f,
- "color.hsv({:?}, {:?}, {:?}, {:?})",
+ eco_format!(
+ "color.hsv({}, {}, {}, {})",
Angle::deg(
c.hue.into_degrees().rem_euclid(360.0 + ANGLE_EPSILON) as _
- ),
- Ratio::new(c.saturation as _),
- Ratio::new(c.value as _),
- Ratio::new(c.alpha as _),
+ )
+ .repr(),
+ Ratio::new(c.saturation as _).repr(),
+ 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.
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Cmyk {
/// The cyan component.
pub c: f32,
diff --git a/crates/typst/src/geom/corners.rs b/crates/typst/src/geom/corners.rs
index a7cd0eed..bb8a4e4c 100644
--- a/crates/typst/src/geom/corners.rs
+++ b/crates/typst/src/geom/corners.rs
@@ -1,6 +1,5 @@
-use crate::eval::{CastInfo, FromValue, IntoValue, Reflect};
-
use super::*;
+use crate::eval::{CastInfo, FromValue, IntoValue, Reflect};
/// A container with components for the four corners of a rectangle.
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
diff --git a/crates/typst/src/geom/dir.rs b/crates/typst/src/geom/dir.rs
index 897d7769..dc622d3a 100644
--- a/crates/typst/src/geom/dir.rs
+++ b/crates/typst/src/geom/dir.rs
@@ -16,7 +16,7 @@ use super::*;
/// #stack(dir: direction.rtl)[A][B][C]
/// ```
#[ty(scope, name = "direction")]
-#[derive(Copy, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum Dir {
/// Left to right.
LTR,
@@ -117,14 +117,14 @@ impl Dir {
}
}
-impl Debug for Dir {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.pad(match self {
- Self::LTR => "ltr",
- Self::RTL => "rtl",
- Self::TTB => "ttb",
- Self::BTT => "btt",
- })
+impl Repr for Dir {
+ fn repr(&self) -> EcoString {
+ match self {
+ Self::LTR => "ltr".into(),
+ Self::RTL => "rtl".into(),
+ Self::TTB => "ttb".into(),
+ Self::BTT => "btt".into(),
+ }
}
}
diff --git a/crates/typst/src/geom/em.rs b/crates/typst/src/geom/em.rs
index e6597098..9cb0c55a 100644
--- a/crates/typst/src/geom/em.rs
+++ b/crates/typst/src/geom/em.rs
@@ -3,7 +3,7 @@ use super::*;
/// A length that is relative to 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);
impl Em {
@@ -68,9 +68,9 @@ impl Numeric for Em {
}
}
-impl Debug for Em {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- write!(f, "{}em", self.get())
+impl Repr for Em {
+ fn repr(&self) -> EcoString {
+ format_float(self.get(), None, "em")
}
}
diff --git a/crates/typst/src/geom/fr.rs b/crates/typst/src/geom/fr.rs
index ad301558..f0cb4250 100644
--- a/crates/typst/src/geom/fr.rs
+++ b/crates/typst/src/geom/fr.rs
@@ -13,7 +13,7 @@ use super::*;
/// Left #h(1fr) Left-ish #h(2fr) Right
/// ```
#[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);
impl Fr {
@@ -63,9 +63,9 @@ impl Numeric for Fr {
}
}
-impl Debug for Fr {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- write!(f, "{}fr", round_2(self.get()))
+impl Repr for Fr {
+ fn repr(&self) -> EcoString {
+ format_float(self.get(), Some(2), "fr")
}
}
diff --git a/crates/typst/src/geom/gradient.rs b/crates/typst/src/geom/gradient.rs
index 38763626..ba1ae786 100644
--- a/crates/typst/src/geom/gradient.rs
+++ b/crates/typst/src/geom/gradient.rs
@@ -1,17 +1,14 @@
use std::f64::consts::{FRAC_PI_2, PI, TAU};
use std::f64::{EPSILON, NEG_INFINITY};
-use std::fmt::{self, Debug, Write};
use std::hash::Hash;
use std::sync::Arc;
-use typst_macros::{cast, func, scope, ty, Cast};
-use typst_syntax::{Span, Spanned};
-
use super::color::{Hsl, Hsv};
use super::*;
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::syntax::{Span, Spanned};
/// A color gradient.
///
@@ -169,7 +166,7 @@ use crate::geom::{ColorSpace, Smart};
/// )
/// ```
#[ty(scope)]
-#[derive(Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Gradient {
Linear(Arc<LinearGradient>),
}
@@ -531,16 +528,16 @@ impl Gradient {
}
}
-impl Debug for Gradient {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+impl Repr for Gradient {
+ fn repr(&self) -> EcoString {
match self {
- Self::Linear(linear) => linear.fmt(f),
+ Self::Linear(linear) => linear.repr(),
}
}
}
/// A gradient that interpolates between two colors along an axis.
-#[derive(Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct LinearGradient {
/// The color stops of this gradient.
pub stops: Vec<(Color, Ratio)>,
@@ -554,40 +551,50 @@ pub struct LinearGradient {
pub anti_alias: bool,
}
-impl Debug for LinearGradient {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.write_str("gradient.linear(")?;
+impl Repr for LinearGradient {
+ fn repr(&self) -> EcoString {
+ let mut r = EcoString::from("gradient.linear(");
let angle = self.angle.to_rad().rem_euclid(TAU);
if angle.abs() < EPSILON {
// Default value, do nothing
} else if (angle - FRAC_PI_2).abs() < EPSILON {
- f.write_str("dir: rtl, ")?;
+ r.push_str("dir: rtl, ");
} 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 {
- f.write_str("dir: btt, ")?;
+ r.push_str("dir: btt, ");
} else {
- write!(f, "angle: {:?}, ", self.angle)?;
+ r.push_str("angle: ");
+ r.push_str(&self.angle.repr());
+ r.push_str(", ");
}
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() {
- 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() {
- 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 {
- f.write_str(", ")?;
+ r.push_str(", ");
}
}
- f.write_char(')')
+ r.push(')');
+ r
}
}
diff --git a/crates/typst/src/geom/length.rs b/crates/typst/src/geom/length.rs
index 453dbe59..b8db6e50 100644
--- a/crates/typst/src/geom/length.rs
+++ b/crates/typst/src/geom/length.rs
@@ -1,5 +1,3 @@
-use ecow::eco_format;
-
use super::*;
use crate::diag::{At, Hint, SourceResult};
use crate::syntax::Span;
@@ -33,7 +31,7 @@ use crate::syntax::Span;
/// (that is, excluding the `em` component).
/// - `em`: The amount of `em` units in this length, as a [float]($float).
#[ty(scope)]
-#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Length {
/// The absolute part.
pub abs: Abs,
@@ -75,7 +73,8 @@ impl Length {
return Ok(());
}
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"))
.at(span)
@@ -127,12 +126,12 @@ impl Length {
}
}
-impl Debug for Length {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+impl Repr for Length {
+ fn repr(&self) -> EcoString {
match (self.abs.is_zero(), self.em.is_zero()) {
- (false, false) => write!(f, "{:?} + {:?}", self.abs, self.em),
- (true, false) => self.em.fmt(f),
- (_, true) => self.abs.fmt(f),
+ (false, false) => eco_format!("{} + {}", self.abs.repr(), self.em.repr()),
+ (true, false) => self.em.repr(),
+ (_, true) => self.abs.repr(),
}
}
}
diff --git a/crates/typst/src/geom/mod.rs b/crates/typst/src/geom/mod.rs
index 2da38a1e..29ecbe74 100644
--- a/crates/typst/src/geom/mod.rs
+++ b/crates/typst/src/geom/mod.rs
@@ -61,9 +61,12 @@ use std::hash::{Hash, Hasher};
use std::iter::Sum;
use std::ops::*;
+use ecow::{eco_format, EcoString};
+
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::util::fmt::format_float;
/// Generic access to a structure's components.
pub trait Get<Index> {
diff --git a/crates/typst/src/geom/paint.rs b/crates/typst/src/geom/paint.rs
index 1c24c1ff..c5a6c7e4 100644
--- a/crates/typst/src/geom/paint.rs
+++ b/crates/typst/src/geom/paint.rs
@@ -1,7 +1,7 @@
use super::*;
/// How a fill or stroke should be painted.
-#[derive(Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Paint {
/// A solid color.
Solid(Color),
@@ -32,11 +32,11 @@ impl From<Gradient> for Paint {
}
}
-impl Debug for Paint {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+impl Repr for Paint {
+ fn repr(&self) -> EcoString {
match self {
- Self::Solid(color) => color.fmt(f),
- Self::Gradient(gradient) => gradient.fmt(f),
+ Self::Solid(color) => color.repr(),
+ Self::Gradient(gradient) => gradient.repr(),
}
}
}
diff --git a/crates/typst/src/geom/ratio.rs b/crates/typst/src/geom/ratio.rs
index b1488276..b0a092ba 100644
--- a/crates/typst/src/geom/ratio.rs
+++ b/crates/typst/src/geom/ratio.rs
@@ -12,7 +12,7 @@ use super::*;
/// ]
/// ```
#[ty]
-#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Ratio(Scalar);
impl Ratio {
@@ -62,9 +62,9 @@ impl Ratio {
}
}
-impl Debug for Ratio {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- write!(f, "{}%", round_2(100.0 * self.get()))
+impl Repr for Ratio {
+ fn repr(&self) -> EcoString {
+ format_float(self.get() * 100.0, Some(2), "%")
}
}
diff --git a/crates/typst/src/geom/rel.rs b/crates/typst/src/geom/rel.rs
index 59a1348d..09a737e7 100644
--- a/crates/typst/src/geom/rel.rs
+++ b/crates/typst/src/geom/rel.rs
@@ -18,7 +18,7 @@ use super::*;
/// - `length`: Its length component.
/// - `ratio`: Its ratio component.
#[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> {
/// The relative part.
pub rel: Ratio,
@@ -80,12 +80,12 @@ impl Rel<Length> {
}
}
-impl<T: Numeric> Debug for Rel<T> {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+impl<T: Numeric + Repr> Repr for Rel<T> {
+ fn repr(&self) -> EcoString {
match (self.rel.is_zero(), self.abs.is_zero()) {
- (false, false) => write!(f, "{:?} + {:?}", self.rel, self.abs),
- (false, true) => self.rel.fmt(f),
- (true, _) => self.abs.fmt(f),
+ (false, false) => eco_format!("{} + {}", self.rel.repr(), self.abs.repr()),
+ (false, true) => self.rel.repr(),
+ (true, _) => self.abs.repr(),
}
}
}
diff --git a/crates/typst/src/geom/scalar.rs b/crates/typst/src/geom/scalar.rs
index 6801bbc0..3fbf03ba 100644
--- a/crates/typst/src/geom/scalar.rs
+++ b/crates/typst/src/geom/scalar.rs
@@ -3,7 +3,7 @@ use super::*;
/// A 64-bit float that implements `Eq`, `Ord` and `Hash`.
///
/// Panics if it's `NaN` during any of those operations.
-#[derive(Default, Copy, Clone)]
+#[derive(Debug, Default, Copy, Clone)]
pub struct Scalar(f64);
// 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 {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- Debug::fmt(&self.0, f)
+impl Repr for Scalar {
+ fn repr(&self) -> EcoString {
+ self.0.repr()
}
}
diff --git a/crates/typst/src/geom/sides.rs b/crates/typst/src/geom/sides.rs
index c1c2dadf..e21fe63f 100644
--- a/crates/typst/src/geom/sides.rs
+++ b/crates/typst/src/geom/sides.rs
@@ -1,6 +1,5 @@
-use crate::eval::{CastInfo, FromValue, IntoValue, Reflect};
-
use super::*;
+use crate::eval::{CastInfo, FromValue, IntoValue, Reflect};
/// A container with left, top, right and bottom components.
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
diff --git a/crates/typst/src/geom/smart.rs b/crates/typst/src/geom/smart.rs
index 2a21490b..6f6dcb49 100644
--- a/crates/typst/src/geom/smart.rs
+++ b/crates/typst/src/geom/smart.rs
@@ -1,6 +1,5 @@
-use crate::eval::{AutoValue, CastInfo, FromValue, IntoValue, Reflect};
-
use super::*;
+use crate::eval::{AutoValue, CastInfo, FromValue, IntoValue, Reflect};
/// A value that can be automatically determined.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
diff --git a/crates/typst/src/geom/stroke.rs b/crates/typst/src/geom/stroke.rs
index 91e7ee2e..1896bbf2 100644
--- a/crates/typst/src/geom/stroke.rs
+++ b/crates/typst/src/geom/stroke.rs
@@ -1,6 +1,5 @@
-use crate::eval::{dict, Cast, FromValue, NoneValue};
-
use super::*;
+use crate::eval::{dict, Cast, FromValue, NoneValue};
/// Defines how to draw a line.
///
@@ -67,7 +66,7 @@ use super::*;
/// dictionary format above. For example, `{(2pt + blue).thickness}` is `{2pt}`.
/// Meanwhile, `{(2pt + blue).cap}` is `{auto}` because it's unspecified.
#[ty]
-#[derive(Default, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
pub struct Stroke<T: Numeric = Length> {
/// The stroke's paint.
pub paint: Smart<Paint>,
@@ -146,8 +145,9 @@ impl Stroke<Abs> {
}
}
-impl<T: Numeric + Debug> Debug for Stroke<T> {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+impl<T: Numeric + Repr> Repr for Stroke<T> {
+ fn repr(&self) -> EcoString {
+ let mut r = EcoString::new();
let Self {
paint,
thickness,
@@ -163,46 +163,59 @@ impl<T: Numeric + Debug> Debug for Stroke<T> {
{
match (&self.paint, &self.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::Auto, Smart::Custom(thickness)) => thickness.fmt(f),
- (Smart::Auto, Smart::Auto) => f.pad("1pt + black"),
+ (Smart::Custom(paint), Smart::Auto) => r.push_str(&paint.repr()),
+ (Smart::Auto, Smart::Custom(thickness)) => r.push_str(&thickness.repr()),
+ (Smart::Auto, Smart::Auto) => r.push_str("1pt + black"),
}
} else {
- write!(f, "(")?;
+ r.push('(');
let mut sep = "";
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 = ", ";
}
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 = ", ";
}
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 = ", ";
}
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 = ", ";
}
if let Smart::Custom(dash) = &dash_pattern {
- write!(f, "{}dash: ", sep)?;
+ r.push_str(sep);
+ r.push_str("cap: ");
if let Some(dash) = dash {
- Debug::fmt(dash, f)?;
+ r.push_str(&dash.repr());
} else {
- Debug::fmt(&NoneValue, f)?;
+ r.push_str(&NoneValue.repr());
}
sep = ", ";
}
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, ")")?;
- Ok(())
+ r.push(')');
}
+ r
}
}
@@ -277,43 +290,43 @@ cast! {
}
/// The line cap of a stroke
-#[derive(Copy, Clone, Eq, PartialEq, Hash, Cast)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)]
pub enum LineCap {
Butt,
Round,
Square,
}
-impl Debug for LineCap {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+impl Repr for LineCap {
+ fn repr(&self) -> EcoString {
match self {
- LineCap::Butt => write!(f, "\"butt\""),
- LineCap::Round => write!(f, "\"round\""),
- LineCap::Square => write!(f, "\"square\""),
+ Self::Butt => "butt".repr(),
+ Self::Round => "round".repr(),
+ Self::Square => "square".repr(),
}
}
}
/// The line join of a stroke
-#[derive(Copy, Clone, Eq, PartialEq, Hash, Cast)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)]
pub enum LineJoin {
Miter,
Round,
Bevel,
}
-impl Debug for LineJoin {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+impl Repr for LineJoin {
+ fn repr(&self) -> EcoString {
match self {
- LineJoin::Miter => write!(f, "\"miter\""),
- LineJoin::Round => write!(f, "\"round\""),
- LineJoin::Bevel => write!(f, "\"bevel\""),
+ Self::Miter => "miter".repr(),
+ Self::Round => "round".repr(),
+ Self::Bevel => "bevel".repr(),
}
}
}
/// A line dash pattern.
-#[derive(Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct DashPattern<T: Numeric = Length, DT = DashLength<T>> {
/// The dash array.
pub array: Vec<DT>,
@@ -321,18 +334,19 @@ pub struct DashPattern<T: Numeric = Length, DT = DashLength<T>> {
pub phase: T,
}
-impl<T: Numeric + Debug, DT: Debug> Debug for DashPattern<T, DT> {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- write!(f, "(array: (")?;
+impl<T: Numeric + Repr, DT: Repr> Repr for DashPattern<T, DT> {
+ fn repr(&self) -> EcoString {
+ let mut r = EcoString::from("(array: (");
for (i, elem) in self.array.iter().enumerate() {
- if i == 0 {
- write!(f, "{:?}", elem)?;
- } else {
- write!(f, ", {:?}", elem)?;
+ if i != 0 {
+ r.push_str(", ")
}
+ r.push_str(&elem.repr())
}
- write!(f, "), phase: {:?})", self.phase)?;
- Ok(())
+ r.push_str("), phase: ");
+ r.push_str(&self.phase.repr());
+ r.push(')');
+ r
}
}
@@ -384,7 +398,7 @@ cast! {
}
/// 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> {
LineWidth,
Length(T),
@@ -399,11 +413,11 @@ impl<T: Numeric> DashLength<T> {
}
}
-impl<T: Numeric + Debug> Debug for DashLength<T> {
- fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+impl<T: Numeric + Repr> Repr for DashLength<T> {
+ fn repr(&self) -> EcoString {
match self {
- Self::LineWidth => write!(f, "\"dot\""),
- Self::Length(v) => Debug::fmt(v, f),
+ Self::LineWidth => "dot".repr(),
+ Self::Length(v) => v.repr(),
}
}
}
diff --git a/crates/typst/src/model/content.rs b/crates/typst/src/model/content.rs
index 3a6c648c..9205f4d8 100644
--- a/crates/typst/src/model/content.rs
+++ b/crates/typst/src/model/content.rs
@@ -1,5 +1,5 @@
use std::any::TypeId;
-use std::fmt::{self, Debug, Formatter, Write};
+use std::fmt::Debug;
use std::iter::{self, Sum};
use std::ops::{Add, AddAssign};
@@ -13,7 +13,7 @@ use super::{
};
use crate::diag::{SourceResult, StrResult};
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::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.
/// Alternatively, you can inspect the output of the [`repr`]($repr) function.
#[ty(scope)]
-#[derive(Clone, Hash)]
+#[derive(Debug, Clone, Hash)]
#[allow(clippy::derived_hash_with_manual_eq)]
pub struct Content {
elem: Element,
@@ -528,30 +528,26 @@ impl Content {
}
}
-impl Debug for Content {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+impl Repr for Content {
+ fn repr(&self) -> EcoString {
let name = self.elem.name();
if let Some(text) = item!(text_str)(self) {
- f.write_char('[')?;
- f.write_str(&text)?;
- f.write_char(']')?;
- return Ok(());
+ return eco_format!("[{}]", text);
} else if name == "space" {
- return f.write_str("[ ]");
+ return ("[ ]").into();
}
let mut pieces: Vec<_> = self
.fields()
.into_iter()
- .map(|(name, value)| eco_format!("{name}: {value:?}"))
+ .map(|(name, value)| eco_format!("{}: {}", name, value.repr()))
.collect();
if self.is::<StyledElem>() {
pieces.push(EcoString::from(".."));
}
- f.write_str(name)?;
- f.write_str(&pretty_array_like(&pieces, false))
+ eco_format!("{}{}", name, pretty_array_like(&pieces, false))
}
}
@@ -696,15 +692,15 @@ pub trait PlainText {
/// The missing field access error message.
#[cold]
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.
#[cold]
fn missing_field_no_default(field: &str) -> EcoString {
eco_format!(
- "content does not contain field {:?} and \
+ "content does not contain field {} and \
no default value was specified",
- Str::from(field)
+ field.repr()
)
}
diff --git a/crates/typst/src/model/element.rs b/crates/typst/src/model/element.rs
index c9744cda..e783614f 100644
--- a/crates/typst/src/model/element.rs
+++ b/crates/typst/src/model/element.rs
@@ -1,16 +1,17 @@
+use ecow::EcoString;
use std::any::TypeId;
use std::cmp::Ordering;
-use std::fmt::{self, Debug, Formatter};
+use std::fmt::Debug;
use once_cell::sync::Lazy;
use super::{Content, Selector, Styles};
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;
/// A document element.
-#[derive(Copy, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Element(Static<NativeElementData>);
impl Element {
@@ -93,9 +94,9 @@ impl Element {
}
}
-impl Debug for Element {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.pad(self.name())
+impl Repr for Element {
+ fn repr(&self) -> EcoString {
+ self.name().into()
}
}
@@ -150,6 +151,7 @@ pub trait Set {
}
/// Defines a native element.
+#[derive(Debug)]
pub struct NativeElementData {
pub name: &'static str,
pub title: &'static str,
diff --git a/crates/typst/src/model/introspect.rs b/crates/typst/src/model/introspect.rs
index ebf2ab75..f8a3358e 100644
--- a/crates/typst/src/model/introspect.rs
+++ b/crates/typst/src/model/introspect.rs
@@ -1,17 +1,17 @@
use std::cell::RefCell;
use std::collections::{BTreeSet, HashMap};
-use std::fmt::{self, Debug, Formatter};
+use std::fmt::Debug;
use std::hash::Hash;
use std::num::NonZeroUsize;
use comemo::{Prehashed, Track, Tracked, Validate};
-use ecow::EcoVec;
+use ecow::{EcoString, EcoVec};
use indexmap::IndexMap;
use super::{Content, Selector};
use crate::diag::{bail, StrResult};
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::model::Label;
use crate::util::NonZeroExt;
@@ -24,7 +24,7 @@ use crate::util::NonZeroExt;
/// or shown element with the [`location()`]($content.location) method on
/// content.
#[ty(scope)]
-#[derive(Copy, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Location {
/// The hash of the element.
hash: u128,
@@ -83,9 +83,9 @@ impl Location {
}
}
-impl Debug for Location {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.pad("..")
+impl Repr for Location {
+ fn repr(&self) -> EcoString {
+ "..".into()
}
}
diff --git a/crates/typst/src/model/label.rs b/crates/typst/src/model/label.rs
index 79f73881..0beb3bfc 100644
--- a/crates/typst/src/model/label.rs
+++ b/crates/typst/src/model/label.rs
@@ -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.
///
@@ -23,7 +23,7 @@ use crate::eval::{func, scope, ty};
/// 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.
#[ty(scope)]
-#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Label(pub EcoString);
#[scope]
@@ -38,9 +38,9 @@ impl Label {
}
}
-impl Debug for Label {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- write!(f, "<{}>", self.0)
+impl Repr for Label {
+ fn repr(&self) -> EcoString {
+ eco_format!("<{}>", self.0)
}
}
diff --git a/crates/typst/src/model/selector.rs b/crates/typst/src/model/selector.rs
index 9264c9ea..ce0e62cc 100644
--- a/crates/typst/src/model/selector.rs
+++ b/crates/typst/src/model/selector.rs
@@ -1,5 +1,5 @@
use std::any::{Any, TypeId};
-use std::fmt::{self, Debug, Formatter, Write};
+use std::fmt::Debug;
use std::sync::Arc;
use ecow::{eco_format, EcoString, EcoVec};
@@ -7,8 +7,8 @@ use ecow::{eco_format, EcoString, EcoVec};
use super::{Content, Element, Label, Locatable, Location};
use crate::diag::{bail, StrResult};
use crate::eval::{
- cast, func, scope, ty, CastInfo, Dict, FromValue, Func, Reflect, Regex, Str, Symbol,
- Type, Value,
+ cast, func, scope, ty, CastInfo, Dict, FromValue, Func, Reflect, Regex, Repr, Str,
+ Symbol, Type, Value,
};
use crate::util::pretty_array_like;
@@ -49,7 +49,7 @@ use crate::util::pretty_array_like;
/// === But this will not.
/// ```
#[ty(scope)]
-#[derive(Clone, PartialEq, Hash)]
+#[derive(Debug, Clone, PartialEq, Hash)]
pub enum Selector {
/// Matches a specific type of element.
///
@@ -209,42 +209,37 @@ impl From<Location> for Selector {
}
}
-impl Debug for Selector {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+impl Repr for Selector {
+ fn repr(&self) -> EcoString {
match self {
Self::Elem(elem, dict) => {
- f.write_str(elem.name())?;
if let Some(dict) = dict {
- f.write_str(".where")?;
- dict.fmt(f)?;
+ eco_format!("{}.where{}", elem.name(), dict.repr())
+ } else {
+ elem.name().into()
}
- Ok(())
}
- Self::Label(label) => label.fmt(f),
- Self::Regex(regex) => regex.fmt(f),
- Self::Can(cap) => cap.fmt(f),
+ Self::Label(label) => label.repr(),
+ Self::Regex(regex) => regex.repr(),
+ Self::Can(cap) => eco_format!("{cap:?}"),
Self::Or(selectors) | Self::And(selectors) => {
- f.write_str(if matches!(self, Self::Or(_)) { "or" } else { "and" })?;
- let pieces: Vec<_> =
- selectors.iter().map(|sel| eco_format!("{sel:?}")).collect();
- f.write_str(&pretty_array_like(&pieces, false))
+ let function = if matches!(self, Self::Or(_)) { "or" } else { "and" };
+ let pieces: Vec<_> = selectors.iter().map(Selector::repr).collect();
+ eco_format!("{}{}", function, pretty_array_like(&pieces, false))
}
- Self::Location(loc) => loc.fmt(f),
+ Self::Location(loc) => loc.repr(),
Self::Before { selector, end: split, inclusive }
| Self::After { selector, start: split, inclusive } => {
- selector.fmt(f)?;
-
- if matches!(self, Self::Before { .. }) {
- f.write_str(".before(")?;
- } else {
- f.write_str(".after(")?;
- }
-
- split.fmt(f)?;
- if !*inclusive {
- f.write_str(", inclusive: false")?;
- }
- f.write_char(')')
+ let method =
+ if matches!(self, Self::Before { .. }) { "before" } else { "after" };
+ let inclusive_arg = if !*inclusive { ", inclusive: false" } else { "" };
+ eco_format!(
+ "{}.{}({}{})",
+ selector.repr(),
+ method,
+ split.repr(),
+ inclusive_arg
+ )
}
}
}
diff --git a/crates/typst/src/model/styles.rs b/crates/typst/src/model/styles.rs
index 347eae4c..118f5f45 100644
--- a/crates/typst/src/model/styles.rs
+++ b/crates/typst/src/model/styles.rs
@@ -8,12 +8,12 @@ use ecow::{eco_vec, EcoString, EcoVec};
use super::{Content, Element, NativeElement, Selector, Vt};
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;
/// A list of style properties.
#[ty]
-#[derive(Default, PartialEq, Clone, Hash)]
+#[derive(Debug, Default, PartialEq, Clone, Hash)]
pub struct Styles(EcoVec<Prehashed<Style>>);
impl Styles {
@@ -86,9 +86,9 @@ impl From<Style> for Styles {
}
}
-impl Debug for Styles {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.pad("..")
+impl Repr for Styles {
+ fn repr(&self) -> EcoString {
+ "..".into()
}
}
diff --git a/crates/typst/src/util/fmt.rs b/crates/typst/src/util/fmt.rs
index a2686dd7..8400b871 100644
--- a/crates/typst/src/util/fmt.rs
+++ b/crates/typst/src/util/fmt.rs
@@ -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".
pub fn separated_list(pieces: &[impl AsRef<str>], last: &str) -> String {
let mut buf = String::new();
diff --git a/crates/typst/src/util/mod.rs b/crates/typst/src/util/mod.rs
index 6c183a4f..f5c20520 100644
--- a/crates/typst/src/util/mod.rs
+++ b/crates/typst/src/util/mod.rs
@@ -1,7 +1,7 @@
//! Utilities.
pub mod fat;
-mod fmt;
+pub mod fmt;
pub use self::fmt::{pretty_array_like, pretty_comma_list, separated_list};
diff --git a/tests/ref/compiler/repr-color-gradient.png b/tests/ref/compiler/repr-color-gradient.png
index e44238b0..53c734c9 100644
--- a/tests/ref/compiler/repr-color-gradient.png
+++ b/tests/ref/compiler/repr-color-gradient.png
Binary files differ
diff --git a/tests/src/tests.rs b/tests/src/tests.rs
index d7536907..d690cdb3 100644
--- a/tests/src/tests.rs
+++ b/tests/src/tests.rs
@@ -22,7 +22,9 @@ use walkdir::WalkDir;
use typst::diag::{bail, FileError, FileResult, Severity, StrResult};
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::geom::{Abs, Color, Smart};
use typst::syntax::{FileId, PackageVersion, Source, SyntaxNode, VirtualPath};
@@ -154,7 +156,7 @@ fn library() -> Library {
#[func]
fn test(lhs: Value, rhs: Value) -> StrResult<NoneValue> {
if lhs != rhs {
- bail!("Assertion failed: {lhs:?} != {rhs:?}");
+ bail!("Assertion failed: {} != {}", lhs.repr(), rhs.repr());
}
Ok(NoneValue)
}
@@ -162,7 +164,7 @@ fn library() -> Library {
#[func]
fn test_repr(lhs: Value, rhs: Value) -> StrResult<NoneValue> {
if lhs.repr() != rhs.repr() {
- bail!("Assertion failed: {lhs:?} != {rhs:?}");
+ bail!("Assertion failed: {} != {}", lhs.repr(), rhs.repr());
}
Ok(NoneValue)
}