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}