From 37e9dabfee3fa7590cac873c4100e51a7f303e06 Mon Sep 17 00:00:00 2001 From: Mohamed Tarek Date: Sat, 29 Jun 2024 01:13:03 +0300 Subject: [PATCH] add option to change default config path --- Cargo.toml | 3 ++- README.md | 6 +++++- src/cli/args.rs | 8 ++++++++ src/cli/main.rs | 7 +++++-- src/core/config.rs | 28 +++++++++++++++++++--------- src/core/keywords.rs | 10 +++------- src/core/templates.rs | 29 +++++++++++++---------------- src/core/utils.rs | 9 --------- 8 files changed, 55 insertions(+), 45 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f9c9e77..cde3a91 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,8 +18,9 @@ path="src/cli/main.rs" chrono = "0.4.34" clap = { version = "3.2.17", features = ["derive"] } colored = "2.0.0" -dirs = "5.0.1" +indexmap = "2.2.6" promptly = "0.3.1" regex = "1.7.1" serde = { version = "1.0.152", features = ["serde_derive"] } +shellexpand = "3.1.0" toml = "0.5.9" diff --git a/README.md b/README.md index 93fc85b..e19ca2d 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,9 @@ note that the template `info` section can be totally ignored, straight to the po --> Default templates path is `~/.config/idkmng/templates`
+> [!NOTE] +> You can use -c option to override the config path if you needed to. + The template structure is like the following: ```toml [info] @@ -236,7 +239,8 @@ Also there is one more time saving way! if you have some files in `/foo/bar/` yo ## Special Keywords 🔧 You can have your own Keywords for idkmng to replace with desired values! -Idkmng finds them stored in $HOME/.config/idkmng/config.toml +Idkmng finds them stored in $HOME/.config/idkmng/config.toml Or the config path you specified using -c/--config option 🦀 + ```toml [Keywords] AUTHOR = "Mohamed Tarek" diff --git a/src/cli/args.rs b/src/cli/args.rs index 1ffe030..842cde8 100644 --- a/src/cli/args.rs +++ b/src/cli/args.rs @@ -20,6 +20,14 @@ impl Cli { .short('q') .requires("template"), ) + .arg( + Arg::with_name("config") + .long("config") + .short('c') + .help("Config path") + .default_value("~/.config/idkmng/config.toml") + .requires("template") + ) .subcommand(Command::new("init").about("Creates a template for the current directory")) .get_matches() } diff --git a/src/cli/main.rs b/src/cli/main.rs index 8c6e8d4..367b8cc 100644 --- a/src/cli/main.rs +++ b/src/cli/main.rs @@ -1,3 +1,4 @@ +use idkmng::config::Config; use idkmng::types::Template; mod args; use args::Cli; @@ -6,6 +7,8 @@ use colored::*; fn main() { let args = Cli::parse(); + let config = Config::new(args.value_of("config").unwrap()); + if args.subcommand_matches("init").is_some() { let dest = format!( "{}.toml", @@ -19,13 +22,13 @@ fn main() { println!("{}: {}", "Creating Template".bold().green(), &dest.yellow()); Template::generate(&dest); } else if let Some(filename) = args.value_of("template") { - let template = Template::validate(filename.to_string()); + let template = Template::validate(filename.to_string(), config.templates_path.clone()); println!("\n{}: {}", "Using Template".blue(), &template.magenta()); if !args.is_present("quiet") { Template::show_info(&Template::parse(&template, true)); } - Template::extract(template, true); + Template::extract(template, true, config); } else { println!( "{} {}", diff --git a/src/core/config.rs b/src/core/config.rs index c00b642..dfee3d1 100644 --- a/src/core/config.rs +++ b/src/core/config.rs @@ -1,20 +1,33 @@ use crate::keywords::Keywords; use crate::types::Template; -use crate::utils::gethome; use std::collections::HashMap; use std::fs; use toml::Value; -pub const CONFIG_PATH: &str = "{{$HOME}}/.config/idkmng/config.toml"; -pub const TEMPLATES_PATH: &str = "{{$HOME}}/.config/idkmng/templates/"; pub const KEYWORDS_FORMAT: &str = "{{$%s:f}}"; pub const KEYWORDS_REGEX: &str = r"\{\{\$[^\s}]+(:[^\s}]+)?\}\}"; pub struct Config { pub path: String, + pub templates_path: String, } impl Config { + pub fn new(path: &str) -> Self { + let config_path = shellexpand::tilde(path).to_string(); + let mut config_dir: Vec<&str> = path.split("/").collect(); + + config_dir.pop(); + + //NOTE: maybe templates path should be parsed from config.toml itself?? + let templates = config_dir.join("/") + "/templates/"; + + Config { + path: config_path, + templates_path: shellexpand::tilde(&templates).to_string(), + } + } + pub fn init(self) { // this sample is just a template that create config.toml and the new.toml template for the // first time, Now something maybe confusing is the "initPJNAME" wtf is it ? @@ -29,7 +42,7 @@ description = "A Template for making a template" author = "Mohamed Tarek @pwnxpl0it" [[files]] -path="~/.config/idkmng/templates/initPJNAME.toml" +path="TEMPLATES_PATH/initPJNAME.toml" content=""" [info] name = "initPJNAME" @@ -51,12 +64,9 @@ content = ''' ''' "# .replace("CONFIGPATH", &self.path) - .replace( - "TEMPLATES_PATH", - &TEMPLATES_PATH.replace("{{$HOME}}", &gethome()), - ); + .replace("TEMPLATES_PATH", &self.templates_path); - Template::extract(sample, false); + Template::extract(sample, false, self); } pub fn get_keywords(self) -> HashMap { diff --git a/src/core/keywords.rs b/src/core/keywords.rs index 3d4d407..8b9f574 100644 --- a/src/core/keywords.rs +++ b/src/core/keywords.rs @@ -1,5 +1,4 @@ -use crate::config::{Config, CONFIG_PATH, KEYWORDS_FORMAT}; -use crate::utils::gethome; +use crate::config::{Config, KEYWORDS_FORMAT}; use chrono::Datelike; use std::{collections::HashMap, env}; @@ -20,7 +19,7 @@ impl Keywords { } } - pub fn init() -> HashMap { + pub fn init(config: Config) -> HashMap { let mut keywords = HashMap::new(); keywords.insert( Self::new(String::from("HOME"), "".to_string()), @@ -71,10 +70,7 @@ impl Keywords { chrono::Local::now().day().to_string(), ); - let other_keywords = Config { - path: CONFIG_PATH.replace("{{$HOME}}", &gethome()), - } - .get_keywords(); + let other_keywords = config.get_keywords(); keywords.extend(other_keywords); keywords diff --git a/src/core/templates.rs b/src/core/templates.rs index 55b87f3..0f14366 100644 --- a/src/core/templates.rs +++ b/src/core/templates.rs @@ -52,11 +52,11 @@ impl Template { } /// This method "extracts" a template, means it takes a template and starts initializing files based that template - pub fn extract(template: String, is_file: bool) { + pub fn extract(template: String, is_file: bool, config: Config) { let mut keywords: HashMap; let re = Regex::new(KEYWORDS_REGEX).unwrap(); - keywords = Keywords::init(); + keywords = Keywords::init(config); let sample = Self::parse(&template, is_file); @@ -77,17 +77,14 @@ impl Template { let path = Keywords::replace_keywords(keywords.to_owned(), file.path.to_owned()); if dir.len() > 1 { - create_dirs( - &Keywords::replace_keywords( - keywords.to_owned(), - file.path.to_owned().replace(dir[dir.len() - 1], ""), - ) - .replace('~', &gethome()), - ) + create_dirs(&shellexpand::tilde(&Keywords::replace_keywords( + keywords.to_owned(), + file.path.to_owned().replace(dir[dir.len() - 1], ""), + ))) } write_content( - &path.replace('~', &gethome()), + &shellexpand::tilde(&path), Keywords::replace_keywords(keywords.to_owned(), file.content), ) }); @@ -108,9 +105,9 @@ impl Template { toml::from_str(&content).unwrap() } - /// This method validates Template path, in other words it just checks if the template is in - /// the current working Directory,if not it uses the default templates directory, also automatically adds .toml - pub fn validate(mut template: String) -> String { + /// This method validates template path, in other words it just checks if the template is in + /// the current working directory,if not it uses the default templates directory, also automatically adds .toml + pub fn validate(mut template: String, template_path: String) -> String { if template.contains(".toml") { //IGNORE } else { @@ -120,14 +117,14 @@ impl Template { if fs::read_to_string(&template).is_ok() { //IGNORE } else { - template = TEMPLATES_PATH.replace("{{$HOME}}", &gethome()) + &template + template = template_path + &template } template } - /// This method shows information about current Template, basically Reads them from Information - /// section in the Template TOML file + /// This method shows information about current template, basically Reads them from Information + /// section in the template TOML file pub fn show_info(template: &Self) { match &template.info { Some(information) => println!( diff --git a/src/core/utils.rs b/src/core/utils.rs index 40a99bf..d7adc13 100644 --- a/src/core/utils.rs +++ b/src/core/utils.rs @@ -1,17 +1,8 @@ use crate::types::Fns; use colored::*; -use dirs; use regex::Regex; use std::{collections::HashMap, fs, path::Path}; -pub fn gethome() -> String { - dirs::home_dir() - .expect("Failed to know home directory") - .to_str() - .unwrap() - .to_string() -} - pub fn create_dirs(dir: &str) { match fs::create_dir_all(dir) { Ok(_) => println!("{}: {}", "creating directory".blue(), dir.bold().green()),