summaryrefslogtreecommitdiff
path: root/crates/typst-library/src/foundations
diff options
context:
space:
mode:
Diffstat (limited to 'crates/typst-library/src/foundations')
-rw-r--r--crates/typst-library/src/foundations/str.rs46
1 files changed, 45 insertions, 1 deletions
diff --git a/crates/typst-library/src/foundations/str.rs b/crates/typst-library/src/foundations/str.rs
index 551ac04f..23a1bd4c 100644
--- a/crates/typst-library/src/foundations/str.rs
+++ b/crates/typst-library/src/foundations/str.rs
@@ -7,12 +7,13 @@ use comemo::Tracked;
use ecow::EcoString;
use serde::{Deserialize, Serialize};
use typst_syntax::{Span, Spanned};
+use unicode_normalization::UnicodeNormalization;
use unicode_segmentation::UnicodeSegmentation;
use crate::diag::{bail, At, SourceResult, StrResult};
use crate::engine::Engine;
use crate::foundations::{
- cast, dict, func, repr, scope, ty, Array, Bytes, Context, Decimal, Dict, Func,
+ cast, dict, func, repr, scope, ty, Array, Bytes, Cast, Context, Decimal, Dict, Func,
IntoValue, Label, Repr, Type, Value, Version,
};
use crate::layout::Alignment;
@@ -286,6 +287,30 @@ impl Str {
Ok(c.into())
}
+ /// Normalizes the string to the given Unicode normal form.
+ ///
+ /// This is useful when manipulating strings containing Unicode combining
+ /// characters.
+ ///
+ /// ```typ
+ /// #assert.eq("é".normalize(form: "nfd"), "e\u{0301}")
+ /// #assert.eq("ſ́".normalize(form: "nfkc"), "ś")
+ /// ```
+ #[func]
+ pub fn normalize(
+ &self,
+ #[named]
+ #[default(UnicodeNormalForm::Nfc)]
+ form: UnicodeNormalForm,
+ ) -> Str {
+ match form {
+ UnicodeNormalForm::Nfc => self.nfc().collect(),
+ UnicodeNormalForm::Nfd => self.nfd().collect(),
+ UnicodeNormalForm::Nfkc => self.nfkc().collect(),
+ UnicodeNormalForm::Nfkd => self.nfkd().collect(),
+ }
+ }
+
/// Whether the string contains the specified pattern.
///
/// This method also has dedicated syntax: You can write `{"bc" in "abcd"}`
@@ -788,6 +813,25 @@ cast! {
v: Str => Self::Str(v),
}
+/// A Unicode normalization form.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)]
+pub enum UnicodeNormalForm {
+ /// Canonical composition where e.g. accented letters are turned into a
+ /// single Unicode codepoint.
+ #[string("nfc")]
+ Nfc,
+ /// Canonical decomposition where e.g. accented letters are split into a
+ /// separate base and diacritic.
+ #[string("nfd")]
+ Nfd,
+ /// Like NFC, but using the Unicode compatibility decompositions.
+ #[string("nfkc")]
+ Nfkc,
+ /// Like NFD, but using the Unicode compatibility decompositions.
+ #[string("nfkd")]
+ Nfkd,
+}
+
/// Convert an item of std's `match_indices` to a dictionary.
fn match_to_dict((start, text): (usize, &str)) -> Dict {
dict! {