rnotifylib/message/
detail_builder.rs1use crate::message::formatted_detail::{FormattedMessageComponent, FormattedMessageDetail, FormattedString, Style};
2use crate::message::MessageDetail;
3
4pub trait FormattedStringAppendable {
5 fn append(&mut self, s: FormattedString) -> &mut Self;
6
7 fn append_styled<S: ToString>(&mut self, s: S, style: Style) -> &mut Self {
8 self.append(FormattedString::styled(s, style));
9 self
10 }
11
12 fn append_plain<S: ToString>(&mut self, s: S) -> &mut Self {
13 self.append(FormattedString::plain(s));
14 self
15 }
16}
17
18pub struct MessageDetailBuilder {
19 contents: Vec<FormattedMessageComponent>,
20 raw: String,
21}
22
23impl MessageDetailBuilder {
24 pub fn new() -> Self {
25 Self::with_raw(String::from("Raw not available"))
26 }
27
28 pub fn with_raw(raw: String) -> Self {
29 Self {
30 contents: vec![],
31 raw,
32 }
33 }
34
35 pub fn raw(&mut self, raw: String) -> &mut Self {
36 self.raw = raw;
37 self
38 }
39
40 pub fn section<F, S>(&mut self, name: S, apply: F) -> &mut Self
41 where F: FnOnce(&mut SectionBuilder),
42 S: ToString {
43 let mut section = SectionBuilder {
44 name: name.to_string(),
45 contents: vec![],
46 };
47 apply(&mut section);
48 self.contents.push(section.build());
49 self
50 }
51
52 pub fn text_block<F>(&mut self, apply: F) -> &mut Self
53 where F: FnOnce(&mut TextBlockBuilder) {
54 let mut text_block = TextBlockBuilder::default();
55 apply(&mut text_block);
56 self.contents.push(text_block.build());
57 self
58 }
59
60 pub fn build(self) -> MessageDetail {
61 MessageDetail::Formatted(FormattedMessageDetail::new(self.raw, self.contents))
62 }
63}
64
65#[derive(Default)]
66pub struct TextBlockBuilder {
67 contents: Vec<FormattedString>,
68}
69
70impl TextBlockBuilder {
71 pub fn build(self) -> FormattedMessageComponent {
72 FormattedMessageComponent::Text(self.contents)
73 }
74
75 pub fn build_vec(self) -> Vec<FormattedString> {
76 self.contents
77 }
78}
79
80impl FormattedStringAppendable for TextBlockBuilder {
81 fn append(&mut self, s: FormattedString) -> &mut Self {
82 self.contents.push(s);
83 self
84 }
85}
86
87pub struct SectionBuilder {
88 name: String,
89 contents: Vec<FormattedString>,
90}
91
92impl SectionBuilder {
93 pub fn build(self) -> FormattedMessageComponent {
94 FormattedMessageComponent::Section(self.name, self.contents)
95 }
96}
97
98impl FormattedStringAppendable for SectionBuilder {
99 fn append(&mut self, s: FormattedString) -> &mut Self {
100 self.contents.push(s);
101 self
102 }
103}
104
105#[cfg(test)]
106mod test {
107 use crate::message::formatted_detail::{FormattedMessageComponent, FormattedMessageDetail, FormattedString, Style};
108 use crate::message::detail_builder::{FormattedStringAppendable, MessageDetailBuilder};
109 use crate::message::MessageDetail;
110
111 #[test]
112 fn test_detail_builder() {
113 let mut builder = MessageDetailBuilder::new();
114 builder.text_block(|block| {
115 block.append_plain("Base Description");
116 })
117 .section("New section", |section| {
118 section.append_styled("hello", Style::Monospace);
119 });
120
121 let built = builder.build();
122
123 let test = MessageDetail::Formatted(FormattedMessageDetail::new(
124 "Raw not available".to_string(),
125 vec![
126 FormattedMessageComponent::Text(vec![FormattedString::plain("Base Description".to_owned())]),
127 FormattedMessageComponent::Section("New section".to_owned(),
128 vec![FormattedString::styled("hello", Style::Monospace)])]
129 ));
130
131 assert_eq!(built, test);
132 }
133}