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),alt((backslash,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 eval_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::EvalInlineMechCode(expr)))
265}
266
267pub fn inline_mech_code(input: ParseString) -> ParseResult<ParagraphElement> {
269 let (input, _) = left_brace(input)?;
270 let (input, _) = left_brace(input)?;
271 let (input, (expr,_)) = mech_code(input)?;
272 let (input, _) = right_brace(input)?;
273 let (input, _) = right_brace(input)?;
274 Ok((input, ParagraphElement::InlineMechCode(expr)))
275}
276
277pub fn footnote_reference(input: ParseString) -> ParseResult<ParagraphElement> {
279 let (input, _) = footnote_prefix(input)?;
280 let (input, text) = many1(tuple((is_not(right_bracket),text)))(input)?;
281 let (input, _) = right_bracket(input)?;
282 let mut tokens = text.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>();
283 let footnote_text = Token::merge_tokens(&mut tokens).unwrap();
284 Ok((input, ParagraphElement::FootnoteReference(footnote_text)))
285}
286
287pub fn reference(input: ParseString) -> ParseResult<ParagraphElement> {
289 let (input, _) = left_bracket(input)?;
290 let (input, mut txt) = many1(alphanumeric)(input)?;
291 let (input, _) = right_bracket(input)?;
292 let ref_text = Token::merge_tokens(&mut txt).unwrap();
293 Ok((input, ParagraphElement::Reference(ref_text)))
294}
295
296pub fn paragraph_element(input: ParseString) -> ParseResult<ParagraphElement> {
298 alt((hyperlink, reference, raw_hyperlink, highlight, footnote_reference, inline_mech_code, eval_inline_mech_code, inline_equation, paragraph_text, strong, highlight, emphasis, inline_code, strikethrough, underline))(input)
299}
300
301pub fn paragraph(input: ParseString) -> ParseResult<Paragraph> {
303 let (input, elements) = many1(paragraph_element)(input)?;
304 Ok((input, Paragraph{elements}))
305}
306
307pub fn ordered_list_item(input: ParseString) -> ParseResult<(Number,Paragraph)> {
309 let (input, number) = number(input)?;
310 let (input, _) = period(input)?;
311 let (input, list_item) = paragraph(input)?;
312 let (input, _) = new_line(input)?;
313 Ok((input, (number,list_item)))
314}
315
316pub fn checked_item(input: ParseString) -> ParseResult<(bool,Paragraph)> {
318 let (input, _) = dash(input)?;
319 let (input, _) = left_bracket(input)?;
320 let (input, _) = alt((tag("x"),tag("✓"),tag("✗")))(input)?;
321 let (input, _) = right_bracket(input)?;
322 let (input, list_item) = paragraph(input)?;
323 let (input, _) = new_line(input)?;
324 Ok((input, (true,list_item)))
325}
326
327pub fn unchecked_item(input: ParseString) -> ParseResult<(bool,Paragraph)> {
329 let (input, _) = dash(input)?;
330 let (input, _) = left_bracket(input)?;
331 let (input, _) = whitespace0(input)?;
332 let (input, _) = right_bracket(input)?;
333 let (input, list_item) = paragraph(input)?;
334 let (input, _) = new_line(input)?;
335 Ok((input, (false,list_item)))
336}
337
338pub fn check_list_item(input: ParseString) -> ParseResult<(bool,Paragraph)> {
340 let (input, item) = alt((checked_item, unchecked_item))(input)?;
341 Ok((input, item))
342}
343
344pub fn check_list(mut input: ParseString, level: usize) -> ParseResult<MDList> {
345 let mut items = vec![];
346 loop {
347 let mut indent = 0;
349 let mut current = input.peek(indent);
350 while current == Some(" ") || current == Some("\t") {
351 indent += 1;
352 current = input.peek(indent);
353 }
354 if indent < level {
356 break;
357 }
358 let (next_input, _) = many0(space_tab)(input.clone())?;
360 let (next_input, list_item) = match check_list_item(next_input.clone()) {
362 Ok((next_input, list_item)) => (next_input, list_item),
363 Err(err) => {
364 if !items.is_empty() {
365 break;
366 } else {
367 return Err(err);
368 }
369 }
370 };
371 let mut lookahead_indent = 0;
373 let mut current = next_input.peek(lookahead_indent);
374 while current == Some(" ") || current == Some("\t") {
375 lookahead_indent += 1;
376 current = next_input.peek(lookahead_indent);
377 }
378 input = next_input;
379 if lookahead_indent < level {
380 items.push((list_item, None));
382 break;
383 } else if lookahead_indent == level {
384 items.push((list_item, None));
386 continue;
387 } else {
388 let (next_input, sublist_md) = sublist(input.clone(), lookahead_indent)?;
390 items.push((list_item, Some(sublist_md)));
391 input = next_input;
392 }
393 }
394 Ok((input, MDList::Check(items)))
395}
396
397
398pub fn unordered_list(mut input: ParseString, level: usize) -> ParseResult<MDList> {
400 let mut items = vec![];
401 loop {
402 let mut indent = 0;
403 let mut current = input.peek(indent);
404 while current == Some(" ") || current == Some("\t") {
405 indent += 1;
406 current = input.peek(indent);
407 }
408 if indent < level {
410 return Ok((input, MDList::Unordered(items)));
411 }
412 let (next_input, _) = many0(space_tab)(input.clone())?;
413 let (next_input, list_item) = match unordered_list_item(next_input.clone()) {
415 Ok((next_input, list_item)) => (next_input, list_item),
416 Err(err) => {
417 if !items.is_empty() {
418 return Ok((input, MDList::Unordered(items)));
419 } else {
420 return Err(err);
421 }
422 }
423 };
424 let mut lookahead_indent = 0;
426 let mut current = next_input.peek(lookahead_indent);
427 while current == Some(" ") || current == Some("\t") {
428 lookahead_indent += 1;
429 current = next_input.peek(lookahead_indent);
430 }
431 input = next_input;
432 if lookahead_indent < level {
433 items.push((list_item, None));
435 return Ok((input, MDList::Unordered(items)));
436 } else if lookahead_indent == level {
437 items.push((list_item, None));
439 continue;
440 } else {
441 let (next_input, sub) = sublist(input.clone(), lookahead_indent)?;
443 items.push((list_item, Some(sub)));
444 input = next_input;
445 }
446 }
447}
448
449pub fn ordered_list(mut input: ParseString, level: usize) -> ParseResult<MDList> {
451 let mut items = vec![];
452 loop {
453 let mut indent = 0;
454 let mut current = input.peek(indent);
455 while current == Some(" ") || current == Some("\t") {
456 indent += 1;
457 current = input.peek(indent);
458 }
459 if indent < level {
461 let start = items.first()
462 .map(|item: &((Number, Paragraph), Option<MDList>)| item.0.0.clone())
463 .unwrap_or(Number::from_integer(1));
464 return Ok((input, MDList::Ordered(OrderedList { start, items })));
465 }
466 let (next_input, _) = many0(space_tab)(input.clone())?;
468 let (next_input, (list_item, _)) = match tuple((ordered_list_item, is_not(tuple((dash, dash)))))(next_input.clone()) {
470 Ok((next_input, res)) => (next_input, res),
471 Err(err) => {
472 if !items.is_empty() {
473 let start = items.first()
474 .map(|((number, _), _)| number.clone())
475 .unwrap_or(Number::from_integer(1));
476 return Ok((input, MDList::Ordered(OrderedList { start, items })));
477 } else {
478 return Err(err);
479 }
480 }
481 };
482
483 let mut lookahead_indent = 0;
485 let mut current = next_input.peek(lookahead_indent);
486 while current == Some(" ") || current == Some("\t") {
487 lookahead_indent += 1;
488 current = next_input.peek(lookahead_indent);
489 }
490
491 input = next_input;
492
493 if lookahead_indent < level {
494 items.push((list_item, None));
495 let start = items.first()
496 .map(|((number, _), _)| number.clone())
497 .unwrap_or(Number::from_integer(1));
498 return Ok((input, MDList::Ordered(OrderedList { start, items })));
499 } else if lookahead_indent == level {
500 items.push((list_item, None));
501 continue;
502 } else {
503 let (next_input, sub) = sublist(input.clone(), lookahead_indent)?;
505 items.push((list_item, Some(sub)));
506 input = next_input;
507 }
508 }
509}
510
511
512
513pub fn sublist(input: ParseString, level: usize) -> ParseResult<MDList> {
514 let (input, list) = match ordered_list(input.clone(), level) {
515 Ok((input, list)) => (input, list),
516 _ => match check_list(input.clone(), level) {
517 Ok((input, list)) => (input, list),
518 _ => match unordered_list(input.clone(), level) {
519 Ok((input, list)) => (input, list),
520 Err(err) => { return Err(err); }
521 }
522 }
523 };
524 Ok((input, list))
525}
526
527pub fn mechdown_list(input: ParseString) -> ParseResult<MDList> {
529 let (input, list) = match ordered_list(input.clone(), 0) {
530 Ok((input, list)) => (input, list),
531 _ => match check_list(input.clone(), 0) {
532 Ok((input, list)) => (input, list),
533 _ => match unordered_list(input.clone(), 0) {
534 Ok((input, list)) => (input, list),
535 Err(err) => { return Err(err); }
536 }
537 }
538 };
539 Ok((input, list))
540}
541
542pub fn unordered_list_item(input: ParseString) -> ParseResult<(Option<Token>,Paragraph)> {
544 let msg1 = "Expects space after dash";
545 let msg2 = "Expects paragraph as list item";
546 let (input, _) = dash(input)?;
547 let (input, bullet) = opt(tuple((left_parenthesis, emoji, right_parenthesis)))(input)?;
548 let (input, _) = labelr!(null(many1(space)), skip_nil, msg1)(input)?;
549 let (input, list_item) = label!(paragraph, msg2)(input)?;
550 let (input, _) = many0(new_line)(input)?;
551 let bullet = match bullet {
552 Some((_,b,_)) => Some(b),
553 None => None,
554 };
555 Ok((input, (bullet, list_item)))
556}
557
558
559pub fn skip_till_eol(input: ParseString) -> ParseResult<()> {
560
561 Ok((input, ()))
562}
563
564pub fn code_block(input: ParseString) -> ParseResult<SectionElement> {
566 let msg1 = "Expects 3 graves to start a code block";
567 let msg2 = "Expects new_line";
568 let msg3 = "Expects 3 graves followed by new_line to terminate a code block";
569 let (input, (_, r)) = range(nom_tuple((
570 grave,
571 label!(grave, msg1),
572 label!(grave, msg1),
573 )))(input)?;
574 let (input, code_id) = many0(text)(input)?;
575 let (input, _) = label!(new_line, msg2)(input)?;
576 let (input, (text,src_range)) = range(many0(nom_tuple((
577 is_not(nom_tuple((grave, grave, grave))),
578 any,
579 ))))(input)?;
580 let (input, _) = nom_tuple((grave, grave, grave))(input)?;
581 let (input, _) = many0(space_tab)(input)?;
582 let (input, _) = new_line(input)?;
583 let block_src: Vec<char> = text.into_iter().flat_map(|(_, s)| s.chars().collect::<Vec<char>>()).collect();
584 let code_token = Token::new(TokenKind::CodeBlock, src_range, block_src.clone());
585
586 let code_id = code_id.iter().flat_map(|tkn| tkn.chars.clone().into_iter().collect::<Vec<char>>()).collect::<String>();
587 match code_id.as_str() {
588 "ebnf" => {
589 let ebnf_text = block_src.iter().collect::<String>();
590 match parse_grammar(&ebnf_text) {
591 Ok(grammar_tree) => {return Ok((input, SectionElement::Grammar(grammar_tree)));},
592 Err(err) => {
593 println!("Error parsing EBNF grammar: {:?}", err);
594 todo!();
595 }
596 }
597 }
598 tag => {
599 if tag.starts_with("mech") || tag.starts_with("mec") || tag.starts_with("🤖") {
601
602 let rest = tag.trim_start_matches("mech").trim_start_matches("mec").trim_start_matches("🤖").trim_start_matches(":");
604
605 let config = if rest == "" {BlockConfig { namespace: 0, disabled: false}}
606 else if rest == "disabled" { BlockConfig { namespace: hash_str(rest), disabled: true }}
607 else { BlockConfig { namespace: hash_str(rest), disabled: false} };
608
609 let mech_src = block_src.iter().collect::<String>();
610 let graphemes = graphemes::init_source(&mech_src);
611 let parse_string = ParseString::new(&graphemes);
612
613 match many1(mech_code)(parse_string) {
614 Ok((_, mech_tree)) => {
615 return Ok((input, SectionElement::FencedMechCode((mech_tree,config))));
617 },
618 Err(err) => {
619 println!("Error parsing Mech code: {:?}", err);
620 todo!();
621 }
622 };
623 } else if tag.starts_with("equation") || tag.starts_with("eq") || tag.starts_with("math") || tag.starts_with("latex") || tag.starts_with("tex") {
624 return Ok((input, SectionElement::Equation(code_token)));
625 } else if tag.starts_with("diagram") || tag.starts_with("chart") || tag.starts_with("mermaid") {
626 return Ok((input, SectionElement::Diagram(code_token)));
627 } else {
628 }
630 }
631 }
632 Ok((input, SectionElement::CodeBlock(code_token)))
633}
634
635pub fn block_quote(input: ParseString) -> ParseResult<Paragraph> {
636 let (input, _) = quote_sigil(input)?;
637 let (input, _) = many0(space_tab)(input)?;
638 let (input, text) = paragraph(input)?;
639 let (input, _) = many0(space_tab)(input)?;
640 Ok((input, text))
641}
642
643pub fn thematic_break(input: ParseString) -> ParseResult<SectionElement> {
644 let (input, _) = many1(asterisk)(input)?;
645 let (input, _) = many0(space_tab)(input)?;
646 let (input, _) = new_line(input)?;
647 Ok((input, SectionElement::ThematicBreak))
648}
649
650pub fn footnote(input: ParseString) -> ParseResult<Footnote> {
652 let (input, _) = footnote_prefix(input)?;
653 let (input, text) = many1(tuple((is_not(right_bracket),text)))(input)?;
654 let (input, _) = right_bracket(input)?;
655 let (input, _) = colon(input)?;
656 let (input, _) = whitespace0(input)?;
657 let (input, paragraph) = paragraph(input)?;
658 let mut tokens = text.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>();
659 let footnote_text = Token::merge_tokens(&mut tokens).unwrap();
660 let footnote = (footnote_text, paragraph);
661 Ok((input, footnote))
662}
663
664pub fn blank_line(input: ParseString) -> ParseResult<Vec<Token>> {
665 let (input, mut st) = many0(space_tab)(input)?;
666 let (input, n) = new_line(input)?;
667 st.push(n);
668 Ok((input, st))
669}
670
671pub fn abstract_el(input: ParseString) -> ParseResult<Paragraph> {
672 let (input, _) = abstract_sigil(input)?;
673 let (input, _) = many0(space_tab)(input)?;
674 let (input, text) = paragraph(input)?;
675 Ok((input, text))
676}
677
678pub fn equation(input: ParseString) -> ParseResult<Token> {
680 let (input, _) = equation_sigil(input)?;
681 let (input, mut txt) = many1(alt((backslash,text)))(input)?;
682 let mut eqn = Token::merge_tokens(&mut txt).unwrap();
683 Ok((input, eqn))
684}
685
686pub fn citation(input: ParseString) -> ParseResult<Citation> {
688 let (input, _) = left_bracket(input)?;
689 let (input, mut id) = many1(alphanumeric)(input)?;
690 let (input, _) = right_bracket(input)?;
691 let (input, _) = colon(input)?;
692 let (input, _) = whitespace0(input)?;
693 let (input, txt) = paragraph(input)?;
694 let (input, _) = whitespace0(input)?;
695 let id = Token::merge_tokens(&mut id).unwrap();
696 Ok((input, Citation{id, text: txt}))
697}
698
699pub fn float_sigil(input: ParseString) -> ParseResult<FloatDirection> {
701 let (input, d) = alt((float_left, float_right))(input)?;
702 let d = match d.kind {
703 TokenKind::FloatLeft => FloatDirection::Left,
704 TokenKind::FloatRight => FloatDirection::Right,
705 _ => unreachable!(),
706 };
707 Ok((input, d))
708}
709
710pub fn float(input: ParseString) -> ParseResult<(Box<SectionElement>,FloatDirection)> {
712 let (input, direction) = float_sigil(input)?;
713 let (input, _) = many0(space_tab)(input)?;
714 let (input, el) = section_element(input)?;
715 Ok((input, (Box::new(el), direction)))
716}
717
718pub fn section_element(input: ParseString) -> ParseResult<SectionElement> {
720 let (input, section_element) = match many1(mech_code)(input.clone()) {
721 Ok((input, code)) => (input, SectionElement::MechCode(code)),
722 _ =>match mechdown_list(input.clone()) {
723 Ok((input, lst)) => (input, SectionElement::List(lst)),
724 _ => match footnote(input.clone()) {
725 Ok((input, ftnote)) => (input, SectionElement::Footnote(ftnote)),
726 _ => match citation(input.clone()) {
727 Ok((input, citation)) => (input, SectionElement::Citation(citation)),
728 _ => match abstract_el(input.clone()) {
729 Ok((input, abstrct)) => (input, SectionElement::Abstract(abstrct)),
730 _ => match img(input.clone()) {
731 Ok((input, img)) => (input, SectionElement::Image(img)),
732 _ => match equation(input.clone()) {
733 Ok((input, eqn)) => (input, SectionElement::Equation(eqn)),
734 _ => match markdown_table(input.clone()) {
735 Ok((input, table)) => (input, SectionElement::Table(table)),
736 _ => match float(input.clone()) {
737 Ok((input, flt)) => (input, SectionElement::Float(flt)),
738 _ => match block_quote(input.clone()) {
739 Ok((input, quote)) => (input, SectionElement::BlockQuote(quote)),
740 _ => match code_block(input.clone()) {
741 Ok((input, m)) => (input,m),
742 _ => match thematic_break(input.clone()) {
743 Ok((input, _)) => (input, SectionElement::ThematicBreak),
744 _ => match subtitle(input.clone()) {
745 Ok((input, subtitle)) => (input, SectionElement::Subtitle(subtitle)),
746 _ => match paragraph(input) {
747 Ok((input, p)) => (input, SectionElement::Paragraph(p)),
748 Err(err) => { return Err(err); }
749 }
750 }
751 }
752 }
753 }
754 }
755 }
756 }
757 }
758 }
759 }
760 }
761 }
762 };
763 let (input, _) = many0(blank_line)(input)?;
764 Ok((input, section_element))
765}
766
767pub fn section(input: ParseString) -> ParseResult<Section> {
769 let msg = "Expects user function, block, mech code block, code block, statement, paragraph, or unordered list";
770 let (input, subtitle) = ul_subtitle(input)?;
771 let (input, elements) = many0(tuple((is_not(ul_subtitle),section_element)))(input)?;
772 let elements = elements.into_iter().map(|(_,e)| e).collect();
773 Ok((input, Section{subtitle: Some(subtitle), elements}))
774}
775
776pub fn section_elements(input: ParseString) -> ParseResult<Section> {
778 let msg = "Expects user function, block, mech code block, code block, statement, paragraph, or unordered list";
779 let (input, elements) = many1(tuple((is_not(ul_subtitle),section_element)))(input)?;
780 let elements = elements.into_iter().map(|(_,e)| e).collect();
781 Ok((input, Section{subtitle: None, elements}))
782}
783
784pub fn body(input: ParseString) -> ParseResult<Body> {
786 let (input, _) = whitespace0(input)?;
787 let (input, sections) = many0(alt((section,section_elements)))(input)?;
788 let (input, _) = whitespace0(input)?;
789 Ok((input, Body{sections}))
790}