Skip to main content

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}