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
24#[derive(Default)]
25pub struct TitleFrontMatter {
26 pub author: Option<Paragraph>,
27 pub date: Option<Paragraph>,
28 pub hero: Option<SectionElement>,
29 pub kicker: Option<Paragraph>,
30 pub summary: Option<Paragraph>,
31 pub next: Option<Paragraph>,
32 pub previous: Option<Paragraph>,
33}
34
35pub fn title(input: ParseString) -> ParseResult<Title> {
40 let (input, mut text) = many1(text)(input)?;
41 let (input, _) = new_line(input)?;
42 let (input, _) = many1(equal)(input)?;
43 let (input, _) = whitespace0(input)?;
44 let (input, front_matter) = opt(title_front_matter)(input)?;
45 let mut title = Token::merge_tokens(&mut text).unwrap();
46 title.kind = TokenKind::Title;
47 let front_matter = front_matter.unwrap_or_default();
48 Ok((input, Title{
49 text: title,
50 author: front_matter.author,
51 date: front_matter.date,
52 hero: front_matter.hero,
53 kicker: front_matter.kicker,
54 summary: front_matter.summary,
55 next: front_matter.next,
56 previous: front_matter.previous,
57 }))
58}
59
60pub fn title_front_matter(input: ParseString) -> ParseResult<TitleFrontMatter> {
61 let mut input = input;
62 let mut front_matter = TitleFrontMatter::default();
63
64 while many1(equal)(input.clone()).is_err() {
65 let (next_input, key) = identifier(input.clone())?;
66 let (next_input, _) = many0(space_tab)(next_input)?;
67 let (next_input, _) = colon(next_input)?;
68 let (next_input, _) = many0(space_tab)(next_input)?;
69 let key_name = key.to_string().to_lowercase();
70
71 if key_name == "hero" {
72 if let Ok((next_input, image)) = img(next_input.clone()) {
73 let (next_input, _) = whitespace0(next_input)?;
74 input = next_input;
75 front_matter.hero = Some(SectionElement::Image(image));
76 continue;
77 } else if let Ok((next_input, figure_table)) = figures(next_input.clone()) {
78 let (next_input, _) = whitespace0(next_input)?;
79 input = next_input;
80 front_matter.hero = Some(SectionElement::FigureTable(figure_table));
81 continue;
82 }
83 }
84
85 let (next_input, paragraph) = inline_paragraph(next_input)?;
86 let (next_input, _) = new_line(next_input)?;
87 input = next_input;
88 match key_name.as_str() {
89 "author" => front_matter.author = Some(paragraph),
90 "date" => front_matter.date = Some(paragraph),
91 "kicker" => front_matter.kicker = Some(paragraph),
92 "summary" => front_matter.summary = Some(paragraph),
93 "next" => front_matter.next = Some(paragraph),
94 "previous" => front_matter.previous = Some(paragraph),
95 _ => (),
96 }
97 }
98
99 let (input, _) = many1(equal)(input)?;
100 let (input, _) = whitespace0(input)?;
101 Ok((input, front_matter))
102}
103
104pub struct MarkdownTableHeader {
105 pub header: Vec<(Token, Token)>,
106}
107
108pub fn no_alignment(input: ParseString) -> ParseResult<ColumnAlignment> {
109 let (input, _) = many1(dash)(input)?;
110 Ok((input, ColumnAlignment::Left))
111}
112
113pub fn left_alignment(input: ParseString) -> ParseResult<ColumnAlignment> {
114 let (input, _) = colon(input)?;
115 let (input, _) = many1(dash)(input)?;
116 Ok((input, ColumnAlignment::Left))
117}
118
119pub fn right_alignment(input: ParseString) -> ParseResult<ColumnAlignment> {
120 let (input, _) = many1(dash)(input)?;
121 let (input, _) = colon(input)?;
122 Ok((input, ColumnAlignment::Right))
123}
124
125pub fn center_alignment(input: ParseString) -> ParseResult<ColumnAlignment> {
126 let (input, _) = colon(input)?;
127 let (input, _) = many1(dash)(input)?;
128 let (input, _) = colon(input)?;
129 Ok((input, ColumnAlignment::Center))
130}
131
132pub fn alignment_separator(input: ParseString) -> ParseResult<ColumnAlignment> {
133 let (input, _) = many0(space_tab)(input)?;
134 let (input, separator) = alt((center_alignment, left_alignment, right_alignment, no_alignment))(input)?;
135 let (input, _) = many0(space_tab)(input)?;
136 Ok((input, separator))
137}
138
139pub fn mechdown_table(input: ParseString) -> ParseResult<MarkdownTable> {
140 let (input, _) = whitespace0(input)?;
141 let (input, table) = alt((mechdown_table_with_header, mechdown_table_no_header))(input)?;
142 Ok((input, table))
143}
144
145pub fn mechdown_table_with_header(input: ParseString) -> ParseResult<MarkdownTable> {
146 let (input, (header,alignment)) = mechdown_table_header(input)?;
147 let (input, rows) = many1(mechdown_table_row)(input)?;
148 Ok((input, MarkdownTable{header, rows, alignment}))
149}
150
151pub fn mechdown_table_no_header(input: ParseString) -> ParseResult<MarkdownTable> {
152 let (input, rows) = many1(mechdown_table_row)(input)?;
153 let header = vec![];
154 let alignment = vec![];
155 Ok((input, MarkdownTable{header, rows, alignment}))
156}
157
158pub fn mechdown_table_header(input: ParseString) -> ParseResult<(Vec<Paragraph>,Vec<ColumnAlignment>)> {
159 let (input, _) = whitespace0(input)?;
160 let (input, header) = many1(tuple((bar, tuple((many0(space_tab), inline_paragraph)))))(input)?;
161 let (input, _) = bar(input)?;
162 let (input, _) = whitespace0(input)?;
163 let (input, alignment) = many1(tuple((bar, tuple((many0(space_tab), alignment_separator)))))(input)?;
164 let (input, _) = bar(input)?;
165 let (input, _) = whitespace0(input)?;
166 let column_names: Vec<Paragraph> = header.into_iter().map(|(_,(_,tkn))| tkn).collect();
167 let column_alignments = alignment.into_iter().map(|(_,(_,tkn))| tkn).collect();
168 Ok((input, (column_names,column_alignments)))
169}
170
171pub fn empty_paragraph(input: ParseString) -> ParseResult<Paragraph> {
172 Ok((input, Paragraph{elements: vec![], error_range: None}))
173}
174
175pub fn mechdown_table_row(input: ParseString) -> ParseResult<Vec<Paragraph>> {
177 let (input, _) = whitespace0(input)?;
178 let (input, _) = bar(input)?;
179 let (input, row) = many1(tuple((alt((tuple((many0(space_tab), inline_paragraph)),tuple((many1(space_tab), empty_paragraph)))),bar)))(input)?;
180 let (input, _) = whitespace0(input)?;
181 let row = row.into_iter().map(|((_,tkn),_)| tkn).collect();
182 Ok((input, row))
183}
184
185pub fn ul_subtitle(input: ParseString) -> ParseResult<Subtitle> {
187 let (input, _) = many1((alt((digit_token, alpha_token))))(input)?;
188 let (input, _) = period(input)?;
189 let (input, _) = many0(space_tab)(input)?;
190 let (input, text) = paragraph_newline(input)?;
191 let (input, _) = many1(dash)(input)?;
192 let (input, _) = many0(space_tab)(input)?;
193 let (input, _) = new_line(input)?;
194 let (input, _) = many0(space_tab)(input)?;
195 let (input, _) = whitespace0(input)?;
196 Ok((input, Subtitle{text, level: 2}))
197}
198
199pub fn subtitle(input: ParseString) -> ParseResult<Subtitle> {
201 let (input, _) = peek(is_not(alt((error_sigil, info_sigil))))(input)?;
202 let (input, _) = many0(space_tab)(input)?;
203 let (input, _) = left_parenthesis(input)?;
204 let (input, num) = separated_list1(period,alt((many1(alpha),many1(digit))))(input)?;
205 let (input, _) = right_parenthesis(input)?;
206 let (input, _) = many0(space_tab)(input)?;
207 let (input, text) = paragraph_newline(input)?;
208 let (input, _) = many0(space_tab)(input)?;
209 let (input, _) = whitespace0(input)?;
210 let level: u8 = if num.len() < 3 { 3 } else { num.len() as u8 + 1 };
211 Ok((input, Subtitle{text, level}))
212}
213
214pub fn strong(input: ParseString) -> ParseResult<ParagraphElement> {
216 let (input, _) = tuple((asterisk,asterisk))(input)?;
217 let (input, text) = paragraph_element(input)?;
218 let (input, _) = tuple((asterisk,asterisk))(input)?;
219 Ok((input, ParagraphElement::Strong(Box::new(text))))
220}
221
222pub fn emphasis(input: ParseString) -> ParseResult<ParagraphElement> {
224 let (input, _) = asterisk(input)?;
225 let (input, text) = paragraph_element(input)?;
226 let (input, _) = asterisk(input)?;
227 Ok((input, ParagraphElement::Emphasis(Box::new(text))))
228}
229
230pub fn strikethrough(input: ParseString) -> ParseResult<ParagraphElement> {
232 let (input, _) = tilde(input)?;
233 let (input, text) = paragraph_element(input)?;
234 let (input, _) = tilde(input)?;
235 Ok((input, ParagraphElement::Strikethrough(Box::new(text))))
236}
237
238pub fn underline(input: ParseString) -> ParseResult<ParagraphElement> {
240 let (input, _) = underscore(input)?;
241 let (input, text) = paragraph_element(input)?;
242 let (input, _) = underscore(input)?;
243 Ok((input, ParagraphElement::Underline(Box::new(text))))
244}
245
246pub fn highlight(input: ParseString) -> ParseResult<ParagraphElement> {
248 let (input, _) = highlight_sigil(input)?;
249 let (input, text) = paragraph_element(input)?;
250 let (input, _) = highlight_sigil(input)?;
251 Ok((input, ParagraphElement::Highlight(Box::new(text))))
252}
253
254pub fn inline_code(input: ParseString) -> ParseResult<ParagraphElement> {
256 let (input, _) = is_not(grave_codeblock_sigil)(input)?; let (input, _) = grave(input)?;
258 let (input, text) = many0(tuple((is_not(grave),text)))(input)?;
259 let (input, _) = grave(input)?;
260 let mut text = text.into_iter().map(|(_,tkn)| tkn).collect();
261 let mut text = match Token::merge_tokens(&mut text) {
263 Some(t) => t,
264 None => {
265 return Ok((input, ParagraphElement::InlineCode(Token::default())));
266 }
267 };
268 text.kind = TokenKind::Text;
269 Ok((input, ParagraphElement::InlineCode(text)))
270}
271
272pub fn inline_equation(input: ParseString) -> ParseResult<ParagraphElement> {
274 let (input, _) = equation_sigil(input)?;
275 let (input, txt) = many0(tuple((is_not(equation_sigil),alt((backslash,text)))))(input)?;
276 let (input, _) = equation_sigil(input)?;
277 let mut txt = txt.into_iter().map(|(_,tkn)| tkn).collect();
278 let mut eqn = Token::merge_tokens(&mut txt).unwrap();
279 eqn.kind = TokenKind::Text;
280 Ok((input, ParagraphElement::InlineEquation(eqn)))
281}
282
283pub fn hyperlink(input: ParseString) -> ParseResult<ParagraphElement> {
285 let (input, _) = left_bracket(input)?;
286 let (input, link_text) = inline_paragraph(input)?;
287 let (input, _) = right_bracket(input)?;
288 let (input, _) = left_parenthesis(input)?;
289 let (input, link) = many1(tuple((is_not(right_parenthesis),text)))(input)?;
290 let (input, _) = right_parenthesis(input)?;
291 let mut tokens = link.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>();
292 let link_merged = Token::merge_tokens(&mut tokens).unwrap();
293 Ok((input, ParagraphElement::Hyperlink((link_text, link_merged))))
294}
295
296pub fn raw_hyperlink(input: ParseString) -> ParseResult<ParagraphElement> {
298 let (input, _) = peek(http_prefix)(input)?;
299 let (input, address) = many1(tuple((is_not(space), text)))(input)?;
300 let mut tokens = address.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>();
301 let url_token = Token::merge_tokens(&mut tokens).unwrap();
302 let url_paragraph = Paragraph::from_tokens(vec![url_token.clone()]);
303 Ok((input, ParagraphElement::Hyperlink((url_paragraph, url_token))))
304}
305
306pub fn option_map(input: ParseString) -> ParseResult<OptionMap> {
308 let msg = "Expects right bracket '}' to terminate map.";
309 let (input, (_, r)) = range(left_brace)(input)?;
310 let (input, _) = whitespace0(input)?;
311 let (input, elements) = many1(option_mapping)(input)?;
312 let (input, _) = whitespace0(input)?;
313 let (input, _) = label!(right_brace, msg, r)(input)?;
314 Ok((input, OptionMap{elements}))
315}
316
317pub fn option_mapping(input: ParseString) -> ParseResult<(Identifier, MechString)> {
319 let msg1 = "Unexpected space before colon ':'";
320 let msg2 = "Expects a value";
321 let msg3 = "Expects whitespace or comma followed by whitespace";
322 let msg4 = "Expects whitespace";
323 let (input, _) = whitespace0(input)?;
324 let (input, key) = identifier(input)?;
325 let (input, _) = whitespace0(input)?;
326 let (input, _) = colon(input)?;
327 let (input, _) = whitespace0(input)?;
328 let (input, value) = option_value(input)?;
329 let (input, _) = whitespace0(input)?;
330 let (input, _) = opt(comma)(input)?;
331 let (input, _) = whitespace0(input)?;
332 Ok((input, (key, value)))
333}
334
335pub fn option_value(input: ParseString) -> ParseResult<MechString> {
337 if let Ok((input, value)) = string(input.clone()) {
338 return Ok((input, value));
339 }
340 let (input, mut identifier_value) = identifier(input)?;
341 identifier_value.name.kind = TokenKind::String;
342 Ok((input, MechString { text: identifier_value.name }))
343}
344
345pub fn img(input: ParseString) -> ParseResult<Image> {
347 let (input, _) = img_prefix(input)?;
348 let (input, caption_text) = opt(inline_paragraph)(input)?;
349 let (input, _) = right_bracket(input)?;
350 let (input, _) = left_parenthesis(input)?;
351 let (input, src) = many1(tuple((is_not(right_parenthesis),text)))(input)?;
352 let (input, _) = right_parenthesis(input)?;
353 let (input, style) = opt(option_map)(input)?;
354 let merged_src = Token::merge_tokens(&mut src.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>()).unwrap();
355 Ok((input, Image{src: merged_src, caption: caption_text, style}))
356}
357
358pub fn figure_item(input: ParseString) -> ParseResult<FigureItem> {
359 let (input, image) = img(input)?;
360 let caption = image.caption.unwrap_or(Paragraph { elements: vec![], error_range: None });
361 Ok((input, FigureItem { src: image.src, caption }))
362}
363
364pub fn figures_row(input: ParseString) -> ParseResult<Vec<FigureItem>> {
366 let (input, _) = whitespace0(input)?;
367 let (input, _) = bar(input)?;
368 let (input, cells) = many1(tuple((many0(space_tab), figure_item, many0(space_tab), bar)))(input)?;
369 let (input, _) = whitespace0(input)?;
370 let row = cells.into_iter().map(|(_, item, _, _)| item).collect();
371 Ok((input, row))
372}
373
374pub fn figures(input: ParseString) -> ParseResult<FigureTable> {
376 let (input, rows) = many1(figures_row)(input)?;
377 Ok((input, FigureTable { rows }))
378}
379
380pub fn paragraph_text(input: ParseString) -> ParseResult<ParagraphElement> {
382 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) {
383 Ok((input, mut text)) => {
384 let mut text = text.into_iter().map(|(_,tkn)| tkn).collect();
385 let mut text = Token::merge_tokens(&mut text).unwrap();
386 text.kind = TokenKind::Text;
387 (input, ParagraphElement::Text(text))
388 },
389 Err(err) => {return Err(err);},
390 };
391 Ok((input, elements))
392}
393
394pub fn eval_inline_mech_code(input: ParseString) -> ParseResult<ParagraphElement> {
396 let (input, _) = left_brace(input)?;
397 let (input, _) = whitespace0(input)?;
398 let (input, expr) = expression(input)?;
399 let (input, _) = whitespace0(input)?;
400 let (input, _) = right_brace(input)?;
401 Ok((input, ParagraphElement::EvalInlineMechCode(expr)))
402}
403
404pub fn inline_mech_code(input: ParseString) -> ParseResult<ParagraphElement> {
406 let (input, _) = left_brace(input)?;
407 let (input, _) = left_brace(input)?;
408 let (input, _) = whitespace0(input)?;
409 let (input, expr) = mech_code_alt(input)?;
410 let (input, _) = whitespace0(input)?;
411 let (input, _) = right_brace(input)?;
412 let (input, _) = right_brace(input)?;
413 Ok((input, ParagraphElement::InlineMechCode(expr)))
414}
415
416pub fn footnote_reference(input: ParseString) -> ParseResult<ParagraphElement> {
418 let (input, _) = footnote_prefix(input)?;
419 let (input, text) = many1(tuple((is_not(right_bracket),text)))(input)?;
420 let (input, _) = right_bracket(input)?;
421 let mut tokens = text.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>();
422 let footnote_text = Token::merge_tokens(&mut tokens).unwrap();
423 Ok((input, ParagraphElement::FootnoteReference(footnote_text)))
424}
425
426pub fn reference(input: ParseString) -> ParseResult<ParagraphElement> {
428 let (input, _) = left_bracket(input)?;
429 let (input, mut txt) = many1(alphanumeric)(input)?;
430 let (input, _) = right_bracket(input)?;
431 let ref_text = Token::merge_tokens(&mut txt).unwrap();
432 Ok((input, ParagraphElement::Reference(ref_text)))
433}
434
435pub fn section_reference(input: ParseString) -> ParseResult<ParagraphElement> {
437 let (input, _) = section_sigil(input)?;
438 let (input, mut txt) = many1(alt((alphanumeric, period)))(input)?;
439 let section_text = Token::merge_tokens(&mut txt).unwrap();
440 Ok((input, ParagraphElement::SectionReference(section_text)))
441}
442
443pub fn paragraph_element(input: ParseString) -> ParseResult<ParagraphElement> {
445 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)
446}
447
448pub fn inline_paragraph(input: ParseString) -> ParseResult<Paragraph> {
450 let (input, _) = peek(paragraph_element)(input)?;
451 let (input, elements) = many1(
452 pair(
453 is_not(new_line),
454 paragraph_element
455 )
456 )(input)?;
457 let elements = elements.into_iter().map(|(_,elem)| elem).collect();
458 Ok((input, Paragraph{elements, error_range: None}))
459}
460
461pub fn paragraph(input: ParseString) -> ParseResult<Paragraph> {
463 let (input, _) = peek(paragraph_element)(input)?;
464 let (input, elements) = many1(
465 pair(
466 is_not(alt((null(new_line), null(mika_section_close), null(idea_sigil)))),
467 labelr!(paragraph_element,
468 |input| recover::<ParagraphElement, _>(input, skip_till_paragraph_element),
469 "Unexpected paragraph element")
470 )
471 )(input)?;
472 let elements = elements.into_iter().map(|(_,elem)| elem).collect();
473 Ok((input, Paragraph{elements, error_range: None}))
474}
475
476pub fn paragraph_newline(input: ParseString) -> ParseResult<Paragraph> {
478 let (input, elements) = paragraph(input)?;
479 let (input, _) = new_line(input)?;
480 Ok((input, elements))
481}
482
483pub fn ordered_list_item(input: ParseString) -> ParseResult<(Number,Paragraph)> {
485 let (input, number) = number(input)?;
486 let (input, _) = period(input)?;
487 let (input, list_item) = labelr!(paragraph_newline, |input| recover::<Paragraph, _>(input, skip_till_eol), "Expects paragraph as list item")(input)?;
488 Ok((input, (number,list_item)))
489}
490
491pub fn checked_item(input: ParseString) -> ParseResult<(bool,Paragraph)> {
493 let (input, _) = dash(input)?;
494 let (input, _) = left_bracket(input)?;
495 let (input, _) = alt((tag("x"),tag("✓"),tag("✗")))(input)?;
496 let (input, _) = right_bracket(input)?;
497 let (input, list_item) = labelr!(paragraph_newline, |input| recover::<Paragraph, _>(input, skip_till_eol), "Expects paragraph as list item")(input)?;
498 Ok((input, (true,list_item)))
499}
500
501pub fn unchecked_item(input: ParseString) -> ParseResult<(bool,Paragraph)> {
503 let (input, _) = dash(input)?;
504 let (input, _) = left_bracket(input)?;
505 let (input, _) = whitespace0(input)?;
506 let (input, _) = right_bracket(input)?;
507 let (input, list_item) = labelr!(paragraph_newline, |input| recover::<Paragraph, _>(input, skip_till_eol), "Expects paragraph as list item")(input)?;
508 Ok((input, (false,list_item)))
509}
510
511pub fn check_list_item(input: ParseString) -> ParseResult<(bool,Paragraph)> {
513 let (input, item) = alt((checked_item, unchecked_item))(input)?;
514 Ok((input, item))
515}
516
517pub fn check_list(mut input: ParseString, level: usize) -> ParseResult<MDList> {
518 let mut items = vec![];
519 loop {
520 let mut indent = 0;
522 let mut current = input.peek(indent);
523 while current == Some(" ") || current == Some("\t") {
524 indent += 1;
525 current = input.peek(indent);
526 }
527 if indent < level {
529 break;
530 }
531 let (next_input, _) = many0(space_tab)(input.clone())?;
533 let (next_input, list_item) = match check_list_item(next_input.clone()) {
535 Ok((next_input, list_item)) => (next_input, list_item),
536 Err(err) => {
537 if !items.is_empty() {
538 break;
539 } else {
540 return Err(err);
541 }
542 }
543 };
544 let mut lookahead_indent = 0;
546 let mut current = next_input.peek(lookahead_indent);
547 while current == Some(" ") || current == Some("\t") {
548 lookahead_indent += 1;
549 current = next_input.peek(lookahead_indent);
550 }
551 input = next_input;
552 if lookahead_indent < level {
553 items.push((list_item, None));
555 break;
556 } else if lookahead_indent == level {
557 items.push((list_item, None));
559 continue;
560 } else {
561 let (next_input, sublist_md) = sublist(input.clone(), lookahead_indent)?;
563 items.push((list_item, Some(sublist_md)));
564 input = next_input;
565 }
566 }
567 Ok((input, MDList::Check(items)))
568}
569
570
571pub fn unordered_list(mut input: ParseString, level: usize) -> ParseResult<MDList> {
573 let mut items = vec![];
574 loop {
575 let mut indent = 0;
576 let mut current = input.peek(indent);
577 while current == Some(" ") || current == Some("\t") {
578 indent += 1;
579 current = input.peek(indent);
580 }
581 if indent < level {
583 return Ok((input, MDList::Unordered(items)));
584 }
585 let (next_input, _) = many0(space_tab)(input.clone())?;
586 let (next_input, list_item) = match unordered_list_item(next_input.clone()) {
588 Ok((next_input, list_item)) => (next_input, list_item),
589 Err(err) => {
590 if !items.is_empty() {
591 return Ok((input, MDList::Unordered(items)));
592 } else {
593 return Err(err);
594 }
595 }
596 };
597 let mut lookahead_indent = 0;
599 let mut current = next_input.peek(lookahead_indent);
600 while current == Some(" ") || current == Some("\t") {
601 lookahead_indent += 1;
602 current = next_input.peek(lookahead_indent);
603 }
604 input = next_input;
605 if lookahead_indent < level {
606 items.push((list_item, None));
608 return Ok((input, MDList::Unordered(items)));
609 } else if lookahead_indent == level {
610 items.push((list_item, None));
612 continue;
613 } else {
614 let (next_input, sub) = sublist(input.clone(), lookahead_indent)?;
616 items.push((list_item, Some(sub)));
617 input = next_input;
618 }
619 }
620}
621
622pub fn ordered_list(mut input: ParseString, level: usize) -> ParseResult<MDList> {
624 let mut items = vec![];
625 loop {
626 let mut indent = 0;
627 let mut current = input.peek(indent);
628 while current == Some(" ") || current == Some("\t") {
629 indent += 1;
630 current = input.peek(indent);
631 }
632 if indent < level {
634 let start = items.first()
635 .map(|item: &((Number, Paragraph), Option<MDList>)| item.0.0.clone())
636 .unwrap_or(Number::from_integer(1));
637 return Ok((input, MDList::Ordered(OrderedList { start, items })));
638 }
639 let (next_input, _) = many0(space_tab)(input.clone())?;
641 let (next_input, (list_item, _)) = match tuple((ordered_list_item, is_not(tuple((dash, dash)))))(next_input.clone()) {
643 Ok((next_input, res)) => (next_input, res),
644 Err(err) => {
645 if !items.is_empty() {
646 let start = items.first()
647 .map(|((number, _), _)| number.clone())
648 .unwrap_or(Number::from_integer(1));
649 return Ok((input, MDList::Ordered(OrderedList { start, items })));
650 } else {
651 return Err(err);
652 }
653 }
654 };
655
656 let mut lookahead_indent = 0;
658 let mut current = next_input.peek(lookahead_indent);
659 while current == Some(" ") || current == Some("\t") {
660 lookahead_indent += 1;
661 current = next_input.peek(lookahead_indent);
662 }
663
664 input = next_input;
665
666 if lookahead_indent < level {
667 items.push((list_item, None));
668 let start = items.first()
669 .map(|((number, _), _)| number.clone())
670 .unwrap_or(Number::from_integer(1));
671 return Ok((input, MDList::Ordered(OrderedList { start, items })));
672 } else if lookahead_indent == level {
673 items.push((list_item, None));
674 continue;
675 } else {
676 let (next_input, sub) = sublist(input.clone(), lookahead_indent)?;
678 items.push((list_item, Some(sub)));
679 input = next_input;
680 }
681 }
682}
683
684
685
686pub fn sublist(input: ParseString, level: usize) -> ParseResult<MDList> {
687 let (input, list) = match ordered_list(input.clone(), level) {
688 Ok((input, list)) => (input, list),
689 _ => match check_list(input.clone(), level) {
690 Ok((input, list)) => (input, list),
691 _ => match unordered_list(input.clone(), level) {
692 Ok((input, list)) => (input, list),
693 Err(err) => { return Err(err); }
694 }
695 }
696 };
697 Ok((input, list))
698}
699
700pub fn mechdown_list(input: ParseString) -> ParseResult<MDList> {
702 let (input, list) = match ordered_list(input.clone(), 0) {
703 Ok((input, list)) => (input, list),
704 _ => match check_list(input.clone(), 0) {
705 Ok((input, list)) => (input, list),
706 _ => match unordered_list(input.clone(), 0) {
707 Ok((input, list)) => (input, list),
708 Err(err) => { return Err(err); }
709 }
710 }
711 };
712 Ok((input, list))
713}
714
715pub fn unordered_list_item(input: ParseString) -> ParseResult<(Option<Token>,Paragraph)> {
717 let msg1 = "Expects space after dash";
718 let msg2 = "Expects paragraph as list item";
719 let (input, _) = dash(input)?;
720 let (input, bullet) = opt(tuple((left_parenthesis, emoji, right_parenthesis)))(input)?;
721 let (input, _) = labelr!(null(many1(space)), skip_nil, msg1)(input)?;
722 let (input, list_item) = labelr!(paragraph_newline, |input| recover::<Paragraph, _>(input, skip_till_eol), msg2)(input)?;
723 let (input, _) = many0(new_line)(input)?;
724 let bullet = match bullet {
725 Some((_,b,_)) => Some(b),
726 None => None,
727 };
728 Ok((input, (bullet, list_item)))
729}
730
731pub fn codeblock_sigil(input: ParseString) -> ParseResult<fn(ParseString) -> ParseResult<Token>> {
733 let (input, sgl_tkn) = alt((grave_codeblock_sigil, tilde_codeblock_sigil))(input)?;
734 let sgl_cmb = match sgl_tkn.kind {
735 TokenKind::GraveCodeBlockSigil => grave_codeblock_sigil,
736 TokenKind::TildeCodeBlockSigil => tilde_codeblock_sigil,
737 _ => unreachable!(),
738 };
739 Ok((input, sgl_cmb))
740}
741
742pub fn code_block(input: ParseString) -> ParseResult<SectionElement> {
744 let msg1 = "Expects 3 graves to start a code block";
745 let msg2 = "Expects new_line";
746 let msg3 = "Expects 3 graves followed by new_line to terminate a code block";
747 let (input, (end_sgl,r)) = range(codeblock_sigil)(input)?;
748 let (input, _) = many0(space_tab)(input)?;
749 let (input, code_id) = many0(tuple((is_not(left_brace),text)))(input)?;
750 let code_id = code_id.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>();
751 let (input, options) = opt(option_map)(input)?;
752 let (input, _) = many0(space_tab)(input)?;
753 let (input, _) = label!(new_line, msg2)(input)?;
754 let (input, (text,src_range)) = range(many0(nom_tuple((
755 is_not(end_sgl),
756 any,
757 ))))(input)?;
758 let (input, _) = end_sgl(input)?;
759 let (input, _) = whitespace0(input)?;
760 let block_src: Vec<char> = text.into_iter().flat_map(|(_, s)| s.chars().collect::<Vec<char>>()).collect();
761 let code_token = Token::new(TokenKind::CodeBlock, src_range, block_src.clone());
762
763 let code_id = code_id.iter().flat_map(|tkn| tkn.chars.clone().into_iter().collect::<Vec<char>>()).collect::<String>();
764 match code_id.as_str() {
765 "ebnf" => {
766 let ebnf_text = block_src.iter().collect::<String>();
767 match parse_grammar(&ebnf_text) {
768 Ok(grammar_tree) => {return Ok((input, SectionElement::Grammar(grammar_tree)));},
769 Err(err) => {
770 println!("Error parsing EBNF grammar: {:?}", err);
771 todo!();
772 }
773 }
774 }
775 tag => {
776 if tag.starts_with("mech") || tag.starts_with("mec") || tag.starts_with("🤖") {
778
779 let rest = tag.trim_start_matches("mech").trim_start_matches("mec").trim_start_matches("🤖").trim_start_matches(":");
781
782 let mut config = if rest == "" {BlockConfig { namespace_str: "".to_string(), namespace: 0, disabled: false, hidden: false, output: true}}
783 else if rest == "disabled" { BlockConfig { namespace_str: "".to_string(), namespace: 0, disabled: true, hidden: false, output: true} }
784 else if rest == "hidden" { BlockConfig { namespace_str: "".to_string(), namespace: 0, disabled: false, hidden: true, output: true} }
785 else { BlockConfig { namespace_str: rest.to_string(), namespace: hash_str(rest), disabled: false, hidden: false, output: true} };
786
787 if let Some(options_map) = &options {
788 for (key, value) in &options_map.elements {
789 if key.to_string() == "output" {
790 let output_value = value.to_string().trim().trim_matches('"').to_ascii_lowercase();
791 config.output = !matches!(output_value.as_str(), "false" | "no" | "off" | "0");
792 }
793 }
794 }
795
796 let mech_src = block_src.iter().collect::<String>();
797 let graphemes = graphemes::init_source(&mech_src);
798 let parse_string = ParseString::new(&graphemes);
799
800 match mech_code(parse_string) {
801 Ok((_, mech_tree)) => {
802 return Ok((input, SectionElement::FencedMechCode(FencedMechCode{code: mech_tree, config, options})));
804 },
805 Err(err) => {
806 return Err(nom::Err::Error(ParseError {
807 cause_range: SourceRange::default(),
808 remaining_input: input,
809 error_detail: ParseErrorDetail {
810 message: "Generic error parsing Mech code block",
811 annotation_rngs: Vec::new(),
812 },
813 }));
814 }
815 };
816 } else if tag.starts_with("equation") || tag.starts_with("eq") || tag.starts_with("math") || tag.starts_with("latex") || tag.starts_with("tex") {
817 return Ok((input, SectionElement::Equation(code_token)));
818 } else if tag.starts_with("diagram") || tag.starts_with("chart") || tag.starts_with("mermaid") {
819 return Ok((input, SectionElement::Diagram(code_token)));
820 } else {
821 }
823 }
824 }
825 Ok((input, SectionElement::CodeBlock(code_token)))
826}
827
828pub fn thematic_break(input: ParseString) -> ParseResult<SectionElement> {
829 let (input, _) = many1(asterisk)(input)?;
830 let (input, _) = many0(space_tab)(input)?;
831 let (input, _) = new_line(input)?;
832 Ok((input, SectionElement::ThematicBreak))
833}
834
835pub fn footnote(input: ParseString) -> ParseResult<Footnote> {
837 let (input, _) = footnote_prefix(input)?;
838 let (input, text) = many1(tuple((is_not(right_bracket),text)))(input)?;
839 let (input, _) = right_bracket(input)?;
840 let (input, _) = colon(input)?;
841 let (input, _) = whitespace0(input)?;
842 let (input, paragraph) = many1(paragraph_newline)(input)?;
843 let mut tokens = text.into_iter().map(|(_,tkn)| tkn).collect::<Vec<Token>>();
844 let footnote_text = Token::merge_tokens(&mut tokens).unwrap();
845 let footnote = (footnote_text, paragraph);
846 Ok((input, footnote))
847}
848
849pub fn prompt(input: ParseString) -> ParseResult<SectionElement> {
851 let (input, _) = prompt_sigil(input)?;
852 let (input, _) = many0(space_tab)(input)?;
853 let (input, element) = section_element(input)?;
854 Ok((input, SectionElement::Prompt(Box::new(element))))
855}
856
857pub fn blank_line(input: ParseString) -> ParseResult<Vec<Token>> {
858 let (input, mut st) = many0(space_tab)(input)?;
859 let (input, n) = new_line(input)?;
860 st.push(n);
861 Ok((input, st))
862}
863
864pub fn question_block(input: ParseString) -> ParseResult<SectionElement> {
866 let (input, _) = question_sigil(input)?;
867 let (input, _) = many0(space_tab)(input)?;
868 let (input, paragraphs) = many1(paragraph_newline)(input)?;
869 Ok((input, SectionElement::QuestionBlock(paragraphs)))
870}
871
872pub fn info_block(input: ParseString) -> ParseResult<SectionElement> {
874 let (input, _) = info_sigil(input)?;
875 let (input, _) = many0(space_tab)(input)?;
876 let (input, paragraphs) = many1(paragraph_newline)(input)?;
877 Ok((input, SectionElement::InfoBlock(paragraphs)))
878}
879
880pub fn quote_block(input: ParseString) -> ParseResult<SectionElement> {
882 let (input, _) = peek(is_not(float_sigil))(input)?;
883 let (input, _) = peek(is_not(prompt_sigil))(input)?;
884 let (input, _) = quote_sigil(input)?;
885 let (input, _) = many0(space_tab)(input)?;
886 let (input, paragraphs) = many1(paragraph_newline)(input)?;
887 Ok((input, SectionElement::QuoteBlock(paragraphs)))
888}
889
890pub fn warning_block(input: ParseString) -> ParseResult<SectionElement> {
892 let (input, _) = peek(is_not(float_sigil))(input)?;
893 let (input, _) = warning_sigil(input)?;
894 let (input, _) = many0(space_tab)(input)?;
895 let (input, paragraphs) = many1(paragraph_newline)(input)?;
896 Ok((input, SectionElement::WarningBlock(paragraphs)))
897}
898
899pub fn success_block(input: ParseString) -> ParseResult<SectionElement> {
901 let (input, _) = peek(is_not(float_sigil))(input)?;
902 let (input, _) = alt((success_sigil, success_check_sigil))(input)?;
903 let (input, _) = many0(space_tab)(input)?;
904 let (input, paragraphs) = many1(paragraph_newline)(input)?;
905 Ok((input, SectionElement::SuccessBlock(paragraphs)))
906}
907
908pub fn error_block(input: ParseString) -> ParseResult<SectionElement> {
910 let (input, _) = peek(is_not(float_sigil))(input)?;
911 let (input, _) = alt((error_sigil, error_alt_sigil))(input)?;
912 let (input, _) = many0(space_tab)(input)?;
913 let (input, paragraphs) = many1(paragraph_newline)(input)?;
914 Ok((input, SectionElement::ErrorBlock(paragraphs)))
915}
916
917pub fn idea_block(input: ParseString) -> ParseResult<SectionElement> {
919 let (input, _) = idea_sigil(input)?;
920 let (input, _) = many0(space_tab)(input)?;
921 let (input, paragraphs) = many1(paragraph_newline)(input)?;
922 Ok((input, SectionElement::IdeaBlock(paragraphs)))
923}
924
925pub fn abstract_el(input: ParseString) -> ParseResult<SectionElement> {
927 let (input, _) = abstract_sigil(input)?;
928 let (input, _) = many0(space_tab)(input)?;
929 let (input, paragraphs) = many1(paragraph_newline)(input)?;
930 Ok((input, SectionElement::Abstract(paragraphs)))
931}
932
933pub fn equation(input: ParseString) -> ParseResult<Token> {
935 let (input, _) = equation_sigil(input)?;
936 let (input, mut txt) = many1(alt((backslash,text)))(input)?;
937 let mut eqn = Token::merge_tokens(&mut txt).unwrap();
938 Ok((input, eqn))
939}
940
941pub fn citation(input: ParseString) -> ParseResult<Citation> {
943 let (input, _) = left_bracket(input)?;
944 let (input, mut id) = many1(alphanumeric)(input)?;
945 let (input, _) = right_bracket(input)?;
946 let (input, _) = colon(input)?;
947 let (input, _) = whitespace0(input)?;
948 let (input, txt) = paragraph(input)?;
949 let (input, _) = whitespace0(input)?;
950 let id = Token::merge_tokens(&mut id).unwrap();
951 Ok((input, Citation{id, text: txt}))
952}
953
954pub fn float_sigil(input: ParseString) -> ParseResult<FloatDirection> {
956 let (input, d) = alt((float_left, float_right))(input)?;
957 let d = match d.kind {
958 TokenKind::FloatLeft => FloatDirection::Left,
959 TokenKind::FloatRight => FloatDirection::Right,
960 _ => unreachable!(),
961 };
962 Ok((input, d))
963}
964
965pub fn float(input: ParseString) -> ParseResult<(Box<SectionElement>,FloatDirection)> {
967 let (input, direction) = float_sigil(input)?;
968 let (input, _) = many0(space_tab)(input)?;
969 let (input, el) = section_element(input)?;
970 Ok((input, (Box::new(el), direction)))
971}
972
973pub fn not_mech_code(input: ParseString) -> ParseResult<()> {
975 let (input, _) = alt((null(question_block),
976 null(info_block),
977 null(success_block),
978 null(warning_block),
979 null(error_block),
980 null(idea_block),
981 null(img),
982 null(mika_section_close),
983 null(float)))(input)?;
984 Ok((input, ()))
985}
986
987pub fn section_element(input: ParseString) -> ParseResult<SectionElement> {
989 let parsers: Vec<(&'static str, Box<dyn Fn(ParseString) -> ParseResult<SectionElement>>)> = vec![
990 ("list", Box::new(|i| mechdown_list(i).map(|(i, lst)| (i, SectionElement::List(lst))))),
991 ("prompt", Box::new(prompt)),
992 ("footnote", Box::new(|i| footnote(i).map(|(i, f)| (i, SectionElement::Footnote(f))))),
993 ("citation", Box::new(|i| citation(i).map(|(i, c)| (i, SectionElement::Citation(c))))),
994 ("abstract", Box::new(abstract_el)),
995 ("img", Box::new(|i| img(i).map(|(i, img)| (i, SectionElement::Image(img))))),
996 ("figures", Box::new(|i| figures(i).map(|(i, f)| (i, SectionElement::FigureTable(f))))),
997 ("equation", Box::new(|i| equation(i).map(|(i, e)| (i, SectionElement::Equation(e))))),
998 ("table", Box::new(|i| mechdown_table(i).map(|(i, t)| (i, SectionElement::Table(t))))),
999 ("float", Box::new(|i| float(i).map(|(i, f)| (i, SectionElement::Float(f))))),
1000 ("quote_block", Box::new(quote_block)),
1001 ("code_block", Box::new(code_block)),
1002 ("thematic_break", Box::new(|i| thematic_break(i).map(|(i, _)| (i, SectionElement::ThematicBreak)))),
1003 ("subtitle", Box::new(|i| subtitle(i).map(|(i, s)| (i, SectionElement::Subtitle(s))))),
1004 ("question_block", Box::new(question_block)),
1005 ("info_block", Box::new(info_block)),
1006 ("success_block", Box::new(success_block)),
1007 ("warning_block", Box::new(warning_block)),
1008 ("error_block", Box::new(error_block)),
1009 ("idea_block", Box::new(idea_block)),
1010 ("paragraph", Box::new(|i| paragraph(i).map(|(i, p)| (i, SectionElement::Paragraph(p))))),
1011 ];
1012
1013 alt_best(input, &parsers)
1014
1015}
1016
1017pub fn section(input: ParseString) -> ParseResult<Section> {
1019 let (input, subtitle) = opt(ul_subtitle)(input)?;
1020
1021 let mut elements = vec![];
1022
1023 let mut new_input = input.clone();
1024
1025 loop {
1026 if new_input.cursor >= new_input.graphemes.len() {
1028 break;
1030 }
1031
1032 if ul_subtitle(new_input.clone()).is_ok() {
1034 break;
1036 }
1037
1038 #[cfg(feature = "mika")]
1039 if mika_section_close(new_input.clone()).is_ok() {
1040 break;
1041 }
1042
1043 #[cfg(feature = "mika")]
1053 match mika(new_input.clone()) {
1054 Ok((input, mika)) => {
1055 elements.push(SectionElement::Mika(mika));
1056 new_input = input;
1057 continue;
1058 }
1059 Err(e) => {
1060 }
1063 }
1064
1065 match mech_code(new_input.clone()) {
1067 Ok((input, mech_tree)) => {
1068 elements.push(SectionElement::MechCode(mech_tree));
1069 new_input = input;
1070 continue;
1071 }
1072 Err(e) => {
1073 }
1076 }
1077
1078 match section_element(new_input.clone()) {
1079 Ok((input, element)) => {
1080
1081 elements.push(element);
1082
1083 let (input, _) = many0(blank_line)(input.clone())?;
1085 new_input = input;
1086 }
1087 Err(err) => {
1088 return Err(err);
1090 }
1091 }
1092 }
1093 Ok((new_input, Section { subtitle, elements }))
1094}
1095
1096pub fn body(input: ParseString) -> ParseResult<Body> {
1098 let (mut input, _) = whitespace0(input)?;
1099 let mut sections = vec![];
1100 let mut new_input = input.clone();
1101 loop {
1102 if new_input.cursor >= new_input.graphemes.len() {
1103 break;
1104 }
1105 match section(new_input.clone()) {
1107 Ok((input, sect)) => {
1108 sections.push(sect);
1110 new_input = input;
1111 }
1112 Err(err) => {
1113 return Err(err);
1114 }
1115 }
1116 }
1117 Ok((new_input, Body { sections }))
1118}