1use super::*;
8use crate::parser::types_and_aliases::IndentedBlockResult;
9
10pub fn bullet(
15 src_lines: &Vec<String>,
16 base_indent: usize,
17 section_level: &mut usize,
18 line_cursor: &mut LineCursor,
19 mut doctree: DocTree,
20 captures: ®ex::Captures,
21 pattern_name: &Pattern,
22) -> TransitionResult {
23
24 let detected_bullet = captures.get(2).unwrap().as_str().chars().next().unwrap();
25 let detected_bullet_indent = captures.get(1).unwrap().as_str().chars().count() + base_indent;
26 let detected_text_indent = captures.get(0).unwrap().as_str().chars().count() + base_indent;
27
28 let sublist_data = TreeNodeType::BulletList {
29 bullet: detected_bullet,
30 bullet_indent: detected_bullet_indent,
31 text_indent: detected_text_indent,
32 };
33
34 match Parser::parent_indent_matches(doctree.shared_node_data(), detected_bullet_indent) {
35 IndentationMatch::JustRight => {
36 doctree = match doctree.push_data_and_focus(sublist_data) {
37 Ok(tree) => tree,
38 Err(tree) => {
39 return TransitionResult::Failure {
40 message: format!(
41 "Node insertion error on line {}. Computer says no...",
42 line_cursor.sum_total()
43 ),
44 doctree: tree,
45 }
46 }
47 };
48 return TransitionResult::Success {
49 doctree: doctree,
50 push_or_pop: PushOrPop::Push(vec![State::BulletList]),
51 line_advance: LineAdvance::None,
52 };
53 }
54 IndentationMatch::TooMuch => {
55 doctree = match doctree.push_data_and_focus(TreeNodeType::BlockQuote {
56 body_indent: detected_bullet_indent,
57 }) {
58 Ok(tree) => tree,
59 Err(tree) => {
60 return TransitionResult::Failure {
61 message: format!(
62 "Node insertion error on line {}. Computer says no...",
63 line_cursor.sum_total()
64 ),
65 doctree: tree,
66 }
67 }
68 };
69 return TransitionResult::Success {
70 doctree: doctree,
71 push_or_pop: PushOrPop::Push(vec![State::BlockQuote]),
72 line_advance: LineAdvance::None,
73 };
74 }
75 _ => {
76 doctree = doctree.focus_on_parent();
77 return TransitionResult::Success {
78 doctree: doctree,
79 push_or_pop: PushOrPop::Pop,
80 line_advance: LineAdvance::None,
81 };
82 }
83 }
84}
85
86pub fn enumerator(
95 src_lines: &Vec<String>,
96 base_indent: usize,
97 section_level: &mut usize,
98 line_cursor: &mut LineCursor,
99 mut doctree: DocTree,
100 captures: ®ex::Captures,
101 pattern_name: &Pattern,
102) -> TransitionResult {
103
104 let detected_enumerator_indent =
105 captures.get(1).unwrap().as_str().chars().count() + base_indent;
106 let detected_text_indent = captures.get(0).unwrap().as_str().chars().count() + base_indent;
107 let (detected_number, detected_kind, detected_delims) =
110 match converters::enum_captures_to_int_kind_and_delims(
111 &captures,
112 None,
113 false,
114 false,
115 0,
116 1
117 ) {
118 Some((number, kind, delims)) => (number, kind, delims),
119 None => return TransitionResult::Failure {
120 message: format!(
121 "Could not convert a list enumerator to number on line {}. Computer says no...",
122 line_cursor.sum_total()
123 ),
124 doctree: doctree,
125 },
126 };
127
128 if ! Parser::is_enumerated_list_item(
130 src_lines,
131 line_cursor,
132 captures,
133 section_level,
134 base_indent,
135 detected_enumerator_indent,
136 detected_number,
137 detected_kind,
138 detected_delims,
139 pattern_name,
140 &detected_kind,
141 false,
142 0,
143 1,
144 ) {
145 return text(src_lines, base_indent, section_level, line_cursor, doctree, captures, pattern_name)
146 };
147
148 let list_node_data = TreeNodeType::EnumeratedList {
149 delims: detected_delims,
150 kind: detected_kind,
151 start_index: detected_number, n_of_items: 0,
153 enumerator_indent: detected_enumerator_indent,
154 };
155
156 match Parser::parent_indent_matches(doctree.shared_node_data(), detected_enumerator_indent) {
157 IndentationMatch::JustRight => {
158 doctree = match doctree.push_data_and_focus(list_node_data) {
159 Ok(tree) => tree,
160 Err(tree) => {
161 return TransitionResult::Failure {
162 message: format!(
163 "Node insertion error on line {}. Computer says no...",
164 line_cursor.sum_total()
165 ),
166 doctree: tree,
167 }
168 }
169 };
170 return TransitionResult::Success {
171 doctree: doctree,
172 push_or_pop: PushOrPop::Push(vec![State::EnumeratedList]),
173 line_advance: LineAdvance::None,
174 };
175 }
176 IndentationMatch::TooMuch => {
177 doctree = match doctree.push_data_and_focus(
178 TreeNodeType::BlockQuote {
179 body_indent: detected_enumerator_indent,
180 }
181 ) {
182 Ok(tree) => tree,
183 Err(tree) => {
184 return TransitionResult::Failure {
185 message: format!(
186 "Node insertion error on line {}. Computer says no...",
187 line_cursor.sum_total()
188 ),
189 doctree: tree,
190 }
191 }
192 };
193 return TransitionResult::Success {
194 doctree: doctree,
195 push_or_pop: PushOrPop::Push(vec![State::BlockQuote]),
196 line_advance: LineAdvance::None,
197 };
198 }
199 _ => {
200 return TransitionResult::Success {
201 doctree: doctree.focus_on_parent(),
202 push_or_pop: PushOrPop::Pop,
203 line_advance: LineAdvance::None,
204 };
205 }
206 }
207}
208
209pub fn field_marker(
211 src_lines: &Vec<String>,
212 base_indent: usize,
213 section_level: &mut usize,
214 line_cursor: &mut LineCursor,
215 mut doctree: DocTree,
216 captures: ®ex::Captures,
217 pattern_name: &Pattern,
218) -> TransitionResult {
219
220
221 let detected_marker_indent = captures.get(1).unwrap().as_str().chars().count() + base_indent;
222
223 let list_node_data = TreeNodeType::FieldList {
224 marker_indent: detected_marker_indent,
225 };
226
227 match Parser::parent_indent_matches(doctree.shared_node_data(), detected_marker_indent) {
230 IndentationMatch::JustRight => {
231 doctree = match doctree.push_data_and_focus(list_node_data) {
232 Ok(tree) => tree,
233 Err(tree) => {
234 return TransitionResult::Failure {
235 message: format!(
236 "Node insertion error on line {}. Computer says no...",
237 line_cursor.sum_total()
238 ),
239 doctree: tree,
240 }
241 }
242 };
243 return TransitionResult::Success {
244 doctree: doctree,
245 push_or_pop: PushOrPop::Push(vec![State::FieldList]),
246 line_advance: LineAdvance::None,
247 };
248 }
249 IndentationMatch::TooMuch => {
250 doctree = match doctree.push_data_and_focus(
251 TreeNodeType::BlockQuote {
252 body_indent: detected_marker_indent,
253 }
254 ) {
255 Ok(tree) => tree,
256 Err(tree) => {
257 return TransitionResult::Failure {
258 message: format!(
259 "Node insertion error on line {}. Computer says no...",
260 line_cursor.sum_total()
261 ),
262 doctree: tree,
263 }
264 }
265 };
266 return TransitionResult::Success {
267 doctree: doctree,
268 push_or_pop: PushOrPop::Push(vec![State::BlockQuote]),
269 line_advance: LineAdvance::None,
270 };
271 }
272 _ => {
273 return TransitionResult::Success {
274 doctree: doctree.focus_on_parent(),
275 push_or_pop: PushOrPop::Pop,
276 line_advance: LineAdvance::None,
277 };
278 }
279 }
280}
281
282pub fn footnote(
284 src_lines: &Vec<String>,
285 base_indent: usize,
286 section_level: &mut usize,
287 line_cursor: &mut LineCursor,
288 mut doctree: DocTree,
289 captures: ®ex::Captures,
290 pattern_name: &Pattern,
291) -> TransitionResult {
292
293
294 let indent_after_marker = captures.get(0).unwrap().as_str().chars().count() + base_indent;
296 let detected_marker_indent = match captures.name("indent") {
297 Some(whitespace) => whitespace.as_str().chars().count() + base_indent,
298 None => return TransitionResult::Failure {
299 message: format!(
300 "Could not scan footnote marker for indentation on line {}. Computer says no...",
301 line_cursor.sum_total()
302 ),
303 doctree: doctree
304 }
305 };
306 let (detected_kind, detected_label_str) = if let Some(label) = captures.name("manual") {
307 (FootnoteKind::Manual, label.as_str())
308 } else if let Some(label) = captures.name("autonumbered") {
309 (FootnoteKind::AutoNumbered, label.as_str())
310 } else if let Some(label) = captures.name("simplename") {
311 (FootnoteKind::SimpleRefName, label.as_str())
312 } else if let Some(label) = captures.name("autosymbol") {
313 (FootnoteKind::AutoSymbol, label.as_str())
314 } else {
315 return TransitionResult::Failure {
316 message: format!("No footnote type information inside footnote transition function. Computer says no..."),
317 doctree: doctree
318 };
319 };
320 let (detected_body_indent, offset) = match Parser::indent_on_subsequent_lines(
321 src_lines,
322 line_cursor.relative_offset(),
323 ) {
324 Some((indent, offset)) => {
325 let indent = if indent > detected_marker_indent {
326 indent
327 } else {
328 indent_after_marker
329 };
330 (indent, offset)
331 },
332 None => (indent_after_marker, 0 as usize)
333 };
334
335 let (label, target) = match detected_footnote_label_to_ref_label(
336 &doctree,
337 &detected_kind,
338 detected_label_str
339 ){
340 Some((label, target)) => (label, target),
341 None => return TransitionResult::Failure {
342 message: format!(
343 "Cound not transform a footnote marker into a label--target-pair on line {}. Computer says no...",
344 line_cursor.sum_total()
345 ),
346 doctree: doctree
347 }
348 };
349
350 match Parser::parent_indent_matches(doctree.shared_node_data(), detected_marker_indent) {
353 IndentationMatch::JustRight => {
354 let footnote_data = TreeNodeType::Footnote {
355 body_indent: detected_body_indent,
356 kind: detected_kind,
357 label: label.clone(),
358 target: target.clone(),
359 };
360 doctree = match doctree.push_data_and_focus(footnote_data) {
361 Ok(tree) => tree,
362 Err(tree) => {
363 return TransitionResult::Failure {
364 message: format!(
365 "Node insertion error on line {}. Computer says no...",
366 line_cursor.sum_total()
367 ),
368 doctree: tree,
369 }
370 }
371 };
372
373 let (doctree, offset, state_stack) = match Parser::parse_first_node_block(doctree, src_lines, base_indent, line_cursor, detected_body_indent, Some(indent_after_marker), State::Footnote, section_level, false) {
374 Ok((parsing_result, offset)) => if let ParsingResult::EOF { doctree, state_stack } | ParsingResult::EmptyStateStack { doctree, state_stack } = parsing_result {
375 (doctree, offset, state_stack)
376 } else {
377 unreachable!(
378 "Returned from a nested parsing session on line {} without necessary information. Computer says no...",
379 line_cursor.sum_total()
380 )
381 },
382 Err(ParsingResult::Failure { message, doctree }) => return TransitionResult::Failure {
383 message: format!("Looks like footnote on line {} has no content. Computer says no...", line_cursor.sum_total()),
384 doctree: doctree
385 },
386 _ => unreachable!("Parsing first node block on line {} resulted in unknown combination of return values. Computer says no...", line_cursor.sum_total())
387 };
388
389 return TransitionResult::Success {
390 doctree: doctree,
391 push_or_pop: PushOrPop::Push(state_stack),
392 line_advance: LineAdvance::Some(offset),
393 };
394 }
395 IndentationMatch::TooMuch => {
396 doctree = match doctree.push_data_and_focus(TreeNodeType::BlockQuote {
397 body_indent: detected_marker_indent,
398 }) {
399 Ok(tree) => tree,
400 Err(tree) => {
401 return TransitionResult::Failure {
402 message: format!(
403 "Node insertion error on line {}. Computer says no...",
404 line_cursor.sum_total()
405 ),
406 doctree: tree,
407 }
408 }
409 };
410 return TransitionResult::Success {
411 doctree: doctree,
412 push_or_pop: PushOrPop::Push(vec![State::BlockQuote]),
413 line_advance: LineAdvance::None,
414 };
415 }
416 _ => {
417 return TransitionResult::Success {
418 doctree: doctree.focus_on_parent(),
419 push_or_pop: PushOrPop::Pop,
420 line_advance: LineAdvance::None,
421 };
422 }
423 }
424}
425
426pub fn citation(
428 src_lines: &Vec<String>,
429 base_indent: usize,
430 section_level: &mut usize,
431 line_cursor: &mut LineCursor,
432 mut doctree: DocTree,
433 captures: ®ex::Captures,
434 pattern_name: &Pattern,
435) -> TransitionResult {
436
437 let indent_after_marker = captures.get(0).unwrap().as_str().chars().count() + base_indent;
439 let detected_marker_indent = captures.get(1).unwrap().as_str().chars().count() + base_indent;
440 let detected_label_str = captures.get(2).unwrap().as_str();
441
442 let detected_body_indent = match Parser::indent_on_subsequent_lines(
443 src_lines,
444 line_cursor.relative_offset(),
445 ) {
446 Some((indent, offset)) => {
447 let indent = if indent > detected_marker_indent {
448 indent
449 } else {
450 indent_after_marker
451 };
452 indent
453 },
454 None => indent_after_marker
455 };
456
457 match Parser::parent_indent_matches(doctree.shared_node_data(), detected_marker_indent) {
460 IndentationMatch::JustRight => {
461 let citation_data = TreeNodeType::Citation {
462 body_indent: detected_body_indent,
463 label: detected_label_str.trim().to_string(),
464 };
465 doctree = match doctree.push_data_and_focus(citation_data) {
466 Ok(tree) => tree,
467 Err(tree) => {
468 return TransitionResult::Failure {
469 message: format!(
470 "Node insertion error on line {}. Computer says no...",
471 line_cursor.sum_total()
472 ),
473 doctree: tree,
474 }
475 }
476 };
477
478 let (doctree, offset, state_stack) = match Parser::parse_first_node_block(doctree, src_lines, base_indent, line_cursor, detected_body_indent, Some(indent_after_marker), State::Citation, section_level,false) {
479 Ok((parsing_result, offset)) => if let ParsingResult::EOF { doctree, state_stack } | ParsingResult::EmptyStateStack { doctree, state_stack } = parsing_result {
480 (doctree, offset, state_stack)
481 } else {
482 unreachable!(
483 "Returned from a nested parsing session on line {} without necessary information. Computer says no...",
484 line_cursor.sum_total()
485 )
486 },
487 Err(ParsingResult::Failure { message, doctree }) => return TransitionResult::Failure {
488 message: format!(
489 "Looks like citation on line {} has no content. Computer says no...",
490 line_cursor.sum_total()
491 ),
492 doctree: doctree
493 },
494 _ => unreachable!("Parsing first node block on line {} resulted in unknown combination of return values. Computer says no...", line_cursor.sum_total())
495 };
496
497 return TransitionResult::Success {
498 doctree: doctree,
499 push_or_pop: PushOrPop::Push(state_stack),
500 line_advance: LineAdvance::Some(offset),
501 };
502 }
503 IndentationMatch::TooMuch => {
504 doctree = match doctree.push_data_and_focus(
505 TreeNodeType::BlockQuote {
506 body_indent: detected_marker_indent,
507 }
508 ) {
509 Ok(tree) => tree,
510 Err(tree) => {
511 return TransitionResult::Failure {
512 message: format!(
513 "Node insertion error on line {}. Computer says no...",
514 line_cursor.sum_total()
515 ),
516 doctree: tree,
517 }
518 }
519 };
520 return TransitionResult::Success {
521 doctree: doctree,
522 push_or_pop: PushOrPop::Push(vec![State::BlockQuote]),
523 line_advance: LineAdvance::None,
524 };
525 }
526 _ => {
527 return TransitionResult::Success {
528 doctree: doctree.focus_on_parent(),
529 push_or_pop: PushOrPop::Pop,
530 line_advance: LineAdvance::None,
531 };
532 }
533 }
534}
535
536pub fn hyperlink_target(
538 src_lines: &Vec<String>,
539 base_indent: usize,
540 section_level: &mut usize,
541 line_cursor: &mut LineCursor,
542 mut doctree: DocTree,
543 captures: ®ex::Captures,
544 pattern_name: &Pattern,
545) -> TransitionResult {
546
547
548
549 let detected_marker_indent = captures.get(1).unwrap().as_str().chars().count();
551 let detected_text_indent = captures.get(0).unwrap().as_str().chars().count();
552 let detected_target_label = captures.get(2).unwrap().as_str();
553
554 let label_as_string = if detected_target_label == "_" {
556 doctree.next_anon_target_label()
557 } else {
558 crate::common::normalize_refname(detected_target_label)
559 };
560
561 let detected_body_indent = if let Some(line) = src_lines.get(line_cursor.relative_offset() + 1)
562 {
563 if line.trim().is_empty() {
564 detected_text_indent
565 } else {
566 let indent = line.chars().take_while(|c| c.is_whitespace()).count() + base_indent;
567 if indent < detected_marker_indent + 3 {
568 detected_text_indent
569 } else {
570 indent
571 }
572 }
573 } else {
574 detected_text_indent
575 };
576
577 match Parser::parent_indent_matches(doctree.shared_node_data(), detected_marker_indent) {
578
579 IndentationMatch::JustRight => {
580 let (block_string, offset): (String, usize) = match Parser::read_indented_block(
583 src_lines,
584 line_cursor.relative_offset(),
585 true,
586 true,
587 Some(detected_body_indent),
588 Some(detected_text_indent),
589 false,
590 ) {
591 IndentedBlockResult::Ok {lines, minimum_indent, offset, blank_finish } => (
592 lines
593 .join("\n")
594 .chars()
595 .filter(|c| !c.is_whitespace())
596 .collect(),
597 offset,
598 ),
599 _ => {
600 return TransitionResult::Failure {
601 message: format!(
602 "Error when reading indented text block on line {}.",
603 line_cursor.sum_total()
604 ),
605 doctree: doctree,
606 }
607 }
608 };
609
610 if block_string.is_empty() {
616 doctree.push_to_internal_target_stack(label_as_string);
623
624 return TransitionResult::Success {
625 doctree: doctree,
626 push_or_pop: PushOrPop::Neither,
627 line_advance: LineAdvance::Some(1), };
629 }
630
631 let node_type: TreeNodeType = match Parser::inline_parse(block_string, Some(&mut doctree), line_cursor) {
632
633 InlineParsingResult::Nodes(nodes_data) => {
634
635 if nodes_data.len() != 1 {
636 return TransitionResult::Failure {
637 message: format!("Hyperlink targets should only contain a single node. Computer says no on line {}...", line_cursor.sum_total()),
638 doctree: doctree
639 }
640 }
641 match nodes_data.get(0) {
642 Some(TreeNodeType::Reference { reference, displayed_text }) => {
643
644 use crate::common::Reference;
645
646 match reference {
647 Reference::Internal (ref_str) => TreeNodeType::IndirectHyperlinkTarget {
648 target: label_as_string,
649 indirect_target: match reference {
650 Reference::Internal(ref_str) => ref_str.to_string(),
651 Reference::URI(ref_str) | Reference::EMail(ref_str) => return TransitionResult::Failure {
652 message: format!("Wrong type of inline node when parsing an indirect target {} on line {}. Computer says no...", ref_str, line_cursor.sum_total()),
653 doctree: doctree
654 },
655 },
656 marker_indent: detected_marker_indent
657 },
658 Reference::URI (ref_str) => TreeNodeType::ExternalHyperlinkTarget {
659 marker_indent: detected_marker_indent,
660 target: label_as_string,
661 uri: ref_str.to_owned()
662 },
663 Reference::EMail (ref_str) => TreeNodeType::ExternalHyperlinkTarget {
664 marker_indent: detected_marker_indent,
665 target: label_as_string,
666 uri: ref_str.to_owned()
667 }
668 }
669 }
670 _ => return TransitionResult::Failure {
671 message: format!("Hyperlink target on line {} didn't match any known types. Computer says no...", line_cursor.sum_total()),
672 doctree: doctree
673 }
674 }
675 }
676
677 _ => panic!("Inline parser failed when parsing a hyperlink target on line {} .Computer says no...", line_cursor.sum_total())
678
679 };
680
681 let node = TreeNode::new(node_type, doctree.node_count(), None, None);
682
683 match doctree.push_child(node) {
684 Ok(()) => {}
685 Err(node) => {
686 return TransitionResult::Failure {
687 message: format!(
688 "Node insertion error on line {}. Computer says no...",
689 line_cursor.sum_total()
690 ),
691 doctree: doctree,
692 }
693 }
694 };
695
696 return TransitionResult::Success {
697 doctree: doctree,
698 push_or_pop: PushOrPop::Neither,
699 line_advance: LineAdvance::Some(1),
700 };
701 }
702
703 IndentationMatch::TooMuch => {
704 doctree = match doctree.push_data_and_focus(
705 TreeNodeType::BlockQuote {
706 body_indent: detected_marker_indent,
707 }
708 ) {
709 Ok(tree) => tree,
710 Err(tree) => {
711 return TransitionResult::Failure {
712 message: format!(
713 "Node insertion error on line {}. Computer says no...",
714 line_cursor.sum_total()
715 ),
716 doctree: tree,
717 }
718 }
719 };
720 return TransitionResult::Success {
721 doctree: doctree,
722 push_or_pop: PushOrPop::Push(vec![State::BlockQuote]),
723 line_advance: LineAdvance::None,
724 };
725 }
726 _ => {
727 return TransitionResult::Success {
728 doctree: doctree.focus_on_parent(),
729 push_or_pop: PushOrPop::Pop,
730 line_advance: LineAdvance::None,
731 };
732 }
733 }
734}
735
736pub fn directive(
738 src_lines: &Vec<String>,
739 base_indent: usize,
740 section_level: &mut usize,
741 line_cursor: &mut LineCursor,
742 mut doctree: DocTree,
743 captures: ®ex::Captures,
744 pattern_name: &Pattern,
745) -> TransitionResult {
746
747
748 let detected_marker_indent = captures.get(1).unwrap().as_str().chars().count() + base_indent;
749 let detected_directive_label = captures
750 .get(2)
751 .unwrap()
752 .as_str()
753 .to_lowercase()
754 .split_whitespace()
755 .collect::<String>()
756 .to_lowercase();
757 let detected_first_indent = captures.get(0).unwrap().as_str().chars().count();
758
759 let empty_after_marker: bool = {
760 let line = src_lines.get(line_cursor.relative_offset()).unwrap(); match line.char_indices().nth(detected_first_indent) {
763 Some((index, _)) => line[index..].trim().is_empty(),
764 None => true,
765 }
766 };
767
768 let (body_indent, body_offset) =
769 match Parser::indent_on_subsequent_lines(src_lines, line_cursor.relative_offset()) {
770 Some((indent, offset)) => (indent, offset),
771 None => (detected_first_indent, 0), };
773
774 match Parser::parent_indent_matches(doctree.shared_node_data(), detected_marker_indent) {
775 IndentationMatch::JustRight => {
776 match detected_directive_label.as_str() {
777 "attention" | "caution" | "danger" | "error" | "hint" | "important" | "note"
778 | "tip" | "warning" => directive_parsers::parse_standard_admonition(
779 src_lines,
780 body_indent,
781 *section_level,
782 detected_first_indent,
783 doctree,
784 line_cursor,
785 detected_directive_label.as_str(),
786 empty_after_marker,
787 ),
788
789 "admonition" => directive_parsers::parse_generic_admonition(
790 src_lines,
791 doctree,
792 line_cursor,
793 empty_after_marker,
794 body_indent,
795 Some(detected_first_indent),
796 ),
797
798 "image" => directive_parsers::parse_image(
799 src_lines,
800 doctree,
801 line_cursor,
802 empty_after_marker,
803 body_indent,
804 Some(detected_first_indent),
805 ),
806
807 "figure" => directive_parsers::parse_figure(
808 src_lines,
809 doctree,
810 line_cursor,
811 base_indent,
812 empty_after_marker,
813 body_indent,
814 Some(detected_first_indent),
815 *section_level,
816 ),
817
818 "topic" => directive_parsers::parse_unknown_directive(
819 doctree,
820 src_lines,
821 line_cursor,
822 detected_directive_label.as_str(),
823 detected_first_indent,
824 body_indent,
825 empty_after_marker,
826 ),
827
828 "sidebar" => directive_parsers::parse_unknown_directive(
829 doctree,
830 src_lines,
831 line_cursor,
832 detected_directive_label.as_str(),
833 detected_first_indent,
834 body_indent,
835 empty_after_marker,
836 ),
837
838 "line-block" => directive_parsers::parse_unknown_directive(
839 doctree,
840 src_lines,
841 line_cursor,
842 detected_directive_label.as_str(),
843 detected_first_indent,
844 body_indent,
845 empty_after_marker,
846 ),
847
848 "parsed-literal" => directive_parsers::parse_unknown_directive(
849 doctree,
850 src_lines,
851 line_cursor,
852 detected_directive_label.as_str(),
853 detected_first_indent,
854 body_indent,
855 empty_after_marker,
856 ),
857
858 "code" => directive_parsers::parse_code(
859 src_lines,
860 doctree,
861 line_cursor,
862 base_indent,
863 empty_after_marker,
864 body_indent,
865 Some(detected_first_indent),
866 *section_level,
867 ),
868
869 "math" => directive_parsers::parse_math_block(
870 src_lines,
871 doctree,
872 line_cursor,
873 body_indent,
874 empty_after_marker,
875 detected_first_indent
876 ),
877
878 "rubric" => directive_parsers::parse_unknown_directive(
879 doctree,
880 src_lines,
881 line_cursor,
882 detected_directive_label.as_str(),
883 detected_first_indent,
884 body_indent,
885 empty_after_marker,
886 ),
887
888 "epigraph" => directive_parsers::parse_unknown_directive(
889 doctree,
890 src_lines,
891 line_cursor,
892 detected_directive_label.as_str(),
893 detected_first_indent,
894 body_indent,
895 empty_after_marker,
896 ),
897
898 "highlights" => directive_parsers::parse_unknown_directive(
899 doctree,
900 src_lines,
901 line_cursor,
902 detected_directive_label.as_str(),
903 detected_first_indent,
904 body_indent,
905 empty_after_marker,
906 ),
907
908 "pull-quote" => directive_parsers::parse_unknown_directive(
909 doctree,
910 src_lines,
911 line_cursor,
912 detected_directive_label.as_str(),
913 detected_first_indent,
914 body_indent,
915 empty_after_marker,
916 ),
917
918 "compound" => directive_parsers::parse_unknown_directive(
919 doctree,
920 src_lines,
921 line_cursor,
922 detected_directive_label.as_str(),
923 detected_first_indent,
924 body_indent,
925 empty_after_marker,
926 ),
927
928 "container" => directive_parsers::parse_unknown_directive(
929 doctree,
930 src_lines,
931 line_cursor,
932 detected_directive_label.as_str(),
933 detected_first_indent,
934 body_indent,
935 empty_after_marker,
936 ),
937
938 "table" => directive_parsers::parse_unknown_directive(
939 doctree,
940 src_lines,
941 line_cursor,
942 detected_directive_label.as_str(),
943 detected_first_indent,
944 body_indent,
945 empty_after_marker,
946 ),
947
948 "csv-table" => directive_parsers::parse_unknown_directive(
949 doctree,
950 src_lines,
951 line_cursor,
952 detected_directive_label.as_str(),
953 detected_first_indent,
954 body_indent,
955 empty_after_marker,
956 ),
957
958 "list-table" => directive_parsers::parse_list_table(
959 src_lines,
960 doctree,
961 line_cursor,
962 base_indent,
963 empty_after_marker,
964 Some(detected_first_indent),
965 body_indent,
966 *section_level,
967 ),
968
969 "contents" => directive_parsers::parse_unknown_directive(
971 doctree,
972 src_lines,
973 line_cursor,
974 detected_directive_label.as_str(),
975 detected_first_indent,
976 body_indent,
977 empty_after_marker,
978 ),
979
980 "sectnum" | "section-numbering" => directive_parsers::parse_unknown_directive(
981 doctree,
982 src_lines,
983 line_cursor,
984 detected_directive_label.as_str(),
985 detected_first_indent,
986 body_indent,
987 empty_after_marker,
988 ),
989
990 "header" => directive_parsers::parse_unknown_directive(
991 doctree,
992 src_lines,
993 line_cursor,
994 detected_directive_label.as_str(),
995 detected_first_indent,
996 body_indent,
997 empty_after_marker,
998 ),
999
1000 "footer" => directive_parsers::parse_unknown_directive(
1001 doctree,
1002 src_lines,
1003 line_cursor,
1004 detected_directive_label.as_str(),
1005 detected_first_indent,
1006 body_indent,
1007 empty_after_marker,
1008 ),
1009
1010 "target-notes" => directive_parsers::parse_unknown_directive(
1011 doctree,
1012 src_lines,
1013 line_cursor,
1014 detected_directive_label.as_str(),
1015 detected_first_indent,
1016 body_indent,
1017 empty_after_marker,
1018 ),
1019
1020 "footnotes" => {
1021 unimplemented!("Footnotes (plural) directive is mentioned in the rST specification but is not implemented yet.")
1022 }
1023
1024 "citations" => {
1025 unimplemented!("Citations (plural) directive is mentioned in the rST specification but is not implemented yet.")
1026 }
1027
1028 "meta" => directive_parsers::parse_unknown_directive(
1029 doctree,
1030 src_lines,
1031 line_cursor,
1032 detected_directive_label.as_str(),
1033 detected_first_indent,
1034 body_indent,
1035 empty_after_marker,
1036 ),
1037
1038 "include" => directive_parsers::parse_unknown_directive(
1040 doctree,
1041 src_lines,
1042 line_cursor,
1043 detected_directive_label.as_str(),
1044 detected_first_indent,
1045 body_indent,
1046 empty_after_marker,
1047 ),
1048
1049 "raw" => directive_parsers::parse_unknown_directive(
1050 doctree,
1051 src_lines,
1052 line_cursor,
1053 detected_directive_label.as_str(),
1054 detected_first_indent,
1055 body_indent,
1056 empty_after_marker,
1057 ),
1058
1059 "class" => directive_parsers::parse_class(
1060 src_lines,
1061 doctree,
1062 line_cursor,
1063 detected_first_indent,
1064 body_indent,
1065 empty_after_marker,
1066 *section_level,
1067 ),
1068
1069 "role" => directive_parsers::parse_unknown_directive(
1070 doctree,
1071 src_lines,
1072 line_cursor,
1073 detected_directive_label.as_str(),
1074 detected_first_indent,
1075 body_indent,
1076 empty_after_marker,
1077 ),
1078
1079 "default-role" => directive_parsers::parse_unknown_directive(
1080 doctree,
1081 src_lines,
1082 line_cursor,
1083 detected_directive_label.as_str(),
1084 detected_first_indent,
1085 body_indent,
1086 empty_after_marker,
1087 ),
1088
1089 "title" => directive_parsers::parse_unknown_directive(
1090 doctree,
1091 src_lines,
1092 line_cursor,
1093 detected_directive_label.as_str(),
1094 detected_first_indent,
1095 body_indent,
1096 empty_after_marker,
1097 ),
1098
1099 "restructuredtext-test-directive" => directive_parsers::parse_unknown_directive(
1100 doctree,
1101 src_lines,
1102 line_cursor,
1103 detected_directive_label.as_str(),
1104 detected_first_indent,
1105 body_indent,
1106 empty_after_marker,
1107 ),
1108
1109 "toctree" => directive_parsers::parse_unknown_directive(
1111 doctree,
1112 src_lines,
1113 line_cursor,
1114 detected_directive_label.as_str(),
1115 detected_first_indent,
1116 body_indent,
1117 empty_after_marker,
1118 ),
1119
1120 "versionadded" => directive_parsers::parse_unknown_directive(
1121 doctree,
1122 src_lines,
1123 line_cursor,
1124 detected_directive_label.as_str(),
1125 detected_first_indent,
1126 body_indent,
1127 empty_after_marker,
1128 ),
1129
1130 "versionchanged" => directive_parsers::parse_unknown_directive(
1131 doctree,
1132 src_lines,
1133 line_cursor,
1134 detected_directive_label.as_str(),
1135 detected_first_indent,
1136 body_indent,
1137 empty_after_marker,
1138 ),
1139
1140 "deprecated" => directive_parsers::parse_unknown_directive(
1141 doctree,
1142 src_lines,
1143 line_cursor,
1144 detected_directive_label.as_str(),
1145 detected_first_indent,
1146 body_indent,
1147 empty_after_marker,
1148 ),
1149
1150 "seealso" => directive_parsers::parse_unknown_directive(
1151 doctree,
1152 src_lines,
1153 line_cursor,
1154 detected_directive_label.as_str(),
1155 detected_first_indent,
1156 body_indent,
1157 empty_after_marker,
1158 ),
1159
1160 "centered" => directive_parsers::parse_unknown_directive(
1161 doctree,
1162 src_lines,
1163 line_cursor,
1164 detected_directive_label.as_str(),
1165 detected_first_indent,
1166 body_indent,
1167 empty_after_marker,
1168 ),
1169
1170 "hlist" => directive_parsers::parse_unknown_directive(
1171 doctree,
1172 src_lines,
1173 line_cursor,
1174 detected_directive_label.as_str(),
1175 detected_first_indent,
1176 body_indent,
1177 empty_after_marker,
1178 ),
1179
1180 "highlight" => directive_parsers::parse_unknown_directive(
1181 doctree,
1182 src_lines,
1183 line_cursor,
1184 detected_directive_label.as_str(),
1185 detected_first_indent,
1186 body_indent,
1187 empty_after_marker,
1188 ),
1189
1190 "code-block" | "sourcecode" => directive_parsers::parse_sphinx_code_block(
1191 src_lines,
1192 doctree,
1193 line_cursor,
1194 base_indent,
1195 empty_after_marker,
1196 body_indent,
1197 Some(detected_first_indent),
1198 ),
1199
1200 "literalinclude" => directive_parsers::parse_unknown_directive(
1201 doctree,
1202 src_lines,
1203 line_cursor,
1204 detected_directive_label.as_str(),
1205 detected_first_indent,
1206 body_indent,
1207 empty_after_marker,
1208 ),
1209
1210 "glossary" => directive_parsers::parse_unknown_directive(
1211 doctree,
1212 src_lines,
1213 line_cursor,
1214 detected_directive_label.as_str(),
1215 detected_first_indent,
1216 body_indent,
1217 empty_after_marker,
1218 ),
1219
1220 "sectionauthor" => directive_parsers::parse_unknown_directive(
1221 doctree,
1222 src_lines,
1223 line_cursor,
1224 detected_directive_label.as_str(),
1225 detected_first_indent,
1226 body_indent,
1227 empty_after_marker,
1228 ),
1229
1230 "codeauthor" => directive_parsers::parse_unknown_directive(
1231 doctree,
1232 src_lines,
1233 line_cursor,
1234 detected_directive_label.as_str(),
1235 detected_first_indent,
1236 body_indent,
1237 empty_after_marker,
1238 ),
1239
1240 "index" => directive_parsers::parse_unknown_directive(
1241 doctree,
1242 src_lines,
1243 line_cursor,
1244 detected_directive_label.as_str(),
1245 detected_first_indent,
1246 body_indent,
1247 empty_after_marker,
1248 ),
1249
1250 "only" => directive_parsers::parse_sphinx_only(
1251 src_lines,
1252 doctree,
1253 line_cursor,
1254 empty_after_marker,
1255 detected_first_indent,
1256 body_indent,
1257 ),
1258
1259 "tabularcolumns" => directive_parsers::parse_unknown_directive(
1260 doctree,
1261 src_lines,
1262 line_cursor,
1263 detected_directive_label.as_str(),
1264 detected_first_indent,
1265 body_indent,
1266 empty_after_marker,
1267 ),
1268
1269 "productionlist" => directive_parsers::parse_unknown_directive(
1270 doctree,
1271 src_lines,
1272 line_cursor,
1273 detected_directive_label.as_str(),
1274 detected_first_indent,
1275 body_indent,
1276 empty_after_marker,
1277 ),
1278
1279 "questionnaire" => directive_parsers::parse_aplus_questionnaire(
1281 src_lines,
1282 doctree,
1283 line_cursor,
1284 base_indent,
1285 empty_after_marker,
1286 detected_first_indent,
1287 body_indent,
1288 ),
1289
1290 "submit" => directive_parsers::parse_aplus_submit(
1291 src_lines,
1292 doctree,
1293 line_cursor,
1294 detected_first_indent,
1295 body_indent,
1296 empty_after_marker,
1297 ),
1298
1299 "ae-input" => directive_parsers::parse_aplus_active_element_input(
1300 src_lines,
1301 doctree,
1302 line_cursor,
1303 base_indent,
1304 empty_after_marker,
1305 detected_first_indent,
1306 body_indent,
1307 ),
1308
1309 "ae-output" => directive_parsers::parse_aplus_active_element_output(
1310 src_lines,
1311 doctree,
1312 line_cursor,
1313 base_indent,
1314 empty_after_marker,
1315 detected_first_indent,
1316 body_indent,
1317 ),
1318
1319 "hidden_block" => directive_parsers::parse_unknown_directive(
1320 doctree,
1321 src_lines,
1322 line_cursor,
1323 detected_directive_label.as_str(),
1324 detected_first_indent,
1325 body_indent,
1326 empty_after_marker,
1327 ),
1328
1329 "point-of-interest" => directive_parsers::parse_aplus_point_of_interest(
1330 src_lines,
1331 doctree,
1332 line_cursor,
1333 base_indent,
1334 empty_after_marker,
1335 detected_first_indent,
1336 body_indent,
1337 *section_level,
1338 ),
1339
1340 "annotated" => directive_parsers::parse_unknown_directive(
1341 doctree,
1342 src_lines,
1343 line_cursor,
1344 detected_directive_label.as_str(),
1345 detected_first_indent,
1346 body_indent,
1347 empty_after_marker,
1348 ),
1349
1350 "lineref-code-block" => directive_parsers::parse_unknown_directive(
1351 doctree,
1352 src_lines,
1353 line_cursor,
1354 detected_directive_label.as_str(),
1355 detected_first_indent,
1356 body_indent,
1357 empty_after_marker,
1358 ),
1359
1360 "repl-res-count-reset" => directive_parsers::parse_unknown_directive(
1361 doctree,
1362 src_lines,
1363 line_cursor,
1364 detected_directive_label.as_str(),
1365 detected_first_indent,
1366 body_indent,
1367 empty_after_marker,
1368 ),
1369
1370 "acos-submit" => directive_parsers::parse_unknown_directive(
1371 doctree,
1372 src_lines,
1373 line_cursor,
1374 detected_directive_label.as_str(),
1375 detected_first_indent,
1376 body_indent,
1377 empty_after_marker,
1378 ),
1379
1380 "div" => directive_parsers::parse_unknown_directive(
1381 doctree,
1382 src_lines,
1383 line_cursor,
1384 detected_directive_label.as_str(),
1385 detected_first_indent,
1386 body_indent,
1387 empty_after_marker,
1388 ),
1389
1390 "styled-topic" => directive_parsers::parse_unknown_directive(
1391 doctree,
1392 src_lines,
1393 line_cursor,
1394 detected_directive_label.as_str(),
1395 detected_first_indent,
1396 body_indent,
1397 empty_after_marker,
1398 ),
1399
1400 "story" => directive_parsers::parse_unknown_directive(
1402 doctree,
1403 src_lines,
1404 line_cursor,
1405 detected_directive_label.as_str(),
1406 detected_first_indent,
1407 body_indent,
1408 empty_after_marker,
1409 ),
1410
1411 "jsvee" => directive_parsers::parse_unknown_directive(
1412 doctree,
1413 src_lines,
1414 line_cursor,
1415 detected_directive_label.as_str(),
1416 detected_first_indent,
1417 body_indent,
1418 empty_after_marker,
1419 ),
1420
1421 "youtube" => directive_parsers::parse_unknown_directive(
1422 doctree,
1423 src_lines,
1424 line_cursor,
1425 detected_directive_label.as_str(),
1426 detected_first_indent,
1427 body_indent,
1428 empty_after_marker,
1429 ),
1430
1431 "local-video" => directive_parsers::parse_unknown_directive(
1432 doctree,
1433 src_lines,
1434 line_cursor,
1435 detected_directive_label.as_str(),
1436 detected_first_indent,
1437 body_indent,
1438 empty_after_marker,
1439 ),
1440
1441 "embedded-page" => directive_parsers::parse_unknown_directive(
1442 doctree,
1443 src_lines,
1444 line_cursor,
1445 detected_directive_label.as_str(),
1446 detected_first_indent,
1447 body_indent,
1448 empty_after_marker,
1449 ),
1450
1451 _ => directive_parsers::parse_unknown_directive(
1452 doctree,
1453 src_lines,
1454 line_cursor,
1455 detected_directive_label.as_str(),
1456 detected_first_indent,
1457 body_indent,
1458 empty_after_marker,
1459 ),
1460 }
1461 }
1462 IndentationMatch::TooMuch => {
1463 doctree = match doctree.push_data_and_focus(
1464 TreeNodeType::BlockQuote {
1465 body_indent: detected_marker_indent,
1466 }
1467 ) {
1468 Ok(tree) => tree,
1469 Err(tree) => {
1470 return TransitionResult::Failure {
1471 message: format!(
1472 "Node insertion error on line {}. Computer says no...",
1473 line_cursor.sum_total()
1474 ),
1475 doctree: tree,
1476 }
1477 }
1478 };
1479 return TransitionResult::Success {
1480 doctree: doctree,
1481 push_or_pop: PushOrPop::Push(vec![State::BlockQuote]),
1482 line_advance: LineAdvance::None,
1483 };
1484 }
1485 _ => {
1486 return TransitionResult::Success {
1487 doctree: doctree.focus_on_parent(),
1488 push_or_pop: PushOrPop::Pop,
1489 line_advance: LineAdvance::None,
1490 };
1491 }
1492 }
1493}
1494
1495pub fn comment(
1497 src_lines: &Vec<String>,
1498 base_indent: usize,
1499 section_level: &mut usize,
1500 line_cursor: &mut LineCursor,
1501 mut doctree: DocTree,
1502 captures: ®ex::Captures,
1503 pattern_name: &Pattern,
1504) -> TransitionResult {
1505
1506
1507 let match_len = captures.get(0).unwrap().as_str().chars().count() + base_indent;
1508 let detected_marker_indent = captures.get(1).unwrap().as_str().chars().count() + base_indent;
1509 let next_line_indent = if let Some(line) = src_lines.get(line_cursor.relative_offset() + 1) {
1510 if line.trim().is_empty() {
1511 match_len
1512 } else {
1513 let indent = line.chars().take_while(|c| c.is_whitespace()).count() + base_indent;
1514 if indent < detected_marker_indent + 1 {
1515 match_len
1516 } else {
1517 indent
1518 }
1519 }
1520 } else {
1521 match_len
1522 };
1523
1524 match Parser::parent_indent_matches(doctree.shared_node_data(), detected_marker_indent) {
1525 IndentationMatch::JustRight => {
1526 let (comment_string, offset) = match Parser::read_indented_block(
1527 src_lines,
1528 line_cursor.relative_offset(),
1529 false,
1530 true,
1531 Some(next_line_indent - base_indent),
1532 Some(match_len - base_indent),
1533 false,
1534 ) {
1535 IndentedBlockResult::Ok {lines, minimum_indent, offset, blank_finish } => (lines.join("\n").trim().to_string(), offset),
1536 _ => {
1537 return TransitionResult::Failure {
1538 message: format!(
1539 "Could not read comment on line {}.",
1540 line_cursor.sum_total(),
1541 ),
1542 doctree: doctree,
1543 }
1544 }
1545 };
1546
1547 let comment_data = if comment_string.is_empty() {
1548 TreeNodeType::Comment { text: None }
1549 } else {
1550 TreeNodeType::Comment {
1551 text: Some(comment_string),
1552 }
1553 };
1554
1555 return TransitionResult::Success {
1556 doctree: match doctree.push_data(comment_data) {
1557 Ok(doctree) => doctree,
1558 Err(doctree) => {
1559 return TransitionResult::Failure {
1560 message: format!(
1561 "Error when reading comment on line {}. Computer says no...",
1562 line_cursor.sum_total()
1563 ),
1564 doctree: doctree,
1565 }
1566 }
1567 },
1568 push_or_pop: PushOrPop::Neither,
1569 line_advance: LineAdvance::Some(offset),
1570 };
1571 }
1572 IndentationMatch::TooMuch => {
1573 doctree = match doctree.push_data_and_focus(
1574 TreeNodeType::BlockQuote {
1575 body_indent: detected_marker_indent,
1576 }
1577 ) {
1578 Ok(tree) => tree,
1579 Err(tree) => {
1580 return TransitionResult::Failure {
1581 message: format!(
1582 "Node insertion error on line {}. Computer says no...",
1583 line_cursor.sum_total()
1584 ),
1585 doctree: tree,
1586 }
1587 }
1588 };
1589 return TransitionResult::Success {
1590 doctree: doctree,
1591 push_or_pop: PushOrPop::Push(vec![State::BlockQuote]),
1592 line_advance: LineAdvance::None,
1593 };
1594 }
1595 _ => {
1596 return TransitionResult::Success {
1597 doctree: doctree.focus_on_parent(),
1598 push_or_pop: PushOrPop::Pop,
1599 line_advance: LineAdvance::None,
1600 };
1601 }
1602 }
1603}
1604
1605pub fn text(
1609 src_lines: &Vec<String>,
1610 base_indent: usize,
1611 section_level: &mut usize,
1612 line_cursor: &mut LineCursor,
1613 mut doctree: DocTree,
1614 captures: ®ex::Captures,
1615 pattern_name: &Pattern,
1616) -> TransitionResult {
1617
1618 let detected_indent = captures.get(1).unwrap().as_str().chars().count() + base_indent;
1619
1620 let next_line = src_lines.get(line_cursor.relative_offset() + 1);
1621
1622 if next_line.is_some() {
1623 let next_line_str = next_line.unwrap();
1624
1625 if let Some(line_capts) = crate::parser::automata::LINE_AUTOMATON.captures(next_line_str) {
1626 if detected_indent > 0 {
1628 return TransitionResult::Failure {
1629 message: format!(
1630 "Found indented underlined section on line {}. Computer says no...",
1631 line_cursor.sum_total()
1632 ),
1633 doctree: doctree,
1634 };
1635 }
1636
1637 let line_char = next_line_str.chars().next().unwrap();
1638 let section_style = SectionLineStyle::Under(line_char);
1639 let title_text = src_lines.get(line_cursor.relative_offset()).unwrap().trim();
1640 let section_data = doctree.new_section_data(title_text, section_style);
1641
1642 if let TreeNodeType::Section { level, .. } = section_data {
1643 let detected_level = level;
1644
1645 match doctree.shared_data() {
1646 TreeNodeType::Document { .. } => {
1647 doctree = match doctree.push_data_and_focus(section_data) {
1648 Ok(tree) => tree,
1649 Err(tree) => {
1650 return TransitionResult::Failure {
1651 message: format!(
1652 "Node insertion error on line {}. Computer says no...",
1653 line_cursor.sum_total()
1654 ),
1655 doctree: tree,
1656 }
1657 }
1658 };
1659 *section_level = detected_level;
1660 }
1661
1662 TreeNodeType::Section { level, .. } => {
1663 if detected_level <= *level {
1664 *section_level = *level;
1665 doctree = doctree.focus_on_parent();
1666 return TransitionResult::Success {
1667 doctree: doctree,
1668 push_or_pop: PushOrPop::Pop,
1669 line_advance: LineAdvance::None,
1670 };
1671 } else {
1672 *section_level = detected_level;
1673 doctree =
1674 match doctree.push_data_and_focus(section_data) {
1675 Ok(tree) => tree,
1676 Err(tree) => return TransitionResult::Failure {
1677 message: format!(
1678 "Node insertion error on line {}. Computer says no...",
1679 line_cursor.sum_total()
1680 ),
1681 doctree: tree,
1682 },
1683 };
1684 }
1685 }
1686
1687 _ => {
1688 doctree = doctree.focus_on_parent();
1689
1690 if let TreeNodeType::Section { level, .. } = doctree.shared_data() {
1691 *section_level = *level;
1692 }
1693
1694 return TransitionResult::Success {
1695 doctree: doctree,
1696 push_or_pop: PushOrPop::Pop,
1697 line_advance: LineAdvance::None,
1698 };
1699 }
1700 }
1701 return TransitionResult::Success {
1702 doctree: doctree,
1703 push_or_pop: PushOrPop::Push(vec![State::Section]),
1704 line_advance: LineAdvance::Some(2), };
1706 }
1707 }
1708
1709 if let Some(text_capts) = crate::parser::automata::TEXT_AUTOMATON.captures(next_line_str) {
1710 let next_line_indent =
1713 text_capts.get(1).unwrap().as_str().chars().count() + base_indent;
1714
1715 if next_line_indent == detected_indent {
1716 return parse_paragraph(
1719 src_lines,
1720 base_indent,
1721 line_cursor,
1722 doctree,
1723 detected_indent,
1724 );
1725 } else if next_line_indent > detected_indent {
1726 match Parser::parent_indent_matches(doctree.shared_data(), detected_indent) {
1729 IndentationMatch::JustRight => {
1730 doctree = match doctree.push_data_and_focus(TreeNodeType::DefinitionList {
1731 term_indent: detected_indent,
1732 }) {
1733 Ok(tree) => tree,
1734 Err(tree) => {
1735 return TransitionResult::Failure {
1736 message: format!(
1737 "Node insertion error on line {}. Computer says no...",
1738 line_cursor.sum_total()
1739 ),
1740 doctree: tree,
1741 }
1742 }
1743 };
1744
1745 return TransitionResult::Success {
1746 doctree: doctree,
1747 push_or_pop: PushOrPop::Push(vec![State::DefinitionList]),
1748 line_advance: LineAdvance::None,
1749 };
1750 }
1751 IndentationMatch::TooMuch => {
1752 doctree = match doctree.push_data_and_focus(
1753 TreeNodeType::BlockQuote {
1754 body_indent: detected_indent,
1755 }
1756 ) {
1757 Ok(tree) => tree,
1758 Err(tree) => {
1759 return TransitionResult::Failure {
1760 message: format!(
1761 "Node insertion error on line {}. Computer says no...",
1762 line_cursor.sum_total()
1763 ),
1764 doctree: tree,
1765 }
1766 }
1767 };
1768 return TransitionResult::Success {
1769 doctree: doctree,
1770 push_or_pop: PushOrPop::Push(vec![State::BlockQuote]),
1771 line_advance: LineAdvance::None,
1772 };
1773 }
1774 _ => {
1775 return TransitionResult::Success {
1776 doctree: doctree.focus_on_parent(),
1777 push_or_pop: PushOrPop::Pop,
1778 line_advance: LineAdvance::None,
1779 };
1780 }
1781 }
1782 } else {
1783 return parse_paragraph(
1786 src_lines,
1787 base_indent,
1788 line_cursor,
1789 doctree,
1790 detected_indent,
1791 );
1792 }
1793 } else {
1794 return parse_paragraph(
1795 src_lines,
1796 base_indent,
1797 line_cursor,
1798 doctree,
1799 detected_indent,
1800 );
1801 }
1802 } else {
1803 return parse_paragraph(
1805 src_lines,
1806 base_indent,
1807 line_cursor,
1808 doctree,
1809 detected_indent,
1810 );
1811 }
1812}
1813
1814pub fn line(
1816 src_lines: &Vec<String>,
1817 base_indent: usize,
1818 section_level: &mut usize,
1819 line_cursor: &mut LineCursor,
1820 mut doctree: DocTree,
1821 captures: ®ex::Captures,
1822 pattern_name: &Pattern,
1823) -> TransitionResult {
1824
1825
1826 const TRANSITION_LINE_LENGTH: usize = 4;
1829
1830 let detected_line = captures.get(1).unwrap().as_str();
1831 let detected_line_char = detected_line.chars().next().unwrap();
1832 let detected_line_length = detected_line.trim_end().chars().count();
1833
1834 let current_line = line_cursor.relative_offset();
1835
1836 let previous_line = if let Some(num) = usize::checked_sub(current_line, 1) {
1837 src_lines.get(current_line - 1)
1838 } else {
1839 None
1840 };
1841
1842 let next_line = if let Some(num) = usize::checked_add(current_line, 1) {
1843 src_lines.get(current_line + 1)
1844 } else {
1845 None
1846 };
1847
1848 let at_doc_root = if let TreeNodeType::Document { .. } = doctree.shared_node_data() {
1849 true
1850 } else {
1851 false
1852 };
1853 let at_input_start = previous_line.is_none();
1854 let at_input_end = next_line.is_none();
1855
1856 if at_input_end {
1857 return TransitionResult::Failure {
1858 message: format!("Discovered a transition or an incomplete section at the end of (nested) input on line {}. Computer says no...", line_cursor.sum_total()),
1859 doctree: doctree
1860 };
1861 }
1862
1863 match (previous_line, next_line) {
1864 (Some(p_line), Some(n_line)) => {
1865 if p_line.trim().is_empty()
1866 && n_line.trim().is_empty()
1867 && detected_line_length >= TRANSITION_LINE_LENGTH
1868 {
1869 doctree = match doctree.push_data(TreeNodeType::Transition) {
1872 Ok(tree) => tree,
1873 Err(tree) => return TransitionResult::Success {
1874 doctree: tree.focus_on_parent(),
1875 push_or_pop: PushOrPop::Pop,
1876 line_advance: LineAdvance::None
1877 }
1878 };
1879 return TransitionResult::Success {
1880 doctree: doctree,
1881 push_or_pop: PushOrPop::Neither,
1882 line_advance: LineAdvance::Some(2) }
1884 } else if crate::parser::automata::TEXT_AUTOMATON.is_match(n_line) {
1885 if let Some(next_next_line) = src_lines.get(line_cursor.relative_offset() + 2) {
1888 if let Some(capts) = crate::parser::automata::LINE_AUTOMATON.captures(next_next_line) {
1889 let next_line_len = n_line.trim_end().chars().count(); let next_next_line_char = next_next_line.trim_end().chars().next().unwrap();
1891 let next_next_line_len = next_next_line.trim_end().chars().count();
1892
1893 if detected_line_char == next_next_line_char
1894 && detected_line_length == next_next_line_len
1895 && next_line_len <= detected_line_length
1896 {
1897 let section_line_style = SectionLineStyle::OverAndUnder(detected_line_char);
1899 let section_data = doctree.new_section_data(n_line.trim(), section_line_style);
1900 if let TreeNodeType::Section { level, .. } = section_data {
1901 let detected_level = level;
1902 match doctree.shared_data() {
1903 TreeNodeType::Document { .. } => {
1904 doctree = match doctree.push_data_and_focus(section_data) {
1905 Ok(tree) => tree,
1906 Err(tree) => return TransitionResult::Failure {
1907 message: format!(
1908 "Node insertion error on line {}. Computer says no...",
1909 line_cursor.sum_total()
1910 ),
1911 doctree: tree
1912 }
1913 };
1914 *section_level = detected_level;
1915 }
1916 TreeNodeType::Section { level, .. } => {
1917 if detected_level <= *level {
1918 *section_level = *level;
1919 doctree = doctree.focus_on_parent();
1920 return TransitionResult::Success {
1921 doctree: doctree,
1922 push_or_pop: PushOrPop::Pop,
1923 line_advance: LineAdvance::None
1924 }
1925 } else {
1926 *section_level = detected_level;
1927 doctree = match doctree.push_data_and_focus(section_data) {
1928 Ok(tree) => tree,
1929 Err(tree) => return TransitionResult::Failure {
1930 message: format!("Node insertion error on line {}. Computer says no...", line_cursor.sum_total()),
1931 doctree: tree
1932 }
1933 };
1934 }
1935 }
1936 _ => {
1937 doctree = doctree.focus_on_parent();
1938 if let TreeNodeType::Section{level, .. } = doctree.shared_data() {
1939 *section_level = *level;
1940 }
1941 return TransitionResult::Success {
1942 doctree: doctree,
1943 push_or_pop: PushOrPop::Pop,
1944 line_advance: LineAdvance::None
1945 }
1946 }
1947 }
1948 return TransitionResult::Success {
1949 doctree: doctree,
1950 push_or_pop: PushOrPop::Push(vec![State::Section]),
1951 line_advance: LineAdvance::Some(3) }
1953 } else {
1954 return TransitionResult::Failure {
1955 message: format!("No generated section where one was expected on line {}. Computer says no...", line_cursor.sum_total()),
1956 doctree: doctree
1957 }
1958 }
1959 } else {
1960 return TransitionResult::Failure {
1961 message: format!("Found a section with unmatching over- and underline lengths or characters on line {}. Computer says no...", line_cursor.sum_total()),
1962 doctree: doctree
1963 }
1964 }
1965 } else {
1966 return TransitionResult::Failure {
1967 message: format!("Found section-like construct without underline on line {}. Computer says no...", line_cursor.sum_total()),
1968 doctree: doctree
1969 }
1970 }
1971 } else {
1972 return TransitionResult::Failure {
1973 message: format!("Found something akin to an section title but no underline at the end of input on line {}. Computer says no...", line_cursor.sum_total()),
1974 doctree: doctree
1975 }
1976 }
1977 } else if captures.get(0).unwrap().as_str().trim() == "::" {
1978 return parse_paragraph(src_lines, base_indent, line_cursor, doctree, 0)
1980 } else {
1981 return TransitionResult::Failure {
1982 message: format!("Unknown line construct on line {}. Computer says no...", line_cursor.sum_total()),
1983 doctree: doctree
1984 }
1985 }
1986 }
1987
1988 (None, Some(n_line)) => {
1989 if crate::parser::automata::TEXT_AUTOMATON.is_match(n_line) {
1990 if let Some(next_next_line) = src_lines.get(line_cursor.relative_offset() + 2) {
1993 if let Some(capts) = crate::parser::automata::LINE_AUTOMATON.captures(next_next_line) {
1994
1995 let next_line_len = n_line.trim_end().chars().count(); let next_next_line_char = next_next_line.trim_end().chars().next().unwrap();
1997 let next_next_line_len = next_next_line.trim_end().chars().count();
1998
1999 if detected_line_char == next_next_line_char
2000 && detected_line_length == next_next_line_len
2001 && next_line_len <= detected_line_length
2002 {
2003 let section_line_style = SectionLineStyle::OverAndUnder(detected_line_char);
2005 let section_data = doctree.new_section_data(n_line.trim(), section_line_style);
2006 if let TreeNodeType::Section { level, .. } = section_data {
2007 let detected_level = level;
2008 match doctree.shared_data() {
2009
2010 TreeNodeType::Document { .. } => {
2011 doctree = match doctree.push_data_and_focus(section_data) {
2012 Ok(tree) => tree,
2013 Err(tree) => return TransitionResult::Failure {
2014 message: format!("Node insertion error on line {}. Computer says no...", line_cursor.sum_total()),
2015 doctree: tree
2016 }
2017 };
2018 *section_level = detected_level;
2019 }
2020
2021 TreeNodeType::Section { level, .. } => {
2022 if detected_level <= *level {
2023 *section_level = *level;
2024 doctree = doctree.focus_on_parent();
2025 return TransitionResult::Success {
2026 doctree: doctree,
2027 push_or_pop: PushOrPop::Pop,
2028 line_advance: LineAdvance::None
2029 }
2030 } else {
2031 *section_level = detected_level;
2032 doctree = match doctree.push_data_and_focus(section_data) {
2033 Ok(tree) => tree,
2034 Err(tree) => return TransitionResult::Failure {
2035 message: format!(
2036 "Node insertion error on line {}. Computer says no...",
2037 line_cursor.sum_total()
2038 ),
2039 doctree: tree
2040 }
2041 };
2042 }
2043 }
2044 _ => {
2045 doctree = doctree.focus_on_parent();
2046 if let TreeNodeType::Section{level, .. } = doctree.shared_data() {
2047 *section_level = *level;
2048 }
2049 return TransitionResult::Success {
2050 doctree: doctree,
2051 push_or_pop: PushOrPop::Pop,
2052 line_advance: LineAdvance::None
2053 }
2054 }
2055 }
2056 return TransitionResult::Success {
2057 doctree: doctree,
2058 push_or_pop: PushOrPop::Push(vec![State::Section]),
2059 line_advance: LineAdvance::Some(3) }
2061 } else {
2062 return TransitionResult::Failure {
2063 message: format!("No generated section where one was expected on line {}. Computer says no...", line_cursor.sum_total()),
2064 doctree: doctree
2065 }
2066 }
2067 } else {
2068 return TransitionResult::Failure {
2069 message: format!("Found a section with unmatching over- and underline lengths or characters on line {}. Computer says no...", line_cursor.sum_total()),
2070 doctree: doctree
2071 }
2072 }
2073 } else {
2074 return TransitionResult::Failure {
2075 message: format!(
2076 "Found section-like construct without underline on line {}. Computer says no...",
2077 line_cursor.sum_total()
2078 ),
2079 doctree: doctree
2080 }
2081 }
2082 } else {
2083 return TransitionResult::Failure {
2084 message: format!("Found something akin to an section title but no underline at the end of input on line {}. Computer says no...", line_cursor.sum_total()),
2085 doctree: doctree
2086 }
2087 }
2088 } else if captures.get(0).unwrap().as_str().trim() == "::" {
2089 return parse_paragraph(src_lines, base_indent, line_cursor, doctree, 0)
2091 } else {
2092 return TransitionResult::Failure {
2093 message: format!("No known pattern during a line transition on line {}. Computer says no...", line_cursor.sum_total()),
2094 doctree: doctree
2095 }
2096 }
2097 }
2098 _ => return TransitionResult::Failure {
2099 message: format!("Found a transition-like construct on line {}, but no existing previous or next line. Computer says no...", line_cursor.sum_total()),
2100 doctree: doctree
2101 }
2102 }
2103}
2104
2105pub fn detected_footnote_label_to_ref_label(
2112 doctree: &DocTree,
2113 footnotekind: &FootnoteKind,
2114 detected_label_str: &str,
2115) -> Option<(String, String)> {
2116 use crate::common::normalize_refname;
2117
2118 let normalized_name = normalize_refname(detected_label_str);
2119 match footnotekind {
2120 FootnoteKind::Manual => {
2121 return Some((normalized_name.clone(), normalized_name));
2126 }
2127
2128 FootnoteKind::AutoNumbered => {
2129 let next_autonumber = if let Some(number_str) = doctree.new_autonumber_footnote_label() {
2136 number_str
2137 } else {
2138 return None
2139 };
2140 Some((next_autonumber.clone(), next_autonumber))
2141 }
2142
2143 FootnoteKind::SimpleRefName => {
2144 let next_autonumber = if let Some(number_str) = doctree.new_autonumber_footnote_label() {
2148 number_str
2149 } else {
2150 return None
2151 };
2152 Some((next_autonumber, normalized_name))
2153 }
2154
2155 FootnoteKind::AutoSymbol => {
2156 if let Some(label) = doctree.new_symbolic_footnote_label() {
2159 return Some((label.clone(), label))
2160 } else {
2161 None
2162 }
2163 }
2164 }
2165}
2166
2167fn parse_paragraph(
2169 src_lines: &Vec<String>,
2170 base_indent: usize,
2171 line_cursor: &mut LineCursor,
2172 mut doctree: DocTree,
2173 detected_indent: usize,
2174) -> TransitionResult {
2175
2176 match Parser::parent_indent_matches(doctree.shared_node_data(), detected_indent) {
2177 IndentationMatch::JustRight => {
2178 let relative_indent = detected_indent - base_indent;
2179
2180 let mut block = match Parser::read_text_block(
2181 src_lines,
2182 line_cursor.relative_offset(),
2183 true,
2184 true,
2185 Some(relative_indent),
2186 true
2187 ) {
2188 TextBlockResult::Ok {lines, offset } => lines.join("\n").trim_end().to_string(),
2189 TextBlockResult::Err {lines, offset } => {
2190 return TransitionResult::Failure {
2191 message: format!("Error when reading text block on line {}.", line_cursor.sum_total()),
2192 doctree: doctree,
2193 }
2194 }
2195 };
2196
2197 lazy_static! {
2198 static ref LITERAL_BLOCK_INDICATOR: Regex = Regex::new(r"(\s{0,1}|\S)::$").unwrap();
2204 }
2205
2206 let literal_block_next: bool = if let Some(capts)
2207 = LITERAL_BLOCK_INDICATOR.captures(block.as_str())
2208 {
2209 let indicator_len = if capts.get(1).unwrap().as_str().trim().is_empty() {
2211 "::".chars().count()
2212 } else {
2213 ":".chars().count()
2214 };
2215
2216 for _ in 0..indicator_len {
2217 if let None = block.pop() {
2218 return TransitionResult::Failure { message: format!("Tried removing a literal block indicator from a paragraph starting on line {} but failed. Computer says no...", line_cursor.sum_total()),
2220 doctree: doctree
2221 };
2222 }
2223 }
2224 true
2225 } else {
2226 false
2227 };
2228
2229 doctree = match doctree.push_data_and_focus(TreeNodeType::Paragraph {
2230 indent: detected_indent,
2231 }) {
2232 Ok(tree) => tree,
2233 Err(tree) => {
2234 return TransitionResult::Failure {
2235 message: format!(
2236 "Node insertion error on line {}. Computer says no...",
2237 line_cursor.sum_total()
2238 ),
2239 doctree: tree,
2240 }
2241 }
2242 };
2243
2244 doctree = match Parser::inline_parse(block, Some(&mut doctree), line_cursor) {
2246 InlineParsingResult::Nodes(nodes_data) => {
2247 for data in nodes_data {
2248 doctree = match doctree.push_data(data) {
2249 Ok(tree) => tree,
2250 Err(tree) => {
2251 return TransitionResult::Failure {
2252 message: format!(
2253 "Node insertion error on line {}. Computer says no...",
2254 line_cursor.sum_total()
2255 ),
2256 doctree: tree,
2257 }
2258 }
2259 };
2260 }
2261
2262 doctree.focus_on_parent()
2263 }
2264 InlineParsingResult::NoNodes => {
2265 doctree = doctree.focus_on_parent();
2266 match doctree.pop_child() {
2267 Some(child) => {
2268 eprintln!(
2269 "Removing an empty paragraph from the tree on line {}...",
2270 line_cursor.sum_total()
2271 );
2272 }
2273 None => {}
2274 };
2275 doctree
2276 }
2277 };
2278
2279 if literal_block_next {
2280 return TransitionResult::Success {
2281 doctree: doctree,
2282 push_or_pop: PushOrPop::Push(vec![State::LiteralBlock]),
2283 line_advance: LineAdvance::Some(1),
2284 };
2285 } else {
2286 return TransitionResult::Success {
2287 doctree: doctree,
2288 push_or_pop: PushOrPop::Neither,
2289 line_advance: LineAdvance::Some(1),
2290 };
2291 }
2292 }
2293
2294 IndentationMatch::TooMuch => {
2295 doctree = match doctree.push_data_and_focus(
2296 TreeNodeType::BlockQuote {
2297 body_indent: detected_indent,
2298 }
2299 ) {
2300 Ok(tree) => tree,
2301 Err(tree) => {
2302 return TransitionResult::Failure {
2303 message: format!(
2304 "Node insertion error on line {}. Computer says no...",
2305 line_cursor.sum_total()
2306 ),
2307 doctree: tree,
2308 }
2309 }
2310 };
2311 return TransitionResult::Success {
2312 doctree: doctree,
2313 push_or_pop: PushOrPop::Push(vec![State::BlockQuote]),
2314 line_advance: LineAdvance::None,
2315 };
2316 }
2317
2318 _ => {
2319 return TransitionResult::Success {
2320 doctree: doctree.focus_on_parent(),
2321 push_or_pop: PushOrPop::Pop,
2322 line_advance: LineAdvance::None,
2323 };
2324 }
2325 }
2326}