markdown_composer/types/markdown.rs
1use crate::{
2 traits::{AsFooter, MarkdownElement},
3 types::{header::Header, link::Link, list::List, paragraph::Paragraph},
4};
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7use std::fmt;
8use tousize::ToUsize;
9
10/// A markdown document.
11#[derive(Default)]
12// #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
13pub struct Markdown {
14 /// The markdown elements.
15 pub elements: Vec<Box<dyn MarkdownElement>>,
16 /// The markdown footer elements.
17 pub footers: Vec<Box<dyn MarkdownElement>>,
18}
19
20impl<'a> Markdown {
21 /// Creates a new default `Markdown` instance.
22 pub fn new() -> Self {
23 Self::default()
24 }
25
26 /// Creates a new `Markdown` instance with the given elements and footers.
27 pub fn with(
28 elements: Vec<Box<dyn MarkdownElement>>,
29 footers: Vec<Box<dyn MarkdownElement>>,
30 ) -> Self {
31 Self { elements, footers }
32 }
33
34 /// Adds a header to the document.
35 ///
36 /// # Arguments
37 ///
38 /// - `text`: The header's text.
39 /// - `level`: The header's level.
40 ///
41 /// # Panics
42 ///
43 /// Panics if the header level is not valid (one to six inclusive).
44 pub fn header(&mut self, text: impl Into<String>, level: impl ToUsize) -> &mut Self {
45 let header = Header::from(text, level);
46 self.elements.push(Box::new(header));
47 self
48 }
49
50 /// Adds a header with level 1 to the document.
51 ///
52 /// # Arguments
53 ///
54 /// - `text`: The header's text.
55 pub fn header1(&mut self, text: impl Into<String>) -> &mut Self {
56 self.header(text, 1usize);
57 self
58 }
59
60 /// Adds a header with level 2 to the document.
61 ///
62 /// # Arguments
63 ///
64 /// - `text`: The header's text.
65 pub fn header2(&mut self, text: impl Into<String>) -> &mut Self {
66 self.header(text, 2usize);
67 self
68 }
69
70 /// Adds a header with level 3 to the document.
71 ///
72 /// # Arguments
73 ///
74 /// - `text`: The header's text.
75 pub fn header3(&mut self, text: impl Into<String>) -> &mut Self {
76 self.header(text, 3usize);
77 self
78 }
79
80 /// Adds a header with level 4 to the document.
81 ///
82 /// # Arguments
83 ///
84 /// - `text`: The header's text.
85 pub fn header4(&mut self, text: impl Into<String>) -> &mut Self {
86 self.header(text, 4usize);
87 self
88 }
89
90 /// Adds a header with level 5 to the document.
91 ///
92 /// # Arguments
93 ///
94 /// - `text`: The header's text.
95 pub fn header5(&mut self, text: impl Into<String>) -> &mut Self {
96 self.header(text, 5usize);
97 self
98 }
99
100 /// Adds a header with level 6 to the document.
101 ///
102 /// # Arguments
103 ///
104 /// - `text`: The header's text.
105 pub fn header6(&mut self, text: impl Into<String>) -> &mut Self {
106 self.header(text, 6usize);
107 self
108 }
109
110 /// Adds a list to the document.
111 ///
112 /// # Arguments
113 ///
114 /// - `list`: The list instance to add.
115 pub fn list(&mut self, list: List) -> &mut Self {
116 self.elements.push(Box::new(list));
117 self
118 }
119
120 /// Adds a link to the document.
121 ///
122 /// # Arguments
123 ///
124 /// - `link`: The link instance to add.
125 ///
126 /// # Note
127 ///
128 /// The associated footer element is added as well if the passed link is
129 /// marked as footer.
130 pub fn link(&mut self, link: Link) -> &mut Self {
131 if link.footer {
132 self.footers.push(link.as_footer());
133 }
134 self.elements.push(Box::new(link));
135 self
136 }
137
138 /// Adds a paragraph to the document.
139 ///
140 /// # Arguments
141 ///
142 /// - `text`: The paragraph's text.
143 pub fn paragraph(&mut self, text: impl Into<String>) -> &mut Self {
144 self.elements.push(Box::new(Paragraph::from(text)));
145 self
146 }
147
148 /// Renders the markdown document to a `String`.
149 ///
150 /// The method does render each
151 /// [element](struct.Markdown.structfield.elements) in order, followed by
152 /// each [footer](struct.Markdown.structfield.footers).
153 pub fn render(&self) -> String {
154 self.to_string()
155 }
156}
157
158impl fmt::Display for Markdown {
159 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
160 for element in &self.elements {
161 writeln!(f, "{}", element.render())?;
162 }
163
164 for footer in &self.footers {
165 writeln!(f, "{}", footer.render())?;
166 }
167
168 Ok(())
169 }
170}