docspec_core/event.rs
1//! Event types for the streaming document pipeline.
2//!
3//! Events represent the atomic units of document structure. Sources emit events
4//! in document order; sinks consume them. This decouples all readers from all writers.
5
6/// Generates boolean builder methods for a struct field.
7///
8/// Each method takes `self`, sets the corresponding field to `true`, and returns `self`.
9/// Doc comments are auto-generated via `concat!` and `stringify!`.
10macro_rules! bool_setters {
11 ($($field:ident),+ $(,)?) => {
12 $(
13 #[inline]
14 #[must_use]
15 #[doc = concat!("Enables ", stringify!($field), " formatting.")]
16 pub fn $field(mut self) -> Self {
17 self.$field = true;
18 self
19 }
20 )+
21 };
22}
23
24/// Text formatting attributes for an [`Event::Text`] event.
25#[expect(
26 clippy::struct_excessive_bools,
27 reason = "TextStyle intentionally stores one boolean per formatting attribute for a simple builder API"
28)]
29#[derive(Debug, Clone, PartialEq, Eq, Default)]
30pub struct TextStyle {
31 /// Bold formatting.
32 pub bold: bool,
33 /// Monospace/code formatting.
34 pub code: bool,
35 /// Italic formatting.
36 pub italic: bool,
37 /// Highlight/mark color.
38 pub mark: Option<crate::Color>,
39 /// Strikethrough formatting.
40 pub strikethrough: bool,
41 /// Subscript formatting.
42 pub subscript: bool,
43 /// Superscript formatting.
44 pub superscript: bool,
45 /// Underline formatting.
46 pub underline: bool,
47}
48
49impl TextStyle {
50 bool_setters!(bold, code, italic);
51
52 /// Sets the highlight/mark color.
53 #[inline]
54 #[must_use]
55 pub fn mark(mut self, color: crate::Color) -> Self {
56 self.mark = Some(color);
57 self
58 }
59
60 bool_setters!(strikethrough, subscript, superscript, underline);
61}
62
63/// A streaming document event.
64///
65/// Events flow from [`crate::EventSource`] readers to [`crate::EventSink`] writers. The enum is
66/// marked `#[non_exhaustive]` to allow adding new event types in future versions.
67///
68/// Events come in three categories:
69/// - **Start/End pairs**: Container elements like headings, paragraphs, tables
70/// - **Self-contained**: Standalone elements like text, images, line breaks
71/// - **Block vs Inline**: Block events create new vertical sections; inline events flow within blocks
72#[non_exhaustive]
73#[derive(Debug, Clone, PartialEq)]
74pub enum Event {
75 /// End a block quote.
76 EndBlockQuote,
77
78 /// End a table caption.
79 EndCaption,
80
81 /// End a definition detail.
82 EndDefinitionDetail,
83
84 /// End a definition list.
85 EndDefinitionList,
86
87 /// End a definition term.
88 EndDefinitionTerm,
89
90 /// End a document.
91 EndDocument,
92
93 /// End a footnote definition.
94 EndFootnote,
95
96 /// End a heading.
97 EndHeading,
98
99 /// End a hyperlink.
100 EndLink,
101
102 /// End an ordered (numbered) list item.
103 EndOrderedListItem,
104
105 /// End a paragraph.
106 EndParagraph,
107
108 /// End a preformatted block.
109 EndPreformatted,
110
111 /// End a table.
112 EndTable,
113
114 /// End a table data cell.
115 EndTableCell,
116
117 /// End a table header cell.
118 EndTableHeader,
119
120 /// End a table row.
121 EndTableRow,
122
123 /// End an unordered (bulleted) list item.
124 EndUnorderedListItem,
125
126 /// A reference to a footnote.
127 FootnoteRef {
128 /// The footnote identifier being referenced.
129 id: u32,
130 },
131
132 /// An image reference.
133 Image {
134 /// Alternative text for accessibility.
135 alt: Option<String>,
136 /// Whether the image is purely decorative (no alt text needed).
137 decorative: bool,
138 /// Optional block identifier for the image.
139 id: Option<String>,
140 /// Source of the image (embedded asset or external URI).
141 source: crate::ImageSource,
142 /// Optional tooltip text.
143 title: Option<String>,
144 },
145
146 /// A hard line break within a paragraph.
147 LineBreak,
148
149 /// A soft line break in source markup, such as a markdown line wrap.
150 ///
151 /// Soft breaks correspond to source line wraps that do not enforce a
152 /// visible break. Writers choose rendering policy: space, newline,
153 /// `<br>`, etc.
154 SoftBreak,
155
156 /// Begin a block quote.
157 StartBlockQuote {
158 /// Optional block identifier.
159 id: Option<String>,
160 },
161
162 /// Begin a table caption.
163 StartCaption {
164 /// Optional block identifier.
165 id: Option<String>,
166 },
167
168 /// Begin a definition detail (description).
169 StartDefinitionDetail {
170 /// Optional block identifier.
171 id: Option<String>,
172 },
173
174 /// Begin a definition list.
175 StartDefinitionList {
176 /// Optional block identifier.
177 id: Option<String>,
178 },
179
180 /// Begin a definition term.
181 StartDefinitionTerm {
182 /// Optional block identifier.
183 id: Option<String>,
184 },
185
186 /// Begin a document with optional language and metadata.
187 StartDocument {
188 /// Optional block identifier.
189 id: Option<String>,
190 /// BCP 47 language tag (e.g., "en", "en-US", "zh-Hans").
191 language: Option<String>,
192 /// Document metadata including title, authors, and description.
193 metadata: Option<crate::DocumentMeta>,
194 },
195
196 /// Begin a footnote definition.
197 StartFootnote {
198 /// Unique identifier for this footnote.
199 id: u32,
200 },
201
202 /// Begin a heading of the given level.
203 StartHeading {
204 /// Optional block identifier for the heading.
205 id: Option<String>,
206 /// Heading level, 1–9 (1 is most prominent).
207 level: u8,
208 },
209
210 /// Begin a hyperlink.
211 StartLink {
212 /// URL or URI target of the link.
213 href: String,
214 /// Optional block identifier.
215 id: Option<String>,
216 /// Optional tooltip text.
217 title: Option<String>,
218 },
219
220 /// Begin an ordered (numbered) list item.
221 StartOrderedListItem {
222 /// Optional block identifier.
223 id: Option<String>,
224 /// Zero-indexed nesting depth (0 = top-level list).
225 level: u32,
226 /// Starting number for the list, populated only on the first item of an ordered list
227 /// (subsequent items in the same list: `None`).
228 start: Option<u64>,
229 /// Visual style of the list marker. Writers tolerate mismatches per `ListStyleType` convention.
230 style_type: crate::ListStyleType,
231 },
232
233 /// Begin a paragraph with optional alignment.
234 StartParagraph {
235 /// Text alignment for the paragraph.
236 alignment: Option<crate::TextAlignment>,
237 /// Optional block identifier for the paragraph.
238 id: Option<String>,
239 },
240
241 /// Begin a preformatted (code) block with optional syntax highlighting.
242 StartPreformatted {
243 /// Optional block identifier.
244 id: Option<String>,
245 /// Language identifier for syntax highlighting (e.g., "rust", "python").
246 syntax: Option<String>,
247 },
248
249 /// Begin a table.
250 StartTable {
251 /// Optional block identifier.
252 id: Option<String>,
253 },
254
255 /// Begin a table data cell.
256 StartTableCell {
257 /// Number of columns this cell spans.
258 colspan: Option<u32>,
259 /// Optional block identifier.
260 id: Option<String>,
261 /// Number of rows this cell spans.
262 rowspan: Option<u32>,
263 },
264
265 /// Begin a table header cell.
266 StartTableHeader {
267 /// Abbreviated content for accessibility.
268 abbr: Option<String>,
269 /// Number of columns this cell spans.
270 colspan: Option<u32>,
271 /// Optional block identifier.
272 id: Option<String>,
273 /// Number of rows this cell spans.
274 rowspan: Option<u32>,
275 /// Whether this header applies to a column or row.
276 scope: Option<crate::TableHeaderScope>,
277 },
278
279 /// Begin a table row.
280 StartTableRow {
281 /// Optional block identifier.
282 id: Option<String>,
283 },
284
285 /// Begin an unordered (bulleted) list item.
286 StartUnorderedListItem {
287 /// Optional block identifier.
288 id: Option<String>,
289 /// Zero-indexed nesting depth (0 = top-level list).
290 level: u32,
291 /// Visual style of the list marker. Writers tolerate mismatches per `ListStyleType` convention.
292 style_type: crate::ListStyleType,
293 },
294
295 /// A text run with formatting attributes.
296 Text {
297 /// The text content.
298 content: String,
299 /// Text formatting attributes.
300 style: TextStyle,
301 },
302
303 /// A horizontal rule / thematic break.
304 ThematicBreak {
305 /// Optional block identifier.
306 id: Option<String>,
307 },
308}