From 7709762ddd377a99829419e3ae771bb633b516d2 Mon Sep 17 00:00:00 2001 From: Michael Aaron Murphy <mmstickman@gmail.com> Date: Wed, 16 Aug 2017 19:41:19 -0400 Subject: [PATCH] Enable setting multiple color parameters Try the following out in the prompt: echo ${color::magenta,whitebg}Magenta text with a white background. --- src/parser/statement/splitter.rs | 4 +- src/shell/colors.rs | 113 +++++++++++++++++++++++++++++++ src/shell/mod.rs | 1 + src/shell/variables.rs | 56 +-------------- 4 files changed, 118 insertions(+), 56 deletions(-) create mode 100644 src/shell/colors.rs diff --git a/src/parser/statement/splitter.rs b/src/parser/statement/splitter.rs index 70b71f99..4d637d1f 100644 --- a/src/parser/statement/splitter.rs +++ b/src/parser/statement/splitter.rs @@ -94,8 +94,8 @@ impl<'a> Iterator for StatementSplitter<'a> { _ if self.flags.contains(POST_MATHEXPR) => { self.flags -= POST_MATHEXPR; } - // [^A-Za-z0-9_:}] - 0...47 | 59...64 | 91...94 | 96 | 123...124 | 126...127 if self.flags.contains(VBRACE) => { + // [^A-Za-z0-9_:,}] + 0...43 | 45...47 | 59...64 | 91...94 | 96 | 123...124 | 126...127 if self.flags.contains(VBRACE) => { // If we are just ending the braced section continue as normal if error.is_none() { error = Some(StatementError::InvalidCharacter(character as char, self.read)) diff --git a/src/shell/colors.rs b/src/shell/colors.rs new file mode 100644 index 00000000..127a4f4e --- /dev/null +++ b/src/shell/colors.rs @@ -0,0 +1,113 @@ +use fnv::FnvHashMap; + +lazy_static! { + static ref ATTRIBUTES: FnvHashMap<&'static str, &'static str> = { + let mut map = FnvHashMap::default(); + map.insert("bold", "1"); + map.insert("dim", "2"); + map.insert("underlined", "4"); + map.insert("blink", "5"); + map.insert("reverse", "7"); + map.insert("hidden", "8"); + map + }; +} + +lazy_static! { + static ref COLORS: FnvHashMap<&'static str, &'static str> = { + let mut map = FnvHashMap::default(); + map.insert("black", "30"); + map.insert("red", "31"); + map.insert("green", "32"); + map.insert("yellow", "33"); + map.insert("blue", "34"); + map.insert("magenta", "35"); + map.insert("cyan", "36"); + map.insert("light_gray", "37"); + map.insert("default", "39"); + map.insert("blackbg", "40"); + map.insert("dark_gray", "90"); + map.insert("light_red", "91"); + map.insert("light_green", "92"); + map.insert("light_yellow", "93"); + map.insert("light_blue", "94"); + map.insert("light_magenta", "95"); + map.insert("light_cyan", "96"); + map + }; +} + +lazy_static! { + static ref BG_COLORS: FnvHashMap<&'static str, &'static str> = { + let mut map = FnvHashMap::default(); + map.insert("redbg", "41"); + map.insert("greenbg", "42"); + map.insert("yellowbg", "43"); + map.insert("bluebg", "44"); + map.insert("magentabg", "45"); + map.insert("cyanbg", "46"); + map.insert("light_graybg", "47"); + map.insert("defaultbg", "49"); + map.insert("dark_graybg", "100"); + map.insert("light_redbg", "101"); + map.insert("light_greenbg", "102"); + map.insert("light_yellowbg", "103"); + map.insert("light_bluebg", "104"); + map.insert("light_magentabg", "105"); + map.insert("light_cyanbg", "106"); + map.insert("whitebg", "107"); + map + }; +} + +pub struct Colors { + foreground: Option<&'static str>, + background: Option<&'static str>, + attribute: Option<Vec<&'static str>> +} + +impl Colors { + pub fn collect(input: &str) -> Colors { + let mut colors = Colors { foreground: None, background: None, attribute: None }; + for variable in input.split(",") { + if variable == "reset" { + return Colors { foreground: None, background: None, attribute: Some(vec!["0"]) }; + } else if let Some(color) = ATTRIBUTES.get(&variable) { + let vec_exists = match colors.attribute.as_mut() { + Some(mut vec) => { vec.push(color); true }, + None => false + }; + + if vec_exists { + colors.attribute = Some(vec![color]); + } + } else if let Some(color) = COLORS.get(&variable) { + colors.foreground = Some(*color) + } else { + match BG_COLORS.get(&variable) { + Some(color) => colors.background = Some(*color), + None => eprintln!("ion: {} is not a valid color", variable), + } + } + } + colors + } + + pub fn into_string(self) -> Option<String> { + let mut output = String::from("\x1b["); + if let Some(attr) = self.attribute { + output.push_str(&attr.join(";")); + match (self.foreground, self.background) { + (Some(c), None) | (None, Some(c)) => Some([&output, ";", c, "m"].concat()), + (None, None) => Some([&output, "m"].concat()), + (Some(fg), Some(bg)) => Some([&output, ";", fg, ";", bg, "m"].concat()) + } + } else { + match (self.foreground, self.background) { + (Some(c), None) | (None, Some(c)) => Some([&output, c, "m"].concat()), + (None, None) => None, + (Some(fg), Some(bg)) => Some([&output, fg, ";", bg, "m"].concat()) + } + } + } +} diff --git a/src/shell/mod.rs b/src/shell/mod.rs index da734ce6..c2191a2d 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -5,6 +5,7 @@ mod flow; mod history; mod job; mod pipe_exec; +pub mod colors; pub mod directory_stack; pub mod flags; pub mod plugins; diff --git a/src/shell/variables.rs b/src/shell/variables.rs index e08f9690..1e74ca57 100644 --- a/src/shell/variables.rs +++ b/src/shell/variables.rs @@ -17,58 +17,12 @@ use sys::getpid; use sys; use sys::variables as self_sys; +use super::colors::Colors; lazy_static! { static ref STRING_NAMESPACES: FnvHashMap<Identifier, StringNamespace> = namespaces::collect(); } -lazy_static! { - static ref COLORS: FnvHashMap<&'static str, &'static str> = { - let mut map = FnvHashMap::default(); - map.insert("reset", "\x1b[0m"); - map.insert("bold", "\x1b[1m"); - map.insert("dim", "\x1b[2m"); - map.insert("underlined", "\x1b[4m"); - map.insert("blink", "\x1b[5m"); - map.insert("reverse", "\x1b[7m"); - map.insert("hidden", "\x1b[8m"); - map.insert("black", "\x1b[30m"); - map.insert("red", "\x1b[31m"); - map.insert("green", "\x1b[32m"); - map.insert("yellow", "\x1b[33m"); - map.insert("blue", "\x1b[34m"); - map.insert("magenta", "\x1b[35m"); - map.insert("cyan", "\x1b[36m"); - map.insert("light_gray", "\x1b[37m"); - map.insert("default", "\x1b[39m"); - map.insert("blackbg", "\x1b[40m"); - map.insert("redbg", "\x1b[41m"); - map.insert("greenbg", "\x1b[42m"); - map.insert("yellowbg", "\x1b[43m"); - map.insert("bluebg", "\x1b[44m"); - map.insert("magentabg", "\x1b[45m"); - map.insert("cyanbg", "\x1b[46m"); - map.insert("light_graybg", "\x1b[47m"); - map.insert("defaultbg", "\x1b[49m"); - map.insert("dark_gray", "\x1b[90m"); - map.insert("light_red", "\x1b[91m"); - map.insert("light_green", "\x1b[92m"); - map.insert("light_yellow", "\x1b[93m"); - map.insert("light_blue", "\x1b[94m"); - map.insert("light_magenta", "\x1b[95m"); - map.insert("light_cyan", "\x1b[96m"); - map.insert("dark_graybg", "\x1b[100m"); - map.insert("light_redbg", "\x1b[101m"); - map.insert("light_greenbg", "\x1b[102m"); - map.insert("light_yellowbg", "\x1b[103m"); - map.insert("light_bluebg", "\x1b[104m"); - map.insert("light_magentabg", "\x1b[105m"); - map.insert("light_cyanbg", "\x1b[106m"); - map.insert("white_bg", "\x1b[107m"); - map - }; -} - #[derive(Debug)] pub struct Variables { pub hashmaps: HashMapVariableContext, @@ -194,13 +148,7 @@ impl Variables { if let Some((name, variable)) = name.find("::").map(|pos| (&name[..pos], &name[pos + 2..])) { // If the parsed name contains the '::' pattern, then a namespace was designated. Find it. match name { - "color" => match COLORS.get(&variable) { - Some(color) => Some((*color).into()), - None => { - eprintln!("ion: {} is not a valid color", name); - None - } - } + "color" => Colors::collect(variable).into_string(), "env" => env::var(variable).map(Into::into).ok(), _ => { // Attempt to obtain the given namespace from our lazily-generated map of namespaces. -- GitLab