#[macro_use]
extern crate lazy_static;
use regex::Regex;
use std::{
collections::HashMap,
env::{self},
fs::{self, File},
io::{BufRead, BufReader, Result, Write},
path::Path,
};
lazy_static! {
static ref REG: HashMap<&'static str, Regex> = {
let mut reg_map = HashMap::new();
reg_map.insert(
"extension_re",
Regex::new(r"\.(.+)$").expect("No valid match"),
);
reg_map.insert(
"line_re",
Regex::new(r"////(.+)$").expect("No matched line"),
);
reg_map
};
}
fn main() {
let cli_options: Vec<_> = env::args().skip(1).collect();
if cli_options.is_empty() || cli_options.len() < 2 {
println!("Usage: plyg <programming_language_to_write> <filename>");
std::process::exit(-1);
}
let filename = cli_options[1].clone();
let path = Path::new(&filename);
if path.exists() {
write_file(
&filename.clone(),
&cli_options[0],
read_file(&filename).unwrap(),
)
.expect("can't write file");
} else {
println!("{:?} doesn't exit. Use a valid filename", filename);
std::process::exit(-1);
}
}
fn get_new_file_name(filename: &str, extension: &str) -> String {
let filename = Path::new(filename).file_name().unwrap();
let filename: String = filename
.to_str()
.unwrap()
.to_string()
.chars()
.rev()
.collect();
let filename: String = format!(
"{}.{}",
if let Some(val) = REG.get("extension_re").unwrap().captures(&filename) {
val[1].chars().rev().collect()
} else {
"rs".to_owned()
},
extension
);
filename
}
fn write_file(filename: &str, extension: &str, map: HashMap<String, Vec<String>>) -> Result<()> {
if !map.keys().any(|x| x == &extension.clone().to_string()) {
println!(
"File Extension provided [.{}], has no corresponding write up in the file been used.",
&extension
);
std::process::exit(-1);
}
fs::remove_file(filename)?;
let filename = get_new_file_name(filename, extension);
let mut file = File::create(filename.clone()).unwrap();
if map.contains_key(extension) {
for line in map.get(extension).unwrap() {
if REG.get("line_re").unwrap().is_match(line) {
let line = REG.get("line_re").unwrap().captures(&line).unwrap();
if line[1].starts_with("start") {
writeln!(file, "{}", &line[0])?; } else {
writeln!(file, "{}", &line[1])?; }
} else {
writeln!(file, "{}", line)?;
}
}
}
for key in map
.keys()
.filter(|a| **a != extension.to_string())
.collect::<Vec<_>>()
{
for line in map.get(key).unwrap() {
if line.starts_with("////") || line.contains("////") {
writeln!(file, "{}", line)?;
} else {
writeln!(file, "////{}", line)?;
}
}
}
println!("New file: {} created.", filename);
Ok(())
}
fn read_file(filename: &str) -> Result<HashMap<String, Vec<String>>> {
let mut map: HashMap<String, Vec<String>> = HashMap::new();
let file = File::open(filename.to_owned())?;
let buf = BufReader::new(file);
let mut key = String::with_capacity(10);
let mut store = vec![];
for line in buf.lines() {
let line = line?;
if line.trim().starts_with("////start") {
let keys = line.split_whitespace().into_iter().collect::<Vec<_>>();
key = keys[1].to_string();
key.shrink_to_fit();
store = vec![line.clone()];
} else {
store.push(line.clone());
}
map.insert(key.clone(), store.clone());
}
map.insert(key, store);
Ok(map)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_new_file_name() {
assert_eq!(
"hello.go",
get_new_file_name( "hello.rs", "go")
);
}
#[test]
fn test_get_new_file_name_with_several_ext() {
assert_eq!(
"hello.copy.new.dart",
get_new_file_name(
"hello.copy.new.c",
"dart"
),
"It changes only the last extension for the file"
);
}
}