diff --git a/.gitignore b/.gitignore index 029a7af..384b407 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ bacon.toml Cargo.lock .DS_Store -Dockerfile \ No newline at end of file +Dockerfile +.idea/ \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 185977b..63b250f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ keywords = ["system", "cli", "fetch", "asynchronous", "asynch"] categories = ["command-line-utilities"] [dependencies] +any_terminal_size = {version = "0.1.21", default-features = false} console = { version = "0.15.0", default-features = false, features = ["ansi-parsing"] } dirs = { version = "4.0.0", default-features = false } libmacchina = { version = "3.8.6", default-features = false } diff --git a/README.md b/README.md index 2fdae46..fab05e5 100644 --- a/README.md +++ b/README.md @@ -178,7 +178,7 @@ OPTIONS: | pre_text_style | A format string with each word separated by dots that describes the style of the text that before this module | | pre_text | Text that comes before this module | | output_style | A format string with each word separated by dots that describes the style of the output text | -| Command | The command to run to get the output of the module | +| command | The command to run to get the output of the module | # Default Configuration A default Configuration will look like so: diff --git a/src/config.rs b/src/config.rs index 1dd2000..fb2db5d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,7 +1,10 @@ use crate::cli::Mode; use crate::cli::Opt; use crate::handle_error; -use crate::modules::*; +use crate::modules::{ + Cpu, Delimiter, DesktopEnvironment, Format, Host, Kernel, Module, Os, Packages, Resolution, + Shell, Terminal, Uptime, User, WindowManager, +}; use console::measure_text_width; use console::style; use console::Style; @@ -29,6 +32,7 @@ pub struct Config { desktop_environment: DesktopEnvironment, window_manager: WindowManager, terminal: Terminal, + cpu: Cpu, #[serde(flatten)] custom_modules: HashMap, @@ -84,7 +88,7 @@ impl Config { {line_len_sep} |", error = r, line_len_sep = " ".repeat(line.to_string().len()), - col_len_sep = " ".repeat(column as usize), + col_len_sep = " ".repeat(column.try_into().unwrap()), line = line, line_contents = string.lines().collect::>()[(line - 1) as usize], @@ -123,7 +127,9 @@ impl Config { let desktop_environment = self_clone.desktop_environment; let window_manager = self_clone.window_manager; let terminal = self_clone.terminal; + let cpu = self_clone.cpu; let custom = self_clone.custom_modules; + if modules.contains(&"user") { let handle = thread::spawn(move || (String::from("user"), user.get_info())); handles.push(handle); @@ -174,6 +180,10 @@ impl Config { let handle = thread::spawn(move || (String::from("terminal"), terminal.get_info())); handles.push(handle); } + if modules.contains(&"cpu") { + let handle = thread::spawn(move || (String::from("cpu"), cpu.get_info())); + handles.push(handle); + } for (name, module) in custom { let handle = thread::spawn(move || (name, module.get_info())); handles.push(handle); @@ -202,8 +212,8 @@ impl Config { vec } - fn logo(&self) -> Vec { - let os = self.os.get_os(); + fn logo() -> Vec { + let os = crate::modules::Os::get_os(); match os.trim() { x if x.contains("macOS") => { let yellow = Style::from_dotted_str("yellow.bold"); @@ -270,18 +280,49 @@ impl Config { fn get_logo(&self) -> Vec { if self.logo_cmd.is_empty() || self.logo_cmd == "auto" { - self.logo() + Config::logo() } else { Config::run_cmd(&self.logo_cmd, "Failed to run logo command") .lines() - .map(|v| v.to_string()) + .map(str::to_string) .collect::>() } } + fn wrap_lines(module_order: &[String], logo: &[String]) -> Vec { + use any_terminal_size::{any_terminal_size, Width}; + + let size = any_terminal_size(); + let mut terminal_width: usize = 0; + if let Some((Width(width), _)) = size { + terminal_width = width as usize; + } + let mut module_order_wrapped = Vec::new(); + + for (i, string) in module_order.iter().enumerate() { + if string.len() >= terminal_width - logo[i].len() { + use std::str; + let mut subs = string + .as_bytes() + .chunks(terminal_width - logo[i].len()) + .map(str::from_utf8) + .collect::, _>>() + .unwrap(); + + module_order_wrapped.append(&mut subs); + } else { + module_order_wrapped.push(string); + } + } + module_order_wrapped + .iter() + .map(|&x| x.to_string()) + .collect::>() + } + fn print_classic(&self) { let mut sidelogo = self.get_logo(); - let mut order = self.module_order(); + let mut order = Config::wrap_lines(&self.module_order(), &sidelogo); let maxlength = self.logo_maxlength(); @@ -319,35 +360,30 @@ impl Config { } fn logo_maxlength(&self) -> usize { - match self + if let Some(v) = self .get_logo() .iter() .max_by_key(|&x| measure_text_width(x)) { - Some(v) => measure_text_width(v), - None => { - UserFacingError::new("Failed to find logo line with greatest length") - .print_and_exit(); - unreachable!() - } + return measure_text_width(v); } + UserFacingError::new("Failed to find logo line with greatest length").print_and_exit(); + unreachable!() } fn info_maxlength(info: &[String]) -> usize { - match info.iter().max_by_key(|&x| measure_text_width(x)) { - Some(v) => measure_text_width(v), - None => { - UserFacingError::new("Failed to find info line with the greatest length") - .help("Make sure that you have some modules defined.") - .print_and_exit(); - unreachable!() - } + if let Some(v) = info.iter().max_by_key(|&x| measure_text_width(x)) { + return measure_text_width(v); } + UserFacingError::new("Failed to find info line with the greatest length") + .help("Make sure that you have some modules defined.") + .print_and_exit(); + unreachable!() } fn print_side_table(&self) { let mut sidelogo = self.get_logo(); - let mut info = self.module_order(); + let mut info = Config::wrap_lines(&self.module_order(), &sidelogo); let mut counter = 0; info.resize(sidelogo.len() + self.format.padding_top, String::from("")); sidelogo.resize(info.len() + self.format.padding_top, String::from("")); @@ -412,7 +448,7 @@ impl Config { fn print_bottom_table(&self) { let sidelogo = self.get_logo(); - let info = self.module_order(); + let info = Config::wrap_lines(&self.module_order(), &sidelogo); let info_maxlength = Config::info_maxlength(&info); for line in sidelogo { @@ -432,7 +468,7 @@ impl Config { "{vertical}{}{vertical}", " ".repeat(info_maxlength + self.format.padding_right + self.format.padding_left), vertical = self.format.vertical_char - ) + ); } for line in info { println!( @@ -457,19 +493,18 @@ impl Config { pub fn print(&self) { let matches = Config::get_args(); - if let Some(v) = matches.mode { - match v { + matches.mode.map_or_else( + || match self.format.mode { Mode::Classic => self.print_classic(), Mode::BottomBlock => self.print_bottom_table(), Mode::SideBlock => self.print_side_table(), - } - } else { - match self.format.mode { + }, + |v| match v { Mode::Classic => self.print_classic(), Mode::BottomBlock => self.print_bottom_table(), Mode::SideBlock => self.print_side_table(), - } - } + }, + ); } } @@ -478,7 +513,7 @@ impl Default for Config { Config { offset: 4, module_order: String::from( - "user delimiter os host kernel uptime packages shell resolution desktop_environment window_manager terminal", + "user delimiter os host kernel uptime packages shell resolution desktop_environment window_manager terminal cpu", ), logo_cmd: String::from("auto"), format: Format::default(), @@ -495,6 +530,7 @@ impl Default for Config { desktop_environment: DesktopEnvironment::default(), window_manager: WindowManager::default(), terminal: Terminal::default(), + cpu: Cpu::default(), } } } diff --git a/src/main.rs b/src/main.rs index 79b4d6c..103763d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +#![warn(clippy::pedantic)] mod cli; mod config; mod modules; diff --git a/src/modules.rs b/src/modules.rs index d72d6d1..8124799 100644 --- a/src/modules.rs +++ b/src/modules.rs @@ -27,7 +27,7 @@ pub struct Format { impl Default for Format { fn default() -> Self { - Format { + Self { mode: Mode::Classic, top_left_corner_char: '╭', top_right_corner_char: '╮', @@ -54,7 +54,7 @@ pub struct User { impl Default for User { fn default() -> Self { - User { + Self { pre_text_style: String::from("bold.yellow"), pre_text: String::from(""), output_style: String::from("bold.yellow"), @@ -89,7 +89,7 @@ pub struct Delimiter { impl Default for Delimiter { fn default() -> Self { - Delimiter { + Self { style: String::from("white"), repeat_num: 0, char: '-', @@ -120,7 +120,7 @@ pub struct Os { impl Default for Os { fn default() -> Self { - Os { + Self { pre_text_style: String::from("bold.yellow"), pre_text: String::from("OS: "), output_style: String::from("white"), @@ -129,7 +129,7 @@ impl Default for Os { } impl Os { - pub fn get_os(&self) -> String { + pub fn get_os() -> String { let general_readout = GeneralReadout::new(); let os: String; if cfg!(target_os = "linux") { @@ -140,9 +140,9 @@ impl Os { os } pub fn get_info(&self) -> String { - let os = self.get_os(); + let os = Os::get_os(); let build_version = Config::run_cmd("sw_vers -buildVersion", "Failed to get build version"); - let arch = Config::run_cmd("uname -m", "Failed to get arch"); + let arch = Config::run_cmd("machine", "Failed to get arch"); let output_style = Style::from_dotted_str(&self.output_style); format!( @@ -165,7 +165,7 @@ pub struct Host { impl Default for Host { fn default() -> Self { - Host { + Self { pre_text_style: String::from("bold.yellow"), pre_text: String::from("Host: "), output_style: String::from("white"), @@ -194,7 +194,7 @@ pub struct Kernel { impl Default for Kernel { fn default() -> Self { - Kernel { + Self { pre_text_style: String::from("bold.yellow"), pre_text: String::from("Kernel: "), output_style: String::from("white"), @@ -228,7 +228,7 @@ pub struct Uptime { impl Default for Uptime { fn default() -> Self { - Uptime { + Self { pre_text_style: String::from("bold.yellow"), pre_text: String::from("Uptime: "), output_style: String::from("white"), @@ -270,7 +270,7 @@ pub struct Packages { impl Default for Packages { fn default() -> Self { - Packages { + Self { pre_text_style: String::from("bold.yellow"), pre_text: String::from("Packages: "), output_style: String::from("white"), @@ -304,7 +304,7 @@ pub struct Shell { impl Default for Shell { fn default() -> Self { - Shell { + Self { pre_text_style: String::from("bold.yellow"), pre_text: String::from("Shell: "), output_style: String::from("white"), @@ -347,7 +347,7 @@ pub struct Resolution { impl Default for Resolution { fn default() -> Self { - Resolution { + Self { pre_text_style: String::from("bold.yellow"), pre_text: String::from("Resolution: "), output_style: String::from("white"), @@ -378,7 +378,7 @@ pub struct DesktopEnvironment { impl Default for DesktopEnvironment { fn default() -> Self { - DesktopEnvironment { + Self { pre_text_style: String::from("bold.yellow"), pre_text: String::from("Desktop Environment: "), output_style: String::from("white"), @@ -412,7 +412,7 @@ pub struct WindowManager { impl Default for WindowManager { fn default() -> Self { - WindowManager { + Self { pre_text_style: String::from("bold.yellow"), pre_text: String::from("Window Manager: "), output_style: String::from("white"), @@ -446,7 +446,7 @@ pub struct Terminal { impl Default for Terminal { fn default() -> Self { - Terminal { + Self { pre_text_style: String::from("bold.yellow"), pre_text: String::from("Terminal: "), output_style: String::from("white"), @@ -467,6 +467,37 @@ impl Terminal { } } +#[derive(Deserialize, Debug, PartialEq, Clone)] +#[serde(deny_unknown_fields, default)] +pub struct Cpu { + pre_text_style: String, + pre_text: String, + output_style: String, +} + +impl Default for Cpu { + fn default() -> Self { + Self { + pre_text_style: String::from("bold.yellow"), + pre_text: String::from("CPU: "), + output_style: String::from("white"), + } + } +} + +impl Cpu { + pub fn get_info(&self) -> String { + let general_readout = GeneralReadout::new(); + let cpu = handle_error!(general_readout.cpu_model_name(), "Failed to get CPU name"); + + format!( + "{}{}", + Style::from_dotted_str(&self.pre_text_style).apply_to(&self.pre_text), + Style::from_dotted_str(&self.output_style).apply_to(cpu), + ) + } +} + #[derive(Deserialize, Debug, PartialEq, Clone)] #[serde(deny_unknown_fields, default)] pub struct Module { @@ -490,7 +521,7 @@ impl Module { impl Default for Module { fn default() -> Self { - Module { + Self { command: String::from(""), output_style: String::from("white"), pre_text: String::from(""), diff --git a/src/utils.rs b/src/utils.rs index 233cd68..b759be0 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -5,14 +5,14 @@ macro_rules! handle_error { v } else { let r = $err.unwrap_err().to_string(); - if r != "" { + if r == "" { UserFacingError::new($err_msg) .help($help_msg) - .reason(r) .print_and_exit(); } else { UserFacingError::new($err_msg) .help($help_msg) + .reason(r) .print_and_exit(); } unreachable!() @@ -23,10 +23,10 @@ macro_rules! handle_error { v } else { let r = $err.unwrap_err().to_string(); - if r != "" { - UserFacingError::new($err_msg).reason(r).print_and_exit(); - } else { + if r == "" { UserFacingError::new($err_msg).print_and_exit(); + } else { + UserFacingError::new($err_msg).reason(r).print_and_exit(); } unreachable!() }