markdown_extract/
lib.rs

1mod heading;
2mod state;
3
4use heading::try_parse_heading;
5use regex::Regex;
6use state::State;
7use std::fs::File;
8use std::io::prelude::*;
9use std::io::BufReader;
10use std::path::PathBuf;
11
12pub type MarkdownSection = Vec<String>;
13
14pub fn extract_from_path(
15    path: &PathBuf,
16    regex: &Regex,
17) -> Result<Vec<MarkdownSection>, std::io::Error> {
18    let file = File::open(&path)?;
19    let mut reader = BufReader::new(file);
20    return Ok(extract_from_reader(&mut reader, &regex));
21}
22
23pub fn extract_from_reader<R: Read>(
24    reader: &mut BufReader<R>,
25    regex: &Regex,
26) -> Vec<MarkdownSection> {
27    let mut state = State::default();
28
29    for line in reader.lines() {
30        let line = line.unwrap();
31
32        if line.starts_with("```") {
33            state.is_inside_code_block = !state.is_inside_code_block;
34        }
35
36        if !state.is_inside_code_block {
37            let heading = try_parse_heading(&line);
38
39            if let Some(heading) = heading {
40                if heading.depth <= state.depth {
41                    state.exit_matched_section();
42                }
43
44                if !state.is_within_matched_section && regex.is_match(&heading.content) {
45                    state.enter_matched_section(&heading);
46                }
47            }
48        }
49
50        if state.is_within_matched_section {
51            state.current.as_mut().unwrap().push(line);
52        }
53    }
54
55    state.push_current();
56
57    return state.matches;
58}