1#[macro_use]
2use crate::*;
3
4#[cfg(not(feature = "no-std"))] use core::fmt;
5#[cfg(feature = "no-std")] use alloc::fmt;
6#[cfg(feature = "no-std")] use alloc::string::String;
7#[cfg(feature = "no-std")] use alloc::vec::Vec;
8use nom::{
9 IResult,
10 branch::alt,
11 sequence::tuple as nom_tuple,
12 combinator::{opt, eof, peek},
13 multi::{many1, many_till, many0, separated_list1,separated_list0},
14 bytes::complete::{take_until, take_while},
15 Err,
16 Err::Failure
17};
18
19use std::collections::HashMap;
20use colored::*;
21
22use crate::*;
23
24pub fn title(input: ParseString) -> ParseResult<Title> {
28 let (input, mut text) = many1(text)(input)?;
29 let (input, _) = new_line(input)?;
30 let (input, _) = many1(equal)(input)?;
31 let (input, _) = many0(space_tab)(input)?;
32 let (input, _) = new_line(input)?;
33 let (input, _) = many0(space_tab)(input)?;
34 let (input, _) = whitespace0(input)?;
35 let mut title = Token::merge_tokens(&mut text).unwrap();
36 title.kind = TokenKind::Title;
37 Ok((input, Title{text: title}))
38}
39
40pub struct MarkdownTableHeader {
41 pub header: Vec<(Token, Token)>,
42}
43
44pub fn no_alignment(input: ParseString) -> ParseResult<ColumnAlignment> {
45 let (input, _) = many1(dash)(input)?;
46 Ok((input, ColumnAlignment::Left))
47}
48
49pub fn left_alignment(input: ParseString) -> ParseResult<ColumnAlignment> {
50 let (input, _) = colon(input)?;
51 let (input, _) = many1(dash)(input)?;
52 Ok((input, ColumnAlignment::Left))
53}
54
55pub fn right_alignment(input: ParseString) -> ParseResult<ColumnAlignment> {
56 let (input, _) = many1(dash)(input)?;
57 let (input, _) = colon(input)?;
58 Ok((input, ColumnAlignment::Right))
59}
60
61pub fn center_alignment(input: ParseString) -> ParseResult<ColumnAlignment> {
62 let (input, _) = colon(input)?;
63 let (input, _) = many1(dash)(input)?;
64 let (input, _) = colon(input)?;
65 Ok((input, ColumnAlignment::Center))
66}
67
68pub fn alignment_separator(input: ParseString) -> ParseResult<ColumnAlignment> {
69 let (input, _) = many0(space_tab)(input)?;
70 let (input, separator) = alt((center_alignment, left_alignment, right_alignment, no_alignment))(input)?;
71 let (input, _) = many0(space_tab)(input)?;
72 Ok((input, separator))
73}
74
75pub fn markdown_table(input: ParseString) -> ParseResult<MarkdownTable> {
76 let (input, _) = whitespace0(input)?;
77 let (input, table) = alt((markdown_table_with_header, markdown_table_no_header))(input)?;
78 Ok((input, table))
79}
80
81pub fn markdown_table_with_header(input: ParseString) -> ParseResult<MarkdownTable> {
82 let (input, (header,alignment)) = markdown_table_header(input)?;
83 let (input, rows) = many1(markdown_table_row)(input)?;
84 Ok((input, MarkdownTable{header, rows, alignment}))
85}
86
87pub fn markdown_table_no_header(input: ParseString) -> ParseResult<MarkdownTable> {
88 let (input, rows) = many1(markdown_table_row)(input)?;
89 let header = vec![];
90 let alignment = vec![];
91 Ok((input, MarkdownTable{header, rows, alignment}))
92}
93
94pub fn markdown_table_header(input: ParseString) -> ParseResult<(Vec<Paragraph>,Vec<ColumnAlignment>)> {
95 let (input, _) = whitespace0(input)?;
96 let (input, header) = many1(tuple((bar, paragraph)))(input)?;
97 let (input, _) = bar(input)?;
98 let (input, _) = new_line(input)?;
99 let (input, _) = whitespace0(input)?;
100 let (input, alignment) = many1(tuple((bar, alignment_separator)))(input)?;
101 let (input, _) = bar(input)?;
102 let (input, _) = new_line(input)?;
103 let column_names: Vec<Paragraph> = header.into_iter().map(|(_,tkn)| tkn).collect();
104 let column_alignments = alignment.into_iter().map(|(_,tkn)| tkn).collect();
105 Ok((input, (column_names,column_alignments)))
106}
107
108pub fn markdown_table_row(input: ParseString) -> ParseResult<Vec<Paragraph>> {
110 let (input, _) = whitespace0(input)?;
111 let (input, row) = many1(tuple((bar, paragraph)))(input)?;
112 let (input, _) = bar(input)?;
113 let (input, _) = whitespace0(input)?;
114 let row = row.into_iter().map(|(_,tkn)| tkn).collect();
115 Ok((input, row))
116}
117
118pub fn ul_subtitle(input: ParseString) -> ParseResult<Subtitle> {
120 let (input, _) = many1(digit_token)(input)?;
121 let (input, _) = period(input)?;
122 let (input, _) = many0(space)(input)?;
123 let (input, text) = paragraph(input)?;
124 let (input, _) = new_line(input)?;
125 let (input, _) = many1(dash)(input)?;
126 let (input, _) = many0(space_tab)(input)?;
127 let (input, _) = new_line(input)?;
128 let (input, _) = many0(space_tab)(input)?;
129 let (input, _) = whitespace0(input)?;
130 Ok((input, Subtitle{text, level: 2}))
131}
132
133pub fn subtitle(input: ParseString) -> ParseResult<Subtitle> {
135 let (input, _) = many0(space_tab)(input)?;
136 let (input, _) = left_parenthesis(input)?;
137 let (input, num) = separated_list1(period,alt((many1(alpha),many1(digit))))(input)?;
138 let (input, _) = right_parenthesis(input)?;
139 let (input, _) = many0(space_tab)(input)?;
140 let (input, text) = paragraph(input)?;
141 let (input, _) = many0(space_tab)(input)?;
142 let (input, _) = whitespace0(input)?;
143 let level: u8 = if num.len() < 3 { 3 } else { num.len() as u8 + 1 };
144 Ok((input, Subtitle{text, level}))
145}
146
147pub fn strong(input: ParseString) -> ParseResult<ParagraphElement> {
149 let (input, _) = tuple((asterisk,asterisk))(input)?;
150 let (input, text) = paragraph_element(input)?;
151 let (input, _) = tuple((asterisk,asterisk))(input)?;
152 Ok((input, ParagraphElement::Strong(Box::new(text))))
153}
154
155pub fn emphasis(input: ParseString) -> ParseResult<ParagraphElement> {
157 let (input, _) = asterisk(input)?;
158 let (input, text) = paragraph_element(input)?;
159 let (input, _) = asterisk(input)?;
160 Ok((input, ParagraphElement::Emphasis(Box::new(text))))
161}
162
163pub fn strikethrough(input: ParseString) -> ParseResult<ParagraphElement> {
165 let (input, _) = tilde(input)?;
166 let (input, text) = paragraph_element(input)?;
167 let (input, _) = tilde(input)?;
168 Ok((input, ParagraphElement::Strikethrough(Box::new(text))))
169}
170
171pub fn underline(input: ParseString) -> ParseResult<ParagraphElement> {
173 let (input, _) = underscore(input)?;
174 let (input, text) = paragraph_element(input)?;
175 let (input, _) = underscore(input)?;
176 Ok((input, ParagraphElement::Underline(Box::new(text))))
177}
178
179pub fn highlight(input: ParseString) -> ParseResult<ParagraphElement> {
181 let (input, _) = highlight_sigil(input)?;
182 let (input, text) = paragraph_element(input)?;
183 let (input, _) = highlight_sigil(input)?;
184 Ok((input, ParagraphElement::Highlight(Box::new(text))))
185}
186
187pub fn inline_code(input: ParseString) -> ParseResult<ParagraphElement> {
189 let (input, _) = grave(input)?;
190 let (input, text) = many0(tuple((is_not(grave),text)))(input)?;
191 let (input, _) = grave(input)?;
192 let mut text = text.into_iter().map(|(_,tkn)| tkn).collect();
193 let mut text = Token::merge_tokens(&mut text).unwrap();
194 text.kind = TokenKind::Text;
195 Ok((input, ParagraphElement::InlineCode(text)))
196}
197
198pub fn inline_equation(input: ParseString) -> ParseResult<ParagraphElement> {
200 let (input, _) = equation_sigil(input)?;
201 let (input, txt) = many0(tuple((is_not(equation_sigil),text)))(input)?;
202 let (input, _) = equation_sigil(input)?;
203 let mut txt = txt.into_iter().map(|(_,tkn)| tkn).collect();
204 let mut eqn = Token::merge_tokens(&mut txt).unwrap();
205 eqn.kind = TokenKind::Text;
206 Ok((input, ParagraphElement::InlineEquation(eqn)))
207}
208
209pub fn hyperlink(input: ParseString) -> ParseResult<ParagraphElement> {
211 let (input, _) = left_bracket(input)?;
212 let (input, link_text) = many1(tuple((is_not(right_bracket),text)))(input)?;
213 let (input, _) = right_bracket(input)?;
214 let (input, _) = left_parenthesis(input)?;
215 let (input, link) = many1(tuple((is_not(right_parenthesis),text)))(input)?;
216 let (input, _) = right_parenthesis(input)?;
217 let mut tokens = link.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>();
218 let link_merged = Token::merge_tokens(&mut tokens).unwrap();
219 let mut tokens = link_text.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>();
220 let text_merged = Token::merge_tokens(&mut tokens).unwrap();
221 Ok((input, ParagraphElement::Hyperlink((text_merged, link_merged))))
222}
223
224pub fn raw_hyperlink(input: ParseString) -> ParseResult<ParagraphElement> {
226 let (input, _) = peek(http_prefix)(input)?;
227 let (input, address) = many1(tuple((is_not(space), text)))(input)?;
228 let mut tokens = address.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>();
229 let url = Token::merge_tokens(&mut tokens).unwrap();
230 Ok((input, ParagraphElement::Hyperlink((url.clone(), url))))
231}
232
233pub fn img(input: ParseString) -> ParseResult<Image> {
235 let (input, _) = img_prefix(input)?;
236 let (input, caption_text) = paragraph(input)?;
237 let (input, _) = right_bracket(input)?;
238 let (input, _) = left_parenthesis(input)?;
239 let (input, src) = many1(tuple((is_not(right_parenthesis),text)))(input)?;
240 let (input, _) = right_parenthesis(input)?;
241 let merged_src = Token::merge_tokens(&mut src.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>()).unwrap();
242 Ok((input, Image{src: merged_src, caption: Some(caption_text)} ))
243}
244
245pub fn paragraph_text(input: ParseString) -> ParseResult<ParagraphElement> {
247 let (input, elements) = match many1(nom_tuple((is_not(alt((footnote_prefix, highlight_sigil, equation_sigil, img_prefix, http_prefix, left_brace, left_bracket, right_bracket, tilde, asterisk, underscore, grave, define_operator, bar))),text)))(input) {
248 Ok((input, mut text)) => {
249 let mut text = text.into_iter().map(|(_,tkn)| tkn).collect();
250 let mut text = Token::merge_tokens(&mut text).unwrap();
251 text.kind = TokenKind::Text;
252 (input, ParagraphElement::Text(text))
253 },
254 Err(err) => {return Err(err);},
255 };
256 Ok((input, elements))
257}
258
259pub fn inline_mech_code(input: ParseString) -> ParseResult<ParagraphElement> {
261 let (input, _) = left_brace(input)?;
262 let (input, expr) = expression(input)?;
263 let (input, _) = right_brace(input)?;
264 Ok((input, ParagraphElement::InlineMechCode(expr)))
265}
266
267pub fn footnote_reference(input: ParseString) -> ParseResult<ParagraphElement> {
269 let (input, _) = footnote_prefix(input)?;
270 let (input, text) = many1(tuple((is_not(right_bracket),text)))(input)?;
271 let (input, _) = right_bracket(input)?;
272 let mut tokens = text.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>();
273 let footnote_text = Token::merge_tokens(&mut tokens).unwrap();
274 Ok((input, ParagraphElement::FootnoteReference(footnote_text)))
275}
276
277pub fn reference(input: ParseString) -> ParseResult<ParagraphElement> {
279 let (input, _) = left_bracket(input)?;
280 let (input, mut txt) = many1(alphanumeric)(input)?;
281 let (input, _) = right_bracket(input)?;
282 let ref_text = Token::merge_tokens(&mut txt).unwrap();
283 Ok((input, ParagraphElement::Reference(ref_text)))
284}
285
286pub fn paragraph_element(input: ParseString) -> ParseResult<ParagraphElement> {
288 alt((hyperlink, reference, raw_hyperlink, highlight, footnote_reference, inline_mech_code, inline_equation, paragraph_text, strong, highlight, emphasis, inline_code, strikethrough, underline))(input)
289}
290
291pub fn paragraph(input: ParseString) -> ParseResult<Paragraph> {
293 let (input, elements) = many1(paragraph_element)(input)?;
294 Ok((input, Paragraph{elements}))
295}
296
297pub fn ordered_list_item(input: ParseString) -> ParseResult<(Number,Paragraph)> {
299 let (input, number) = number(input)?;
300 let (input, _) = period(input)?;
301 let (input, list_item) = paragraph(input)?;
302 let (input, _) = new_line(input)?;
303 Ok((input, (number,list_item)))
304}
305
306pub fn checked_item(input: ParseString) -> ParseResult<(bool,Paragraph)> {
308 let (input, _) = dash(input)?;
309 let (input, _) = left_bracket(input)?;
310 let (input, _) = alt((tag("x"),tag("✓"),tag("✗")))(input)?;
311 let (input, _) = right_bracket(input)?;
312 let (input, list_item) = paragraph(input)?;
313 let (input, _) = new_line(input)?;
314 Ok((input, (true,list_item)))
315}
316
317pub fn unchecked_item(input: ParseString) -> ParseResult<(bool,Paragraph)> {
319 let (input, _) = dash(input)?;
320 let (input, _) = left_bracket(input)?;
321 let (input, _) = whitespace0(input)?;
322 let (input, _) = right_bracket(input)?;
323 let (input, list_item) = paragraph(input)?;
324 let (input, _) = new_line(input)?;
325 Ok((input, (false,list_item)))
326}
327
328pub fn check_list_item(input: ParseString) -> ParseResult<(bool,Paragraph)> {
330 let (input, item) = alt((checked_item, unchecked_item))(input)?;
331 Ok((input, item))
332}
333
334pub fn check_list(mut input: ParseString, level: usize) -> ParseResult<MDList> {
335 let mut items = vec![];
336 let mut i = 0;
337 loop {
338 let mut indent = 0;
339 let mut current = input.peek(indent);
340 while current == Some(" ") || current == Some("\t") {
341 current = input.peek(indent);
342 indent += 1;
343 }
344 let (next_input, _) = many0(space_tab)(input)?;
346 let (next_input,list_item) = match check_list_item(next_input.clone()) {
347 Ok((next_input, list_item)) => (next_input, list_item),
348 Err(err) => {
349 if items.len() != 0 {
350 input = next_input.clone();
351 break;
352 } else {
353 return Err(err);
354 }
355 }
356 };
357 let mut indent = 0;
361 let mut current = next_input.peek(indent);
362 while current == Some(" ") || current == Some("\t") {
363 current = next_input.peek(indent);
364 indent += 1;
365 }
366 input = next_input;
367 if indent < level {
369 items.push((list_item, None));
370 break;
371 } else if indent == level {
373 items.push((list_item, None));
374 continue;
375 } else if indent > level {
377 let (next_input, list) = sublist(input.clone(), indent)?;
379 items.push((list_item, Some(list)));
380 input = next_input;
381 continue;
382 }
383 }
384 Ok((input, MDList::Check(items)))
385}
386
387pub fn unordered_list(mut input: ParseString, level: usize) -> ParseResult<MDList> {
389 let mut items = vec![];
390 let mut i = 0;
391 loop {
392 let mut indent = 0;
393 let mut current = input.peek(indent);
394 while current == Some(" ") || current == Some("\t") {
395 current = input.peek(indent);
396 indent += 1;
397 }
398 let (next_input, _) = many0(space_tab)(input)?;
400 let (next_input,list_item) = match unordered_list_item(next_input.clone()) {
401 Ok((next_input, list_item)) => (next_input, list_item),
402 Err(err) => {
403 if items.len() != 0 {
404 input = next_input.clone();
405 break;
406 } else {
407 return Err(err);
408 }
409 }
410 };
411 let mut indent = 0;
415 let mut current = next_input.peek(indent);
416 while current == Some(" ") || current == Some("\t") {
417 current = next_input.peek(indent);
418 indent += 1;
419 }
420 input = next_input;
421 if indent < level {
423 items.push((list_item, None));
424 break;
425 } else if indent == level {
427 items.push((list_item, None));
428 continue;
429 } else if indent > level {
431 let (next_input, list) = sublist(input.clone(), indent)?;
433 items.push((list_item, Some(list)));
434 input = next_input;
435 continue;
436 }
437 }
438 Ok((input, MDList::Unordered(items)))
439}
440
441pub fn ordered_list(mut input: ParseString, level: usize) -> ParseResult<MDList> {
443 let mut items = vec![];
444 let mut i = 0;
445 loop {
446 let mut indent = 0;
447 let mut current = input.peek(indent);
448 while current == Some(" ") || current == Some("\t") {
449 current = input.peek(indent);
450 indent += 1;
451 }
452 let (next_input, _) = many0(space_tab)(input)?;
454 let (next_input, (list_item,_)) = match tuple((ordered_list_item,is_not(tuple((dash,dash)))))(next_input.clone()) {
455 Ok((next_input, list_item)) => (next_input, list_item),
456 Err(err) => {
457 if items.len() != 0 {
458 input = next_input.clone();
459 break;
460 } else {
461 return Err(err);
462 }
463 }
464 };
465 let mut indent = 0;
469 let mut current = next_input.peek(indent);
470 while current == Some(" ") || current == Some("\t") {
471 current = next_input.peek(indent);
472 indent += 1;
473 }
474 input = next_input;
475 if indent < level {
477 items.push((list_item, None));
478 break;
479 } else if indent == level {
481 items.push((list_item, None));
482 continue;
483 } else if indent > level {
485 let (next_input, list) = sublist(input.clone(), indent)?;
487 items.push((list_item, Some(list)));
488 input = next_input;
489 continue;
490 }
491 }
492 let start = match items.first() {
493 Some(((number,_), _)) =>number.clone(),
494 None => unreachable!(),
495 };
496 Ok((input, MDList::Ordered(OrderedList{start, items})))
497}
498
499pub fn sublist(input: ParseString, level: usize) -> ParseResult<MDList> {
500 let (input, list) = match ordered_list(input.clone(), level) {
501 Ok((input, list)) => (input, list),
502 _ => match check_list(input.clone(), level) {
503 Ok((input, list)) => (input, list),
504 _ => match unordered_list(input.clone(), level) {
505 Ok((input, list)) => (input, list),
506 Err(err) => { return Err(err); }
507 }
508 }
509 };
510 Ok((input, list))
511}
512
513pub fn mechdown_list(input: ParseString) -> ParseResult<MDList> {
515 let (input, list) = match ordered_list(input.clone(), 0) {
516 Ok((input, list)) => (input, list),
517 _ => match check_list(input.clone(), 0) {
518 Ok((input, list)) => (input, list),
519 _ => match unordered_list(input.clone(), 0) {
520 Ok((input, list)) => (input, list),
521 Err(err) => { return Err(err); }
522 }
523 }
524 };
525 Ok((input, list))
526}
527
528pub fn unordered_list_item(input: ParseString) -> ParseResult<(Option<Token>,Paragraph)> {
530 let msg1 = "Expects space after dash";
531 let msg2 = "Expects paragraph as list item";
532 let (input, _) = dash(input)?;
533 let (input, bullet) = opt(tuple((left_parenthesis, emoji, right_parenthesis)))(input)?;
534 let (input, _) = labelr!(null(many1(space)), skip_nil, msg1)(input)?;
535 let (input, list_item) = label!(paragraph, msg2)(input)?;
536 let (input, _) = many0(new_line)(input)?;
537 let bullet = match bullet {
538 Some((_,b,_)) => Some(b),
539 None => None,
540 };
541 Ok((input, (bullet, list_item)))
542}
543
544
545pub fn skip_till_eol(input: ParseString) -> ParseResult<()> {
546
547 Ok((input, ()))
548}
549
550pub fn code_block(input: ParseString) -> ParseResult<SectionElement> {
552 let msg1 = "Expects 3 graves to start a code block";
553 let msg2 = "Expects new_line";
554 let msg3 = "Expects 3 graves followed by new_line to terminate a code block";
555 let (input, (_, r)) = range(nom_tuple((
556 grave,
557 label!(grave, msg1),
558 label!(grave, msg1),
559 )))(input)?;
560 let (input, code_id) = opt(identifier)(input)?;
561 let (input, _) = many0(space_tab)(input)?;
562 let (input, _) = label!(new_line, msg2)(input)?;
563 let (input, (text,src_range)) = range(many0(nom_tuple((
564 is_not(nom_tuple((grave, grave, grave))),
565 any,
566 ))))(input)?;
567 let (input, _) = nom_tuple((grave, grave, grave))(input)?;
568 let (input, _) = many0(space_tab)(input)?;
569 let (input, _) = new_line(input)?;
570 let block_src: Vec<char> = text.into_iter().flat_map(|(_, s)| s.chars().collect::<Vec<char>>()).collect();
571
572 match code_id {
573 Some(id) => {
574 match id.to_string().as_str() {
575 "ebnf" => {
576 let ebnf_text = block_src.iter().collect::<String>();
577 match parse_grammar(&ebnf_text) {
578 Ok(grammar_tree) => {return Ok((input, SectionElement::Grammar(grammar_tree)));},
579 Err(err) => {
580 println!("Error parsing EBNF grammar: {:?}", err);
581 todo!();
582 }
583 }
584 }
585 tag => {
586 if tag.starts_with("mech") || tag.starts_with("mec") || tag.starts_with("🤖") {
588
589 let rest = tag.trim_start_matches("mech").trim_start_matches("mec").trim_start_matches("🤖");
591 let code_id = if rest == "" { 0 } else {
592 hash_str(rest)
593 };
594
595 let mech_src = block_src.iter().collect::<String>();
596 let graphemes = graphemes::init_source(&mech_src);
597 let parse_string = ParseString::new(&graphemes);
598
599 match many1(mech_code)(parse_string) {
600 Ok((_, mech_tree)) => {
601 return Ok((input, SectionElement::FencedMechCode((mech_tree,code_id))));
603 },
604 Err(err) => {
605 println!("Error parsing Mech code: {:?}", err);
606 todo!();
607 }
608 };
609 } else {
610 }
612 }
613 }
614 },
615 None => (),
616 }
617 let code_token = Token::new(TokenKind::CodeBlock, src_range, block_src);
618 Ok((input, SectionElement::CodeBlock(code_token)))
619}
620
621pub fn block_quote(input: ParseString) -> ParseResult<Paragraph> {
622 let (input, _) = quote_sigil(input)?;
623 let (input, _) = many0(space_tab)(input)?;
624 let (input, text) = paragraph(input)?;
625 let (input, _) = many0(space_tab)(input)?;
626 Ok((input, text))
627}
628
629pub fn thematic_break(input: ParseString) -> ParseResult<SectionElement> {
630 let (input, _) = many1(asterisk)(input)?;
631 let (input, _) = many0(space_tab)(input)?;
632 let (input, _) = new_line(input)?;
633 Ok((input, SectionElement::ThematicBreak))
634}
635
636pub fn footnote(input: ParseString) -> ParseResult<Footnote> {
638 let (input, _) = footnote_prefix(input)?;
639 let (input, text) = many1(tuple((is_not(right_bracket),text)))(input)?;
640 let (input, _) = right_bracket(input)?;
641 let (input, _) = colon(input)?;
642 let (input, _) = whitespace0(input)?;
643 let (input, paragraph) = paragraph(input)?;
644 let mut tokens = text.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>();
645 let footnote_text = Token::merge_tokens(&mut tokens).unwrap();
646 let footnote = (footnote_text, paragraph);
647 Ok((input, footnote))
648}
649
650pub fn blank_line(input: ParseString) -> ParseResult<Vec<Token>> {
651 let (input, mut st) = many0(space_tab)(input)?;
652 let (input, n) = new_line(input)?;
653 st.push(n);
654 Ok((input, st))
655}
656
657pub fn abstract_el(input: ParseString) -> ParseResult<Paragraph> {
658 let (input, _) = abstract_sigil(input)?;
659 let (input, _) = many0(space_tab)(input)?;
660 let (input, text) = paragraph(input)?;
661 Ok((input, text))
662}
663
664pub fn equation(input: ParseString) -> ParseResult<Token> {
666 let (input, _) = equation_sigil(input)?;
667 let (input, mut txt) = many1(text)(input)?;
668 let mut eqn = Token::merge_tokens(&mut txt).unwrap();
669 Ok((input, eqn))
670}
671
672pub fn citation(input: ParseString) -> ParseResult<Citation> {
674 let (input, _) = left_bracket(input)?;
675 let (input, mut id) = many1(alphanumeric)(input)?;
676 let (input, _) = right_bracket(input)?;
677 let (input, _) = colon(input)?;
678 let (input, _) = whitespace0(input)?;
679 let (input, txt) = paragraph(input)?;
680 let (input, _) = whitespace0(input)?;
681 let id = Token::merge_tokens(&mut id).unwrap();
682 Ok((input, Citation{id, text: txt}))
683}
684
685pub fn float_sigil(input: ParseString) -> ParseResult<FloatDirection> {
687 let (input, d) = alt((float_left, float_right))(input)?;
688 let d = match d.kind {
689 TokenKind::FloatLeft => FloatDirection::Left,
690 TokenKind::FloatRight => FloatDirection::Right,
691 _ => unreachable!(),
692 };
693 Ok((input, d))
694}
695
696pub fn float(input: ParseString) -> ParseResult<(Box<SectionElement>,FloatDirection)> {
698 let (input, direction) = float_sigil(input)?;
699 let (input, _) = many0(space_tab)(input)?;
700 let (input, el) = section_element(input)?;
701 Ok((input, (Box::new(el), direction)))
702}
703
704pub fn section_element(input: ParseString) -> ParseResult<SectionElement> {
706 let (input, section_element) = match many1(mech_code)(input.clone()) {
707 Ok((input, code)) => (input, SectionElement::MechCode(code)),
708 _ =>match mechdown_list(input.clone()) {
709 Ok((input, lst)) => (input, SectionElement::List(lst)),
710 _ => match footnote(input.clone()) {
711 Ok((input, ftnote)) => (input, SectionElement::Footnote(ftnote)),
712 _ => match citation(input.clone()) {
713 Ok((input, citation)) => (input, SectionElement::Citation(citation)),
714 _ => match abstract_el(input.clone()) {
715 Ok((input, abstrct)) => (input, SectionElement::Abstract(abstrct)),
716 _ => match img(input.clone()) {
717 Ok((input, img)) => (input, SectionElement::Image(img)),
718 _ => match equation(input.clone()) {
719 Ok((input, eqn)) => (input, SectionElement::Equation(eqn)),
720 _ => match markdown_table(input.clone()) {
721 Ok((input, table)) => (input, SectionElement::Table(table)),
722 _ => match float(input.clone()) {
723 Ok((input, flt)) => (input, SectionElement::Float(flt)),
724 _ => match block_quote(input.clone()) {
725 Ok((input, quote)) => (input, SectionElement::BlockQuote(quote)),
726 _ => match code_block(input.clone()) {
727 Ok((input, m)) => (input,m),
728 _ => match thematic_break(input.clone()) {
729 Ok((input, _)) => (input, SectionElement::ThematicBreak),
730 _ => match subtitle(input.clone()) {
731 Ok((input, subtitle)) => (input, SectionElement::Subtitle(subtitle)),
732 _ => match paragraph(input) {
733 Ok((input, p)) => (input, SectionElement::Paragraph(p)),
734 Err(err) => { return Err(err); }
735 }
736 }
737 }
738 }
739 }
740 }
741 }
742 }
743 }
744 }
745 }
746 }
747 }
748 };
749 let (input, _) = many0(blank_line)(input)?;
750 Ok((input, section_element))
751}
752
753pub fn section(input: ParseString) -> ParseResult<Section> {
755 let msg = "Expects user function, block, mech code block, code block, statement, paragraph, or unordered list";
756 let (input, subtitle) = ul_subtitle(input)?;
757 let (input, elements) = many0(tuple((is_not(ul_subtitle),section_element)))(input)?;
758 let elements = elements.into_iter().map(|(_,e)| e).collect();
759 Ok((input, Section{subtitle: Some(subtitle), elements}))
760}
761
762pub fn section_elements(input: ParseString) -> ParseResult<Section> {
764 let msg = "Expects user function, block, mech code block, code block, statement, paragraph, or unordered list";
765 let (input, elements) = many1(tuple((is_not(ul_subtitle),section_element)))(input)?;
766 let elements = elements.into_iter().map(|(_,e)| e).collect();
767 Ok((input, Section{subtitle: None, elements}))
768}
769
770pub fn body(input: ParseString) -> ParseResult<Body> {
772 let (input, _) = whitespace0(input)?;
773 let (input, sections) = many0(alt((section,section_elements)))(input)?;
774 let (input, _) = whitespace0(input)?;
775 Ok((input, Body{sections}))
776}