1use crate::message::formatted_detail::{FormattedMessageComponent, FormattedMessageDetail, FormattedString, Style};
2
3pub trait HtmlMessageDetail {
4 fn create_html(&self) -> String;
5}
6
7impl HtmlMessageDetail for FormattedMessageDetail {
8 fn create_html(&self) -> String {
9 formatted_to_html(&self)
10 }
11}
12
13fn formatted_to_html(formatted: &FormattedMessageDetail) -> String {
14 let mut html = String::with_capacity(100);
15 for component in formatted.components() {
16 match component {
17 FormattedMessageComponent::Section(section, formatted_string) => {
18 html.push_str(&format!("<div><h2>{}</h2><p>{}</p></div>",
19 escape_html(section),
20 parse_formatted(formatted_string)
21 ));
22 }
23 FormattedMessageComponent::Text(formatted_string) => {
24 html.push_str(&format!("<p>{}</p>", parse_formatted(formatted_string)))
25 }
26 }
27 }
28 html
29}
30
31fn escape_html(s: &str) -> String {
32 s.replace('&', "&")
33 .replace('>', ">")
34 .replace('<', "<")
35}
36
37fn parse_formatted(formatted: &Vec<FormattedString>) -> String {
38 let mut html = String::new();
39 for part in formatted {
40 for style in part.get_styles() {
41 let start_tag = match style {
42 Style::Bold => "<b>",
43 Style::Italics => "<i>",
44 Style::Monospace => "<code>",
45 Style::Code { lang: _ } => "<code>",
46 };
47 html.push_str(start_tag);
48 }
49 html.push_str(&escape_html(part.get_string()));
50 for style in part.get_styles() {
51 let end_tag = match style {
52 Style::Bold => "</b>",
53 Style::Italics => "</i>",
54 Style::Monospace => "</code>",
55 Style::Code { lang: _ } => "</code>",
56 };
57 html.push_str(end_tag);
58 }
59 }
60 html
61}
62
63#[cfg(test)]
64mod test {
65 use crate::message::detail_builder::{FormattedStringAppendable, MessageDetailBuilder};
66 use crate::message::MessageDetail::Formatted;
67 use super::*;
68
69 #[test]
70 fn test_html_conversion() {
71 let mut builder = MessageDetailBuilder::new();
72 builder.section("hello world", |body| {
73 body.append_plain("Dear fellow inhabitants. it has come to my attention that ");
74 body.append_styled("you have not been doing your job.", Style::Bold);
75 });
76 builder.text_block(|block| {
77 block.append_plain("That is all.");
78 });
79 let message = builder.build();
80 if let Formatted(formatted_detail) = message {
81 let html = formatted_to_html(&formatted_detail);
82 assert_eq!(html, "<div><h2>hello world</h2><p>Dear fellow inhabitants. it has come to my attention that <b>you have not been doing your job.</b></p></div><p>That is all.</p>")
83 }
84 else {
85 panic!("oops");
86 }
87 }
88}