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