markdown_that/plugins/cmark/inline/
escape.rs

1//! Backslash escapes
2//!
3//! Allows escapes like `\*hello*`, also processes hard breaks at the end
4//! of the line.
5//!
6//! <https://spec.commonmark.org/0.30/#backslash-escapes>
7use crate::parser::inline::{InlineRule, InlineState, TextSpecial};
8use crate::plugins::cmark::inline::newline::Hardbreak;
9use crate::{MarkdownThat, Node};
10
11pub fn add(md: &mut MarkdownThat) {
12    md.inline.add_rule::<EscapeScanner>();
13}
14
15#[doc(hidden)]
16pub struct EscapeScanner;
17impl InlineRule for EscapeScanner {
18    const MARKER: char = '\\';
19
20    fn run(state: &mut InlineState) -> Option<(Node, usize)> {
21        let mut chars = state.src[state.pos..state.pos_max].chars();
22        if chars.next().unwrap() != '\\' {
23            return None;
24        }
25
26        match chars.next() {
27            Some('\n') => {
28                // skip leading whitespaces from next line
29                let mut len = 2;
30                while let Some(' ' | '\t') = chars.next() {
31                    len += 1;
32                }
33                Some((Node::new(Hardbreak), len))
34            }
35            Some(chr) => {
36                let start = state.pos;
37                let end = state.pos + 1 + chr.len_utf8();
38
39                let mut orig_str = "\\".to_owned();
40                orig_str.push(chr);
41
42                let content_str = match chr {
43                    '\\' | '!' | '"' | '#' | '$' | '%' | '&' | '\'' | '(' | ')' | '*' | '+'
44                    | ',' | '.' | '/' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '[' | ']'
45                    | '^' | '_' | '`' | '{' | '|' | '}' | '~' | '-' => chr.into(),
46                    _ => orig_str.clone(),
47                };
48
49                let node = Node::new(TextSpecial {
50                    content: content_str,
51                    markup: orig_str,
52                    info: "escape",
53                });
54                Some((node, end - start))
55            }
56            None => None,
57        }
58    }
59}