acdc_parser/
options.rs

1pub use crate::safe_mode::SafeMode;
2
3use crate::{AttributeValue, DocumentAttributes};
4
5#[derive(Debug, Clone, Default)]
6#[non_exhaustive]
7pub struct Options {
8    pub safe_mode: SafeMode,
9    pub timings: bool,
10    pub document_attributes: DocumentAttributes,
11    /// Strict mode - fail on non-conformance instead of warn-and-continue.
12    ///
13    /// When enabled, issues that would normally result in a warning and fallback
14    /// behavior will instead cause parsing to fail. For example:
15    /// - Non-conforming manpage titles (not matching `name(volume)` format)
16    pub strict: bool,
17    /// Enable Setext-style (underlined) header parsing.
18    ///
19    /// When enabled, headers can use the legacy two-line syntax:
20    /// ```text
21    /// Document Title
22    /// ==============
23    /// ```
24    #[cfg(feature = "setext")]
25    pub setext: bool,
26}
27
28impl Options {
29    /// Create a new `OptionsBuilder` for fluent configuration.
30    ///
31    /// # Example
32    ///
33    /// ```
34    /// use acdc_parser::{Options, SafeMode};
35    ///
36    /// let options = Options::builder()
37    ///     .with_safe_mode(SafeMode::Safe)
38    ///     .with_timings()
39    ///     .with_attribute("toc", "left")
40    ///     .build();
41    /// ```
42    #[must_use]
43    pub fn builder() -> OptionsBuilder {
44        OptionsBuilder::default()
45    }
46
47    /// Create a new `Options` with default settings.
48    ///
49    /// Equivalent to `Options::default()`.
50    #[must_use]
51    pub fn new() -> Self {
52        Self::default()
53    }
54
55    /// Create a new `Options` with the given document attributes.
56    ///
57    /// # Example
58    ///
59    /// ```
60    /// use acdc_parser::{Options, DocumentAttributes, AttributeValue};
61    ///
62    /// let mut attrs = DocumentAttributes::default();
63    /// attrs.insert("toc".into(), AttributeValue::String("left".into()));
64    ///
65    /// let options = Options::with_attributes(attrs);
66    /// ```
67    #[must_use]
68    pub fn with_attributes(document_attributes: DocumentAttributes) -> Self {
69        Self {
70            document_attributes,
71            ..Default::default()
72        }
73    }
74}
75
76/// Builder for `Options` that provides an API for configuration.
77///
78/// Create an `OptionsBuilder` using `Options::builder()`.
79///
80/// # Example
81///
82/// ```
83/// use acdc_parser::{Options, SafeMode};
84///
85/// let options = Options::builder()
86///     .with_safe_mode(SafeMode::Safe)
87///     .with_timings()
88///     .with_attribute("toc", "left")
89///     .with_attribute("sectnums", true)
90///     .build();
91/// ```
92#[derive(Debug, Clone, Default)]
93#[non_exhaustive]
94pub struct OptionsBuilder {
95    safe_mode: SafeMode,
96    timings: bool,
97    document_attributes: DocumentAttributes,
98    strict: bool,
99    #[cfg(feature = "setext")]
100    setext: bool,
101}
102
103impl OptionsBuilder {
104    /// Set the safe mode for parsing.
105    ///
106    /// # Example
107    ///
108    /// ```
109    /// use acdc_parser::{Options, SafeMode};
110    ///
111    /// let options = Options::builder()
112    ///     .with_safe_mode(SafeMode::Safe)
113    ///     .build();
114    /// ```
115    #[must_use]
116    pub fn with_safe_mode(mut self, safe_mode: SafeMode) -> Self {
117        self.safe_mode = safe_mode;
118        self
119    }
120
121    /// Enable timing information during parsing.
122    ///
123    /// # Example
124    ///
125    /// ```
126    /// use acdc_parser::Options;
127    ///
128    /// let options = Options::builder()
129    ///     .with_timings()
130    ///     .build();
131    /// ```
132    #[must_use]
133    pub fn with_timings(mut self) -> Self {
134        self.timings = true;
135        self
136    }
137
138    /// Enable strict mode.
139    ///
140    /// When enabled, issues that would normally result in a warning and fallback
141    /// behavior will instead cause parsing to fail.
142    ///
143    /// # Example
144    ///
145    /// ```
146    /// use acdc_parser::Options;
147    ///
148    /// let options = Options::builder()
149    ///     .with_strict()
150    ///     .build();
151    /// ```
152    #[must_use]
153    pub fn with_strict(mut self) -> Self {
154        self.strict = true;
155        self
156    }
157
158    /// Add a document attribute with a string value.
159    ///
160    /// This is a convenience method that accepts various types for the value:
161    /// - `&str` becomes `AttributeValue::String`
162    /// - `bool` becomes `AttributeValue::Bool`
163    /// - `()` becomes `AttributeValue::None`
164    ///
165    /// # Example
166    ///
167    /// ```
168    /// use acdc_parser::Options;
169    ///
170    /// let options = Options::builder()
171    ///     .with_attribute("toc", "left")
172    ///     .with_attribute("sectnums", true)
173    ///     .build();
174    /// ```
175    #[must_use]
176    pub fn with_attribute(
177        mut self,
178        name: impl Into<String>,
179        value: impl Into<AttributeValue>,
180    ) -> Self {
181        self.document_attributes.insert(name.into(), value.into());
182        self
183    }
184
185    /// Set all document attributes at once.
186    ///
187    /// # Example
188    ///
189    /// ```
190    /// use acdc_parser::{Options, DocumentAttributes, AttributeValue};
191    ///
192    /// let mut attrs = DocumentAttributes::default();
193    /// attrs.insert("toc".into(), AttributeValue::String("left".into()));
194    ///
195    /// let options = Options::builder()
196    ///     .with_attributes(attrs)
197    ///     .build();
198    /// ```
199    #[must_use]
200    pub fn with_attributes(mut self, document_attributes: DocumentAttributes) -> Self {
201        self.document_attributes = document_attributes;
202        self
203    }
204
205    /// Enable Setext-style (underlined) header parsing.
206    ///
207    /// When enabled, headers can use the legacy two-line syntax where
208    /// the title is underlined with `=`, `-`, `~`, `^`, or `+` characters.
209    ///
210    /// # Example
211    ///
212    /// ```ignore
213    /// use acdc_parser::Options;
214    ///
215    /// let options = Options::builder()
216    ///     .with_setext()
217    ///     .build();
218    /// ```
219    #[cfg(feature = "setext")]
220    #[must_use]
221    pub fn with_setext(mut self) -> Self {
222        self.setext = true;
223        self
224    }
225
226    /// Build the `Options` from this builder.
227    ///
228    /// # Example
229    ///
230    /// ```
231    /// use acdc_parser::{Options, SafeMode};
232    ///
233    /// let options = Options::builder()
234    ///     .with_safe_mode(SafeMode::Safe)
235    ///     .build();
236    /// ```
237    #[must_use]
238    pub fn build(self) -> Options {
239        Options {
240            safe_mode: self.safe_mode,
241            timings: self.timings,
242            document_attributes: self.document_attributes,
243            strict: self.strict,
244            #[cfg(feature = "setext")]
245            setext: self.setext,
246        }
247    }
248}