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

Code before:

impl Regex {
    /// Create a new regular expression.
    pub fn new(re: &str) -> StrResult<Self> {
        regex::Regex::new(re).map(Self).map_err(|err| eco_format!("{err}"))
    }
}

#[scope]
impl Regex {
    /// Create a regular expression from a string.
    #[func(constructor)]
    pub fn construct(
        /// The regular expression as a string.
        ///
        /// Most regex escape sequences just work because they are not valid
        /// Typst escape sequences (e.g., `\d`, `\b`). To produce regex escape
        /// sequences that are also valid in Typst (e.g. `[\\]`), you need to
        /// escape twice. Thus, to match a verbatim backslash, you would need to
        /// write `{regex("\\\\")}`. To prevent undesired side effects, it's a
        /// good practice to always escape the backslash in regex tokens that
        /// use it.
        ///
        /// If you need many escape sequences, you can also create a raw element
        /// and extract its text to use it for your regular expressions:
        /// `{regex(`\d+\.\d+\.\d+`.text)}`.
        regex: Spanned<Str>,
    ) -> SourceResult<Regex> {
        Self::new(&regex.v).at(regex.span)
    }
}

impl Deref for Regex {
    type Target = regex::Regex;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl Repr for Regex {
    fn repr(&self) -> EcoString {
        eco_format!("regex({})", self.0.as_str().repr())
    }
}

impl PartialEq for Regex {
    fn eq(&self, other: &Self) -> bool {
        self.0.as_str() == other.0.as_str()
    }
}

Review comment (suggestion):
This becomes two parts in the generated HTML.

```html
<code>{regex(</code>\d+.\d+.\d+<code>.text)}</code>.
```


```suggestion
        /// ``{regex(`\d+\.\d+\.\d+`.text)}``.
```

Using two backquotes works.

```html
<code><span class="typ-func">regex</span><span class="typ-punct">(</span><span class="typ-raw">`\d+\.\d+\.\d+`</span><span class="typ-punct">.</span>text<span class="typ-punct">)</span></code>.
```

Code after:
/// The char boundary access error message.
#[cold]
fn not_a_char_boundary(index: i64) -> EcoString {
    eco_format!("string index {} is not a character boundary", index)
}

/// The error message when the string is empty.
#[cold]
fn string_is_empty() -> EcoString {
    "string is empty".into()
}

/// A regular expression.
///
/// Can be used as a [show rule selector]($styling/#show-rules) and with
/// [string methods]($str) like `find`, `split`, and `replace`.
///
/// [See here](https://docs.rs/regex/latest/regex/#syntax) for a specification
/// of the supported syntax.
///
/// # Example
/// ```example
/// // Works with string methods.
/// #"a,b;c".split(regex("[,;]"))
///
/// // Works with show rules.
/// #show regex("\\d+"): set text(red)
///
/// The numbers 1 to 10.
/// ```
#[ty(scope)]
#[derive(Debug, Clone)]
pub struct Regex(regex::Regex);

impl Regex {
    /// Create a new regular expression.
    pub fn new(re: &str) -> StrResult<Self> {
        regex::Regex::new(re).map(Self).map_err(|err| eco_format!("{err}"))
    }
}

#[scope]
impl Regex {
    /// Create a regular expression from a string.
    #[func(constructor)]
    pub fn construct(
        /// The regular expression as a string.
        ///
        /// Both Typst strings and regular expressions use backslashes for
        /// escaping. To produce a regex escape sequence that is also valid in
        /// Typst, you need to escape the backslash itself (e.g., writing