lex_core/lex/ast/elements/
table.rs1use super::super::range::Range;
39use super::super::text_content::TextContent;
40use super::super::traits::{AstNode, Container, Visitor, VisualStructure};
41use super::annotation::Annotation;
42use super::container::GeneralContainer;
43use super::content_item::ContentItem;
44use super::list::List;
45use super::typed_content::ContentElement;
46use super::verbatim::VerbatimBlockMode;
47use std::fmt;
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51pub enum TableCellAlignment {
52 Left,
54 Center,
56 Right,
58 None,
60}
61
62#[derive(Debug, Clone, PartialEq)]
64pub struct TableCell {
65 pub content: TextContent,
67 pub children: GeneralContainer,
69 pub colspan: usize,
71 pub rowspan: usize,
73 pub align: TableCellAlignment,
75 pub header: bool,
77 pub location: Range,
79}
80
81impl TableCell {
82 pub fn new(content: TextContent) -> Self {
83 Self {
84 content,
85 children: GeneralContainer::empty(),
86 colspan: 1,
87 rowspan: 1,
88 align: TableCellAlignment::None,
89 header: false,
90 location: Range::default(),
91 }
92 }
93
94 pub fn with_children(mut self, children: Vec<ContentElement>) -> Self {
95 self.children = GeneralContainer::from_typed(children);
96 self
97 }
98
99 pub fn has_block_content(&self) -> bool {
101 !self.children.is_empty()
102 }
103
104 pub fn with_span(mut self, colspan: usize, rowspan: usize) -> Self {
105 self.colspan = colspan;
106 self.rowspan = rowspan;
107 self
108 }
109
110 pub fn with_align(mut self, align: TableCellAlignment) -> Self {
111 self.align = align;
112 self
113 }
114
115 pub fn with_header(mut self, header: bool) -> Self {
116 self.header = header;
117 self
118 }
119
120 pub fn at(mut self, location: Range) -> Self {
121 self.location = location;
122 self
123 }
124
125 pub fn text(&self) -> &str {
127 self.content.as_string()
128 }
129
130 pub fn is_empty(&self) -> bool {
132 self.content.as_string().trim().is_empty()
133 }
134}
135
136#[derive(Debug, Clone, PartialEq)]
138pub struct TableRow {
139 pub cells: Vec<TableCell>,
141 pub location: Range,
143}
144
145impl TableRow {
146 pub fn new(cells: Vec<TableCell>) -> Self {
147 Self {
148 cells,
149 location: Range::default(),
150 }
151 }
152
153 pub fn at(mut self, location: Range) -> Self {
154 self.location = location;
155 self
156 }
157
158 pub fn cell_count(&self) -> usize {
160 self.cells.len()
161 }
162}
163
164#[derive(Debug, Clone, PartialEq)]
166pub struct Table {
167 pub subject: TextContent,
169 pub header_rows: Vec<TableRow>,
171 pub body_rows: Vec<TableRow>,
173 pub footnotes: Option<Box<List>>,
175 pub annotations: Vec<Annotation>,
177 pub location: Range,
179 pub mode: VerbatimBlockMode,
181}
182
183impl Table {
184 pub fn new(
185 subject: TextContent,
186 header_rows: Vec<TableRow>,
187 body_rows: Vec<TableRow>,
188 mode: VerbatimBlockMode,
189 ) -> Self {
190 Self {
191 subject,
192 header_rows,
193 body_rows,
194 footnotes: None,
195 annotations: Vec::new(),
196 location: Range::default(),
197 mode,
198 }
199 }
200
201 pub fn with_footnotes(mut self, footnotes: List) -> Self {
202 self.footnotes = Some(Box::new(footnotes));
203 self
204 }
205
206 pub fn at(mut self, location: Range) -> Self {
207 self.location = location;
208 self
209 }
210
211 pub fn all_rows(&self) -> impl Iterator<Item = &TableRow> {
213 self.header_rows.iter().chain(self.body_rows.iter())
214 }
215
216 pub fn row_count(&self) -> usize {
218 self.header_rows.len() + self.body_rows.len()
219 }
220
221 pub fn column_count(&self) -> usize {
223 self.all_rows()
224 .map(|row| row.cells.len())
225 .max()
226 .unwrap_or(0)
227 }
228
229 pub fn cell_children_iter(&self) -> impl Iterator<Item = &ContentItem> {
231 self.all_rows()
232 .flat_map(|row| row.cells.iter())
233 .flat_map(|cell| cell.children.iter())
234 }
235
236 pub fn annotations(&self) -> &[Annotation] {
238 &self.annotations
239 }
240
241 pub fn annotations_mut(&mut self) -> &mut Vec<Annotation> {
243 &mut self.annotations
244 }
245}
246
247impl AstNode for Table {
248 fn node_type(&self) -> &'static str {
249 "Table"
250 }
251
252 fn display_label(&self) -> String {
253 let subject_text = self.subject.as_string();
254 if subject_text.chars().count() > 50 {
255 format!("{}…", subject_text.chars().take(50).collect::<String>())
256 } else {
257 subject_text.to_string()
258 }
259 }
260
261 fn range(&self) -> &Range {
262 &self.location
263 }
264
265 fn accept(&self, visitor: &mut dyn Visitor) {
266 visitor.visit_table(self);
267 for row in self.all_rows() {
269 for cell in &row.cells {
270 for child in cell.children.iter() {
271 child.accept(visitor);
272 }
273 }
274 }
275 for annotation in &self.annotations {
277 annotation.accept(visitor);
278 }
279 if let Some(footnotes) = &self.footnotes {
281 footnotes.accept(visitor);
282 }
283 visitor.leave_table(self);
284 }
285}
286
287impl VisualStructure for Table {
288 fn is_source_line_node(&self) -> bool {
289 true
290 }
291
292 fn has_visual_header(&self) -> bool {
293 true
294 }
295}
296
297impl Container for Table {
298 fn label(&self) -> &str {
299 self.subject.as_string()
300 }
301
302 fn children(&self) -> &[ContentItem] {
303 &[]
306 }
307
308 fn children_mut(&mut self) -> &mut Vec<ContentItem> {
309 panic!("Tables use structured rows/cells, not generic children")
313 }
314}
315
316impl fmt::Display for Table {
317 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
318 write!(
319 f,
320 "Table('{}', {} header + {} body rows, {} cols)",
321 self.subject.as_string(),
322 self.header_rows.len(),
323 self.body_rows.len(),
324 self.column_count()
325 )
326 }
327}