Repository: typst/typst
File: crates/typst-library/src/foundations/str.rs (Rust)

Code before:
    /// #str.from-unicode(97)
    /// ```
    #[func]
    pub fn from_unicode(
        /// The code point that should be converted.
        value: u32,
    ) -> StrResult<Str> {
        let c: char = value
            .try_into()
            .map_err(|_| eco_format!("{value:#x} is not a valid codepoint"))?;
        Ok(c.into())
    }

    /// Normalizes the string to the given Unicode Normalization Form. This is useful when
    /// manipulating strings containing combining Unicode characters.
    ///
    /// ```example
    /// #"é".normalize("NFD") \ // "e\u{0301}"
    /// #"ſ́".normalize("NFKC") // "ś", = "\u{015b}"
    /// ```
    #[func]
    pub fn normalize(
        &self,
        /// One of `"NFC"`, `"NFD"`, `"NFKC"`, or `"NFKD"`, specifiying the [Unicode Normalization
        /// Form](https://unicode.org/reports/tr15/#Norm_Forms) to use. If set to `auto`, NFC is used.
        form: Smart<UnicodeNormalForm>,
    ) -> Str {
        match form.unwrap_or(UnicodeNormalForm::Nfc) {
            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"}`
    /// instead of `{"abcd".contains("bc")}`.
    #[func]
    pub fn contains(
        &self,
        /// The pattern to search for.
        pattern: StrPattern,
    ) -> bool {
        match pattern {
            StrPattern::Str(pat) => self.0.contains(pat.as_str()),
            StrPattern::Regex(re) => re.is_match(self),
        }
    }


Review comment (suggestion):
```suggestion
        #[named]
        #[default(UnicodeNormalForm::Nfc)]
        form: UnicodeNormalForm,
```
like mentioned in the other comment, this should just default to nfc instead of being smart. I also think the parameter should be named. That both makes for a clearer call site and is the usual way for optional parameters.

Code after:
    /// ```
    #[func]
    pub fn from_unicode(
        /// The code point that should be converted.
        value: u32,
    ) -> StrResult<Str> {
        let c: char = value
            .try_into()
            .map_err(|_| eco_format!("{value:#x} is not a valid codepoint"))?;
        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"}`
    /// instead of `{"abcd".contains("bc")}`.
    #[func]
    pub fn contains(
        &self,
        /// The pattern to search for.
        pattern: StrPattern,
    ) -> bool {
        match pattern {
            StrPattern::Str(pat) => self.0.contains(pat.as_str()),
            StrPattern::Regex(re) => re.is_match(self),
        }
    }