Skip to main content

s_text_input_f_parser/
paragraph.rs

1use chumsky::prelude::*;
2use s_text_input_f::{Paragraph, ParagraphItem};
3
4#[derive(Debug)]
5pub(crate) struct CorrectParagraphItem {
6    pub(crate) input: ParagraphItem,
7    pub(crate) answer: Option<String>,
8}
9
10#[derive(Debug)]
11pub struct CorrectParagraph {
12    pub input: Paragraph,
13    pub answer: Vec<String>,
14}
15
16impl FromIterator<CorrectParagraphItem> for CorrectParagraph {
17    fn from_iter<T: IntoIterator<Item = CorrectParagraphItem>>(iter: T) -> Self {
18        let (input, answers): (Vec<_>, Vec<_>) = iter
19            .into_iter()
20            .map(|CorrectParagraphItem { input, answer }| (input, answer))
21            .unzip();
22        let answer = answers.into_iter().flatten().collect::<Vec<_>>();
23        Self { input, answer }
24    }
25}
26
27pub(crate) fn paragraph_parser() -> impl Parser<char, CorrectParagraph, Error = Simple<char>> {
28    let text = filter::<_, _, Simple<char>>(|&ch| {
29        ch != '`'
30            && ch != '\n'
31            && (char::is_alphanumeric(ch)
32                || char::is_whitespace(ch)
33                || char::is_ascii_punctuation(&ch))
34    })
35    .repeated()
36    .at_least(1)
37    .collect::<String>();
38    let input_field = just('`')
39        .ignore_then(
40            filter(|&ch| {
41                ch != '`'
42                    && (char::is_alphanumeric(ch)
43                        || char::is_whitespace(ch)
44                        || char::is_ascii_punctuation(&ch))
45            })
46            .repeated()
47            .collect::<String>(),
48        )
49        .then_ignore(just('`'));
50
51    let paragraph_item = choice((
52        text.map(|text| CorrectParagraphItem {
53            input: ParagraphItem::Text(text),
54            answer: None,
55        }),
56        input_field.map(|text| CorrectParagraphItem {
57            input: ParagraphItem::Placeholder,
58            answer: Some(text),
59        }),
60    ));
61
62    paragraph_item
63        .repeated()
64        .at_least(1)
65        .map(CorrectParagraph::from_iter)
66        .then_ignore(choice((just('\n').ignored(), end().ignored())))
67}