summaryrefslogtreecommitdiff
path: root/src/matrix.rs
blob: 92d2eb8b644de6e14ed1f39ab39c1c3b748eb2d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use pyo3::prelude::*;

use crate::parser::parse_with_limits;

const MATRIX_FORMATS: &[(&'static str, (&'static str, &'static str))] = &[
    ("_", ("<em>", "</em>")),
    ("*", ("<strong>", "</strong>")),
    ("~", ("<strike>", "</strike>")),
    ("`", ("<code>", "</code>")),
    ("```", ("<pre><code>", "</code></pre>")),
    ("```language", ("<pre><code class=\"language-{}\">", "</code></pre>")),
    (">", ("<blockquote>", "</blockquote>")),
    ("||", ("<span data-mx-spoiler>", "</span>")),
];

#[pyfunction]
pub fn format_for_matrix(body: String) -> PyResult<String> {
    let mut chars: Vec<char> = body.chars().collect();
    if chars.len() < 1 {
        return Ok(body);
    }
    let styles: Vec<(String, usize, usize, usize, usize)> = parse_with_limits(&chars, 0, chars.len() - 1, 0);

    let mut tags: Vec<(usize, String, usize)> = Vec::with_capacity(styles.len() * 2);
    for (keyword, start, remove_start, end, remove_end) in styles {
        if MATRIX_FORMATS.iter().any(|&(k, _)| k == keyword) {
            let opening_tag = if keyword == "```language" {
                MATRIX_FORMATS.iter().find(|&&(k, _)| k == keyword).unwrap().1.0.clone()
                .replace("{}", &chars[start+3..remove_start-1]
                .into_iter()
                .collect::<String>())
            } else {
                MATRIX_FORMATS.iter().find(|&&(k, _)| k == keyword).unwrap().1.0.clone().to_string()
            };
            tags.push((start, opening_tag, remove_start));
            tags.push((end, MATRIX_FORMATS.iter().find(|&&(k, _)| k == keyword).unwrap().1.1.clone().to_string(), remove_end));
        } else if keyword == ">>" || keyword == "```>" || keyword == "\\" {
            tags.push((start, "".to_string(), start+1));
        }
    }

    tags.sort_by(|a, b| b.0.cmp(&a.0));

    let mut replace_newlines_to = chars.len();
    for (index, tag, end) in tags {
        if tag == "</code></pre>" {
            // index is at \n, add 1 to skip that one
            let substring = chars[index + 1..replace_newlines_to].into_iter().collect::<String>();
            chars = [&chars[..index + 1], &substring.replace('\n', "<br>").chars().collect::<Vec<char>>()[..]].concat();
        } else if tag == "<pre><code>" {
            replace_newlines_to = index;
        }

        let tag: Vec<char> = tag.chars().collect();
        chars = [chars[..index].to_vec(), tag.clone(), chars[end..].to_vec()].concat();
        
        let offset: isize = index as isize - end as isize + tag.len() as isize;
        replace_newlines_to = if offset > 0 {
            replace_newlines_to + offset as usize
        } else {
            replace_newlines_to - offset.abs() as usize
        };
    }
    let substring = chars[..replace_newlines_to].into_iter().collect::<String>();
    let text = [substring.replace('\n', "<br>"), chars[replace_newlines_to..].into_iter().collect::<String>()].concat();

    Ok(text)
}