libmandoc_rs/ast.rs
1//! Owned, renderer-neutral syntax data copied from a completed libmandoc parse.
2//!
3//! These types contain no C pointers and remain valid after the parser session
4//! has been released. They deliberately describe source semantics rather than
5//! imposing a presentation model on downstream renderers.
6
7/// High-level macro package detected by libmandoc.
8#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub enum MacroSet {
11 /// No supported semantic macro package was detected.
12 None,
13 /// The source uses the semantic mdoc(7) macro package.
14 Mdoc,
15 /// The source uses the traditional man(7) macro package.
16 Man,
17}
18
19/// Renderer-neutral node role copied from the libmandoc syntax tree.
20#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
21#[derive(Clone, Copy, Debug, Eq, PartialEq)]
22pub enum NodeKind {
23 /// Synthetic root containing the complete syntax tree.
24 Root,
25 /// A macro block, such as a section or display.
26 Block,
27 /// The heading or term portion of a block.
28 Head,
29 /// The principal content portion of a block.
30 Body,
31 /// The trailing portion of a block, when the macro defines one.
32 Tail,
33 /// A leaf-level semantic macro invocation.
34 Element,
35 /// Literal source text after roff escape processing.
36 Text,
37 /// A source comment retained by libmandoc.
38 Comment,
39 /// A tbl(7) table node.
40 Table,
41 /// An eqn(7) equation node.
42 Equation,
43}
44
45/// Normalized mdoc list behavior copied independently of upstream enum values.
46#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
47#[derive(Clone, Copy, Debug, Eq, PartialEq)]
48pub enum NormalizedListKind {
49 /// An unordered list whose items carry bullets.
50 Bullet,
51 /// An ordered list whose items carry ordinal markers.
52 Ordered,
53 /// A term-and-description list.
54 Definition,
55 /// A list laid out as aligned columns.
56 Column,
57 /// A marker-free list.
58 Plain,
59}
60
61/// Whether an mdoc display preserves source line layout.
62#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
63#[derive(Clone, Copy, Debug, Eq, PartialEq)]
64pub enum DisplayKind {
65 /// Preserve input line breaks and horizontal whitespace.
66 Literal,
67 /// Reflow content as filled prose.
68 Filled,
69}
70
71/// Normalized font selected by an mdoc `Bf` block.
72#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
73#[derive(Clone, Copy, Debug, Eq, PartialEq)]
74pub enum NormalizedFont {
75 /// Typographic emphasis.
76 Emphasis,
77 /// Literal or fixed-width text.
78 Literal,
79 /// Symbolic text, conventionally rendered in bold.
80 Symbolic,
81}
82
83/// Explicit author layout mode selected by an mdoc `An` control macro.
84#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
85#[derive(Clone, Copy, Debug, Eq, PartialEq)]
86pub enum AuthorMode {
87 /// Render each subsequent author separately.
88 Split,
89 /// Keep subsequent authors in a continuous group.
90 NoSplit,
91}
92
93/// Delimiters selected by the obsolete mdoc `Es`/`En` enclosure pair.
94///
95/// libmandoc resolves the stateful `Es` definition while validating each
96/// `En` invocation. Copying that result keeps downstream renderers from
97/// replaying formatter state or exposing the non-printing `Es` arguments.
98#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
99#[derive(Clone, Debug, Eq, PartialEq)]
100pub struct NormalizedEnclosure {
101 /// Visible opening delimiter.
102 pub opening: String,
103 /// Visible closing delimiter, when the definition supplied one.
104 pub closing: Option<String>,
105}
106
107/// Horizontal alignment retained for one parsed tbl(7) cell.
108#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
109#[derive(Clone, Copy, Debug, Eq, PartialEq)]
110pub enum TableAlignment {
111 /// Align cell content to the left edge.
112 Left,
113 /// Center cell content horizontally.
114 Center,
115 /// Align cell content to the right edge.
116 Right,
117}
118
119/// Owned payload of one cell in a libmandoc table row.
120#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
121#[derive(Clone, Debug, Eq, PartialEq)]
122pub struct TableCell {
123 /// Visible cell content, or `None` for a spanning/empty cell.
124 pub text: Option<String>,
125 /// The cell was written using a multiline tbl(7) `T{`/`T}` text block.
126 pub text_block: bool,
127 /// This cell continues a vertical span owned by a cell in an earlier row.
128 ///
129 /// tbl(7) permits both a `^` layout cell and a literal `\^` data cell for
130 /// this purpose. Neither spelling produces printable cell content.
131 pub vertical_continuation: bool,
132 /// Number of logical columns occupied by the cell.
133 pub column_span: u16,
134 /// Number of logical rows occupied by the cell.
135 pub row_span: u16,
136 /// Horizontal alignment requested by tbl(7).
137 pub alignment: TableAlignment,
138}
139
140/// Source and renderer flags needed by a lowering or rendering pass.
141#[allow(clippy::struct_excessive_bools)]
142#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
143#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
144pub struct NodeFlags {
145 /// The node was synthesized by libmandoc rather than written explicitly.
146 pub generated: bool,
147 /// The node ends a sentence according to libmandoc punctuation rules.
148 pub sentence_end: bool,
149 /// The node must not contribute visible output.
150 pub no_print: bool,
151 /// The node belongs to a no-fill region that preserves source lines.
152 pub no_fill: bool,
153 /// libmandoc selected this node as a same-document destination.
154 pub deep_link_target: bool,
155 /// libmandoc renders a self-link for this destination.
156 pub permalink: bool,
157 /// This node begins a roff input line (`NODE_LINE`).
158 ///
159 /// Some man macros keep same-line layout arguments and next-line visible
160 /// content in one syntax head, so source-line role is semantic data.
161 pub line_start: bool,
162 /// This text node is opening punctuation and suppresses spacing after it.
163 pub delimiter_open: bool,
164 /// This text node is closing punctuation and suppresses spacing before it.
165 pub delimiter_close: bool,
166 /// This text node ends with the roff `\c` escape and joins the next input
167 /// line without an implicit space or line break.
168 pub line_continuation: bool,
169 /// libmandoc selected synopsis-style presentation for this node.
170 ///
171 /// Some semantic punctuation is generated only in this context, notably
172 /// the terminating semicolon of mdoc `Fn` and `Fo` declarations.
173 pub synopsis_pretty: bool,
174}
175
176/// An owned syntax node with no pointers into the C parser.
177#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
178#[derive(Clone, Debug, Eq, PartialEq)]
179pub struct Node {
180 /// Structural role of this node in the libmandoc tree.
181 pub kind: NodeKind,
182 /// Source macro name, without the leading dot, when applicable.
183 pub macro_name: Option<String>,
184 /// Visible text carried by a text node.
185 pub text: Option<String>,
186 /// Canonical same-document tag assigned during libmandoc validation.
187 pub tag: Option<String>,
188 /// One-based source line reported by libmandoc, or zero when unavailable.
189 pub line: u32,
190 /// One-based source column reported by libmandoc, or zero when unavailable.
191 pub column: u32,
192 /// Source and renderer flags attached to the node.
193 pub flags: NodeFlags,
194 /// Normalized list behavior for an mdoc list block.
195 pub list_kind: Option<NormalizedListKind>,
196 /// Fill behavior for an mdoc display block.
197 pub display_kind: Option<DisplayKind>,
198 /// Font selected by an mdoc font block.
199 pub font: Option<NormalizedFont>,
200 /// Author layout mode selected by an mdoc author macro.
201 pub author_mode: Option<AuthorMode>,
202 /// Stateful delimiters resolved for an mdoc `En` invocation.
203 pub enclosure: Option<NormalizedEnclosure>,
204 /// Whether the enclosing list requests compact vertical layout.
205 pub compact: bool,
206 /// Raw normalized display/list offset, including a roff scale suffix.
207 pub offset: Option<String>,
208 /// Normalized mdoc(7) list width, including its roff scale suffix.
209 pub width: Option<String>,
210 /// Cells copied from a tbl(7) row represented by this node.
211 pub table_cells: Vec<TableCell>,
212 /// Normalized eqn(7) expression carried by this node.
213 pub equation: Option<String>,
214 /// Child nodes in source order.
215 pub children: Vec<Self>,
216}
217
218/// Metadata copied from a completed libmandoc parse.
219#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
220#[derive(Clone, Debug, Default, Eq, PartialEq)]
221pub struct Metadata {
222 /// Canonical manual title, normally derived from `TH` or `Dt`.
223 pub title: Option<String>,
224 /// Native manual category such as `1` or `3p`.
225 pub section: Option<String>,
226 /// Manual volume or collection label.
227 pub volume: Option<String>,
228 /// Operating-system label declared by the page.
229 pub os: Option<String>,
230 /// Architecture qualifier declared by the page.
231 pub arch: Option<String>,
232 /// Primary display name extracted from the NAME section.
233 pub name: Option<String>,
234 /// Normalized source date when libmandoc recognized it.
235 pub date: Option<String>,
236 /// Target named by a top-level `.so` alias page.
237 pub alias_target: Option<String>,
238 /// Whether the parsed source produced a document body.
239 pub has_body: bool,
240}
241
242/// Complete owned output of the low-level parser, excluding diagnostics.
243#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
244#[derive(Clone, Debug, Eq, PartialEq)]
245pub struct Document {
246 /// Macro package selected for the source.
247 pub macro_set: MacroSet,
248 /// Metadata validated and normalized by libmandoc.
249 pub metadata: Metadata,
250 /// Root of the owned syntax tree.
251 pub root: Node,
252}