markdown_fmt/
builder.rs

1use super::*;
2
3pub(crate) type CodeBlockFormatter = Box<dyn Fn(&str, String) -> String>;
4
5/// Builder for the [MarkdownFormatter](crate::MarkdownFormatter)
6pub struct FormatterBuilder {
7    code_block_formatter: CodeBlockFormatter,
8    config: Config,
9}
10
11impl FormatterBuilder {
12    /// Create a [FormatterBuilder] with custom [`Config`].
13    ///
14    /// ```rust
15    /// # use markdown_fmt::{Config, FormatterBuilder};
16    /// let builder = FormatterBuilder::with_config(Config {
17    ///     max_width: Some(80),
18    ///     ..Default::default()
19    /// });
20    /// let formatter = builder.build();
21    /// ```
22    pub fn with_config(config: Config) -> Self {
23        Self {
24            config,
25            ..Default::default()
26        }
27    }
28
29    /// Create a [FormatterBuilder] with a custom code block formatter.
30    ///
31    /// The closure used to reformat code blocks takes two arguments;
32    /// the [`info string`] and the complete code snippet
33    ///
34    /// ```rust
35    /// # use markdown_fmt::MarkdownFormatter;
36    /// # use markdown_fmt::FormatterBuilder;
37    /// let builder = FormatterBuilder::with_code_block_formatter(|info_string, code_block| {
38    ///     // Set the code block formatting logic
39    ///     match info_string.to_lowercase().as_str() {
40    ///         "rust" => {
41    ///             // format rust code
42    ///             # code_block
43    ///         }
44    ///         _ => code_block,
45    ///     }
46    /// });
47    /// let formatter = builder.build();
48    /// ```
49    /// [`info string`]: https://spec.commonmark.org/0.31.2/#fenced-code-blocks
50    pub fn with_code_block_formatter<F>(formatter: F) -> Self
51    where
52        F: Fn(&str, String) -> String + 'static,
53    {
54        let mut builder = Self::default();
55        builder.code_block_formatter(formatter);
56        builder
57    }
58
59    /// Build a [MarkdownFormatter](crate::MarkdownFormatter)
60    ///
61    /// ```rust
62    /// # use markdown_fmt::MarkdownFormatter;
63    /// # use markdown_fmt::FormatterBuilder;
64    /// let builder = FormatterBuilder::default();
65    /// let formatter: MarkdownFormatter = builder.build();
66    /// ```
67    pub fn build(self) -> crate::MarkdownFormatter {
68        crate::MarkdownFormatter::new(self.code_block_formatter, self.config)
69    }
70
71    /// Configure how code blocks should be reformatted after creating the [FormatterBuilder].
72    ///
73    /// The closure passed to `code_block_formatter` takes two arguments;
74    /// the [`info string`] and the complete code snippet
75    ///
76    /// [`info string`]: https://spec.commonmark.org/0.31.2/#fenced-code-blocks
77    pub fn code_block_formatter<F>(&mut self, formatter: F) -> &mut Self
78    where
79        F: Fn(&str, String) -> String + 'static,
80    {
81        self.code_block_formatter = Box::new(formatter);
82        self
83    }
84
85    /// Configure the max with when rewriting paragraphs.
86    ///
87    /// When set to [None], the deafault, paragraph width is left unchanged.
88    pub fn max_width(&mut self, max_width: Option<usize>) -> &mut Self {
89        self.config.max_width = max_width;
90        self
91    }
92
93    /// Set the configuration based on Steven Hé (Sīchàng)'s opinion.
94    pub fn sichanghe_config(&mut self) -> &mut Self {
95        self.config = Config::sichanghe_opinion();
96        self
97    }
98
99    /// Internal setter for Config. Used for testing
100    #[cfg(test)]
101    pub(crate) fn config(&mut self, config: Config) -> &mut Self {
102        self.config = config;
103        self
104    }
105}
106
107impl std::fmt::Debug for FormatterBuilder {
108    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109        f.debug_struct("FormatterBuilder")
110            .field("config", &self.config)
111            .finish()
112    }
113}
114
115/// Default formatter which leaves code blocks unformatted
116fn default_code_block_formatter(_info_str: &str, code_block: String) -> String {
117    code_block
118}
119
120impl Default for FormatterBuilder {
121    fn default() -> Self {
122        FormatterBuilder {
123            code_block_formatter: Box::new(default_code_block_formatter),
124            config: Config::default(),
125        }
126    }
127}