From 065216af7ca5d1f5a6efd19ae5969d5fa9815689 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Thu, 19 Dec 2024 17:20:46 +0300 Subject: [PATCH 1/8] colors: respect NO_COLOR spec Microfetch will now respect the NO_COLOR environment variable if it has been passed to the program. The performance overhead of this operation is almost none. In addition, the main function has been updated to lock stdout. --- Cargo.lock | 7 ++++++ Cargo.toml | 1 + src/colors.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++------- src/main.rs | 38 ++++++++++++++++++------------- src/system.rs | 33 +++++++++++++-------------- 5 files changed, 99 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f21044e..980d4ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -306,6 +306,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.155" @@ -330,6 +336,7 @@ version = "0.4.0" dependencies = [ "color-eyre", "criterion", + "lazy_static", "nix", ] diff --git a/Cargo.toml b/Cargo.toml index 5c346cb..107d793 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ path = "src/main.rs" [dependencies] nix = { version = "0.29", features = ["fs", "hostname", "feature"] } color-eyre = { version = "0.6", default-features = false } +lazy_static = "1.5.0" [dev-dependencies] criterion = "0.5" diff --git a/src/colors.rs b/src/colors.rs index a8aee60..061db15 100644 --- a/src/colors.rs +++ b/src/colors.rs @@ -1,11 +1,57 @@ -pub const RESET: &str = "\x1b[0m"; -pub const BLUE: &str = "\x1b[34m"; -pub const CYAN: &str = "\x1b[36m"; -pub const GREEN: &str = "\x1b[32m"; -pub const YELLOW: &str = "\x1b[33m"; -pub const RED: &str = "\x1b[31m"; -pub const MAGENTA: &str = "\x1b[35m"; +use std::env; + +pub struct Colors { + pub reset: &'static str, + pub blue: &'static str, + pub cyan: &'static str, + pub green: &'static str, + pub yellow: &'static str, + pub red: &'static str, + pub magenta: &'static str, +} + +impl Colors { + const fn new(is_no_color: bool) -> Self { + match is_no_color { + true => Self { + reset: "", + blue: "", + cyan: "", + green: "", + yellow: "", + red: "", + magenta: "", + }, + false => Self { + reset: "\x1b[0m", + blue: "\x1b[34m", + cyan: "\x1b[36m", + green: "\x1b[32m", + yellow: "\x1b[33m", + red: "\x1b[31m", + magenta: "\x1b[35m", + }, + } + } +} + +lazy_static::lazy_static! { + pub static ref COLORS: Colors = { + // check for NO_COLOR once at startup + let is_no_color = env::var("NO_COLOR").is_ok(); + Colors::new(is_no_color) + }; +} pub fn print_dots() -> String { - format!("{BLUE} {CYAN} {GREEN} {YELLOW} {RED} {MAGENTA} {RESET}") + format!( + "{} {} {} {} {} {} {}", + COLORS.blue, + COLORS.cyan, + COLORS.green, + COLORS.yellow, + COLORS.red, + COLORS.magenta, + COLORS.reset, + ) } diff --git a/src/main.rs b/src/main.rs index 5cb9904..0ea1672 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,15 +4,13 @@ mod release; mod system; mod uptime; -use std::io::Write; - -use crate::colors::{print_dots, BLUE, CYAN, RESET}; +use crate::colors::print_dots; use crate::desktop::get_desktop_info; use crate::release::{get_os_pretty_name, get_system_info}; use crate::system::{get_memory_usage, get_root_disk_usage, get_shell, get_username_and_hostname}; use crate::uptime::get_current; - use color_eyre::Report; +use std::io::Write; fn main() -> Result<(), Report> { color_eyre::install()?; @@ -56,6 +54,8 @@ struct Fields { } fn print_system_info(fields: &Fields) { + use crate::colors::COLORS; + let Fields { user_info, os_name, @@ -68,16 +68,22 @@ fn print_system_info(fields: &Fields) { colors, } = fields; - let _ = std::io::stdout().write_all(format!( - " - {CYAN} ▟█▖ {BLUE}▝█▙ ▗█▛ {user_info} ~{RESET} - {CYAN} ▗▄▄▟██▄▄▄▄▄{BLUE}▝█▙█▛ {CYAN}▖ {CYAN} {BLUE}System{RESET}  {os_name} - {CYAN} ▀▀▀▀▀▀▀▀▀▀▀▘{BLUE}▝██ {CYAN}▟█▖ {CYAN} {BLUE}Kernel{RESET}  {kernel_version} - {BLUE} ▟█▛ {BLUE}▝█▘{CYAN}▟█▛ {CYAN} {BLUE}Shell{RESET}  {shell} - {BLUE}▟█████▛ {CYAN}▟█████▛ {CYAN} {BLUE}Uptime{RESET}  {uptime} - {BLUE} ▟█▛{CYAN}▗█▖ {CYAN}▟█▛ {CYAN} {BLUE}Desktop{RESET}  {desktop} - {BLUE} ▝█▛ {CYAN}██▖{BLUE}▗▄▄▄▄▄▄▄▄▄▄▄ {CYAN}󰍛 {BLUE}Memory{RESET}  {memory_usage} - {BLUE} ▝ {CYAN}▟█▜█▖{BLUE}▀▀▀▀▀██▛▀▀▘ {CYAN}󱥎 {BLUE}Storage (/){RESET}  {storage} - {CYAN} ▟█▘ ▜█▖ {BLUE}▝█▛ {CYAN} {BLUE}Colors{RESET}  {colors} -").as_bytes()); + let cyan = COLORS.cyan; + let blue = COLORS.blue; + let reset = COLORS.reset; + let system_info = format!(" + {cyan} ▟█▖ {blue}▝█▙ ▗█▛ {user_info} ~{reset} + {cyan} ▗▄▄▟██▄▄▄▄▄{blue}▝█▙█▛ {cyan}▖ {cyan} {blue}System{reset}  {os_name} + {cyan} ▀▀▀▀▀▀▀▀▀▀▀▘{blue}▝██ {cyan}▟█▖ {cyan} {blue}Kernel{reset}  {kernel_version} + {blue} ▟█▛ {blue}▝█▘{cyan}▟█▛ {cyan} {blue}Shell{reset}  {shell} + {blue}▟█████▛ {cyan}▟█████▛ {cyan} {blue}Uptime{reset}  {uptime} + {blue} ▟█▛{cyan}▗█▖ {cyan}▟█▛ {cyan} {blue}Desktop{reset}  {desktop} + {blue} ▝█▛ {cyan}██▖{blue}▗▄▄▄▄▄▄▄▄▄▄▄ {cyan}󰍛 {blue}Memory{reset}  {memory_usage} + {blue} ▝ {cyan}▟█▜█▖{blue}▀▀▀▀▀██▛▀▀▘ {cyan}󱥎 {blue}Storage (/){reset}  {storage} + {cyan} ▟█▘ ▜█▖ {blue}▝█▛ {cyan} {blue}Colors{reset}  {colors}"); + + std::io::stdout() + .lock() + .write_all(system_info.as_bytes()) + .expect("Failed to write to stdout"); } diff --git a/src/system.rs b/src/system.rs index 74d774f..11a72d9 100644 --- a/src/system.rs +++ b/src/system.rs @@ -1,14 +1,12 @@ +use crate::colors::COLORS; use color_eyre::Result; use nix::sys::{statvfs::statvfs, utsname::UtsName}; - use std::{ env, fs::File, io::{self, Read}, }; -use crate::colors::{CYAN, GREEN, RED, RESET, YELLOW}; - pub fn get_username_and_hostname(utsname: &UtsName) -> String { let username = env::var("USER").unwrap_or("unknown_user".to_string()); let hostname = utsname @@ -16,14 +14,18 @@ pub fn get_username_and_hostname(utsname: &UtsName) -> String { .to_str() .unwrap_or("unknown_host") .to_string(); - - format!("{YELLOW}{username}{RED}@{GREEN}{hostname}") + format!( + "{yellow}{username}{red}@{green}{hostname}{reset}", + yellow = COLORS.yellow, + red = COLORS.red, + green = COLORS.green, + reset = COLORS.reset, + ) } pub fn get_shell() -> String { let shell_path = env::var("SHELL").unwrap_or("unknown_shell".to_string()); let shell_name = shell_path.rsplit('/').next().unwrap_or("unknown_shell"); - shell_name.to_string() } @@ -32,16 +34,15 @@ pub fn get_root_disk_usage() -> Result { let block_size = vfs.block_size() as u64; let total_blocks = vfs.blocks(); let available_blocks = vfs.blocks_available(); - let total_size = block_size * total_blocks; let used_size = total_size - (block_size * available_blocks); - let total_size = total_size as f64 / (1024.0 * 1024.0 * 1024.0); let used_size = used_size as f64 / (1024.0 * 1024.0 * 1024.0); - let usage = (used_size as f64 / total_size as f64) * 100.0; - + let usage = (used_size / total_size) * 100.0; Ok(format!( - "{used_size:.2} GiB / {total_size:.2} GiB ({CYAN}{usage:.0}%{RESET})" + "{used_size:.2} GiB / {total_size:.2} GiB ({cyan}{usage:.0}%{reset})", + cyan = COLORS.cyan, + reset = COLORS.reset, )) } @@ -50,35 +51,31 @@ pub fn get_memory_usage() -> Result { fn parse_memory_info() -> Result<(f64, f64), io::Error> { let mut total_memory_kb = 0.0; let mut available_memory_kb = 0.0; - let mut meminfo = String::with_capacity(2048); File::open("/proc/meminfo")?.read_to_string(&mut meminfo)?; - for line in meminfo.lines() { let mut split = line.split_whitespace(); match split.next().unwrap_or_default() { "MemTotal:" => total_memory_kb = split.next().unwrap_or("0").parse().unwrap_or(0.0), "MemAvailable:" => { available_memory_kb = split.next().unwrap_or("0").parse().unwrap_or(0.0); - // MemTotal comes before MemAvailable, stop parsing break; } _ => (), } } - let total_memory_gb = total_memory_kb / 1024.0 / 1024.0; let available_memory_gb = available_memory_kb / 1024.0 / 1024.0; let used_memory_gb = total_memory_gb - available_memory_gb; - Ok((used_memory_gb, total_memory_gb)) } let (used_memory, total_memory) = parse_memory_info()?; let percentage_used = (used_memory / total_memory * 100.0).round() as u64; - Ok(format!( - "{used_memory:.2} GiB / {total_memory:.2} GiB ({CYAN}{percentage_used}%{RESET})" + "{used_memory:.2} GiB / {total_memory:.2} GiB ({cyan}{percentage_used}%{reset})", + cyan = COLORS.cyan, + reset = COLORS.reset, )) } From a96effb87542b0f91eb602eb8b00d1356a6b2112 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Thu, 19 Dec 2024 17:23:26 +0300 Subject: [PATCH 2/8] bump version --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 980d4ad..b6ae1dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -332,7 +332,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "microfetch" -version = "0.4.0" +version = "0.4.2" dependencies = [ "color-eyre", "criterion", diff --git a/Cargo.toml b/Cargo.toml index 107d793..d5ced7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "microfetch" -version = "0.4.0" +version = "0.4.2" edition = "2021" [lib] From e19abcedaeef5c640382b2bc67b64419ec5f4acb Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Thu, 19 Dec 2024 17:26:37 +0300 Subject: [PATCH 3/8] docs: update readme; mention `NO_COLOR` changes --- README.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 804fa36..866293e 100644 --- a/README.md +++ b/README.md @@ -34,23 +34,25 @@ than welcome to use it on your system: it's pretty [fast...](#benchmarks) - Name - Version - Architecture - - Current shell (from $SHELL, trimmed if store path) + - Current shell (from `$SHELL`, trimmed if store path) - Current Desktop (DE/WM/Compositor and display backend) - Memory Usage/Total Memory - Storage Usage/Total Storage (for `/` only) - Shell Colors - Did I mention fast? +- Respects [`NO_COLOR` spec](https://no-color.org/) ## Motivation Fastfetch, as its name indicates, a very fast fetch tool written in C, however, -I am not interested in any of its additional features and I very much dislike -the defaults. Microfetch is a fetch tool that you would normally write in Bash -and put in your `~/.bashrc` but actually _really_ fast because it opts-out of -all customization options provided by Fastfetch. Why? Because I can, and because -I prefer Rust for "structured" Bash scripts. +I am not interested in any of its additional features, such as customization, +and I very much dislike the defaults. Microfetch is my response to this problem, +a _very fast_ fetch tool that you would normally write in Bash and put in your +`~/.bashrc` but actually _really_ fast because it opts-out of all customization +options provided by Fastfetch, and is written in Rust. Why? Because I can, and +because I prefer Rust for "structured" Bash scripts. -I cannot re-iterate it enough, Microfetch is annoyingly fast. +I cannot re-iterate it enough, Microfetch is _annoyingly fast_. ## Benchmarks From fd18e9d24467f197c08a9d3498ce5b611ec8bb80 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Thu, 19 Dec 2024 18:27:25 +0300 Subject: [PATCH 4/8] release: conditionally improve performance for `get_os_pretty_name` It is difficult to get completely accurate benchmarks, given how small the numbers we are dealing with are, but this seems to point at an overall trend of *slightly* faster execution. The change minimizes unnecessary memory allocations and string manipulations, to help ensure more performant line reading and immediate return upon finding the PRETTY_NAME without additional, redundant operations. --- src/release.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/release.rs b/src/release.rs index 3f38977..c0036fb 100644 --- a/src/release.rs +++ b/src/release.rs @@ -21,7 +21,13 @@ pub fn get_os_pretty_name() -> Result { for line in reader.lines() { let line = line?; if let Some(pretty_name) = line.strip_prefix("PRETTY_NAME=") { - return Ok(pretty_name.trim_matches('"').to_string()); + if let Some(trimmed) = pretty_name + .strip_prefix('"') + .and_then(|s| s.strip_suffix('"')) + { + return Ok(trimmed.to_string()); + } + return Ok(pretty_name.to_string()); } } From c97fa33aec091242353982062a4ecfa6bcd55679 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Thu, 19 Dec 2024 18:47:04 +0300 Subject: [PATCH 5/8] 0.4.3 Moar speed, NO_COLOR support --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b6ae1dc..f2a7cd6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -332,7 +332,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "microfetch" -version = "0.4.2" +version = "0.4.3" dependencies = [ "color-eyre", "criterion", diff --git a/Cargo.toml b/Cargo.toml index d5ced7c..9e1ea00 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "microfetch" -version = "0.4.2" +version = "0.4.3" edition = "2021" [lib] From 4b7836d572b5bd8b46942e5747437b5bbeeec976 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Thu, 19 Dec 2024 19:13:16 +0300 Subject: [PATCH 6/8] append newline to `write_all` output Fixes a small bug that resulted in terminal artifacts. My bad, gang. --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/main.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f2a7cd6..f4d5a19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -332,7 +332,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "microfetch" -version = "0.4.3" +version = "0.4.4" dependencies = [ "color-eyre", "criterion", diff --git a/Cargo.toml b/Cargo.toml index 9e1ea00..2db7a6a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "microfetch" -version = "0.4.3" +version = "0.4.4" edition = "2021" [lib] diff --git a/src/main.rs b/src/main.rs index 0ea1672..3eee7a0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -84,6 +84,6 @@ fn print_system_info(fields: &Fields) { std::io::stdout() .lock() - .write_all(system_info.as_bytes()) + .write_all(format!("{}\n", system_info).as_bytes()) .expect("Failed to write to stdout"); } From ea8280ef77cf147ff7853f1919ab4325494d411d Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Thu, 19 Dec 2024 20:00:37 +0300 Subject: [PATCH 7/8] docs: update benchmarks to reflect recent improvements Faster and faster we go. --- README.md | 53 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 866293e..28d6338 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ of maintainability. Runs in a _fraction of a millisecond_ and displays _most_ of the nonsense you'd see posted on r/unixporn or other internet communities. Aims to replace [fastfetch](https://github.com/fastfetch-cli/fastfetch) on my personal system, but [probably not yours](#customizing). Though, you are more -than welcome to use it on your system: it's pretty [fast...](#benchmarks) +than welcome to use it on your system: it's pretty [fast](#benchmarks)...

You will need a Nerdfonts patched font installed, and for your terminal > emulator to support said font. Microfetch uses nerdfonts glyphs by default. -Microfetch is packaged in [nixpkgs](https://github.com/nixos/nixpkgs). You can -get it through the unstable channel for the time being. The Nix flake can also -be used for bleeding-edge builds. +Microfetch is packaged in [nixpkgs](https://github.com/nixos/nixpkgs). It can be +installed by adding `pkgs.microfetch` to your `environment.systemPackages`. +Additionally, you can try out Microfetch in a Nix shell. + +```bash +nix shell nixpkgs#microfetch +``` + +Or run it directly with `nix run` + +```bash +nix run nixpkgs#microfetch +``` Non-Nix users will have to build Microfetch with `cargo`. It is not published anywhere but I imagine you can use `cargo install --git` to install it from From 4fff13a51f0e58489d95f43862738c86be5d0147 Mon Sep 17 00:00:00 2001 From: SomeEmptyBox <121939750+SomeEmptyBox@users.noreply.github.com> Date: Thu, 19 Dec 2024 22:32:32 +0530 Subject: [PATCH 8/8] Update memory icon (#15) Makes memory icon bigger by using CPU icon from Nerdfonts instead of the memory icon. --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 3eee7a0..0d70f89 100644 --- a/src/main.rs +++ b/src/main.rs @@ -78,7 +78,7 @@ fn print_system_info(fields: &Fields) { {blue} ▟█▛ {blue}▝█▘{cyan}▟█▛ {cyan} {blue}Shell{reset}  {shell} {blue}▟█████▛ {cyan}▟█████▛ {cyan} {blue}Uptime{reset}  {uptime} {blue} ▟█▛{cyan}▗█▖ {cyan}▟█▛ {cyan} {blue}Desktop{reset}  {desktop} - {blue} ▝█▛ {cyan}██▖{blue}▗▄▄▄▄▄▄▄▄▄▄▄ {cyan}󰍛 {blue}Memory{reset}  {memory_usage} + {blue} ▝█▛ {cyan}██▖{blue}▗▄▄▄▄▄▄▄▄▄▄▄ {cyan} {blue}Memory{reset}  {memory_usage} {blue} ▝ {cyan}▟█▜█▖{blue}▀▀▀▀▀██▛▀▀▘ {cyan}󱥎 {blue}Storage (/){reset}  {storage} {cyan} ▟█▘ ▜█▖ {blue}▝█▛ {cyan} {blue}Colors{reset}  {colors}");