harper_literate_haskell/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
use harper_comments::CommentParser;
use harper_core::{
    parsers::{Markdown, MarkdownOptions, Mask, Parser},
    FullDictionary, Lrc, Masker, Token,
};

mod masker;
use itertools::Itertools;
use masker::LiterateHaskellMasker;

/// Parses a Literate Haskell document by masking out the code and considering text as Markdown.
pub struct LiterateHaskellParser {
    inner: Lrc<dyn Parser>,
}

impl LiterateHaskellParser {
    pub fn new(inner: Lrc<dyn Parser>) -> Self {
        Self { inner }
    }

    pub fn new_markdown(markdown_options: MarkdownOptions) -> Self {
        Self {
            inner: Lrc::new(Markdown::new(markdown_options)),
        }
    }

    pub fn create_ident_dict(
        &self,
        source: &[char],
        markdown_options: MarkdownOptions,
    ) -> Option<FullDictionary> {
        let parser = CommentParser::new_from_language_id("haskell", markdown_options).unwrap();
        let mask = LiterateHaskellMasker::code_only().create_mask(source);

        let code = mask
            .iter_allowed(source)
            .flat_map(|(_, src)| src.to_owned())
            .collect_vec();
        parser.create_ident_dict(&code)
    }
}

impl Parser for LiterateHaskellParser {
    fn parse(&self, source: &[char]) -> Vec<Token> {
        Mask::new(LiterateHaskellMasker::text_only(), self.inner.clone()).parse(source)
    }
}