pub fn emphasis_span(
text: &str,
before: Option<char>,
after: Option<char>,
) -> Option<Range<usize>>Expand description
The part of a styled run that emphasis delimiters (*, **, ~~) can wrap, given the
characters the run lands between, or None when no part can.
before is the last character already written, after the first one the next piece will
write (None at either end of the inline content). The text outside the returned range is
written as-is, outside the delimiters.
CommonMark reads a delimiter as emphasis only when it flanks the text (ยง6.2): it may not touch whitespace on its inside, and when its inside is punctuation its outside must be whitespace, punctuation, or the end of the line. So:
- leading and trailing whitespace always stays outside โ
**word **is not emphasis; - leading or trailing punctuation stays outside too, with any whitespace behind it, when
the run touches a letter or digit on that side โ an italic
", s"after32written as32*, s*shows its asterisks, written as32, *s*it does not; - a run that is nothing but whitespace, or nothing but punctuation between words, has nothing to wrap.
Punctuation that does not touch a word stays inside (*i.e.,*, *(h)*), so a run is not
reshaped unless it has to be.
text may already be escaped: a backslash escape (\*) is one unit and is never split
across a delimiter. Only escapes of ASCII punctuation are units, as in CommonMark.
use unparser_shared::markdown::emphasis_span;
let wrap = |text: &str, before, after| {
emphasis_span(text, before, after).map_or(text.to_string(), |r| {
format!("{}*{}*{}", &text[..r.start], &text[r.clone()], &text[r.end..])
})
};
assert_eq!(wrap(", s", Some('2'), Some(' ')), ", *s*");
assert_eq!(wrap("word ", None, Some('x')), "*word* ");
assert_eq!(wrap(",", Some('8'), Some('a')), ",");
assert_eq!(wrap("(h)", Some(' '), None), "*(h)*");