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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use std::mem;
#[derive(Debug, Clone, PartialEq)]
pub struct FormattedMessageDetail {
raw: String,
components: Vec<FormattedMessageComponent>,
}
impl FormattedMessageDetail {
pub fn new(raw: String, components: Vec<FormattedMessageComponent>) -> Self {
Self {
raw,
components,
}
}
pub fn raw(&self) -> &str {
&self.raw
}
pub fn components(&self) -> &Vec<FormattedMessageComponent> {
&self.components
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum FormattedMessageComponent {
Section(String, Vec<FormattedString>),
Text(Vec<FormattedString>),
}
#[derive(Debug, Clone, PartialEq)]
pub struct FormattedString {
styles: Vec<Style>,
s: String,
}
impl FormattedString {
pub fn new<S: ToString>(s: S, styles: Vec<Style>) -> Self {
Self {
s: s.to_string(),
styles
}
}
pub fn plain<S: ToString>(s: S) -> Self {
Self::new(s, vec![])
}
pub fn styled<S: ToString>(s: S, style: Style) -> Self {
Self::new(s, vec![style])
}
pub fn get_styles(&self) -> &Vec<Style> {
&self.styles
}
pub fn get_string(&self) -> &str {
&self.s
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Style {
Bold,
Italics,
Monospace,
Code{ lang: String }
}
pub fn parse_raw_to_formatted(s: &str) -> FormattedMessageDetail {
let mut components = vec![];
let mut section_title = None;
let mut section_text = vec![];
fn push_section(section_title: &mut Option<String>, section_text: &mut Vec<FormattedString>, components: &mut Vec<FormattedMessageComponent>) {
if section_title.is_some() || !section_text.is_empty() {
let old = mem::replace(section_text, vec![]);
let component = if let Some(title) = section_title.take() {
FormattedMessageComponent::Section(title, old)
} else {
FormattedMessageComponent::Text(old)
};
components.push(component);
}
}
for line in s.lines() {
if line.len() > 4 && line.starts_with("#<") && line.ends_with(">#") {
push_section(&mut section_title, &mut section_text, &mut components);
section_title = Some(line[2..line.len() - 2].to_owned());
} else {
section_text.extend_from_slice(&parse_section_text(&format!("{}\n", line)));
}
}
push_section(&mut section_title, &mut section_text, &mut components);
FormattedMessageDetail::new(s.to_owned(), components)
}
fn parse_section_text(s: &str) -> Vec<FormattedString> {
vec![FormattedString::new(s.to_owned(), vec![])]
}