summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErik Bünnig <github@epbuennig.me>2023-05-30 18:11:30 +0200
committerGitHub <noreply@github.com>2023-05-30 18:11:30 +0200
commitb805c5f10080912cbfb1fd2fd2733c48a92ce4f9 (patch)
treea97a4aca4d2ba05056bac0f9e9ae9075bccfeb52
parent789a54f9e5fcebf4a3b3945d36ce3db7674b0fbc (diff)
Unicode code point conversion (#1068) (#1132)
-rw-r--r--library/src/compute/construct.rs57
-rw-r--r--tests/typ/compute/construct.typ21
2 files changed, 78 insertions, 0 deletions
diff --git a/library/src/compute/construct.rs b/library/src/compute/construct.rs
index 169c5328..d11eb398 100644
--- a/library/src/compute/construct.rs
+++ b/library/src/compute/construct.rs
@@ -461,6 +461,10 @@ cast_from_value! {
/// - Floats are formatted in base 10 and never in exponential notation.
/// - From labels the name is extracted.
///
+/// If you wish to convert from and to Unicode code points, see
+/// [`str.to-unicode`]($func/str.to-unicode) and
+/// [`str.from-unicode`]($func/str.from-unicode).
+///
/// ## Example { #example }
/// ```example
/// #str(10) \
@@ -474,6 +478,11 @@ cast_from_value! {
/// Category: construct
/// Returns: string
#[func]
+#[scope(
+ scope.define("to-unicode", to_unicode);
+ scope.define("from-unicode", from_unicode);
+ scope
+)]
pub fn str(
/// The value that should be converted to a string.
value: ToStr,
@@ -553,6 +562,54 @@ fn int_to_base(mut n: i64, base: i64) -> EcoString {
std::str::from_utf8(&digits[i..]).unwrap_or_default().into()
}
+/// Converts a character into its corresponding code point.
+///
+/// ## Example
+/// ```example
+/// #str.to-unicode("a") \
+/// #"a\u{0300}".codepoints().map(str.to-unicode)
+/// ```
+///
+/// Display: String To Unicode
+/// Category: construct
+/// Returns: int
+#[func]
+pub fn to_unicode(
+ /// The character that should be converted.
+ value: char,
+) -> Value {
+ Value::Int(From::<u32>::from(value.into()))
+}
+
+#[func]
+/// Converts a unicode code point into its corresponding string.
+///
+/// ```example
+/// #str.from-unicode(97)
+/// ```
+///
+/// Display: Sting From Unicode
+/// Category: construct
+/// Returns: string
+pub fn from_unicode(
+ /// The code point that should be converted.
+ value: CodePoint,
+) -> Value {
+ Value::Str(format_str!("{}", value.0))
+}
+
+/// The numeric representation of a single unicode code point.
+struct CodePoint(char);
+
+cast_from_value! {
+ CodePoint,
+ v: i64 => {
+ Self(v.try_into().ok().and_then(|v: u32| v.try_into().ok()).ok_or_else(
+ || eco_format!("{:#x} is not a valid codepoint", v),
+ )?)
+ },
+}
+
/// Create a label from a string.
///
/// Inserting a label into content attaches it to the closest previous element
diff --git a/tests/typ/compute/construct.typ b/tests/typ/compute/construct.typ
index aea15b53..f094b6b2 100644
--- a/tests/typ/compute/construct.typ
+++ b/tests/typ/compute/construct.typ
@@ -83,6 +83,27 @@
#str(1.23, base: 2)
---
+// Test the unicode function.
+#test(str.from-unicode(97), "a")
+#test(str.to-unicode("a"), 97)
+
+---
+// Error: 19-22 expected integer, found content
+#str.from-unicode([a])
+
+---
+// Error: 17-21 expected exactly one character
+#str.to-unicode("ab")
+
+---
+// Error: 19-21 0xffffffffffffffff is not a valid codepoint
+#str.from-unicode(-1) // negative values are not valid
+
+---
+// Error: 19-27 0x110000 is not a valid codepoint
+#str.from-unicode(0x110000) // 0x10ffff is the highest valid code point
+
+---
#assert(range(2, 5) == (2, 3, 4))
---