1use nom::bytes::complete::tag;
2use regex::Regex;
3use syn::ext;
4
5use crate::datacell::{
6 BlockCell::BlockCell, BlockChildType::*, CellTrait::Cell, Datacell::*, ElementCell::ElementCell,
7};
8
9pub struct Desugarer {
10 pub json: String,
11 pub last_id: usize,
12}
13
14pub struct ParagraphIndentOptions {
15 pub tags_before_non_indents: Vec<&'static str>,
16 pub tags_with_non_indent_first_child: Vec<&'static str>,
17}
18
19#[derive(Clone, Debug)]
20pub enum AttachToEnum {
21 BEFORE,
22 AFTER,
23 BOTH,
24 NONE,
25}
26
27#[derive(Clone, Debug)]
28pub struct IgnoreOptions {
29 pub element: &'static str,
30 pub attach_to: AttachToEnum,
31}
32
33
34impl Desugarer {
35 pub fn new(json: &str, last_id: usize) -> Desugarer {
36 Desugarer {
37 json: json.to_string(),
38 last_id,
39 }
40 }
41
42 fn count_element(&mut self, root: &DataCell, tag_name: &str, count: &mut usize) {
43 match &root.cell_type {
44 CellType::Element(el) => {
45 if el.name == tag_name {
46 *count += 1;
47 } else {
48 el.children
49 .iter()
50 .for_each(|child| self.count_element(child, tag_name, count))
51 }
52 }
53 CellType::Root(el) => el
54 .children
55 .iter()
56 .for_each(|child| self.count_element(child, tag_name, count)),
57
58 _ => (),
59 }
60 }
61
62 fn find_cell<'a>(
63 &self,
64 root: &'a DataCell,
65 tag_patterns: &Vec<&str>, cells: &mut Vec<&'a DataCell>,
67 ) {
68 match &root.cell_type {
69 CellType::Element(el) => {
70 let element_found = tag_patterns.is_empty() || tag_patterns.iter().any(|pattern|{
71 let re = Regex::new(&format!("^{}$", pattern)).expect("Unvalid pattern {pattern}");
72 re.is_match(&el.name)
73 });
74 if element_found {
75 cells.push(root)
76 }
77 el.children
78 .iter()
79 .for_each(|child| self.find_cell(child, tag_patterns, cells))
80 }
81 CellType::Root(el) => el
82 .children
83 .iter()
84 .for_each(|child| self.find_cell(child, tag_patterns, cells)),
85 _ => (),
86 }
87 }
88
89 fn find_cell_and_mark_article<'a>(
90 &self,
91 root: &'a DataCell,
92 tag_names: &Vec<&str>,
93 cells: &mut Vec<(usize, &'a DataCell)>, mut article: Option<usize>,
95 article_types: &Vec<String>,
96 ) {
97 match &root.cell_type {
98 CellType::Element(el) => {
99 if tag_names.is_empty() || tag_names.contains(&el.name.as_str()) {
100 if let Some(article_id) = article {
101 cells.push((article_id, root))
102 }
103 }
104 if article_types.contains(&el.name.chars().filter(|c| !c.is_numeric()).collect()) {
105 article = Some(root.id)
106 }
107
108 el.children.iter().for_each(|child| {
109 self.find_cell_and_mark_article(
110 child,
111 tag_names,
112 cells,
113 article,
114 &article_types,
115 )
116 })
117 }
118 CellType::Root(el) => el.children.iter().for_each(|child| {
119 self.find_cell_and_mark_article(child, tag_names, cells, article, &article_types)
120 }),
121 _ => (),
122 }
123 }
124
125 pub fn pre_process_exercises(&mut self) -> Desugarer {
126 let mut root: DataCell = serde_json::from_str(&self.json).unwrap();
127 let mut exercises: Vec<&DataCell> = Vec::new();
128 let binding = root.clone();
129 self.find_cell(&binding, &vec!["Exercises"], &mut exercises);
130
131 for exercises_cell in exercises.iter() {
132 let mut count: usize = 0;
133 self.count_element(exercises_cell, "Exercise", &mut count);
134 let mut prop_line = "labels vec![\"0\"".to_string();
135 if count > 0 {
136 for i in 1..=count - 1 {
137 prop_line += &format!(",\"{}\"", i);
138 }
139 prop_line += "]";
140
141 ElementCell::add_attribute(&mut root, exercises_cell.id, prop_line.as_str());
144 }
145 }
146
147 Desugarer {
148 json: serde_json::to_string_pretty(&root).unwrap(),
149 last_id: self.last_id,
150 }
151 }
152
153 pub fn add_increamental_attr(
154 &mut self,
155 tags_attributes: Vec<(&str, &str)>,
156 article_types: &Vec<String>,
157 ) -> Desugarer {
158 let mut root: DataCell = serde_json::from_str(&self.json).unwrap();
159 let mut elements: Vec<(usize, &DataCell)> = Vec::new();
160 let binding = root.clone();
161 let tag_names: Vec<&str> = tags_attributes.iter().map(|x| x.0).collect();
162 let attribute_names: Vec<&str> = tags_attributes.iter().map(|x| x.1).collect();
163 self.find_cell_and_mark_article(&binding, &tag_names, &mut elements, None, article_types);
164
165 let mut counters = vec![0; tag_names.len()];
166
167 for (i, (article_id, solution_cell)) in elements.iter().enumerate() {
168 if let CellType::Element(el) = &solution_cell.cell_type {
170 let (tag_index, _) = tag_names
171 .iter()
172 .enumerate()
173 .find(|x| x.1 == &el.name)
174 .unwrap();
175
176 if i > 0 && elements[i - 1].0 != *article_id {
178 counters[tag_index] = 0;
179 }
180
181 let prop_line = format!("{} {}", attribute_names[tag_index], counters[tag_index]);
182
183 counters[tag_index] += 1;
184
185 ElementCell::add_attribute(&mut root, solution_cell.id, prop_line.as_str());
186 }
187 }
188
189 Desugarer {
190 json: serde_json::to_string_pretty(&root).unwrap(),
191 last_id: self.last_id,
192 }
193 }
194
195 pub fn auto_increamental_title(
196 &mut self,
197 tag_name: &str,
198 title_label: &str,
199 article_types: &Vec<String>,
200 ) -> Desugarer {
201 let mut root: DataCell = serde_json::from_str(&self.json).unwrap();
202 let mut elements: Vec<(usize, &DataCell)> = Vec::new();
203 let binding = root.clone();
204 self.find_cell_and_mark_article(
205 &binding,
206 &vec![tag_name],
207 &mut elements,
208 None,
209 article_types,
210 );
211
212 for (_, (article_id, element)) in elements.clone().iter_mut().enumerate() {
213 if let CellType::Element(el) = &element.cell_type {
214 ElementCell::add_attribute(
217 &mut root,
218 *article_id,
219 &format!("counter {}{}_counter", title_label, article_id),
220 );
221
222 let handle = el.props.iter().find(|x| x.key == "handle");
223
224 let command = format!(
225 "{} {}::++{}{}_counter.",
226 title_label,
227 if handle.is_some() {
228 handle.unwrap().value.to_owned() + "<<"
229 } else {
230 "".to_string()
231 },
232 title_label,
233 article_id
234 );
235
236 let new_block_child = BlockChildType::Delimited(DelimitedCell {
237 open_delimeter: "*".to_string(),
238 close_delimeter: "*".to_string(),
239 terminal: command,
240 display_type: DelimitedDisplayType::INLINE,
241 wrapped_with: None,
242 });
243
244 BlockChildType::insert_text_to_first_block_child_text(&mut root, element.id, " ");
246
247 BlockChildType::add_block_at_first(
248 &mut root,
249 element.id,
250 &new_block_child,
251 Some(&BlockCell {
252 has_counter_commands: true,
253 ..Default::default()
254 }),
255 );
256 }
257 }
258
259 Desugarer {
260 json: serde_json::to_string_pretty(&root).unwrap(),
261 last_id: self.last_id,
262 }
263 }
264
265 pub fn wrap_children<'a>(
266 &mut self,
267 elements: Vec<&'static str>, wrap_with: &str,
269 ignore_elements: &Option<Vec<IgnoreOptions>>,
270 ) -> Desugarer {
271 let mut root: DataCell = serde_json::from_str(&self.json).unwrap();
274 let binding = root.clone();
275 let mut _elements: Vec<&DataCell> = Vec::new();
276
277 self.find_cell(&binding, &elements, &mut _elements);
278
279 let mut extra_ignored_elements = elements.iter().map(|el|{
281 IgnoreOptions{
282 element: el,
283 attach_to: AttachToEnum::NONE
284 }
285 }).collect::<Vec<IgnoreOptions>>();
286
287 if let Some(ignored) = ignore_elements {
288 ignored.iter().for_each(|i|{
289 extra_ignored_elements.push(i.clone());
290 });
291 }
292
293 for element in _elements {
294 self.wrap_element_children(&mut root, element, &extra_ignored_elements, wrap_with);
296 }
297
298 Desugarer {
299 json: serde_json::to_string_pretty(&root).unwrap(),
300 last_id: self.last_id,
301 }
302
303 }
304
305 fn wrap_element_children<T: FlatElement>(&mut self, root: &mut DataCell, el: &T, ignore_elements: &Vec<IgnoreOptions>, wrap_with: &str) {
306 let mut include_prev_child = false;
307 let mut include_in_prev_wrapper = false;
308 let mut add_wrapper = true;
309 let mut no_wrap = false;
310
311 el.children().unwrap().iter().enumerate().for_each(|(idx, child)| {
312 let mut element_ignored = None;
313 ignore_elements.iter().any(|option| {
314 if let CellType::Element(child_el) = &child.cell_type {
315 if option.element == child_el.name {
316 element_ignored = Some(option);
317 add_wrapper = false;
318 return true;
319 }
320 }
321 add_wrapper = true;
322 false
323 });
324
325 if let Some(el_ignored) = element_ignored {
326 match el_ignored.attach_to {
327 AttachToEnum::BEFORE => {
328 if idx == 0 {
330 add_wrapper = true;
331 } else {
332 ElementCell::move_cell(
333 root,
334 (el.id(), child.id),
335 self.last_id,
336 );
337 }
338 }
339 AttachToEnum::AFTER => {
340 include_prev_child = true
342 }
343 AttachToEnum::BOTH => {
344 if idx == 0 {
346 self.last_id += 1;
347 ElementCell::add_cell(
348 root,
349 el.id(),
350 self.last_id,
351 wrap_with,
352 );
353 }
354 ElementCell::move_cell(
355 root,
357 (el.id(), child.id),
358 self.last_id,
359 );
360 include_in_prev_wrapper = true }
362 AttachToEnum::NONE => {
363 add_wrapper = false;
366 include_in_prev_wrapper = false;
367 ElementCell::move_cell(
368 root,
369 (el.id(), child.id),
370 el.id(),
371 );
372 }
373 }
374 } else if include_in_prev_wrapper {
375 ElementCell::move_cell(root, (el.id(), child.id), self.last_id);
376 include_in_prev_wrapper = false;
377
378 add_wrapper = false
379 }
380
381 if add_wrapper {
382 self.last_id += 1;
383 ElementCell::add_cell(root, el.id(), self.last_id, wrap_with);
384
385 if include_prev_child {
386 ElementCell::move_cell(
387 root,
388 (el.id(), el.children().unwrap()[idx - 1].id),
389 self.last_id,
390 );
391 include_prev_child = false
392 }
393 ElementCell::move_cell(root, (el.id(), child.id), self.last_id);
394 }
395 });
399 }
400
401 pub fn wrap_block_delimited(&self, wrap_with: &str) -> Desugarer {
402 let mut root: DataCell = serde_json::from_str(&self.json).unwrap();
403 self.wrap_recursive(&mut root, wrap_with);
404
405 Desugarer {
406 json: serde_json::to_string_pretty(&root).unwrap(),
407 last_id: self.last_id,
408 }
409 }
410
411 pub fn wrap_recursive<'a>(&self, root: &'a mut DataCell, wrap_with: &str) -> Desugarer {
412 match &mut root.cell_type {
413 CellType::Block(block) => {
414 block
415 .children
416 .iter_mut()
417 .enumerate()
418 .for_each(|(i, child)| {
419 if let BlockChildType::Delimited(dl) = child {
420 if i > 0 && dl.display_type == DelimitedDisplayType::BLOCK {
421 dl.wrapped_with = Some(wrap_with.to_string());
422 }
423 }
424 });
425 }
426 CellType::Element(el) => el.children.iter_mut().for_each(|child| {
427 self.wrap_recursive(child, wrap_with);
428 }),
429 CellType::Root(el) => el.children.iter_mut().for_each(|child| {
430 self.wrap_recursive(child, wrap_with);
431 }),
432 _ => (),
433 }
434
435 Desugarer {
436 json: serde_json::to_string_pretty(&root).unwrap(),
437 last_id: self.last_id,
438 }
439 }
440
441 pub fn add_indent(&mut self, paragraph_tags: &Vec<&str>) -> Desugarer {
442 let mut root: DataCell = serde_json::from_str(&self.json).unwrap();
445 let mut _elements: Vec<&DataCell> = Vec::new();
446 let binding = root.clone();
447
448 self.find_cell(&binding, paragraph_tags, &mut _elements);
449
450 let mut elements_to_indent: Vec<&DataCell> = Vec::new();
451
452 for element in _elements.iter() {
453 let parent: Option<&mut DataCell> =
454 DataCell::get_cell_by_id(&mut root, element.parent_id);
455
456 if Self::paragraph_first_child_is_text(&element)
458 && Self::prev_is_non_block_delimiter(element.id, &parent, paragraph_tags)
459 {
460 elements_to_indent.push(element);
461 }
462 }
463
464 for element in elements_to_indent.iter() {
465 self.last_id += 1;
466 ElementCell::add_cell(&mut root, element.id, self.last_id, "Indent");
467 ElementCell::move_children(&mut root, element.id, self.last_id);
468 }
469
470 Desugarer {
471 json: serde_json::to_string_pretty(&root).unwrap(),
472 last_id: self.last_id,
473 }
474 }
475
476 pub fn paragraph_first_child_is_text(element: &DataCell) -> bool {
477 if let CellType::Element(el) = &element.cell_type {
478 return el.children.first().is_some_and(|c| {
479 if let CellType::Block(block) = &c.cell_type {
480 return block.children.first().is_some_and(|block_child| {
481 if let BlockChildType::Text(_) = &block_child {
482 return true;
483 }
484 false
485 });
486 }
487 false
488 });
489 }
490 false
491 }
492
493 pub fn is_first_child(
494 element_id: usize,
495 parent: &Option<&mut DataCell>,
496 options: &ParagraphIndentOptions,
497 ) -> bool {
498 if let Some(parent) = parent {
499 if let CellType::Element(parent) = &parent.cell_type {
500 if options
501 .tags_with_non_indent_first_child
502 .contains(&parent.name.as_str())
503 && parent.children.first().is_some_and(|c| c.id == element_id)
504 {
505 return true;
506 }
507 }
508 }
509 false
510 }
511
512 fn prev_is_non_block_delimiter(
513 element_id: usize,
514 parent: &Option<&mut DataCell>,
515 paragraph_tags: &Vec<&str>,
516 ) -> bool {
517 if let Some(parent) = parent {
518 if let CellType::Element(parent_el) = &parent.cell_type {
519 let mut prev_el: Option<&DataCell> = None;
520 for child in &parent_el.children {
521 if child.id == element_id {
522 break;
523 }
524 prev_el = Some(&child)
525 }
526 return prev_el.is_some_and(|p| {
527 if let CellType::Element(el) = &p.cell_type {
528 if !paragraph_tags.contains(&el.name.as_str()) {
529 return false;
530 }
531 if let Some(block) = el.children.last() {
532 if let CellType::Block(block) = &block.cell_type {
533 if let Some(block) = block.children.last() {
534 if let BlockChildType::Delimited(b) = &block {
535 return b.display_type != DelimitedDisplayType::BLOCK
536 && b.open_delimeter != "*";
537 }
538 if let BlockChildType::Text(_) = &block {
539 return true;
540 }
541 }
542 }
543 }
544 }
545 false
546 });
547 }
548 }
549 false
550 }
551
552 pub fn add_attribute(&mut self, tag_names: Vec<&str>, attribute: (&str, &str)) -> Desugarer {
553 let mut root: DataCell = serde_json::from_str(&self.json).unwrap();
556 let mut _elements: Vec<&DataCell> = Vec::new();
557 let binding = root.clone();
558 self.find_cell(&binding, &tag_names, &mut _elements);
559
560 for (_, element) in _elements.iter().enumerate() {
561 if let CellType::Element(_) = &element.cell_type {
562 ElementCell::add_attribute(
563 &mut root,
564 element.parent_id,
565 &format!("{} {}", attribute.0, attribute.1),
566 )
567 }
568 }
569
570 Desugarer {
571 json: serde_json::to_string_pretty(&root).unwrap(),
572 last_id: self.last_id,
573 }
574 }
575
576 pub fn auto_convert_to_float(&mut self, attrs: Vec<&str>) -> Desugarer {
577 fn convert_recusive(root: &mut DataCell, attrs: &Vec<&str>) {
578 match &mut root.cell_type {
579 CellType::Element(el) => {
580 el.props.iter_mut().for_each(|prop| {
581 if attrs.contains(&prop.key.as_str()) && !prop.value.contains('.') {
582 prop.value = format!("{}.0", prop.value);
583 }
584 });
585 el.children
586 .iter_mut()
587 .for_each(|child| convert_recusive(child, attrs))
588 }
589 CellType::Root(el) => el
590 .children
591 .iter_mut()
592 .for_each(|child| convert_recusive(child, attrs)),
593 _ => (),
594 }
595 }
596
597 let mut root: DataCell = serde_json::from_str(&self.json).unwrap();
598 convert_recusive(&mut root, &attrs);
599 Desugarer {
600 json: serde_json::to_string_pretty(&root).unwrap(),
601 last_id: self.last_id,
602 }
603 }
604}
605