Skip to main content

lex_core/lex/ast/elements/inlines/
base.rs

1//! Inline AST nodes shared across formatting, literal, and reference elements.
2//!
3//! These nodes are intentionally lightweight so the inline parser can be used
4//! from unit tests before it is integrated into the higher level AST builders.
5//!
6//! # Annotations
7//!
8//! All inline nodes support annotations - metadata that can be attached to provide
9//! additional structured information about the node. This is particularly useful when
10//! processing inline content into other formats (e.g., parsing math expressions into
11//! MathML).
12//!
13//! For format conversion use cases, annotations should use the `doc.data` label with
14//! a `type` parameter indicating the target format:
15//!
16//! ```rust,ignore
17//! use lex_parser::lex::ast::elements::{Annotation, Label, Parameter};
18//!
19//! let annotation = Annotation::with_parameters(
20//!     Label::new("doc.data".to_string()),
21//!     vec![Parameter::new("type".to_string(), "mathml".to_string())]
22//! );
23//! ```
24
25use super::super::annotation::Annotation;
26use super::references::ReferenceInline;
27
28/// Sequence of inline nodes produced from a [`TextContent`](crate::lex::ast::TextContent).
29pub type InlineContent = Vec<InlineNode>;
30
31/// Inline node variants supported by the initial flat inline parser.
32///
33/// All variants include an `annotations` field for attaching metadata. Post-processors
34/// can populate this field when transforming inline content (e.g., parsing math to MathML).
35#[derive(Debug, Clone, PartialEq)]
36pub enum InlineNode {
37    /// Plain text segment with no formatting.
38    Plain {
39        text: String,
40        annotations: Vec<Annotation>,
41    },
42    /// Strong emphasis delimited by `*`.
43    Strong {
44        content: InlineContent,
45        annotations: Vec<Annotation>,
46    },
47    /// Emphasis delimited by `_`.
48    Emphasis {
49        content: InlineContent,
50        annotations: Vec<Annotation>,
51    },
52    /// Inline code delimited by `` ` ``.
53    Code {
54        text: String,
55        annotations: Vec<Annotation>,
56    },
57    /// Simple math span delimited by `#`.
58    Math {
59        text: String,
60        annotations: Vec<Annotation>,
61    },
62    /// Reference enclosed by square brackets.
63    Reference {
64        data: ReferenceInline,
65        annotations: Vec<Annotation>,
66    },
67}
68
69impl InlineNode {
70    /// Creates a plain text node without annotations.
71    pub fn plain(text: String) -> Self {
72        InlineNode::Plain {
73            text,
74            annotations: Vec::new(),
75        }
76    }
77
78    /// Creates a code node without annotations.
79    pub fn code(text: String) -> Self {
80        InlineNode::Code {
81            text,
82            annotations: Vec::new(),
83        }
84    }
85
86    /// Creates a math node without annotations.
87    pub fn math(text: String) -> Self {
88        InlineNode::Math {
89            text,
90            annotations: Vec::new(),
91        }
92    }
93
94    /// Creates a strong node without annotations.
95    pub fn strong(content: InlineContent) -> Self {
96        InlineNode::Strong {
97            content,
98            annotations: Vec::new(),
99        }
100    }
101
102    /// Creates an emphasis node without annotations.
103    pub fn emphasis(content: InlineContent) -> Self {
104        InlineNode::Emphasis {
105            content,
106            annotations: Vec::new(),
107        }
108    }
109
110    /// Creates a reference node without annotations.
111    pub fn reference(data: ReferenceInline) -> Self {
112        InlineNode::Reference {
113            data,
114            annotations: Vec::new(),
115        }
116    }
117
118    /// Returns the plain text from this node when available.
119    pub fn as_plain(&self) -> Option<&str> {
120        match self {
121            InlineNode::Plain { text, .. } => Some(text),
122            InlineNode::Code { text, .. } => Some(text),
123            InlineNode::Math { text, .. } => Some(text),
124            _ => None,
125        }
126    }
127
128    /// Returns nested inline content for container nodes (strong/emphasis).
129    pub fn children(&self) -> Option<&InlineContent> {
130        match self {
131            InlineNode::Strong { content, .. } | InlineNode::Emphasis { content, .. } => {
132                Some(content)
133            }
134            _ => None,
135        }
136    }
137
138    /// Returns `true` when this node is plain text.
139    pub fn is_plain(&self) -> bool {
140        matches!(self, InlineNode::Plain { .. })
141    }
142
143    /// Returns a reference to this node's annotations.
144    pub fn annotations(&self) -> &[Annotation] {
145        match self {
146            InlineNode::Plain { annotations, .. }
147            | InlineNode::Strong { annotations, .. }
148            | InlineNode::Emphasis { annotations, .. }
149            | InlineNode::Code { annotations, .. }
150            | InlineNode::Math { annotations, .. }
151            | InlineNode::Reference { annotations, .. } => annotations,
152        }
153    }
154
155    /// Returns a mutable reference to this node's annotations.
156    pub fn annotations_mut(&mut self) -> &mut Vec<Annotation> {
157        match self {
158            InlineNode::Plain { annotations, .. }
159            | InlineNode::Strong { annotations, .. }
160            | InlineNode::Emphasis { annotations, .. }
161            | InlineNode::Code { annotations, .. }
162            | InlineNode::Math { annotations, .. }
163            | InlineNode::Reference { annotations, .. } => annotations,
164        }
165    }
166
167    /// Adds an annotation to this node.
168    pub fn with_annotation(mut self, annotation: Annotation) -> Self {
169        self.annotations_mut().push(annotation);
170        self
171    }
172
173    /// Adds multiple annotations to this node.
174    pub fn with_annotations(mut self, mut annotations: Vec<Annotation>) -> Self {
175        self.annotations_mut().append(&mut annotations);
176        self
177    }
178}