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
69
70
71
72
73
|
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, mentions: Option<Vec<(String, usize, usize)>>) -> PyResult<String> {
let mut chars: Vec<char> = body.chars().collect();
if chars.len() < 1 {
return Ok(body);
}
let mentions = mentions.unwrap_or(Vec::with_capacity(0));
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_owned()
};
tags.push((start, opening_tag, remove_start));
tags.push((end, MATRIX_FORMATS.iter().find(|&&(k, _)| k == keyword).unwrap().1.1.clone().to_owned(), remove_end));
} else if keyword == ">>" || keyword == "```>" || keyword == "\\" {
tags.push((start, String::new(), start+1));
}
}
for (mxid, start, end) in mentions {
tags.push((start, "<a href='https://matrix.to/#/".to_owned() + &mxid + "'>", start));
tags.push((end, "</a>".to_owned(), end));
}
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>>()[..], &chars[replace_newlines_to..]].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)
}
|