writing/
lib.rs

1extern crate pest;
2#[macro_use]
3extern crate pest_derive;
4
5use std::fs;
6use std::fs::File;
7use std::io::{BufRead, BufReader};
8use std::path::{Path, PathBuf};
9
10use thiserror::Error;
11
12pub use parser::*;
13
14use crate::code_reader::CodeReader;
15
16pub mod parser;
17pub mod code_reader;
18
19#[derive(Error, Debug)]
20pub enum WritingError {
21    #[error("io error: `{0}` ")]
22    IOError(String),
23    #[error("read file error: `{0}` ")]
24    ReadFileError(String),
25    #[error("unknown data store error")]
26    Unknown,
27}
28
29pub struct Writing {}
30
31impl Writing {
32    pub fn process_file<P: AsRef<Path>>(path: P) -> Result<String, WritingError> {
33        let path = path.as_ref().to_path_buf();
34
35        if let Err(err) = Writing::pre_process_file(&path) {
36            return Err(err);
37        };
38
39        let result = Writing::write_it(path).join("\n");
40
41        Ok(result)
42    }
43
44    fn write_it(path: PathBuf) -> Vec<String> {
45        let file = File::open(path).expect("cannot open file");
46        let reader = BufReader::new(file);
47        let mut is_lang = false;
48
49        let mut results = vec![];
50        for res in reader.lines() {
51            let line = res.expect("cannot parse line");
52            if line.starts_with("```") {
53                is_lang = !is_lang
54            }
55
56            // todo: add remove backspace & tab, before check??
57            if is_lang && line.starts_with("// doc-") {
58                let writing = parser::parse(line.replace("//", "").as_str());
59
60                if writing.code_docs.len() > 0 {
61                    results.append(&mut CodeReader::read_doc_code(&writing.code_docs[0]));
62                } else if writing.code_sections.len() > 0 {
63                    results.append(&mut CodeReader::read_doc_section(&writing.code_sections[0]));
64                } else if writing.code_funcs.len() > 0 {
65                    results.append(&mut CodeReader::read_code_func(&writing.code_funcs[0]));
66                } else {
67                    results.push(String::from(line));
68                };
69            } else {
70                results.push(String::from(line));
71            }
72        }
73
74        results
75    }
76
77// doc-start: section1
78    fn pre_process_file(path: &PathBuf) -> Result<(), WritingError> {
79        if path.is_dir() {
80            return Err(WritingError::IOError(format!("path: {:?} is a dir", path)));
81        }
82
83        if let Err(e) = fs::read(path) {
84            return Err(WritingError::IOError(format!("read file error: {:?}", e)));
85        }
86
87        Ok(())
88    }
89// doc-end: section1
90}
91
92#[cfg(test)]
93mod tests {
94    use std::path::PathBuf;
95
96    use crate::Writing;
97
98    #[test]
99    fn should_convert_doc_code() {
100        let path = PathBuf::from("samples").join("doc-code.md");
101        let content = Writing::process_file(path);
102
103        assert_eq!("```writing
104extern crate pest;
105#[macro_use]
106extern crate pest_derive;
107
108use std::fs;
109```", content.expect(""));
110    }
111
112    #[test]
113    fn should_convert_doc_section() {
114        let path = PathBuf::from("samples").join("doc-section.md");
115        let content = Writing::process_file(path);
116
117        assert_eq!("```writing
118    fn pre_process_file(path: &PathBuf) -> Result<(), WritingError> {
119        if path.is_dir() {
120            return Err(WritingError::IOError(format!(\"path: {:?} is a dir\", path)));
121        }
122
123        if let Err(e) = fs::read(path) {
124            return Err(WritingError::IOError(format!(\"read file error: {:?}\", e)));
125        }
126
127        Ok(())
128    }
129```", content.expect(""));
130    }
131}