use super::super::nodes::STIL;
use super::super::parser;
use super::super::ParseOptions;
use crate::ast::Node;
use crate::ast::{Processor, Return};
use crate::Result;
use shellexpand;
use std::collections::HashMap;
use std::env;
use std::path::PathBuf;
pub struct Includer {
load_path: Vec<PathBuf>,
rename: HashMap<String, String>,
parse_options: ParseOptions,
}
impl Includer {
#[allow(dead_code)]
pub fn run(
node: &Node<STIL>,
load_path: Vec<PathBuf>,
rename: HashMap<String, String>,
) -> Result<Node<STIL>> {
Self::run_with_options(node, load_path, rename, ParseOptions::default())
}
pub(crate) fn run_with_options(
node: &Node<STIL>,
load_path: Vec<PathBuf>,
rename: HashMap<String, String>,
parse_options: ParseOptions,
) -> Result<Node<STIL>> {
let mut full_load_path = vec![env::current_dir()?];
for p in load_path {
full_load_path.push(p.to_path_buf());
}
let mut p = Includer {
load_path: full_load_path,
rename: rename,
parse_options,
};
Ok(node.process(&mut p)?.unwrap())
}
}
impl Processor<STIL> for Includer {
fn on_node(&mut self, node: &Node<STIL>) -> Result<Return<STIL>> {
let result = match &node.attrs {
STIL::Include(file, _) => {
let expanded = {
if !self.rename.is_empty() {
let mut file = file.to_owned();
for (orig, new) in &self.rename {
if file.contains(orig) {
file = file.replace(orig, new);
}
}
format!("{}", shellexpand::full(&file)?)
} else {
format!("{}", shellexpand::full(&file)?)
}
};
for p in &self.load_path {
let mut path = p.clone();
path.push(&expanded);
if path.exists() {
let ast = parser::parse_file_with_options(&path, self.parse_options)?;
return Ok(Return::Replace(Includer::run_with_options(
&ast,
self.load_path.clone(),
self.rename.clone(),
self.parse_options,
)?));
}
}
bail!("Unable to find include file: {}", expanded)
}
STIL::Root => Return::ProcessChildren,
_ => Return::Unmodified,
};
Ok(result)
}
}