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, pair},
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> {
29 let (input, mut text) = many1(text)(input)?;
30 let (input, _) = new_line(input)?;
31 let (input, _) = many1(equal)(input)?;
32 let (input, _) = many0(space_tab)(input)?;
33 let (input, _) = new_line(input)?;
34 let (input, _) = many0(space_tab)(input)?;
35 let (input, _) = whitespace0(input)?;
36 let mut title = Token::merge_tokens(&mut text).unwrap();
37 title.kind = TokenKind::Title;
38 Ok((input, Title{text: title}))
39}
40
41pub struct MarkdownTableHeader {
42 pub header: Vec<(Token, Token)>,
43}
44
45pub fn no_alignment(input: ParseString) -> ParseResult<ColumnAlignment> {
46 let (input, _) = many1(dash)(input)?;
47 Ok((input, ColumnAlignment::Left))
48}
49
50pub fn left_alignment(input: ParseString) -> ParseResult<ColumnAlignment> {
51 let (input, _) = colon(input)?;
52 let (input, _) = many1(dash)(input)?;
53 Ok((input, ColumnAlignment::Left))
54}
55
56pub fn right_alignment(input: ParseString) -> ParseResult<ColumnAlignment> {
57 let (input, _) = many1(dash)(input)?;
58 let (input, _) = colon(input)?;
59 Ok((input, ColumnAlignment::Right))
60}
61
62pub fn center_alignment(input: ParseString) -> ParseResult<ColumnAlignment> {
63 let (input, _) = colon(input)?;
64 let (input, _) = many1(dash)(input)?;
65 let (input, _) = colon(input)?;
66 Ok((input, ColumnAlignment::Center))
67}
68
69pub fn alignment_separator(input: ParseString) -> ParseResult<ColumnAlignment> {
70 let (input, _) = many0(space_tab)(input)?;
71 let (input, separator) = alt((center_alignment, left_alignment, right_alignment, no_alignment))(input)?;
72 let (input, _) = many0(space_tab)(input)?;
73 Ok((input, separator))
74}
75
76pub fn mechdown_table(input: ParseString) -> ParseResult<MarkdownTable> {
77 let (input, _) = whitespace0(input)?;
78 let (input, table) = alt((mechdown_table_with_header, mechdown_table_no_header))(input)?;
79 Ok((input, table))
80}
81
82pub fn mechdown_table_with_header(input: ParseString) -> ParseResult<MarkdownTable> {
83 let (input, (header,alignment)) = mechdown_table_header(input)?;
84 let (input, rows) = many1(mechdown_table_row)(input)?;
85 Ok((input, MarkdownTable{header, rows, alignment}))
86}
87
88pub fn mechdown_table_no_header(input: ParseString) -> ParseResult<MarkdownTable> {
89 let (input, rows) = many1(mechdown_table_row)(input)?;
90 let header = vec![];
91 let alignment = vec![];
92 Ok((input, MarkdownTable{header, rows, alignment}))
93}
94
95pub fn mechdown_table_header(input: ParseString) -> ParseResult<(Vec<Paragraph>,Vec<ColumnAlignment>)> {
96 let (input, _) = whitespace0(input)?;
97 let (input, header) = many1(tuple((bar, tuple((many0(space_tab), inline_paragraph)))))(input)?;
98 let (input, _) = bar(input)?;
99 let (input, _) = whitespace0(input)?;
100 let (input, alignment) = many1(tuple((bar, tuple((many0(space_tab), alignment_separator)))))(input)?;
101 let (input, _) = bar(input)?;
102 let (input, _) = whitespace0(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 empty_paragraph(input: ParseString) -> ParseResult<Paragraph> {
109 Ok((input, Paragraph{elements: vec![], error_range: None}))
110}
111
112pub fn mechdown_table_row(input: ParseString) -> ParseResult<Vec<Paragraph>> {
114 let (input, _) = whitespace0(input)?;
115 let (input, _) = bar(input)?;
116 let (input, row) = many1(tuple((alt((tuple((many0(space_tab), inline_paragraph)),tuple((many1(space_tab), empty_paragraph)))),bar)))(input)?;
117 let (input, _) = whitespace0(input)?;
118 let row = row.into_iter().map(|((_,tkn),_)| tkn).collect();
119 Ok((input, row))
120}
121
122pub fn ul_subtitle(input: ParseString) -> ParseResult<Subtitle> {
124 let (input, _) = many1((alt((digit_token, alpha_token))))(input)?;
125 let (input, _) = period(input)?;
126 let (input, _) = many0(space_tab)(input)?;
127 let (input, text) = paragraph_newline(input)?;
128 let (input, _) = many1(dash)(input)?;
129 let (input, _) = many0(space_tab)(input)?;
130 let (input, _) = new_line(input)?;
131 let (input, _) = many0(space_tab)(input)?;
132 let (input, _) = whitespace0(input)?;
133 Ok((input, Subtitle{text, level: 2}))
134}
135
136pub fn subtitle(input: ParseString) -> ParseResult<Subtitle> {
138 let (input, _) = peek(is_not(alt((error_sigil, info_sigil))))(input)?;
139 let (input, _) = many0(space_tab)(input)?;
140 let (input, _) = left_parenthesis(input)?;
141 let (input, num) = separated_list1(period,alt((many1(alpha),many1(digit))))(input)?;
142 let (input, _) = right_parenthesis(input)?;
143 let (input, _) = many0(space_tab)(input)?;
144 let (input, text) = paragraph_newline(input)?;
145 let (input, _) = many0(space_tab)(input)?;
146 let (input, _) = whitespace0(input)?;
147 let level: u8 = if num.len() < 3 { 3 } else { num.len() as u8 + 1 };
148 Ok((input, Subtitle{text, level}))
149}
150
151pub fn strong(input: ParseString) -> ParseResult<ParagraphElement> {
153 let (input, _) = tuple((asterisk,asterisk))(input)?;
154 let (input, text) = paragraph_element(input)?;
155 let (input, _) = tuple((asterisk,asterisk))(input)?;
156 Ok((input, ParagraphElement::Strong(Box::new(text))))
157}
158
159pub fn emphasis(input: ParseString) -> ParseResult<ParagraphElement> {
161 let (input, _) = asterisk(input)?;
162 let (input, text) = paragraph_element(input)?;
163 let (input, _) = asterisk(input)?;
164 Ok((input, ParagraphElement::Emphasis(Box::new(text))))
165}
166
167pub fn strikethrough(input: ParseString) -> ParseResult<ParagraphElement> {
169 let (input, _) = tilde(input)?;
170 let (input, text) = paragraph_element(input)?;
171 let (input, _) = tilde(input)?;
172 Ok((input, ParagraphElement::Strikethrough(Box::new(text))))
173}
174
175pub fn underline(input: ParseString) -> ParseResult<ParagraphElement> {
177 let (input, _) = underscore(input)?;
178 let (input, text) = paragraph_element(input)?;
179 let (input, _) = underscore(input)?;
180 Ok((input, ParagraphElement::Underline(Box::new(text))))
181}
182
183pub fn highlight(input: ParseString) -> ParseResult<ParagraphElement> {
185 let (input, _) = highlight_sigil(input)?;
186 let (input, text) = paragraph_element(input)?;
187 let (input, _) = highlight_sigil(input)?;
188 Ok((input, ParagraphElement::Highlight(Box::new(text))))
189}
190
191pub fn inline_code(input: ParseString) -> ParseResult<ParagraphElement> {
193 let (input, _) = is_not(grave_codeblock_sigil)(input)?; let (input, _) = grave(input)?;
195 let (input, text) = many0(tuple((is_not(grave),text)))(input)?;
196 let (input, _) = grave(input)?;
197 let mut text = text.into_iter().map(|(_,tkn)| tkn).collect();
198 let mut text = match Token::merge_tokens(&mut text) {
200 Some(t) => t,
201 None => {
202 return Ok((input, ParagraphElement::InlineCode(Token::default())));
203 }
204 };
205 text.kind = TokenKind::Text;
206 Ok((input, ParagraphElement::InlineCode(text)))
207}
208
209pub fn inline_equation(input: ParseString) -> ParseResult<ParagraphElement> {
211 let (input, _) = equation_sigil(input)?;
212 let (input, txt) = many0(tuple((is_not(equation_sigil),alt((backslash,text)))))(input)?;
213 let (input, _) = equation_sigil(input)?;
214 let mut txt = txt.into_iter().map(|(_,tkn)| tkn).collect();
215 let mut eqn = Token::merge_tokens(&mut txt).unwrap();
216 eqn.kind = TokenKind::Text;
217 Ok((input, ParagraphElement::InlineEquation(eqn)))
218}
219
220pub fn hyperlink(input: ParseString) -> ParseResult<ParagraphElement> {
222 let (input, _) = left_bracket(input)?;
223 let (input, link_text) = inline_paragraph(input)?;
224 let (input, _) = right_bracket(input)?;
225 let (input, _) = left_parenthesis(input)?;
226 let (input, link) = many1(tuple((is_not(right_parenthesis),text)))(input)?;
227 let (input, _) = right_parenthesis(input)?;
228 let mut tokens = link.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>();
229 let link_merged = Token::merge_tokens(&mut tokens).unwrap();
230 Ok((input, ParagraphElement::Hyperlink((link_text, link_merged))))
231}
232
233pub fn raw_hyperlink(input: ParseString) -> ParseResult<ParagraphElement> {
235 let (input, _) = peek(http_prefix)(input)?;
236 let (input, address) = many1(tuple((is_not(space), text)))(input)?;
237 let mut tokens = address.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>();
238 let url_token = Token::merge_tokens(&mut tokens).unwrap();
239 let url_paragraph = Paragraph::from_tokens(vec![url_token.clone()]);
240 Ok((input, ParagraphElement::Hyperlink((url_paragraph, url_token))))
241}
242
243pub fn option_map(input: ParseString) -> ParseResult<OptionMap> {
245 let msg = "Expects right bracket '}' to terminate inline table";
246 let (input, (_, r)) = range(left_brace)(input)?;
247 let (input, _) = whitespace0(input)?;
248 let (input, elements) = many1(option_mapping)(input)?;
249 let (input, _) = whitespace0(input)?;
250 let (input, _) = label!(right_brace, msg, r)(input)?;
251 Ok((input, OptionMap{elements}))
252}
253
254pub fn option_mapping(input: ParseString) -> ParseResult<(Identifier, MechString)> {
256 let msg1 = "Unexpected space before colon ':'";
257 let msg2 = "Expects a value";
258 let msg3 = "Expects whitespace or comma followed by whitespace";
259 let msg4 = "Expects whitespace";
260 let (input, _) = whitespace0(input)?;
261 let (input, key) = identifier(input)?;
262 let (input, _) = whitespace0(input)?;
263 let (input, _) = colon(input)?;
264 let (input, _) = whitespace0(input)?;
265 let (input, value) = string(input)?;
266 let (input, _) = whitespace0(input)?;
267 let (input, _) = opt(comma)(input)?;
268 let (input, _) = whitespace0(input)?;
269 Ok((input, (key, value)))
270}
271
272pub fn img(input: ParseString) -> ParseResult<Image> {
274 let (input, _) = img_prefix(input)?;
275 let (input, caption_text) = opt(inline_paragraph)(input)?;
276 let (input, _) = right_bracket(input)?;
277 let (input, _) = left_parenthesis(input)?;
278 let (input, src) = many1(tuple((is_not(right_parenthesis),text)))(input)?;
279 let (input, _) = right_parenthesis(input)?;
280 let (input, style) = opt(option_map)(input)?;
281 let merged_src = Token::merge_tokens(&mut src.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>()).unwrap();
282 Ok((input, Image{src: merged_src, caption: caption_text, style}))
283}
284
285pub fn paragraph_text(input: ParseString) -> ParseResult<ParagraphElement> {
287 let (input, elements) = match many1(nom_tuple((is_not(alt((section_sigil, footnote_prefix, highlight_sigil, equation_sigil, img_prefix, http_prefix, left_brace, left_bracket, left_angle, right_bracket, tilde, asterisk, underscore, grave, define_operator, bar, mika_section_open, mika_section_close))),text)))(input) {
288 Ok((input, mut text)) => {
289 let mut text = text.into_iter().map(|(_,tkn)| tkn).collect();
290 let mut text = Token::merge_tokens(&mut text).unwrap();
291 text.kind = TokenKind::Text;
292 (input, ParagraphElement::Text(text))
293 },
294 Err(err) => {return Err(err);},
295 };
296 Ok((input, elements))
297}
298
299pub fn eval_inline_mech_code(input: ParseString) -> ParseResult<ParagraphElement> {
301 let (input, _) = left_brace(input)?;
302 let (input, _) = whitespace0(input)?;
303 let (input, expr) = expression(input)?;
304 let (input, _) = whitespace0(input)?;
305 let (input, _) = right_brace(input)?;
306 Ok((input, ParagraphElement::EvalInlineMechCode(expr)))
307}
308
309pub fn inline_mech_code(input: ParseString) -> ParseResult<ParagraphElement> {
311 let (input, _) = left_brace(input)?;
312 let (input, _) = left_brace(input)?;
313 let (input, _) = whitespace0(input)?;
314 let (input, expr) = mech_code_alt(input)?;
315 let (input, _) = whitespace0(input)?;
316 let (input, _) = right_brace(input)?;
317 let (input, _) = right_brace(input)?;
318 Ok((input, ParagraphElement::InlineMechCode(expr)))
319}
320
321pub fn footnote_reference(input: ParseString) -> ParseResult<ParagraphElement> {
323 let (input, _) = footnote_prefix(input)?;
324 let (input, text) = many1(tuple((is_not(right_bracket),text)))(input)?;
325 let (input, _) = right_bracket(input)?;
326 let mut tokens = text.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>();
327 let footnote_text = Token::merge_tokens(&mut tokens).unwrap();
328 Ok((input, ParagraphElement::FootnoteReference(footnote_text)))
329}
330
331pub fn reference(input: ParseString) -> ParseResult<ParagraphElement> {
333 let (input, _) = left_bracket(input)?;
334 let (input, mut txt) = many1(alphanumeric)(input)?;
335 let (input, _) = right_bracket(input)?;
336 let ref_text = Token::merge_tokens(&mut txt).unwrap();
337 Ok((input, ParagraphElement::Reference(ref_text)))
338}
339
340pub fn section_reference(input: ParseString) -> ParseResult<ParagraphElement> {
342 let (input, _) = section_sigil(input)?;
343 let (input, mut txt) = many1(alt((alphanumeric, period)))(input)?;
344 let section_text = Token::merge_tokens(&mut txt).unwrap();
345 Ok((input, ParagraphElement::SectionReference(section_text)))
346}
347
348pub fn paragraph_element(input: ParseString) -> ParseResult<ParagraphElement> {
350 println!("Parsing paragraph element at: {:?}", input.peek(0));
351 alt((hyperlink, reference, section_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)
352}
353
354pub fn inline_paragraph(input: ParseString) -> ParseResult<Paragraph> {
356 let (input, _) = peek(paragraph_element)(input)?;
357 let (input, elements) = many1(
358 pair(
359 is_not(new_line),
360 paragraph_element
361 )
362 )(input)?;
363 let elements = elements.into_iter().map(|(_,elem)| elem).collect();
364 Ok((input, Paragraph{elements, error_range: None}))
365}
366
367pub fn paragraph(input: ParseString) -> ParseResult<Paragraph> {
369 let (input, _) = peek(paragraph_element)(input)?;
370 let (input, elements) = many1(
371 pair(
372 is_not(alt((null(new_line), null(mika_section_close), null(idea_sigil)))),
373 labelr!(paragraph_element,
374 |input| recover::<ParagraphElement, _>(input, skip_till_paragraph_element),
375 "Unexpected paragraph element")
376 )
377 )(input)?;
378 let elements = elements.into_iter().map(|(_,elem)| elem).collect();
379 Ok((input, Paragraph{elements, error_range: None}))
380}
381
382pub fn paragraph_newline(input: ParseString) -> ParseResult<Paragraph> {
384 let (input, elements) = paragraph(input)?;
385 let (input, _) = new_line(input)?;
386 Ok((input, elements))
387}
388
389pub fn ordered_list_item(input: ParseString) -> ParseResult<(Number,Paragraph)> {
391 let (input, number) = number(input)?;
392 let (input, _) = period(input)?;
393 let (input, list_item) = labelr!(paragraph_newline, |input| recover::<Paragraph, _>(input, skip_till_eol), "Expects paragraph as list item")(input)?;
394 Ok((input, (number,list_item)))
395}
396
397pub fn checked_item(input: ParseString) -> ParseResult<(bool,Paragraph)> {
399 let (input, _) = dash(input)?;
400 let (input, _) = left_bracket(input)?;
401 let (input, _) = alt((tag("x"),tag("✓"),tag("✗")))(input)?;
402 let (input, _) = right_bracket(input)?;
403 let (input, list_item) = labelr!(paragraph_newline, |input| recover::<Paragraph, _>(input, skip_till_eol), "Expects paragraph as list item")(input)?;
404 Ok((input, (true,list_item)))
405}
406
407pub fn unchecked_item(input: ParseString) -> ParseResult<(bool,Paragraph)> {
409 let (input, _) = dash(input)?;
410 let (input, _) = left_bracket(input)?;
411 let (input, _) = whitespace0(input)?;
412 let (input, _) = right_bracket(input)?;
413 let (input, list_item) = labelr!(paragraph_newline, |input| recover::<Paragraph, _>(input, skip_till_eol), "Expects paragraph as list item")(input)?;
414 Ok((input, (false,list_item)))
415}
416
417pub fn check_list_item(input: ParseString) -> ParseResult<(bool,Paragraph)> {
419 let (input, item) = alt((checked_item, unchecked_item))(input)?;
420 Ok((input, item))
421}
422
423pub fn check_list(mut input: ParseString, level: usize) -> ParseResult<MDList> {
424 let mut items = vec![];
425 loop {
426 let mut indent = 0;
428 let mut current = input.peek(indent);
429 while current == Some(" ") || current == Some("\t") {
430 indent += 1;
431 current = input.peek(indent);
432 }
433 if indent < level {
435 break;
436 }
437 let (next_input, _) = many0(space_tab)(input.clone())?;
439 let (next_input, list_item) = match check_list_item(next_input.clone()) {
441 Ok((next_input, list_item)) => (next_input, list_item),
442 Err(err) => {
443 if !items.is_empty() {
444 break;
445 } else {
446 return Err(err);
447 }
448 }
449 };
450 let mut lookahead_indent = 0;
452 let mut current = next_input.peek(lookahead_indent);
453 while current == Some(" ") || current == Some("\t") {
454 lookahead_indent += 1;
455 current = next_input.peek(lookahead_indent);
456 }
457 input = next_input;
458 if lookahead_indent < level {
459 items.push((list_item, None));
461 break;
462 } else if lookahead_indent == level {
463 items.push((list_item, None));
465 continue;
466 } else {
467 let (next_input, sublist_md) = sublist(input.clone(), lookahead_indent)?;
469 items.push((list_item, Some(sublist_md)));
470 input = next_input;
471 }
472 }
473 Ok((input, MDList::Check(items)))
474}
475
476
477pub fn unordered_list(mut input: ParseString, level: usize) -> ParseResult<MDList> {
479 let mut items = vec![];
480 loop {
481 let mut indent = 0;
482 let mut current = input.peek(indent);
483 while current == Some(" ") || current == Some("\t") {
484 indent += 1;
485 current = input.peek(indent);
486 }
487 if indent < level {
489 return Ok((input, MDList::Unordered(items)));
490 }
491 let (next_input, _) = many0(space_tab)(input.clone())?;
492 let (next_input, list_item) = match unordered_list_item(next_input.clone()) {
494 Ok((next_input, list_item)) => (next_input, list_item),
495 Err(err) => {
496 if !items.is_empty() {
497 return Ok((input, MDList::Unordered(items)));
498 } else {
499 return Err(err);
500 }
501 }
502 };
503 let mut lookahead_indent = 0;
505 let mut current = next_input.peek(lookahead_indent);
506 while current == Some(" ") || current == Some("\t") {
507 lookahead_indent += 1;
508 current = next_input.peek(lookahead_indent);
509 }
510 input = next_input;
511 if lookahead_indent < level {
512 items.push((list_item, None));
514 return Ok((input, MDList::Unordered(items)));
515 } else if lookahead_indent == level {
516 items.push((list_item, None));
518 continue;
519 } else {
520 let (next_input, sub) = sublist(input.clone(), lookahead_indent)?;
522 items.push((list_item, Some(sub)));
523 input = next_input;
524 }
525 }
526}
527
528pub fn ordered_list(mut input: ParseString, level: usize) -> ParseResult<MDList> {
530 let mut items = vec![];
531 loop {
532 let mut indent = 0;
533 let mut current = input.peek(indent);
534 while current == Some(" ") || current == Some("\t") {
535 indent += 1;
536 current = input.peek(indent);
537 }
538 if indent < level {
540 let start = items.first()
541 .map(|item: &((Number, Paragraph), Option<MDList>)| item.0.0.clone())
542 .unwrap_or(Number::from_integer(1));
543 return Ok((input, MDList::Ordered(OrderedList { start, items })));
544 }
545 let (next_input, _) = many0(space_tab)(input.clone())?;
547 let (next_input, (list_item, _)) = match tuple((ordered_list_item, is_not(tuple((dash, dash)))))(next_input.clone()) {
549 Ok((next_input, res)) => (next_input, res),
550 Err(err) => {
551 if !items.is_empty() {
552 let start = items.first()
553 .map(|((number, _), _)| number.clone())
554 .unwrap_or(Number::from_integer(1));
555 return Ok((input, MDList::Ordered(OrderedList { start, items })));
556 } else {
557 return Err(err);
558 }
559 }
560 };
561
562 let mut lookahead_indent = 0;
564 let mut current = next_input.peek(lookahead_indent);
565 while current == Some(" ") || current == Some("\t") {
566 lookahead_indent += 1;
567 current = next_input.peek(lookahead_indent);
568 }
569
570 input = next_input;
571
572 if lookahead_indent < level {
573 items.push((list_item, None));
574 let start = items.first()
575 .map(|((number, _), _)| number.clone())
576 .unwrap_or(Number::from_integer(1));
577 return Ok((input, MDList::Ordered(OrderedList { start, items })));
578 } else if lookahead_indent == level {
579 items.push((list_item, None));
580 continue;
581 } else {
582 let (next_input, sub) = sublist(input.clone(), lookahead_indent)?;
584 items.push((list_item, Some(sub)));
585 input = next_input;
586 }
587 }
588}
589
590
591
592pub fn sublist(input: ParseString, level: usize) -> ParseResult<MDList> {
593 let (input, list) = match ordered_list(input.clone(), level) {
594 Ok((input, list)) => (input, list),
595 _ => match check_list(input.clone(), level) {
596 Ok((input, list)) => (input, list),
597 _ => match unordered_list(input.clone(), level) {
598 Ok((input, list)) => (input, list),
599 Err(err) => { return Err(err); }
600 }
601 }
602 };
603 Ok((input, list))
604}
605
606pub fn mechdown_list(input: ParseString) -> ParseResult<MDList> {
608 let (input, list) = match ordered_list(input.clone(), 0) {
609 Ok((input, list)) => (input, list),
610 _ => match check_list(input.clone(), 0) {
611 Ok((input, list)) => (input, list),
612 _ => match unordered_list(input.clone(), 0) {
613 Ok((input, list)) => (input, list),
614 Err(err) => { return Err(err); }
615 }
616 }
617 };
618 Ok((input, list))
619}
620
621pub fn unordered_list_item(input: ParseString) -> ParseResult<(Option<Token>,Paragraph)> {
623 let msg1 = "Expects space after dash";
624 let msg2 = "Expects paragraph as list item";
625 let (input, _) = dash(input)?;
626 let (input, bullet) = opt(tuple((left_parenthesis, emoji, right_parenthesis)))(input)?;
627 let (input, _) = labelr!(null(many1(space)), skip_nil, msg1)(input)?;
628 let (input, list_item) = labelr!(paragraph_newline, |input| recover::<Paragraph, _>(input, skip_till_eol), msg2)(input)?;
629 let (input, _) = many0(new_line)(input)?;
630 let bullet = match bullet {
631 Some((_,b,_)) => Some(b),
632 None => None,
633 };
634 Ok((input, (bullet, list_item)))
635}
636
637pub fn codeblock_sigil(input: ParseString) -> ParseResult<fn(ParseString) -> ParseResult<Token>> {
639 let (input, sgl_tkn) = alt((grave_codeblock_sigil, tilde_codeblock_sigil))(input)?;
640 let sgl_cmb = match sgl_tkn.kind {
641 TokenKind::GraveCodeBlockSigil => grave_codeblock_sigil,
642 TokenKind::TildeCodeBlockSigil => tilde_codeblock_sigil,
643 _ => unreachable!(),
644 };
645 Ok((input, sgl_cmb))
646}
647
648pub fn code_block(input: ParseString) -> ParseResult<SectionElement> {
650 let msg1 = "Expects 3 graves to start a code block";
651 let msg2 = "Expects new_line";
652 let msg3 = "Expects 3 graves followed by new_line to terminate a code block";
653 let (input, (end_sgl,r)) = range(codeblock_sigil)(input)?;
654 let (input, _) = many0(space_tab)(input)?;
655 let (input, code_id) = many0(tuple((is_not(left_brace),text)))(input)?;
656 let code_id = code_id.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>();
657 let (input, options) = opt(option_map)(input)?;
658 let (input, _) = many0(space_tab)(input)?;
659 let (input, _) = label!(new_line, msg2)(input)?;
660 let (input, (text,src_range)) = range(many0(nom_tuple((
661 is_not(end_sgl),
662 any,
663 ))))(input)?;
664 let (input, _) = end_sgl(input)?;
665 let (input, _) = whitespace0(input)?;
666 let block_src: Vec<char> = text.into_iter().flat_map(|(_, s)| s.chars().collect::<Vec<char>>()).collect();
667 let code_token = Token::new(TokenKind::CodeBlock, src_range, block_src.clone());
668
669 let code_id = code_id.iter().flat_map(|tkn| tkn.chars.clone().into_iter().collect::<Vec<char>>()).collect::<String>();
670 match code_id.as_str() {
671 "ebnf" => {
672 let ebnf_text = block_src.iter().collect::<String>();
673 match parse_grammar(&ebnf_text) {
674 Ok(grammar_tree) => {return Ok((input, SectionElement::Grammar(grammar_tree)));},
675 Err(err) => {
676 println!("Error parsing EBNF grammar: {:?}", err);
677 todo!();
678 }
679 }
680 }
681 tag => {
682 if tag.starts_with("mech") || tag.starts_with("mec") || tag.starts_with("🤖") {
684
685 let rest = tag.trim_start_matches("mech").trim_start_matches("mec").trim_start_matches("🤖").trim_start_matches(":");
687
688 let config = if rest == "" {BlockConfig { namespace_str: "".to_string(), namespace: 0, disabled: false, hidden: false}}
689 else if rest == "disabled" { BlockConfig { namespace_str: "".to_string(), namespace: 0, disabled: true, hidden: false} }
690 else if rest == "hidden" { BlockConfig { namespace_str: "".to_string(), namespace: 0, disabled: false, hidden: true} }
691 else { BlockConfig { namespace_str: rest.to_string(), namespace: hash_str(rest), disabled: false, hidden: false} };
692
693 let mech_src = block_src.iter().collect::<String>();
694 let graphemes = graphemes::init_source(&mech_src);
695 let parse_string = ParseString::new(&graphemes);
696
697 match mech_code(parse_string) {
698 Ok((_, mech_tree)) => {
699 return Ok((input, SectionElement::FencedMechCode(FencedMechCode{code: mech_tree, config, options})));
701 },
702 Err(err) => {
703 return Err(nom::Err::Error(ParseError {
704 cause_range: SourceRange::default(),
705 remaining_input: input,
706 error_detail: ParseErrorDetail {
707 message: "Generic error parsing Mech code block",
708 annotation_rngs: Vec::new(),
709 },
710 }));
711 }
712 };
713 } else if tag.starts_with("equation") || tag.starts_with("eq") || tag.starts_with("math") || tag.starts_with("latex") || tag.starts_with("tex") {
714 return Ok((input, SectionElement::Equation(code_token)));
715 } else if tag.starts_with("diagram") || tag.starts_with("chart") || tag.starts_with("mermaid") {
716 return Ok((input, SectionElement::Diagram(code_token)));
717 } else {
718 }
720 }
721 }
722 Ok((input, SectionElement::CodeBlock(code_token)))
723}
724
725pub fn thematic_break(input: ParseString) -> ParseResult<SectionElement> {
726 let (input, _) = many1(asterisk)(input)?;
727 let (input, _) = many0(space_tab)(input)?;
728 let (input, _) = new_line(input)?;
729 Ok((input, SectionElement::ThematicBreak))
730}
731
732pub fn footnote(input: ParseString) -> ParseResult<Footnote> {
734 let (input, _) = footnote_prefix(input)?;
735 let (input, text) = many1(tuple((is_not(right_bracket),text)))(input)?;
736 let (input, _) = right_bracket(input)?;
737 let (input, _) = colon(input)?;
738 let (input, _) = whitespace0(input)?;
739 let (input, paragraph) = many1(paragraph_newline)(input)?;
740 let mut tokens = text.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>();
741 let footnote_text = Token::merge_tokens(&mut tokens).unwrap();
742 let footnote = (footnote_text, paragraph);
743 Ok((input, footnote))
744}
745
746pub fn blank_line(input: ParseString) -> ParseResult<Vec<Token>> {
747 let (input, mut st) = many0(space_tab)(input)?;
748 let (input, n) = new_line(input)?;
749 st.push(n);
750 Ok((input, st))
751}
752
753pub fn question_block(input: ParseString) -> ParseResult<SectionElement> {
755 let (input, _) = question_sigil(input)?;
756 let (input, _) = many0(space_tab)(input)?;
757 let (input, paragraphs) = many1(paragraph_newline)(input)?;
758 Ok((input, SectionElement::QuestionBlock(paragraphs)))
759}
760
761pub fn info_block(input: ParseString) -> ParseResult<SectionElement> {
763 let (input, _) = info_sigil(input)?;
764 let (input, _) = many0(space_tab)(input)?;
765 let (input, paragraphs) = many1(paragraph_newline)(input)?;
766 Ok((input, SectionElement::InfoBlock(paragraphs)))
767}
768
769pub fn quote_block(input: ParseString) -> ParseResult<SectionElement> {
771 let (input, _) = peek(is_not(float_sigil))(input)?;
772 let (input, _) = quote_sigil(input)?;
773 let (input, _) = many0(space_tab)(input)?;
774 let (input, paragraphs) = many1(paragraph_newline)(input)?;
775 Ok((input, SectionElement::QuoteBlock(paragraphs)))
776}
777
778pub fn warning_block(input: ParseString) -> ParseResult<SectionElement> {
780 let (input, _) = peek(is_not(float_sigil))(input)?;
781 let (input, _) = warning_sigil(input)?;
782 let (input, _) = many0(space_tab)(input)?;
783 let (input, paragraphs) = many1(paragraph_newline)(input)?;
784 Ok((input, SectionElement::WarningBlock(paragraphs)))
785}
786
787pub fn success_block(input: ParseString) -> ParseResult<SectionElement> {
789 let (input, _) = peek(is_not(float_sigil))(input)?;
790 let (input, _) = alt((success_sigil, success_check_sigil))(input)?;
791 let (input, _) = many0(space_tab)(input)?;
792 let (input, paragraphs) = many1(paragraph_newline)(input)?;
793 Ok((input, SectionElement::SuccessBlock(paragraphs)))
794}
795
796pub fn error_block(input: ParseString) -> ParseResult<SectionElement> {
798 let (input, _) = peek(is_not(float_sigil))(input)?;
799 let (input, _) = alt((error_sigil, error_alt_sigil))(input)?;
800 let (input, _) = many0(space_tab)(input)?;
801 let (input, paragraphs) = many1(paragraph_newline)(input)?;
802 Ok((input, SectionElement::ErrorBlock(paragraphs)))
803}
804
805pub fn idea_block(input: ParseString) -> ParseResult<SectionElement> {
807 let (input, _) = idea_sigil(input)?;
808 let (input, _) = many0(space_tab)(input)?;
809 let (input, paragraphs) = many1(paragraph_newline)(input)?;
810 Ok((input, SectionElement::IdeaBlock(paragraphs)))
811}
812
813pub fn abstract_el(input: ParseString) -> ParseResult<SectionElement> {
815 let (input, _) = abstract_sigil(input)?;
816 let (input, _) = many0(space_tab)(input)?;
817 let (input, paragraphs) = many1(paragraph_newline)(input)?;
818 Ok((input, SectionElement::Abstract(paragraphs)))
819}
820
821pub fn equation(input: ParseString) -> ParseResult<Token> {
823 let (input, _) = equation_sigil(input)?;
824 let (input, mut txt) = many1(alt((backslash,text)))(input)?;
825 let mut eqn = Token::merge_tokens(&mut txt).unwrap();
826 Ok((input, eqn))
827}
828
829pub fn citation(input: ParseString) -> ParseResult<Citation> {
831 let (input, _) = left_bracket(input)?;
832 let (input, mut id) = many1(alphanumeric)(input)?;
833 let (input, _) = right_bracket(input)?;
834 let (input, _) = colon(input)?;
835 let (input, _) = whitespace0(input)?;
836 let (input, txt) = paragraph(input)?;
837 let (input, _) = whitespace0(input)?;
838 let id = Token::merge_tokens(&mut id).unwrap();
839 Ok((input, Citation{id, text: txt}))
840}
841
842pub fn float_sigil(input: ParseString) -> ParseResult<FloatDirection> {
844 let (input, d) = alt((float_left, float_right))(input)?;
845 let d = match d.kind {
846 TokenKind::FloatLeft => FloatDirection::Left,
847 TokenKind::FloatRight => FloatDirection::Right,
848 _ => unreachable!(),
849 };
850 Ok((input, d))
851}
852
853pub fn float(input: ParseString) -> ParseResult<(Box<SectionElement>,FloatDirection)> {
855 let (input, direction) = float_sigil(input)?;
856 let (input, _) = many0(space_tab)(input)?;
857 let (input, el) = section_element(input)?;
858 Ok((input, (Box::new(el), direction)))
859}
860
861pub fn not_mech_code(input: ParseString) -> ParseResult<()> {
863 let (input, _) = alt((null(question_block),
864 null(info_block),
865 null(success_block),
866 null(warning_block),
867 null(error_block),
868 null(idea_block),
869 null(img),
870 null(float)))(input)?;
871 Ok((input, ()))
872}
873
874pub fn section_element(input: ParseString) -> ParseResult<SectionElement> {
876 let parsers: Vec<(&'static str, Box<dyn Fn(ParseString) -> ParseResult<SectionElement>>)> = vec![
877 ("list", Box::new(|i| mechdown_list(i).map(|(i, lst)| (i, SectionElement::List(lst))))),
878 ("footnote", Box::new(|i| footnote(i).map(|(i, f)| (i, SectionElement::Footnote(f))))),
879 ("citation", Box::new(|i| citation(i).map(|(i, c)| (i, SectionElement::Citation(c))))),
880 ("abstract", Box::new(abstract_el)),
881 ("img", Box::new(|i| img(i).map(|(i, img)| (i, SectionElement::Image(img))))),
882 ("equation", Box::new(|i| equation(i).map(|(i, e)| (i, SectionElement::Equation(e))))),
883 ("table", Box::new(|i| mechdown_table(i).map(|(i, t)| (i, SectionElement::Table(t))))),
884 ("float", Box::new(|i| float(i).map(|(i, f)| (i, SectionElement::Float(f))))),
885 ("quote_block", Box::new(quote_block)),
886 ("code_block", Box::new(code_block)),
887 ("thematic_break", Box::new(|i| thematic_break(i).map(|(i, _)| (i, SectionElement::ThematicBreak)))),
888 ("subtitle", Box::new(|i| subtitle(i).map(|(i, s)| (i, SectionElement::Subtitle(s))))),
889 ("question_block", Box::new(question_block)),
890 ("info_block", Box::new(info_block)),
891 ("success_block", Box::new(success_block)),
892 ("warning_block", Box::new(warning_block)),
893 ("error_block", Box::new(error_block)),
894 ("idea_block", Box::new(idea_block)),
895 ("paragraph", Box::new(|i| paragraph(i).map(|(i, p)| (i, SectionElement::Paragraph(p))))),
896 ];
897
898 alt_best(input, &parsers)
899
900}
901
902pub fn section(input: ParseString) -> ParseResult<Section> {
904 let (input, subtitle) = opt(ul_subtitle)(input)?;
905
906 let mut elements = vec![];
907
908 let mut new_input = input.clone();
909
910 loop {
911 if new_input.cursor >= new_input.graphemes.len() {
913 break;
915 }
916
917 if ul_subtitle(new_input.clone()).is_ok() {
919 break;
921 }
922
923 #[cfg(feature = "mika")]
924 if mika_section_close(new_input.clone()).is_ok() {
925 break;
926 }
927
928 #[cfg(feature = "mika")]
938 match mika(new_input.clone()) {
939 Ok((input, mika)) => {
940 println!("Parsed Mika code block: {:#?}", mika);
941 elements.push(SectionElement::Mika(mika));
942 new_input = input;
943 continue;
944 }
945 Err(e) => {
946 }
949 }
950
951 match mech_code(new_input.clone()) {
953 Ok((input, mech_tree)) => {
954 elements.push(SectionElement::MechCode(mech_tree));
955 new_input = input;
956 continue;
957 }
958 Err(e) => {
959 }
962 }
963
964 println!("Parsing section element at: {:?}", new_input.peek(0));
965 match section_element(new_input.clone()) {
966 Ok((input, element)) => {
967
968 elements.push(element);
969
970 let (input, _) = many0(blank_line)(input.clone())?;
972 new_input = input;
973 }
974 Err(err) => {
975 return Err(err);
977 }
978 }
979 }
980 Ok((new_input, Section { subtitle, elements }))
981}
982
983pub fn body(input: ParseString) -> ParseResult<Body> {
985 let (mut input, _) = whitespace0(input)?;
986 let mut sections = vec![];
987 let mut new_input = input.clone();
988 loop {
989 if new_input.cursor >= new_input.graphemes.len() {
990 break;
991 }
992 match section(new_input.clone()) {
994 Ok((input, sect)) => {
995 sections.push(sect);
997 new_input = input;
998 }
999 Err(err) => {
1000 return Err(err);
1001 }
1002 }
1003 }
1004 Ok((new_input, Body { sections }))
1005}