md_inc/
config.rs

1use crate::parse::CommandTags;
2use crate::ParserConfig;
3use anyhow::Context;
4use anyhow::Result;
5use std::fs::read_to_string;
6use std::path::{Path, PathBuf};
7
8pub static DEFAULT_TAG_BEGIN: &'static str = "<!--{";
9pub static DEFAULT_TAG_END: &'static str = "}-->";
10pub static DEFAULT_END_COMMAND: &'static str = "end";
11
12#[derive(Clone, Debug, Deserialize, PartialEq)]
13#[serde(default)]
14pub struct Config {
15    /// The opening tag for commands
16    pub open_tag: String,
17
18    /// The closing tag for commands
19    pub close_tag: String,
20
21    /// The command used to end a block
22    pub end_command: String,
23
24    /// Relative path of the base directory used to reference imported files
25    pub base_dir: String,
26
27    /// Relative paths of files to process
28    pub files: Vec<String>,
29
30    /// Relative paths of directories to process after this one
31    pub next_dirs: Vec<String>,
32
33    /// Relative paths of directories to process before this one
34    pub depend_dirs: Vec<String>,
35
36    /// Relative path of output directory
37    pub out_dir: Option<String>,
38}
39
40impl Default for Config {
41    fn default() -> Self {
42        Config {
43            open_tag: DEFAULT_TAG_BEGIN.to_string(),
44            close_tag: DEFAULT_TAG_END.to_string(),
45            end_command: DEFAULT_END_COMMAND.to_string(),
46            base_dir: "".to_string(),
47            files: vec![],
48            next_dirs: vec![],
49            depend_dirs: vec![],
50            out_dir: None,
51        }
52    }
53}
54
55#[derive(Clone, Debug)]
56pub struct ConfigAndPath {
57    pub config: Config,
58    pub path: PathBuf,
59}
60
61impl ConfigAndPath {
62    pub(crate) fn parent_path(&self) -> Result<PathBuf> {
63        Ok(self
64            .path
65            .parent()
66            .context("Could not access parent directory of config file.")?
67            .to_path_buf())
68    }
69    pub(crate) fn into_parser(self) -> Result<(ParserConfig, Vec<PathBuf>)> {
70        let parent = self.parent_path()?;
71        Ok((
72            ParserConfig {
73                tags: CommandTags::new(self.config.open_tag, self.config.close_tag),
74                end_command: self.config.end_command,
75                base_dir: parent.join(self.config.base_dir),
76            },
77            self.config.files.iter().map(|x| parent.join(x)).collect(),
78        ))
79    }
80}
81impl Config {
82    pub(crate) fn try_from_path<P: AsRef<Path>>(dir: P) -> Result<Self> {
83        let file =
84            read_to_string(dir.as_ref()).with_context(|| format!("Reading {:?}", dir.as_ref()))?;
85        Ok(toml::from_str::<Config>(&file)
86            .context("Error in toml config file")?
87            .into())
88    }
89
90    /// Returns None if no file exists
91    /// Returns Some(Err) if file exists, but there was a problem reading it
92    pub(crate) fn try_from_dir<P: Into<PathBuf>>(dir: P) -> Result<Option<ConfigAndPath>> {
93        let dir = dir.into();
94        let file = dir.join(".md-inc.toml");
95        if file.exists() && file.is_file() {
96            Ok(Some(ConfigAndPath {
97                config: Config::try_from_path(&file)?,
98                path: file,
99            }))
100        } else {
101            Ok(None)
102        }
103    }
104}
105
106#[derive(Clone, Debug, Default, PartialEq)]
107pub struct OutputTo {
108    pub read_only: bool,
109    pub print: bool,
110    pub out_dir: Option<PathBuf>,
111}
112impl OutputTo {
113    pub fn stdout() -> Self {
114        Self {
115            read_only: true,
116            print: true,
117            out_dir: None,
118        }
119    }
120    pub fn file() -> Self {
121        Self {
122            read_only: false,
123            print: false,
124            out_dir: None,
125        }
126    }
127    pub fn different_file<P: Into<PathBuf>>(path: P) -> Self {
128        Self {
129            read_only: false,
130            print: false,
131            out_dir: Some(path.into()),
132        }
133    }
134}