Skip to main content

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}