diff --git a/crates/typst/src/foundations/float.rs b/crates/typst/src/foundations/float.rs index 3408d1f5c..4b38bdf98 100644 --- a/crates/typst/src/foundations/float.rs +++ b/crates/typst/src/foundations/float.rs @@ -51,7 +51,7 @@ impl f64 { impl Repr for f64 { fn repr(&self) -> EcoString { - repr::format_float(*self, None, "") + repr::format_float(*self, None, true, "") } } diff --git a/crates/typst/src/foundations/int.rs b/crates/typst/src/foundations/int.rs index 41b134845..88b0413ab 100644 --- a/crates/typst/src/foundations/int.rs +++ b/crates/typst/src/foundations/int.rs @@ -53,7 +53,7 @@ impl i64 { impl Repr for i64 { fn repr(&self) -> EcoString { - repr::format_int_with_base(*self, 10) + eco_format!("{:?}", self) } } diff --git a/crates/typst/src/foundations/repr.rs b/crates/typst/src/foundations/repr.rs index 420cb63a8..62611cc82 100644 --- a/crates/typst/src/foundations/repr.rs +++ b/crates/typst/src/foundations/repr.rs @@ -74,20 +74,51 @@ pub fn format_int_with_base(mut n: i64, base: i64) -> EcoString { /// 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, suffix: &str) -> EcoString { +pub fn format_float( + mut value: f64, + precision: Option, + force_separator: bool, + suffix: &str, +) -> EcoString { if let Some(p) = precision { let offset = 10_f64.powi(p as i32); value = (value * offset).round() / offset; } + // Debug for f64 always prints a decimal separator, while Display only does + // when necessary. if value.is_nan() { "NaN".into() - } else if value.is_sign_negative() { - eco_format!("{}{}{}", MINUS_SIGN, value.abs(), suffix) + } else if force_separator { + eco_format!("{:?}{}", value, suffix) } else { eco_format!("{}{}", value, suffix) } } +/// Converts a float to a string representation with a precision of three +/// decimal places. This is intended to be used as part of a larger structure +/// containing multiple float components, such as colors. +pub fn format_float_component(value: f64) -> EcoString { + format_float(value, Some(3), false, "") +} + +/// Converts a float to a string representation with a precision of two decimal +/// places, followed by a unit. +pub fn format_float_with_unit(value: f64, unit: &str) -> EcoString { + format_float(value, Some(2), false, unit) +} + +/// Converts a float to a string that can be used to display the float as text. +pub fn display_float(value: f64) -> EcoString { + if value.is_nan() { + "NaN".into() + } else if value < 0.0 { + eco_format!("{}{}", MINUS_SIGN, value.abs()) + } else { + eco_format!("{}", value.abs()) + } +} + /// Format pieces separated with commas and a final "and" or "or". pub fn separated_list(pieces: &[impl AsRef], last: &str) -> String { let mut buf = String::new(); diff --git a/crates/typst/src/foundations/str.rs b/crates/typst/src/foundations/str.rs index 83bde675b..ab4180495 100644 --- a/crates/typst/src/foundations/str.rs +++ b/crates/typst/src/foundations/str.rs @@ -762,7 +762,7 @@ pub enum ToStr { cast! { ToStr, v: i64 => Self::Int(v), - v: f64 => Self::Str(repr::format_float(v, None, "").into()), + v: f64 => Self::Str(repr::display_float(v).into()), v: Version => Self::Str(format_str!("{}", v)), v: Bytes => Self::Str( std::str::from_utf8(&v) diff --git a/crates/typst/src/foundations/value.rs b/crates/typst/src/foundations/value.rs index d45c8412e..5da915d1e 100644 --- a/crates/typst/src/foundations/value.rs +++ b/crates/typst/src/foundations/value.rs @@ -202,7 +202,7 @@ impl Value { match self { Self::None => Content::empty(), Self::Int(v) => TextElem::packed(repr::format_int_with_base(v, 10)), - Self::Float(v) => TextElem::packed(repr::format_float(v, None, "")), + Self::Float(v) => TextElem::packed(repr::display_float(v)), Self::Str(v) => TextElem::packed(v), Self::Version(v) => TextElem::packed(eco_format!("{v}")), Self::Symbol(v) => TextElem::packed(v.get()), diff --git a/crates/typst/src/layout/abs.rs b/crates/typst/src/layout/abs.rs index 92b4bf2ba..cb61e1b28 100644 --- a/crates/typst/src/layout/abs.rs +++ b/crates/typst/src/layout/abs.rs @@ -148,7 +148,7 @@ impl Debug for Abs { impl Repr for Abs { fn repr(&self) -> EcoString { - repr::format_float(self.to_pt(), Some(2), "pt") + repr::format_float_with_unit(self.to_pt(), "pt") } } diff --git a/crates/typst/src/layout/angle.rs b/crates/typst/src/layout/angle.rs index 4120cbc18..e6ed9a588 100644 --- a/crates/typst/src/layout/angle.rs +++ b/crates/typst/src/layout/angle.rs @@ -135,7 +135,7 @@ impl Debug for Angle { impl Repr for Angle { fn repr(&self) -> EcoString { - repr::format_float(self.to_deg(), Some(2), "deg") + repr::format_float_with_unit(self.to_deg(), "deg") } } diff --git a/crates/typst/src/layout/em.rs b/crates/typst/src/layout/em.rs index b3b416f93..6a44ebb5f 100644 --- a/crates/typst/src/layout/em.rs +++ b/crates/typst/src/layout/em.rs @@ -85,7 +85,7 @@ impl Debug for Em { impl Repr for Em { fn repr(&self) -> EcoString { - repr::format_float(self.get(), None, "em") + repr::format_float_with_unit(self.get(), "em") } } diff --git a/crates/typst/src/layout/fr.rs b/crates/typst/src/layout/fr.rs index 8be70582f..24fe77f86 100644 --- a/crates/typst/src/layout/fr.rs +++ b/crates/typst/src/layout/fr.rs @@ -79,7 +79,7 @@ impl Debug for Fr { impl Repr for Fr { fn repr(&self) -> EcoString { - repr::format_float(self.get(), Some(2), "fr") + repr::format_float_with_unit(self.get(), "fr") } } diff --git a/crates/typst/src/layout/ratio.rs b/crates/typst/src/layout/ratio.rs index c19245b40..b535df38d 100644 --- a/crates/typst/src/layout/ratio.rs +++ b/crates/typst/src/layout/ratio.rs @@ -76,7 +76,7 @@ impl Debug for Ratio { impl Repr for Ratio { fn repr(&self) -> EcoString { - repr::format_float(self.get() * 100.0, Some(2), "%") + repr::format_float_with_unit(self.get() * 100.0, "%") } } diff --git a/crates/typst/src/visualize/color.rs b/crates/typst/src/visualize/color.rs index cb998160f..ab3aa4247 100644 --- a/crates/typst/src/visualize/color.rs +++ b/crates/typst/src/visualize/color.rs @@ -1472,15 +1472,15 @@ impl Repr for Color { eco_format!( "oklab({}, {}, {})", Ratio::new(c.l as _).repr(), - repr::format_float(c.a as _, Some(3), ""), - repr::format_float(c.b as _, Some(3), ""), + repr::format_float_component(c.a as _), + repr::format_float_component(c.b as _), ) } else { eco_format!( "oklab({}, {}, {}, {})", Ratio::new(c.l as _).repr(), - repr::format_float(c.a as _, Some(3), ""), - repr::format_float(c.b as _, Some(3), ""), + repr::format_float_component(c.a as _), + repr::format_float_component(c.b as _), Ratio::new(c.alpha as _).repr(), ) } @@ -1490,14 +1490,14 @@ impl Repr for Color { eco_format!( "oklch({}, {}, {})", Ratio::new(c.l as _).repr(), - repr::format_float(c.chroma as _, Some(3), ""), + repr::format_float_component(c.chroma as _), hue_angle(c.hue.into_degrees()).repr(), ) } else { eco_format!( "oklch({}, {}, {}, {})", Ratio::new(c.l as _).repr(), - repr::format_float(c.chroma as _, Some(3), ""), + repr::format_float_component(c.chroma as _), hue_angle(c.hue.into_degrees()).repr(), Ratio::new(c.alpha as _).repr(), ) diff --git a/tests/ref/compiler/array.png b/tests/ref/compiler/array.png index b97dd317b..9b6bf8b30 100644 Binary files a/tests/ref/compiler/array.png and b/tests/ref/compiler/array.png differ diff --git a/tests/ref/compiler/repr-color-gradient.png b/tests/ref/compiler/repr-color-gradient.png index 95136c1a1..11bde774e 100644 Binary files a/tests/ref/compiler/repr-color-gradient.png and b/tests/ref/compiler/repr-color-gradient.png differ diff --git a/tests/ref/text/edge.png b/tests/ref/text/edge.png index ee5e68d35..1daf4c2fc 100644 Binary files a/tests/ref/text/edge.png and b/tests/ref/text/edge.png differ diff --git a/tests/ref/text/numbers.png b/tests/ref/text/numbers.png index f4d96c17f..9fc76aae2 100644 Binary files a/tests/ref/text/numbers.png and b/tests/ref/text/numbers.png differ diff --git a/tests/typ/compiler/methods.typ b/tests/typ/compiler/methods.typ index bd38bbd4f..692f9ab36 100644 --- a/tests/typ/compiler/methods.typ +++ b/tests/typ/compiler/methods.typ @@ -76,7 +76,7 @@ #test((5em + 6in).abs.inches(), 6.0) --- -// Error: 2-21 cannot convert a length with non-zero em units (`−6pt + 10.5em`) to pt +// Error: 2-21 cannot convert a length with non-zero em units (`-6pt + 10.5em`) to pt // Hint: 2-21 use `length.abs.pt()` instead to ignore its em component #(10.5em - 6pt).pt() @@ -86,7 +86,7 @@ #(3em).cm() --- -// Error: 2-20 cannot convert a length with non-zero em units (`−226.77pt + 93em`) to mm +// Error: 2-20 cannot convert a length with non-zero em units (`-226.77pt + 93em`) to mm // Hint: 2-20 use `length.abs.mm()` instead to ignore its em component #(93em - 80mm).mm()