use users::{get_user_by_uid, get_current_uid}; use termion::{color, style}; use std::{env, fs}; use std::collections::HashMap; use regex::Regex; extern crate dirs; extern crate yaml_rust; use yaml_rust::{YamlLoader, Yaml}; #[derive(Debug)] pub struct SqishConf { pub promptline: String, pub promptline_base: String, pub aliases: HashMap, pub hotkeys: HashMap, pub init: String, } impl SqishConf { pub fn from_sqishrc() -> Result { let mut conf_path = match dirs::home_dir() { Some(p) => p, None => { return Err(String::from("Home dir could not be determined.")); }, }; conf_path.push(".sqishrc"); let sqishrc_file = match fs::read_to_string(conf_path) { Ok(s) => s, Err(_) => { return Err(String::from("Could not read ~/.sqishrc")); }, }; let sqishrc = match YamlLoader::load_from_str(&sqishrc_file) { Ok(s) => s, Err(_) => { return Err(String::from("sqishrc is not valid yaml")); }, }; let sqishrc = &sqishrc[0]; let out_str = String::from(sqishrc["prompt"].as_str().unwrap_or("$ ")); let startup = String::from(sqishrc["init"].as_str().unwrap_or("")); //Loading hotkeys and aliases from yaml //They can be empty, be careful... let aliases_yaml = &sqishrc["aliases"]; let aliases = Self::yaml_dict2hashmap(aliases_yaml); let hotkeys_yaml = &sqishrc["hotkeys"]; let hotkeys = Self::yaml_dict2hashmap(hotkeys_yaml); let mut out_conf = SqishConf { promptline: out_str.clone(), promptline_base: out_str, aliases: aliases, hotkeys: hotkeys, init: startup, }; out_conf.handle_rgb(); out_conf.handle_colors(); return Ok(out_conf); } #[warn(unused_assignments)] pub fn update_prompt(&mut self, hist_nbr: i32) { let user = String::from( get_user_by_uid(get_current_uid()) .unwrap() .name() .to_str() .unwrap() ); let host = String::from( gethostname::gethostname() .to_str() .unwrap() ); let current_dir = String::from( env::current_dir() .unwrap() .to_str() .unwrap() ); let s = current_dir.split('/'); let dir_last = String::from( s.last() .unwrap() ); let hist_nbr = hist_nbr.to_string(); let mut prompt = self.promptline_base.replace("$USER_", &user); prompt = prompt.replace("$HOSTNAME_", &host); prompt = prompt.replace("$DIR_", &dir_last); prompt = prompt.replace("$HISTNUMBER_", &hist_nbr); prompt = prompt.to_owned(); self.promptline = prompt; self.handle_colors(); self.handle_rgb(); } fn handle_colors(&mut self) { //Colors let reset = format!("{}", color::Fg(color::Reset)); let green = format!("{}", color::Fg(color::Green)); let blue = format!("{}", color::Fg(color::Blue)); let red = format!("{}", color::Fg(color::Red)); let black = format!("{}", color::Fg(color::Black)); let white = format!("{}", color::Fg(color::White)); let cyan = format!("{}", color::Fg(color::Cyan)); let lightblack = format!("{}", color::Fg(color::LightBlack)); //Styles let ita = format!("{}", style::Italic); let bold = format!("{}", style::Bold); let stylereset = format!("{}", style::Reset); //Colors replace let mut prompt = self.promptline.replace("$COLORGREEN_", &green); prompt = prompt.replace("$COLORBLUE_", &blue); prompt = prompt.replace("$COLORRED_", &red); prompt = prompt.replace("$COLORBLACK_", &black); prompt = prompt.replace("$COLORWHITE_", &white); prompt = prompt.replace("$COLORCYAN_", &cyan); prompt = prompt.replace("$COLORLBLACK_", &lightblack); prompt = prompt.replace("$COLORRESET_", &reset); //Styles replace prompt = prompt.replace("$ITA_", &ita); prompt = prompt.replace("$BOLD_", &bold); prompt = prompt.replace("$STYLERESET_", &stylereset); let promptown = prompt.to_owned(); self.promptline = promptown; } fn handle_rgb(&mut self) { let re = Regex::new(r"\$RGB[^_]*_").unwrap(); let promptline_copy = &self.promptline.clone(); let matches = re.find_iter(promptline_copy); //println!("Matches : {:?}", &matches.count()); for m in matches { //Copy of the text used for parsing by replacement let mut matchtext = String::from(m.as_str()); //Keep a copy of the original... let matchtext_copy = matchtext.clone(); //Start replacing... matchtext = matchtext.replace("$RGB", ""); matchtext = matchtext.replace("_", ""); matchtext = matchtext.replace("|", " "); matchtext = String::from(matchtext.trim()); let matchvalues = matchtext .split_whitespace() .collect::>(); //We now have a Vector of values that must //converted to u8 before being used by termion //println!("MATCH {:?}", matchvalues); //Get the color... let red: u8 = matchvalues[0].parse().unwrap_or(108); let green: u8 = matchvalues[1].parse().unwrap_or(84); let blue: u8 = matchvalues[0].parse().unwrap_or(30); let color = color::Fg(color::Rgb { 0: red, 1: green, 2: blue, }); let color_display = format!("{}", color); //...and replace in promptline let out_str = self.promptline.replace(&matchtext_copy, &color_display); let out_str = out_str.to_owned(); *&mut self.promptline = out_str; } } ///Takes a YAML dict and converts it into an hashmap. fn yaml_dict2hashmap(yaml_dict: &Yaml) -> HashMap { let mut my_hashmap = HashMap::new(); if let Yaml::Hash(h) = yaml_dict { for (k, v) in h.iter() { if let (Yaml::String(k), Yaml::String(v)) = (k, v) { my_hashmap.insert(k.clone(), v.clone()); } } } return my_hashmap; } }