lex_core/lex/ast/elements/
definition.rs1use super::super::range::{Position, Range};
31use super::super::text_content::TextContent;
32use super::super::traits::{AstNode, Container, Visitor, VisualStructure};
33use super::annotation::Annotation;
34use super::container::GeneralContainer;
35use super::content_item::ContentItem;
36use super::typed_content::ContentElement;
37use std::fmt;
38
39#[derive(Debug, Clone, PartialEq)]
41pub struct Definition {
42 pub subject: TextContent,
43 pub children: GeneralContainer,
44 pub annotations: Vec<Annotation>,
45 pub location: Range,
46}
47
48impl Definition {
49 fn default_location() -> Range {
50 Range::new(0..0, Position::new(0, 0), Position::new(0, 0))
51 }
52 pub fn new(subject: TextContent, children: Vec<ContentElement>) -> Self {
53 Self {
54 subject,
55 children: GeneralContainer::from_typed(children),
56 annotations: Vec::new(),
57 location: Self::default_location(),
58 }
59 }
60 pub fn with_subject(subject: String) -> Self {
61 Self {
62 subject: TextContent::from_string(subject, None),
63 children: GeneralContainer::empty(),
64 annotations: Vec::new(),
65 location: Self::default_location(),
66 }
67 }
68 pub fn at(mut self, location: Range) -> Self {
70 self.location = location;
71 self
72 }
73
74 pub fn annotations(&self) -> &[Annotation] {
76 &self.annotations
77 }
78
79 pub fn annotations_mut(&mut self) -> &mut Vec<Annotation> {
81 &mut self.annotations
82 }
83
84 pub fn iter_annotations(&self) -> std::slice::Iter<'_, Annotation> {
86 self.annotations.iter()
87 }
88
89 pub fn iter_annotation_contents(&self) -> impl Iterator<Item = &ContentItem> {
91 self.annotations
92 .iter()
93 .flat_map(|annotation| annotation.children())
94 }
95
96 pub fn header_location(&self) -> Option<&Range> {
98 self.subject.location.as_ref()
99 }
100
101 pub fn body_location(&self) -> Option<Range> {
103 Range::bounding_box(self.children.iter().map(|item| item.range()))
104 }
105}
106
107impl AstNode for Definition {
108 fn node_type(&self) -> &'static str {
109 "Definition"
110 }
111 fn display_label(&self) -> String {
112 let subject_text = self.subject.as_string();
113 if subject_text.chars().count() > 50 {
114 format!("{}…", subject_text.chars().take(50).collect::<String>())
115 } else {
116 subject_text.to_string()
117 }
118 }
119 fn range(&self) -> &Range {
120 &self.location
121 }
122
123 fn accept(&self, visitor: &mut dyn Visitor) {
124 visitor.visit_definition(self);
125 super::super::traits::visit_children(visitor, &self.children);
126 visitor.leave_definition(self);
127 }
128}
129
130impl VisualStructure for Definition {
131 fn is_source_line_node(&self) -> bool {
132 true
133 }
134
135 fn has_visual_header(&self) -> bool {
136 true
137 }
138}
139
140impl Container for Definition {
141 fn label(&self) -> &str {
142 self.subject.as_string()
143 }
144 fn children(&self) -> &[ContentItem] {
145 &self.children
146 }
147 fn children_mut(&mut self) -> &mut Vec<ContentItem> {
148 self.children.as_mut_vec()
149 }
150}
151
152impl fmt::Display for Definition {
153 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154 write!(
155 f,
156 "Definition('{}', {} items)",
157 self.subject.as_string(),
158 self.children.len()
159 )
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166 use crate::lex::ast::elements::paragraph::Paragraph;
167
168 #[test]
169 fn test_definition() {
170 let location = super::super::super::range::Range::new(
171 0..0,
172 super::super::super::range::Position::new(1, 0),
173 super::super::super::range::Position::new(1, 10),
174 );
175 let definition = Definition::with_subject("Subject".to_string()).at(location.clone());
176 assert_eq!(definition.location, location);
177 }
178
179 #[test]
180 fn test_definition_header_and_body_locations() {
181 let subject_range = Range::new(0..7, Position::new(0, 0), Position::new(0, 7));
182 let child_range = Range::new(10..15, Position::new(1, 0), Position::new(1, 5));
183 let subject = TextContent::from_string("Subject".to_string(), Some(subject_range.clone()));
184 let child = ContentElement::Paragraph(
185 Paragraph::from_line("Body".to_string()).at(child_range.clone()),
186 );
187
188 let definition = Definition::new(subject, vec![child]).at(Range::new(
189 0..20,
190 Position::new(0, 0),
191 Position::new(1, 5),
192 ));
193
194 assert_eq!(definition.header_location(), Some(&subject_range));
195 assert_eq!(definition.body_location().unwrap().span, child_range.span);
196 }
197}