summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMALO <57839069+MDLC01@users.noreply.github.com>2023-10-09 15:30:40 +0200
committerGitHub <noreply@github.com>2023-10-09 15:30:40 +0200
commit0804a9e25d865dc25d10aae22b0a39c4e16cab19 (patch)
tree80550c88a91238e8018ccfb89aae891a7e4c368c
parentdf49d3f0c6ea17e9dcf552106f7b5464bc99c4dc (diff)
Use/allow U+2212 MINUS SIGN instead of U+002D HYPHEN MINUS everywhere (#2318)
-rw-r--r--crates/typst-syntax/src/ast.rs1
-rw-r--r--crates/typst-syntax/src/lexer.rs5
-rw-r--r--crates/typst/src/eval/float.rs22
-rw-r--r--crates/typst/src/eval/int.rs25
-rw-r--r--crates/typst/src/eval/str.rs12
-rw-r--r--crates/typst/src/eval/value.rs5
-rw-r--r--crates/typst/src/util/fmt.rs26
-rw-r--r--tests/ref/compiler/array.pngbin8306 -> 19884 bytes
-rw-r--r--tests/ref/compiler/repr-color-gradient.pngbin53933 -> 101911 bytes
-rw-r--r--tests/ref/layout/grid-2.pngbin14178 -> 61931 bytes
-rw-r--r--tests/ref/text/edge.pngbin28077 -> 58153 bytes
-rw-r--r--tests/ref/text/numbers.pngbin0 -> 183933 bytes
-rw-r--r--tests/typ/compiler/methods.typ4
-rw-r--r--tests/typ/compute/calc.typ6
-rw-r--r--tests/typ/compute/construct.typ2
-rw-r--r--tests/typ/text/numbers.typ110
16 files changed, 182 insertions, 36 deletions
diff --git a/crates/typst-syntax/src/ast.rs b/crates/typst-syntax/src/ast.rs
index cb1d05b2..447903c5 100644
--- a/crates/typst-syntax/src/ast.rs
+++ b/crates/typst-syntax/src/ast.rs
@@ -454,6 +454,7 @@ impl Shorthand<'_> {
pub const MARKUP_LIST: &'static [(&'static str, char)] = &[
("...", '…'),
("~", '\u{00A0}'),
+ ("-", '\u{2212}'), // Only before a digit
("--", '\u{2013}'),
("---", '\u{2014}'),
("-?", '\u{00AD}'),
diff --git a/crates/typst-syntax/src/lexer.rs b/crates/typst-syntax/src/lexer.rs
index b96b3c07..509f5d73 100644
--- a/crates/typst-syntax/src/lexer.rs
+++ b/crates/typst-syntax/src/lexer.rs
@@ -171,6 +171,7 @@ impl Lexer<'_> {
'-' if self.s.eat_if("--") => SyntaxKind::Shorthand,
'-' if self.s.eat_if('-') => SyntaxKind::Shorthand,
'-' if self.s.eat_if('?') => SyntaxKind::Shorthand,
+ '-' if self.s.at(char::is_numeric) => SyntaxKind::Shorthand,
'*' if !self.in_word() => SyntaxKind::Star,
'_' if !self.in_word() => SyntaxKind::Underscore,
@@ -480,7 +481,7 @@ impl Lexer<'_> {
'<' if self.s.eat_if('=') => SyntaxKind::LtEq,
'>' if self.s.eat_if('=') => SyntaxKind::GtEq,
'+' if self.s.eat_if('=') => SyntaxKind::PlusEq,
- '-' if self.s.eat_if('=') => SyntaxKind::HyphEq,
+ '-' | '\u{2212}' if self.s.eat_if('=') => SyntaxKind::HyphEq,
'*' if self.s.eat_if('=') => SyntaxKind::StarEq,
'/' if self.s.eat_if('=') => SyntaxKind::SlashEq,
'.' if self.s.eat_if('.') => SyntaxKind::Dots,
@@ -498,7 +499,7 @@ impl Lexer<'_> {
':' => SyntaxKind::Colon,
'.' => SyntaxKind::Dot,
'+' => SyntaxKind::Plus,
- '-' => SyntaxKind::Minus,
+ '-' | '\u{2212}' => SyntaxKind::Minus,
'*' => SyntaxKind::Star,
'/' => SyntaxKind::Slash,
'=' => SyntaxKind::Eq,
diff --git a/crates/typst/src/eval/float.rs b/crates/typst/src/eval/float.rs
index 094ff1db..55becee2 100644
--- a/crates/typst/src/eval/float.rs
+++ b/crates/typst/src/eval/float.rs
@@ -1,7 +1,10 @@
-use ecow::eco_format;
+use std::num::ParseFloatError;
-use super::{cast, func, scope, ty, Str};
+use ecow::{eco_format, EcoString};
+
+use super::{cast, func, scope, ty, Repr, Str};
use crate::geom::Ratio;
+use crate::util::fmt::{format_float, MINUS_SIGN};
/// A floating-point number.
///
@@ -47,6 +50,12 @@ impl f64 {
}
}
+impl Repr for f64 {
+ fn repr(&self) -> EcoString {
+ format_float(*self, None, "")
+ }
+}
+
/// A value that can be cast to a float.
pub struct ToFloat(f64);
@@ -55,6 +64,13 @@ cast! {
v: bool => Self(v as i64 as f64),
v: i64 => Self(v as f64),
v: Ratio => Self(v.get()),
- v: Str => Self(v.parse().map_err(|_| eco_format!("invalid float: {}", v))?),
+ v: Str => Self(
+ parse_float(v.clone().into())
+ .map_err(|_| eco_format!("invalid float: {}", v))?
+ ),
v: f64 => Self(v),
}
+
+fn parse_float(s: EcoString) -> Result<f64, ParseFloatError> {
+ s.replace(MINUS_SIGN, "-").parse()
+}
diff --git a/crates/typst/src/eval/int.rs b/crates/typst/src/eval/int.rs
index b2b76f30..077a1ec0 100644
--- a/crates/typst/src/eval/int.rs
+++ b/crates/typst/src/eval/int.rs
@@ -1,5 +1,6 @@
-use std::num::{NonZeroI64, NonZeroIsize, NonZeroU64, NonZeroUsize};
+use std::num::{NonZeroI64, NonZeroIsize, NonZeroU64, NonZeroUsize, ParseIntError};
+use crate::util::fmt::{format_int_with_base, MINUS_SIGN};
use ecow::{eco_format, EcoString};
use super::{cast, func, scope, ty, Repr, Str, Value};
@@ -53,13 +54,7 @@ impl i64 {
impl Repr for i64 {
fn repr(&self) -> EcoString {
- eco_format!("{self}")
- }
-}
-
-impl Repr for f64 {
- fn repr(&self) -> EcoString {
- eco_format!("{self}")
+ format_int_with_base(*self, 10)
}
}
@@ -70,10 +65,22 @@ cast! {
ToInt,
v: bool => Self(v as i64),
v: f64 => Self(v as i64),
- v: Str => Self(v.parse().map_err(|_| eco_format!("invalid integer: {}", v))?),
+ v: Str => Self(parse_int(&v).map_err(|_| eco_format!("invalid integer: {}", v))?),
v: i64 => Self(v),
}
+fn parse_int(mut s: &str) -> Result<i64, ParseIntError> {
+ let mut sign = 1;
+ if let Some(rest) = s.strip_prefix('-').or_else(|| s.strip_prefix(MINUS_SIGN)) {
+ sign = -1;
+ s = rest;
+ }
+ if sign == -1 && s == "9223372036854775808" {
+ return Ok(i64::MIN);
+ }
+ Ok(sign * s.parse::<i64>()?)
+}
+
macro_rules! signed_int {
($($ty:ty)*) => {
$(cast! {
diff --git a/crates/typst/src/eval/str.rs b/crates/typst/src/eval/str.rs
index 666c3c72..8b6b766e 100644
--- a/crates/typst/src/eval/str.rs
+++ b/crates/typst/src/eval/str.rs
@@ -15,7 +15,7 @@ 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;
+use crate::util::fmt::{format_float, format_int_with_base};
/// Create a new [`Str`] from a format string.
#[macro_export]
@@ -610,7 +610,7 @@ pub enum ToStr {
cast! {
ToStr,
v: i64 => Self::Int(v),
- v: f64 => Self::Str(format_str!("{}", v)),
+ v: f64 => Self::Str(format_float(v, None, "").into()),
v: Version => Self::Str(format_str!("{}", v)),
v: Bytes => Self::Str(
std::str::from_utf8(&v)
@@ -970,13 +970,13 @@ mod tests {
);
assert_eq!(
&format_int_with_base(i64::MIN, 2),
- "-1000000000000000000000000000000000000000000000000000000000000000"
+ "\u{2212}1000000000000000000000000000000000000000000000000000000000000000"
);
assert_eq!(&format_int_with_base(i64::MAX, 10), "9223372036854775807");
- assert_eq!(&format_int_with_base(i64::MIN, 10), "-9223372036854775808");
+ assert_eq!(&format_int_with_base(i64::MIN, 10), "\u{2212}9223372036854775808");
assert_eq!(&format_int_with_base(i64::MAX, 16), "7fffffffffffffff");
- assert_eq!(&format_int_with_base(i64::MIN, 16), "-8000000000000000");
+ assert_eq!(&format_int_with_base(i64::MIN, 16), "\u{2212}8000000000000000");
assert_eq!(&format_int_with_base(i64::MAX, 36), "1y2p0ij32e8e7");
- assert_eq!(&format_int_with_base(i64::MIN, 36), "-1y2p0ij32e8e8");
+ assert_eq!(&format_int_with_base(i64::MIN, 36), "\u{2212}1y2p0ij32e8e8");
}
}
diff --git a/crates/typst/src/eval/value.rs b/crates/typst/src/eval/value.rs
index 901d3819..19a5610a 100644
--- a/crates/typst/src/eval/value.rs
+++ b/crates/typst/src/eval/value.rs
@@ -21,6 +21,7 @@ use crate::eval::Datetime;
use crate::geom::{Abs, Angle, Color, Em, Fr, Gradient, Length, Ratio, Rel};
use crate::model::{Label, Styles};
use crate::syntax::{ast, Span};
+use crate::util::fmt::{format_float, format_int_with_base};
/// A computational value.
#[derive(Debug, Default, Clone)]
@@ -198,8 +199,8 @@ impl Value {
pub fn display(self) -> Content {
match self {
Self::None => Content::empty(),
- Self::Int(v) => item!(text)(eco_format!("{v}")),
- Self::Float(v) => item!(text)(eco_format!("{v}")),
+ Self::Int(v) => item!(text)(format_int_with_base(v, 10)),
+ Self::Float(v) => item!(text)(format_float(v, None, "")),
Self::Str(v) => item!(text)(v.into()),
Self::Version(v) => item!(text)(eco_format!("{v}")),
Self::Symbol(v) => item!(text)(v.get().into()),
diff --git a/crates/typst/src/util/fmt.rs b/crates/typst/src/util/fmt.rs
index 8400b871..50e59095 100644
--- a/crates/typst/src/util/fmt.rs
+++ b/crates/typst/src/util/fmt.rs
@@ -1,19 +1,16 @@
use ecow::{eco_format, EcoString};
+pub const MINUS_SIGN: &str = "\u{2212}";
+
/// Format an integer in a base.
pub fn format_int_with_base(mut n: i64, base: i64) -> EcoString {
if n == 0 {
return "0".into();
}
- // In Rust, `format!("{:x}", -14i64)` is not `-e` but `fffffffffffffff2`.
- // So we can only use the built-in for decimal, not bin/oct/hex.
- if base == 10 {
- return eco_format!("{n}");
- }
-
- // The largest output is `to_base(i64::MIN, 2)`, which is 65 chars long.
- const SIZE: usize = 65;
+ // The largest output is `to_base(i64::MIN, 2)`, which is 64 bytes long,
+ // plus the length of the minus sign.
+ const SIZE: usize = 64 + MINUS_SIGN.len();
let mut digits = [b'\0'; SIZE];
let mut i = SIZE;
@@ -32,8 +29,9 @@ pub fn format_int_with_base(mut n: i64, base: i64) -> EcoString {
}
if negative {
- i -= 1;
- digits[i] = b'-';
+ let prev = i;
+ i -= MINUS_SIGN.len();
+ digits[i..prev].copy_from_slice(MINUS_SIGN.as_bytes());
}
std::str::from_utf8(&digits[i..]).unwrap_or_default().into()
@@ -46,7 +44,13 @@ pub fn format_float(mut value: f64, precision: Option<u8>, suffix: &str) -> EcoS
let offset = 10_f64.powi(p as i32);
value = (value * offset).round() / offset;
}
- eco_format!("{}{}", value, suffix)
+ if value.is_nan() {
+ "NaN".into()
+ } else if value.is_sign_negative() {
+ eco_format!("{}{}{}", MINUS_SIGN, value.abs(), suffix)
+ } else {
+ eco_format!("{}{}", value, suffix)
+ }
}
/// Format pieces separated with commas and a final "and" or "or".
diff --git a/tests/ref/compiler/array.png b/tests/ref/compiler/array.png
index 9b6bf8b3..b97dd317 100644
--- a/tests/ref/compiler/array.png
+++ b/tests/ref/compiler/array.png
Binary files differ
diff --git a/tests/ref/compiler/repr-color-gradient.png b/tests/ref/compiler/repr-color-gradient.png
index 53c734c9..25aae2e3 100644
--- a/tests/ref/compiler/repr-color-gradient.png
+++ b/tests/ref/compiler/repr-color-gradient.png
Binary files differ
diff --git a/tests/ref/layout/grid-2.png b/tests/ref/layout/grid-2.png
index 23874076..ac1f7014 100644
--- a/tests/ref/layout/grid-2.png
+++ b/tests/ref/layout/grid-2.png
Binary files differ
diff --git a/tests/ref/text/edge.png b/tests/ref/text/edge.png
index 2226af9d..ee5e68d3 100644
--- a/tests/ref/text/edge.png
+++ b/tests/ref/text/edge.png
Binary files differ
diff --git a/tests/ref/text/numbers.png b/tests/ref/text/numbers.png
new file mode 100644
index 00000000..f4d96c17
--- /dev/null
+++ b/tests/ref/text/numbers.png
Binary files differ
diff --git a/tests/typ/compiler/methods.typ b/tests/typ/compiler/methods.typ
index f1017eb5..f7e7ed8f 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()
diff --git a/tests/typ/compute/calc.typ b/tests/typ/compute/calc.typ
index 536c637a..24411ecf 100644
--- a/tests/typ/compute/calc.typ
+++ b/tests/typ/compute/calc.typ
@@ -7,10 +7,16 @@
#test(int(true), 1)
#test(int(10), 10)
#test(int("150"), 150)
+#test(int("-834"), -834)
+#test(int("\u{2212}79"), -79)
#test(int(10 / 3), 3)
#test(float(10), 10.0)
#test(float(50% * 30%), 0.15)
#test(float("31.4e-1"), 3.14)
+#test(float("31.4e\u{2212}1"), 3.14)
+#test(float("3.1415"), 3.1415)
+#test(float("-7654.321"), -7654.321)
+#test(float("\u{2212}7654.321"), -7654.321)
#test(type(float(10)), float)
---
diff --git a/tests/typ/compute/construct.typ b/tests/typ/compute/construct.typ
index 6980c922..d5ded96a 100644
--- a/tests/typ/compute/construct.typ
+++ b/tests/typ/compute/construct.typ
@@ -162,7 +162,7 @@
// Test conversion to string.
#test(str(123), "123")
#test(str(123, base: 3), "11120")
-#test(str(-123, base: 16), "-7b")
+#test(str(-123, base: 16), "−7b")
#test(str(9223372036854775807, base: 36), "1y2p0ij32e8e7")
#test(str(50.14), "50.14")
#test(str(10 / 3).len() > 10, true)
diff --git a/tests/typ/text/numbers.typ b/tests/typ/text/numbers.typ
new file mode 100644
index 00000000..a35798d1
--- /dev/null
+++ b/tests/typ/text/numbers.typ
@@ -0,0 +1,110 @@
+// Test how numbers are displayed.
+
+---
+// Test numbers in text mode.
+12 \
+12.0 \
+3.14 \
+1234567890 \
+0123456789 \
+0 \
+0.0 \
++0 \
++0.0 \
+-0 \
+-0.0 \
+-1 \
+-3.14 \
+-9876543210 \
+-0987654321 \
+٣٫١٤ \
+-٣٫١٤ \
+-¾ \
+#text(fractions: true)[-3/2] \
+2022 - 2023 \
+2022 -- 2023 \
+2022--2023 \
+2022-2023 \
+٢٠٢٢ - ٢٠٢٣ \
+٢٠٢٢ -- ٢٠٢٣ \
+٢٠٢٢--٢٠٢٣ \
+٢٠٢٢-٢٠٢٣ \
+-500 -- -400
+
+---
+// Test integers.
+#12 \
+#1234567890 \
+#0123456789 \
+#0 \
+#(-0) \
+#(-1) \
+#(-9876543210) \
+#(-0987654321) \
+#(4 - 8)
+
+---
+// Test floats.
+#12.0 \
+#3.14 \
+#1234567890.0 \
+#0123456789.0 \
+#0.0 \
+#(-0.0) \
+#(-1.0) \
+#(-9876543210.0) \
+#(-0987654321.0) \
+#(-3.14) \
+#(4.0 - 8.0)
+
+---
+// Test the `str` function with integers.
+#str(12) \
+#str(1234567890) \
+#str(0123456789) \
+#str(0) \
+#str(-0) \
+#str(-1) \
+#str(-9876543210) \
+#str(-0987654321) \
+#str(4 - 8)
+
+---
+// Test the `str` function with floats.
+#str(12.0) \
+#str(3.14) \
+#str(1234567890.0) \
+#str(0123456789.0) \
+#str(0.0) \
+#str(-0.0) \
+#str(-1.0) \
+#str(-9876543210.0) \
+#str(-0987654321.0) \
+#str(-3.14) \
+#str(4.0 - 8.0)
+
+---
+// Test the `repr` function with integers.
+#repr(12) \
+#repr(1234567890) \
+#repr(0123456789) \
+#repr(0) \
+#repr(-0) \
+#repr(-1) \
+#repr(-9876543210) \
+#repr(-0987654321) \
+#repr(4 - 8)
+
+---
+// Test the `repr` function with floats.
+#repr(12.0) \
+#repr(3.14) \
+#repr(1234567890.0) \
+#repr(0123456789.0) \
+#repr(0.0) \
+#repr(-0.0) \
+#repr(-1.0) \
+#repr(-9876543210.0) \
+#repr(-0987654321.0) \
+#repr(-3.14) \
+#repr(4.0 - 8.0)