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
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use crate::parse::CommandTags;
use crate::ParserConfig;
use anyhow::Context;
use anyhow::Result;
use std::fs::read_to_string;
use std::path::{Path, PathBuf};

pub static DEFAULT_TAG_BEGIN: &'static str = "<!--{";
pub static DEFAULT_TAG_END: &'static str = "}-->";
pub static DEFAULT_END_COMMAND: &'static str = "end";

#[derive(Clone, Debug, Deserialize, PartialEq)]
#[serde(default)]
pub struct Config {
    /// The opening tag for commands
    pub open_tag: String,

    /// The closing tag for commands
    pub close_tag: String,

    /// The command used to end a block
    pub end_command: String,

    /// Relative path of the base directory used to reference imported files
    pub base_dir: String,

    /// Relative paths of files to process
    pub files: Vec<String>,

    /// Relative paths of directories to process after this one
    pub next_dirs: Vec<String>,

    /// Relative paths of directories to process before this one
    pub depend_dirs: Vec<String>,

    /// Relative path of output directory
    pub out_dir: Option<String>,
}

impl Default for Config {
    fn default() -> Self {
        Config {
            open_tag: DEFAULT_TAG_BEGIN.to_string(),
            close_tag: DEFAULT_TAG_END.to_string(),
            end_command: DEFAULT_END_COMMAND.to_string(),
            base_dir: "".to_string(),
            files: vec![],
            next_dirs: vec![],
            depend_dirs: vec![],
            out_dir: None,
        }
    }
}

#[derive(Clone, Debug)]
pub struct ConfigAndPath {
    pub config: Config,
    pub path: PathBuf,
}

impl ConfigAndPath {
    pub(crate) fn parent_path(&self) -> Result<PathBuf> {
        Ok(self
            .path
            .parent()
            .context("Could not access parent directory of config file.")?
            .to_path_buf())
    }
    pub(crate) fn into_parser(self) -> Result<(ParserConfig, Vec<PathBuf>)> {
        let parent = self.parent_path()?;
        Ok((
            ParserConfig {
                tags: CommandTags::new(self.config.open_tag, self.config.close_tag),
                end_command: self.config.end_command,
                base_dir: parent.join(self.config.base_dir),
            },
            self.config.files.iter().map(|x| parent.join(x)).collect(),
        ))
    }
}
impl Config {
    pub(crate) fn try_from_path<P: AsRef<Path>>(dir: P) -> Result<Self> {
        let file =
            read_to_string(dir.as_ref()).with_context(|| format!("Reading {:?}", dir.as_ref()))?;
        Ok(toml::from_str::<Config>(&file)
            .context("Error in toml config file")?
            .into())
    }

    /// Returns None if no file exists
    /// Returns Some(Err) if file exists, but there was a problem reading it
    pub(crate) fn try_from_dir<P: Into<PathBuf>>(dir: P) -> Result<Option<ConfigAndPath>> {
        let dir = dir.into();
        let file = dir.join(".md-inc.toml");
        if file.exists() && file.is_file() {
            Ok(Some(ConfigAndPath {
                config: Config::try_from_path(&file)?,
                path: file,
            }))
        } else {
            Ok(None)
        }
    }
}

#[derive(Clone, Debug, Default, PartialEq)]
pub struct OutputTo {
    pub read_only: bool,
    pub print: bool,
    pub out_dir: Option<PathBuf>,
}
impl OutputTo {
    pub fn stdout() -> Self {
        Self {
            read_only: true,
            print: true,
            out_dir: None,
        }
    }
    pub fn file() -> Self {
        Self {
            read_only: false,
            print: false,
            out_dir: None,
        }
    }
    pub fn different_file<P: Into<PathBuf>>(path: P) -> Self {
        Self {
            read_only: false,
            print: false,
            out_dir: Some(path.into()),
        }
    }
}