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}