diff --git a/crates/typst-docs/src/lib.rs b/crates/typst-docs/src/lib.rs index 8f7c8ff8e..30ba4ebb9 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 83e339f9b..bb17dd37e 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 8a418e0e8..37f32e222 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 { 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 250a9f577..b02f9793e 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 88bc82bdd..1ad0bff1c 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 f7b5eb778..137b754e4 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 aca5a0645..329cbf61b 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 6a6b84772..203232071 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 ffd9d4aa3..dd206044a 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 ac403eef6..aad9fda6a 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 { - if let Some(name) = &self.name { - f.write_str(name)?; - f.write_str(": ")?; - } - Debug::fmt(&self.value.v, f) +impl Repr for Args { + fn repr(&self) -> EcoString { + let pieces = self.items.iter().map(Arg::repr).collect::>(); + pretty_array_like(&pieces, false).into() + } +} + +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() + } } } diff --git a/crates/typst/src/eval/array.rs b/crates/typst/src/eval/array.rs index 3da7c0b01..926427027 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 a9d8fc9eb..24254a0fc 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 dcc73e66a..1dca260c8 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 12f9bcf13..691160001 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>>); 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 f457d4d19..0965c8fae 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 6b340a8ed..c76a59bd8 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::>(); - 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 4ac68587e..c5da7c158 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> 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 1bbf8492b..e1e6ee577 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 d8a2c3e8a..d90038502 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), @@ -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, 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 55c709c0d..b2b76f30f 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 f0d1be20e..8627b489c 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 9ae4b0f9c..9169c6d2d 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, "", self.name()) +impl super::Repr for Module { + fn repr(&self) -> EcoString { + eco_format!("", self.name()) } } diff --git a/crates/typst/src/eval/none.rs b/crates/typst/src/eval/none.rs index 5262301f9..90cd0ff95 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 5581e79ed..4a64cfed7 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 { } /// Try to compare two values. -fn try_cmp_values(a: &T, b: &T) -> StrResult { +fn try_cmp_values(a: &T, b: &T) -> StrResult { 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 ee64ec5fd..af7810892 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 3a8d47302..e7df00e1a 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 e74bec3fd..679835d09 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 5a2457e63..82e895fa4 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); 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 901bc2788..901d3819e 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(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); @@ -460,7 +455,7 @@ impl Dynamic { /// Create a new instance from any value that satisfies the required bounds. pub fn new(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 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 6ba0dff4e..e2b4ac520 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); @@ -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 e74f63229..ec247b259 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, } +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 2dd1ad322..953a5122a 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 74053e34b..d3c1f9536 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 d177a3048..3b56f5f26 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 bfe377fbb..59e608b11 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 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 3f187ffef..2c379f262 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 9384b7998..148755533 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 Axes> { diff --git a/crates/typst/src/geom/color.rs b/crates/typst/src/geom/color.rs index fdeb664f6..a5b90aa31 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 a7cd0eed8..bb8a4e4c5 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 897d7769a..dc622d3a7 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 e65970988..9cb0c55a4 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 ad301558e..f0cb42507 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 387636267..ba1ae7869 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), } @@ -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 453dbe599..b8db6e50b 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 2da38a1ed..29ecbe743 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 { diff --git a/crates/typst/src/geom/paint.rs b/crates/typst/src/geom/paint.rs index 1c24c1ff3..c5a6c7e43 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 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 b1488276f..b0a092bac 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 59a1348dd..09a737e79 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 { /// The relative part. pub rel: Ratio, @@ -80,12 +80,12 @@ impl Rel { } } -impl Debug for Rel { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { +impl Repr for Rel { + 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 6801bbc0a..3fbf03ba7 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 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 c1c2dadfd..e21fe63f6 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 2a21490b4..6f6dcb491 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 91e7ee2e1..1896bbf21 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 { /// The stroke's paint. pub paint: Smart, @@ -146,8 +145,9 @@ impl Stroke { } } -impl Debug for Stroke { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { +impl Repr for Stroke { + fn repr(&self) -> EcoString { + let mut r = EcoString::new(); let Self { paint, thickness, @@ -163,46 +163,59 @@ impl Debug for Stroke { { 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> { /// The dash array. pub array: Vec
, @@ -321,18 +334,19 @@ pub struct DashPattern> { pub phase: T, } -impl Debug for DashPattern { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "(array: (")?; +impl Repr for DashPattern { + 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 { LineWidth, Length(T), @@ -399,11 +413,11 @@ impl DashLength { } } -impl Debug for DashLength { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl Repr for DashLength { + 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 3a6c648cc..9205f4d86 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::() { 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 c9744cda2..e783614f8 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); 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 ebf2ab751..f8a3358ef 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 79f73881e..0beb3bfc4 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 9264c9ead..ce0e62ccb 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 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 347eae4c2..118f5f453 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>); impl Styles { @@ -86,9 +86,9 @@ impl From