mirror of
https://github.com/starship/starship.git
synced 2026-06-23 02:05:51 +07:00
feat: Add the ability to configure per-module color styles (#285)
Add parsing logic, config support, docs, and integration with other modules for custom styling of each module.
This commit is contained in:
+199
@@ -4,6 +4,8 @@ use std::env;
|
||||
use dirs::home_dir;
|
||||
use toml::value::Table;
|
||||
|
||||
use ansi_term::Color;
|
||||
|
||||
pub trait Config {
|
||||
fn initialize() -> Table;
|
||||
fn config_from_file() -> Option<Table>;
|
||||
@@ -14,6 +16,7 @@ pub trait Config {
|
||||
fn get_as_str(&self, key: &str) -> Option<&str>;
|
||||
fn get_as_i64(&self, key: &str) -> Option<i64>;
|
||||
fn get_as_array(&self, key: &str) -> Option<&Vec<toml::value::Value>>;
|
||||
fn get_as_ansi_style(&self, key: &str) -> Option<ansi_term::Style>;
|
||||
|
||||
// Internal implementation for accessors
|
||||
fn get_config(&self, key: &str) -> Option<&toml::value::Value>;
|
||||
@@ -157,11 +160,132 @@ impl Config for Table {
|
||||
}
|
||||
array_value
|
||||
}
|
||||
|
||||
/// Get a text key and attempt to interpret it into an ANSI style.
|
||||
fn get_as_ansi_style(&self, key: &str) -> Option<ansi_term::Style> {
|
||||
let style_string = self.get_as_str(key)?;
|
||||
parse_style_string(style_string)
|
||||
}
|
||||
}
|
||||
|
||||
/** Parse a style string which represents an ansi style. Valid tokens in the style
|
||||
string include the following:
|
||||
- 'fg:<color>' (specifies that the color read should be a foreground color)
|
||||
- 'bg:<color>' (specifies that the color read should be a background color)
|
||||
- 'underline'
|
||||
- 'bold'
|
||||
- '<color>' (see the parse_color_string doc for valid color strings)
|
||||
*/
|
||||
fn parse_style_string(style_string: &str) -> Option<ansi_term::Style> {
|
||||
let tokens = style_string.split_whitespace();
|
||||
let mut style = ansi_term::Style::new();
|
||||
|
||||
// If col_fg is true, color the foreground. If it's false, color the background.
|
||||
let mut col_fg: bool;
|
||||
|
||||
for token in tokens {
|
||||
let token = token.to_lowercase();
|
||||
|
||||
// Check for FG/BG identifiers and strip them off if appropriate
|
||||
let token = if token.as_str().starts_with("fg:") {
|
||||
col_fg = true;
|
||||
token.trim_start_matches("fg:").to_owned()
|
||||
} else if token.as_str().starts_with("bg:") {
|
||||
col_fg = false;
|
||||
token.trim_start_matches("bg:").to_owned()
|
||||
} else {
|
||||
col_fg = true; // Bare colors are assumed to color the foreground
|
||||
token
|
||||
};
|
||||
|
||||
match token.as_str() {
|
||||
"underline" => style = style.underline(),
|
||||
"bold" => style = style.bold(),
|
||||
"dimmed" => style = style.dimmed(),
|
||||
"none" => return Some(ansi_term::Style::new()), // Overrides other toks
|
||||
|
||||
// Try to see if this token parses as a valid color string
|
||||
color_string => {
|
||||
// Match found: set either fg or bg color
|
||||
if let Some(ansi_color) = parse_color_string(color_string) {
|
||||
if col_fg {
|
||||
style = style.fg(ansi_color);
|
||||
} else {
|
||||
style = style.on(ansi_color);
|
||||
}
|
||||
} else {
|
||||
// Match failed: skip this token and log it
|
||||
log::debug!("Could not parse token in color string: {}", token)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(style)
|
||||
}
|
||||
|
||||
/** Parse a string that represents a color setting, returning None if this fails
|
||||
There are three valid color formats:
|
||||
- #RRGGBB (a hash followed by an RGB hex)
|
||||
- u8 (a number from 0-255, representing an ANSI color)
|
||||
- colstring (one of the 16 predefined color strings)
|
||||
*/
|
||||
fn parse_color_string(color_string: &str) -> Option<ansi_term::Color> {
|
||||
// Parse RGB hex values
|
||||
log::trace!("Parsing color_string: {}", color_string);
|
||||
if color_string.starts_with('#') {
|
||||
log::trace!(
|
||||
"Attempting to read hexadecimal color string: {}",
|
||||
color_string
|
||||
);
|
||||
let r: u8 = u8::from_str_radix(&color_string[1..3], 16).ok()?;
|
||||
let g: u8 = u8::from_str_radix(&color_string[3..5], 16).ok()?;
|
||||
let b: u8 = u8::from_str_radix(&color_string[5..7], 16).ok()?;
|
||||
log::trace!("Read RGB color string: {},{},{}", r, g, b);
|
||||
return Some(Color::RGB(r, g, b));
|
||||
}
|
||||
|
||||
// Parse a u8 (ansi color)
|
||||
if let Result::Ok(ansi_color_num) = color_string.parse::<u8>() {
|
||||
log::trace!("Read ANSI color string: {}", ansi_color_num);
|
||||
return Some(Color::Fixed(ansi_color_num));
|
||||
}
|
||||
|
||||
// Check for any predefined color strings
|
||||
// There are no predefined enums for bright colors, so we use Color::Fixed
|
||||
let predefined_color = match color_string.to_lowercase().as_str() {
|
||||
"black" => Some(Color::Black),
|
||||
"red" => Some(Color::Red),
|
||||
"green" => Some(Color::Green),
|
||||
"yellow" => Some(Color::Yellow),
|
||||
"blue" => Some(Color::Blue),
|
||||
"purple" => Some(Color::Purple),
|
||||
"cyan" => Some(Color::Cyan),
|
||||
"white" => Some(Color::White),
|
||||
"bright-black" => Some(Color::Fixed(8)), // "bright-black" is dark grey
|
||||
"bright-red" => Some(Color::Fixed(9)),
|
||||
"bright-green" => Some(Color::Fixed(10)),
|
||||
"bright-yellow" => Some(Color::Fixed(11)),
|
||||
"bright-blue" => Some(Color::Fixed(12)),
|
||||
"bright-purple" => Some(Color::Fixed(13)),
|
||||
"bright-cyan" => Some(Color::Fixed(14)),
|
||||
"bright-white" => Some(Color::Fixed(15)),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if predefined_color.is_some() {
|
||||
log::trace!("Read predefined color: {}", color_string);
|
||||
return predefined_color;
|
||||
}
|
||||
|
||||
// All attempts to parse have failed
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use ansi_term::Style;
|
||||
|
||||
#[test]
|
||||
fn table_get_as_bool() {
|
||||
@@ -210,4 +334,79 @@ mod tests {
|
||||
);
|
||||
assert_eq!(table.get_as_bool("string"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn table_get_styles_simple() {
|
||||
let mut table = toml::value::Table::new();
|
||||
|
||||
// Test for a bold underline green module (with SiLlY cApS)
|
||||
table.insert(
|
||||
String::from("mystyle"),
|
||||
toml::value::Value::String(String::from("bOlD uNdErLiNe GrEeN")),
|
||||
);
|
||||
assert!(table.get_as_ansi_style("mystyle").unwrap().is_bold);
|
||||
assert!(table.get_as_ansi_style("mystyle").unwrap().is_underline);
|
||||
assert_eq!(
|
||||
table.get_as_ansi_style("mystyle").unwrap(),
|
||||
ansi_term::Style::new().bold().underline().fg(Color::Green)
|
||||
);
|
||||
|
||||
// Test a "plain" style with no formatting
|
||||
table.insert(
|
||||
String::from("plainstyle"),
|
||||
toml::value::Value::String(String::from("")),
|
||||
);
|
||||
assert_eq!(
|
||||
table.get_as_ansi_style("plainstyle").unwrap(),
|
||||
ansi_term::Style::new()
|
||||
);
|
||||
|
||||
// Test a string that's clearly broken
|
||||
table.insert(
|
||||
String::from("broken"),
|
||||
toml::value::Value::String(String::from("djklgfhjkldhlhk;j")),
|
||||
);
|
||||
assert_eq!(
|
||||
table.get_as_ansi_style("broken").unwrap(),
|
||||
ansi_term::Style::new()
|
||||
);
|
||||
|
||||
// Test a string that's nullified by `none`
|
||||
table.insert(
|
||||
String::from("nullified"),
|
||||
toml::value::Value::String(String::from("fg:red bg:green bold none")),
|
||||
);
|
||||
assert_eq!(
|
||||
table.get_as_ansi_style("nullified").unwrap(),
|
||||
ansi_term::Style::new()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn table_get_styles_ordered() {
|
||||
let mut table = toml::value::Table::new();
|
||||
|
||||
// Test a background style with inverted order (also test hex + ANSI)
|
||||
table.insert(
|
||||
String::from("flipstyle"),
|
||||
toml::value::Value::String(String::from("bg:#050505 underline fg:120")),
|
||||
);
|
||||
assert_eq!(
|
||||
table.get_as_ansi_style("flipstyle").unwrap(),
|
||||
Style::new()
|
||||
.underline()
|
||||
.fg(Color::Fixed(120))
|
||||
.on(Color::RGB(5, 5, 5))
|
||||
);
|
||||
|
||||
// Test that the last color style is always the one used
|
||||
table.insert(
|
||||
String::from("multistyle"),
|
||||
toml::value::Value::String(String::from("bg:120 bg:125 bg:127 fg:127 122 125")),
|
||||
);
|
||||
assert_eq!(
|
||||
table.get_as_ansi_style("multistyle").unwrap(),
|
||||
Style::new().fg(Color::Fixed(125)).on(Color::Fixed(127))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,6 +139,11 @@ impl<'a> Module<'a> {
|
||||
pub fn config_value_bool(&self, key: &str) -> Option<bool> {
|
||||
self.config.and_then(|config| config.get_as_bool(key))
|
||||
}
|
||||
|
||||
/// Get a module's config value as a style
|
||||
pub fn config_value_style(&self, key: &str) -> Option<Style> {
|
||||
self.config.and_then(|config| config.get_as_ansi_style(key))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for Module<'a> {
|
||||
|
||||
@@ -30,7 +30,10 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
|
||||
// TODO: Set style based on percentage when threshold is modifiable
|
||||
let mut module = context.new_module("battery")?;
|
||||
module.set_style(Color::Red.bold());
|
||||
let module_style = module
|
||||
.config_value_style("style")
|
||||
.unwrap_or_else(|| Color::Red.bold());
|
||||
module.set_style(module_style);
|
||||
module.get_prefix().set_value("");
|
||||
|
||||
match state {
|
||||
|
||||
@@ -5,10 +5,10 @@ use ansi_term::Color;
|
||||
///
|
||||
/// The character segment prints an arrow character in a color dependant on the exit-
|
||||
/// code of the last executed command:
|
||||
/// - If the exit-code was "0", the arrow will be formatted with `COLOR_SUCCESS`
|
||||
/// - If the exit-code was "0", the arrow will be formatted with `style_success`
|
||||
/// (green by default)
|
||||
/// - If the exit-code was anything else, the arrow will be formatted with
|
||||
/// `COLOR_FAILURE` (red by default)
|
||||
/// `style_failure` (red by default)
|
||||
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
const SUCCESS_CHAR: &str = "❯";
|
||||
const FAILURE_CHAR: &str = "✖";
|
||||
@@ -20,12 +20,16 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
const ASSUMED_MODE: ShellEditMode = ShellEditMode::Insert;
|
||||
// TODO: extend config to more modes
|
||||
|
||||
let color_success = Color::Green.bold();
|
||||
let color_failure = Color::Red.bold();
|
||||
|
||||
let mut module = context.new_module("character")?;
|
||||
module.get_prefix().set_value("");
|
||||
|
||||
let style_success = module
|
||||
.config_value_style("style_success")
|
||||
.unwrap_or_else(|| Color::Green.bold());
|
||||
let style_failure = module
|
||||
.config_value_style("style_failure")
|
||||
.unwrap_or_else(|| Color::Red.bold());
|
||||
|
||||
let arguments = &context.arguments;
|
||||
let use_symbol = module
|
||||
.config_value_bool("use_symbol_for_status")
|
||||
@@ -56,9 +60,9 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
};
|
||||
|
||||
if exit_success {
|
||||
symbol.set_style(color_success.bold());
|
||||
symbol.set_style(style_success);
|
||||
} else {
|
||||
symbol.set_style(color_failure.bold());
|
||||
symbol.set_style(style_failure);
|
||||
};
|
||||
|
||||
Some(module)
|
||||
|
||||
@@ -32,7 +32,9 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
|
||||
let module_color = match elapsed {
|
||||
time if time < config_min => return None,
|
||||
_ => Color::Yellow.bold(),
|
||||
_ => module
|
||||
.config_value_style("style")
|
||||
.unwrap_or_else(|| Color::Yellow.bold()),
|
||||
};
|
||||
|
||||
module.set_style(module_color);
|
||||
|
||||
@@ -17,9 +17,11 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
const HOME_SYMBOL: &str = "~";
|
||||
const DIR_TRUNCATION_LENGTH: i64 = 3;
|
||||
const FISH_STYLE_PWD_DIR_LENGTH: i64 = 0;
|
||||
let module_color = Color::Cyan.bold();
|
||||
|
||||
let mut module = context.new_module("directory")?;
|
||||
let module_color = module
|
||||
.config_value_style("style")
|
||||
.unwrap_or_else(|| Color::Cyan.bold());
|
||||
module.set_style(module_color);
|
||||
|
||||
let truncation_length = module
|
||||
|
||||
@@ -9,9 +9,11 @@ use super::{Context, Module};
|
||||
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
const GIT_BRANCH_CHAR: &str = " ";
|
||||
|
||||
let segment_color = Color::Purple.bold();
|
||||
|
||||
let mut module = context.new_module("git_branch")?;
|
||||
|
||||
let segment_color = module
|
||||
.config_value_style("style")
|
||||
.unwrap_or_else(|| Color::Purple.bold());
|
||||
module.set_style(segment_color);
|
||||
module.get_prefix().set_value("on ");
|
||||
|
||||
|
||||
@@ -19,9 +19,12 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
return None;
|
||||
}
|
||||
|
||||
let module_style = module
|
||||
.config_value_style("style")
|
||||
.unwrap_or_else(|| Color::Yellow.bold());
|
||||
module.set_style(module_style);
|
||||
module.get_prefix().set_value("(");
|
||||
module.get_suffix().set_value(") ");
|
||||
module.set_style(Color::Yellow.bold());
|
||||
|
||||
let label = match state_description {
|
||||
StateDescription::Label(label) => label,
|
||||
|
||||
@@ -34,10 +34,11 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
let repo_root = context.repo_root.as_ref()?;
|
||||
let repository = Repository::open(repo_root).ok()?;
|
||||
|
||||
let module_style = Color::Red.bold();
|
||||
let mut module = context.new_module("git_status")?;
|
||||
|
||||
let show_sync_count = module.config_value_bool("show_sync_count").unwrap_or(false);
|
||||
let module_style = module
|
||||
.config_value_style("style")
|
||||
.unwrap_or_else(|| Color::Red.bold());
|
||||
|
||||
module.get_prefix().set_value("[").set_style(module_style);
|
||||
module.get_suffix().set_value("] ").set_style(module_style);
|
||||
|
||||
@@ -28,10 +28,12 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
match get_go_version() {
|
||||
Some(go_version) => {
|
||||
const GO_CHAR: &str = "🐹 ";
|
||||
let module_color = Color::Cyan.bold();
|
||||
|
||||
let mut module = context.new_module("golang")?;
|
||||
module.set_style(module_color);
|
||||
let module_style = module
|
||||
.config_value_style("style")
|
||||
.unwrap_or_else(|| Color::Cyan.bold());
|
||||
module.set_style(module_style);
|
||||
|
||||
let formatted_version = format_go_version(&go_version)?;
|
||||
module.new_segment("symbol", GO_CHAR);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use ansi_term::{Color, Style};
|
||||
use ansi_term::Color;
|
||||
use std::env;
|
||||
use std::process::Command;
|
||||
|
||||
use super::{Context, Module};
|
||||
use std::ffi::OsString;
|
||||
@@ -12,6 +11,9 @@ use std::ffi::OsString;
|
||||
/// - hostname.ssh_only is false OR the user is currently connected as an SSH session (`$SSH_CONNECTION`)
|
||||
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
let mut module = context.new_module("hostname")?;
|
||||
let module_style = module
|
||||
.config_value_style("style")
|
||||
.unwrap_or_else(|| Color::Green.bold().dimmed());
|
||||
|
||||
let ssh_connection = env::var("SSH_CONNECTION").ok();
|
||||
if module.config_value_bool("ssh_only").unwrap_or(true) && ssh_connection.is_none() {
|
||||
@@ -31,7 +33,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
let prefix = module.config_value_str("prefix").unwrap_or("").to_owned();
|
||||
let suffix = module.config_value_str("suffix").unwrap_or("").to_owned();
|
||||
|
||||
module.set_style(Color::Green.bold().dimmed());
|
||||
module.set_style(module_style);
|
||||
module.new_segment("hostname", &format!("{}{}{}", prefix, host, suffix));
|
||||
module.get_prefix().set_value("on ");
|
||||
|
||||
|
||||
+4
-3
@@ -9,9 +9,10 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
let threshold = module.config_value_i64("threshold").unwrap_or(1);
|
||||
|
||||
const JOB_CHAR: &str = "✦";
|
||||
let module_color = Color::Blue.bold();
|
||||
|
||||
module.set_style(module_color);
|
||||
let module_style = module
|
||||
.config_value_style("style")
|
||||
.unwrap_or_else(|| Color::Blue.bold());
|
||||
module.set_style(module_style);
|
||||
|
||||
let arguments = &context.arguments;
|
||||
let num_of_jobs = arguments
|
||||
|
||||
@@ -46,8 +46,10 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
}
|
||||
})
|
||||
.map(|segment| {
|
||||
let module_color = Color::Red.bold();
|
||||
module.set_style(module_color);
|
||||
let module_style = module
|
||||
.config_value_style("style")
|
||||
.unwrap_or_else(|| Color::Red.bold());
|
||||
module.set_style(module_style);
|
||||
module.new_segment("nix_shell", &segment);
|
||||
module
|
||||
})
|
||||
|
||||
@@ -24,10 +24,12 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
match get_node_version() {
|
||||
Some(node_version) => {
|
||||
const NODE_CHAR: &str = "⬢ ";
|
||||
let module_color = Color::Green.bold();
|
||||
|
||||
let mut module = context.new_module("nodejs")?;
|
||||
module.set_style(module_color);
|
||||
let module_style = module
|
||||
.config_value_style("style")
|
||||
.unwrap_or_else(|| Color::Green.bold());
|
||||
module.set_style(module_style);
|
||||
|
||||
let formatted_version = node_version.trim();
|
||||
module.new_segment("symbol", NODE_CHAR);
|
||||
|
||||
@@ -12,10 +12,12 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
match get_package_version() {
|
||||
Some(package_version) => {
|
||||
const PACKAGE_CHAR: &str = "📦 ";
|
||||
let module_color = Color::Red.bold();
|
||||
|
||||
let mut module = context.new_module("package")?;
|
||||
module.set_style(module_color);
|
||||
let module_style = module
|
||||
.config_value_style("style")
|
||||
.unwrap_or_else(|| Color::Red.bold());
|
||||
module.set_style(module_style);
|
||||
module.get_prefix().set_value("is ");
|
||||
|
||||
module.new_segment("symbol", PACKAGE_CHAR);
|
||||
|
||||
@@ -36,7 +36,9 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
.unwrap_or(false);
|
||||
|
||||
const PYTHON_CHAR: &str = "🐍 ";
|
||||
let module_color = Color::Yellow.bold();
|
||||
let module_color = module
|
||||
.config_value_style("style")
|
||||
.unwrap_or_else(|| Color::Yellow.bold());
|
||||
module.set_style(module_color);
|
||||
module.new_segment("symbol", PYTHON_CHAR);
|
||||
|
||||
|
||||
+4
-2
@@ -22,10 +22,12 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
match get_ruby_version() {
|
||||
Some(ruby_version) => {
|
||||
const RUBY_CHAR: &str = "💎 ";
|
||||
let module_color = Color::Red.bold();
|
||||
|
||||
let mut module = context.new_module("ruby")?;
|
||||
module.set_style(module_color);
|
||||
let module_style = module
|
||||
.config_value_style("style")
|
||||
.unwrap_or_else(|| Color::Red.bold());
|
||||
module.set_style(module_style);
|
||||
|
||||
let formatted_version = format_ruby_version(&ruby_version)?;
|
||||
module.new_segment("symbol", RUBY_CHAR);
|
||||
|
||||
+4
-2
@@ -22,10 +22,12 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
match get_rust_version() {
|
||||
Some(rust_version) => {
|
||||
const RUST_CHAR: &str = "🦀 ";
|
||||
let module_color = Color::Red.bold();
|
||||
|
||||
let mut module = context.new_module("rust")?;
|
||||
module.set_style(module_color);
|
||||
let module_style = module
|
||||
.config_value_style("style")
|
||||
.unwrap_or_else(|| Color::Red.bold());
|
||||
module.set_style(module_style);
|
||||
|
||||
let formatted_version = format_rustc_version(rust_version);
|
||||
module.new_segment("symbol", RUST_CHAR);
|
||||
|
||||
+13
-12
@@ -15,11 +15,12 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
let logname = env::var("LOGNAME").ok();
|
||||
let ssh_connection = env::var("SSH_CONNECTION").ok();
|
||||
|
||||
let mut module_color = Color::Yellow.bold();
|
||||
|
||||
if user != logname || ssh_connection.is_some() || is_root(&mut module_color) {
|
||||
const ROOT_UID: Option<u32> = Some(0);
|
||||
let user_uid = get_uid();
|
||||
if user != logname || ssh_connection.is_some() || user_uid == ROOT_UID {
|
||||
let mut module = context.new_module("username")?;
|
||||
module.set_style(module_color);
|
||||
let module_style = get_mod_style(user_uid, &module);
|
||||
module.set_style(module_style);
|
||||
module.new_segment("username", &user?);
|
||||
|
||||
return Some(module);
|
||||
@@ -37,13 +38,13 @@ fn get_uid() -> Option<u32> {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_root(style: &mut Style) -> bool {
|
||||
match get_uid() {
|
||||
Some(uid) if uid == 0 => {
|
||||
style.clone_from(&Color::Red.bold());
|
||||
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
fn get_mod_style(user_uid: Option<u32>, module: &Module) -> Style {
|
||||
match user_uid {
|
||||
Some(0) => module
|
||||
.config_value_style("style_root")
|
||||
.unwrap_or_else(|| Color::Red.bold()),
|
||||
_ => module
|
||||
.config_value_style("style_user")
|
||||
.unwrap_or_else(|| Color::Yellow.bold()),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user