1use std::fs;
5use std::sync::Arc;
6
7use corpora_core::subscriber::ek;
8use corpora_core::{Context, DocPath, Event, Interest, ParseError, Record, Subscriber};
9
10use crate::toml_format::TomlFormat;
11
12pub trait FrontMatterFormat {
13 fn parse(&self, path: &DocPath, text: &str) -> Result<Record, ParseError>;
14}
15
16pub struct Parser {
17 fmt: Box<dyn FrontMatterFormat>,
18}
19
20impl Parser {
21 pub fn new(fmt: Box<dyn FrontMatterFormat>) -> Self {
22 Parser { fmt }
23 }
24
25 pub fn toml() -> Self {
26 Parser {
27 fmt: Box::new(TomlFormat),
28 }
29 }
30}
31
32impl Subscriber for Parser {
33 fn name(&self) -> &'static str {
34 "parser"
35 }
36
37 fn interest(&self) -> Interest {
38 Interest::only(ek::DISCOVERED | ek::CHANGED)
39 }
40
41 fn handle(&mut self, ev: &Event, cx: &mut Context<'_>) {
42 let path = match ev {
43 Event::Discovered(p) | Event::Changed(p) => p,
44 _ => return,
45 };
46 let text = match fs::read_to_string(&path.0) {
47 Ok(t) => t,
48 Err(e) => {
49 cx.emit(Event::ParseFailed {
50 path: path.clone(),
51 error: ParseError(e.to_string()),
52 });
53 return;
54 }
55 };
56 match self.fmt.parse(path, &text) {
57 Ok(r) => cx.emit(Event::Parsed(Arc::new(r))),
58 Err(e) => cx.emit(Event::ParseFailed {
59 path: path.clone(),
60 error: e,
61 }),
62 }
63 }
64}
65