diff --git a/src/error.rs b/src/error.rs index 500d9de..9a09f38 100644 --- a/src/error.rs +++ b/src/error.rs @@ -9,17 +9,17 @@ pub fn no_args() { } pub fn missing_config(path: &PathBuf) { - println!("config: no config file found at {:?}", path); + println!("config: no config file found at {path:?}"); exit(2); } pub fn no_section(section: &String) { - println!("config: nothing specified for \"{}\"", section); + println!("config: nothing specified for \"{section}\""); exit(3); } pub fn no_property(section: &String, property: &str) { - println!("config: \"{}\" has no property \"{}\"", section, property); + println!("config: \"{section}\" has no property \"{property}\""); exit(4); } diff --git a/src/main.rs b/src/main.rs index acfda62..bc9d377 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ use std::{ - env::{ args, current_dir, var }, + env::{ current_dir, var }, error::Error, fs::read_to_string, path::PathBuf, @@ -9,6 +9,7 @@ use std::{ } }; +use pico_args::Arguments; use toml::{ Value, value::Map @@ -17,84 +18,62 @@ use toml::{ mod error; fn main() -> Result<(), Box>{ - let home_dir = var("HOME").unwrap(); + // get args + let mut args = Arguments::from_env(); - let mut config_path = PathBuf::from(&home_dir); - config_path.push(".config/config.toml"); - if !config_path.exists() { - error::missing_config(&config_path); + // handle help flag + if args.contains(["-h", "--help"]) { + help_text(); + return Ok(()); } + // get $HOME from env + let home_dir = var("HOME").unwrap(); + + // build + validate config path + let mut config_path = PathBuf::from(&home_dir); + config_path.push(".config/config.toml"); + if !config_path.exists() { error::missing_config(&config_path); } + + // build config table from toml let raw_conf = read_to_string(config_path)?; let toml_conf: Value = toml::from_str(raw_conf.as_str())?; let config = toml_conf.as_table().unwrap(); + // get $EDITOR env let i_editor = var("EDITOR"); let editor: Option = if i_editor.is_ok() { Some(i_editor.unwrap()) } else { None }; let shell_default = if config.contains_key("shell") { config.get("shell").unwrap().as_bool().unwrap() } else { false }; - let args: Vec = args().skip(1).collect(); - let mut dir = false; - let mut list = false; - let mut path = false; + // get argument target + let mut section: &Map = config; + let mut target = args.subcommand().unwrap(); + let mut fullname = String::new(); + while target.is_some() { + let entry = target.unwrap().clone(); + if !fullname.is_empty() { fullname += "."; } + fullname += &entry; + let i_section = section.get(&entry); + if i_section.is_none() { error::no_section(&entry); } + section = i_section.unwrap().as_table().unwrap(); - if args.len() == 0 { - error::no_args(); - } - match args[0].as_str() { - "-d" | - "--dir" => dir = true, - "-l" | - "--list" => list = true, - "-p" | - "--path" => path = true, - "-h" | - "--help" => { - help_text(); - return Ok(()); - } - _ => {} + target = args.subcommand().unwrap(); } - let start_index = if dir || list || path { 1 } else { 0 }; - - if list { - let mut section = config; - if args.len() > 1 { - let mut args = args.clone(); - args.remove(0); - for arg in args { - let i_sub = section.get(arg.as_str()); - if i_sub.is_none() { return Ok(()); } - let sub = i_sub.unwrap().as_table(); - if sub.is_none() { return Ok(()); } - section = sub.unwrap(); - } - } - for (key, value) in section.iter() { - if value.is_table() { - println!("{}", key); - } + // handle list flag + if args.contains(["-l", "--list"]) { + for (key, _) in section.iter() { + println!("{key}"); } return Ok(()); } - let mut section: &Map = config; - let mut fullname: String = "".to_string(); - for i in start_index..args.len() { - let entry = &args[i]; - fullname = if fullname.is_empty() { args[i].clone() } else { fullname + "." + &args[i] }; - let i_section = section.get(entry); - if i_section.is_none() { - error::no_section(&fullname); - } - section = i_section.unwrap().as_table().unwrap(); - } - //let section = i_section.unwrap().as_table().unwrap(); + if target.is_none() { error::no_args(); } let prop_path = section.get("path"); - if dir { + // handle dir flag + if args.contains(["-d", "--dir"]) { if prop_path.is_none() { error::no_property(&fullname, "path"); } @@ -102,25 +81,24 @@ fn main() -> Result<(), Box>{ let expanded = if raw_path.starts_with("~") { raw_path.replacen("~", &home_dir, 1) } else { raw_path.to_string() }; let file_path = PathBuf::from(expanded.to_string()); if file_path.is_dir() { - println!("{}", expanded); - return Ok(()); + println!("{expanded}"); } else { let i_parent = file_path.parent().unwrap().to_str().unwrap(); let parent = if i_parent.starts_with("~") { i_parent.replacen("~", &home_dir, 1) } else { i_parent.to_string() }; - println!("{}", parent); - return Ok(()); + println!("{parent}"); } + return Ok(()); } - if path { - if prop_path.is_none() { - error::no_property(&fullname, "path"); - } + // handle path flag + if args.contains(["-p", "--path"]) { + if prop_path.is_none() { error::no_property(&fullname, "path"); } let i_file_path = prop_path.unwrap().as_str().unwrap(); let file_path = if i_file_path.starts_with("~") { i_file_path.replace("~", &home_dir) } else { i_file_path.to_string() }; - println!("{}", file_path); + println!("{file_path}"); return Ok(()); } + // get properties from config section let prop_command = section.get("command"); let raw_command: String; if prop_command.is_none() { @@ -143,6 +121,7 @@ fn main() -> Result<(), Box>{ shell = shell_default; } + // build command and start process let mut process = Command::new(command); process.current_dir(current_dir()?); let mut arguments: Vec<&str> = parts.collect(); @@ -171,14 +150,21 @@ fn main() -> Result<(), Box>{ } fn help_text() { - println!("config v{}", env!("CARGO_PKG_VERSION")); - println!("Valerie Wolfe "); - println!("A configuration manager written in Rust.\n"); - println!("USAGE:"); - println!("\tconfig NAME\n"); - println!("FLAGS:"); - println!("\t-h, --help\tPrints this help text"); - println!("\t-d, --dir\tGets the directory of the config file"); - println!("\t-l, --list\tLists config sections"); - println!("\t-p, --path\tGets the path to the config file"); + println!( + "config v{} +Valerie Wolfe +A configuration manager written in Rust. + +usage: config [flags] + +args: + The name of the section to configure. + +flags: + -h, --help Prints this help text + -d, --dir Gets the directory of the config file + -l, --list Lists config sections + -p, --path Gets the path to the config file", + env!("CARGO_PKG_VERSION") + ); }