mirror of
				https://github.com/NotAShelf/microfetch.git
				synced 2025-10-31 14:22:38 +00:00 
			
		
		
		
	Compare commits
	
		
			5 commits
		
	
	
		
			
				f0809ce877
			
			...
			
				fc62d72cab
			
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| fc62d72cab | |||
| c2deeb38a4 | |||
| a44db5e5f3 | |||
| 81cdc0a281 | |||
|   | ef2f6dc56e | 
					 9 changed files with 92 additions and 91 deletions
				
			
		
							
								
								
									
										
											BIN
										
									
								
								.github/assets/demo.png
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.github/assets/demo.png
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 32 KiB | 
							
								
								
									
										2
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							|  | @ -105,7 +105,7 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" | |||
| 
 | ||||
| [[package]] | ||||
| name = "microfetch" | ||||
| version = "0.2.0" | ||||
| version = "0.3.0" | ||||
| dependencies = [ | ||||
|  "color-eyre", | ||||
|  "nix", | ||||
|  |  | |||
|  | @ -1,10 +1,10 @@ | |||
| [package] | ||||
| name = "microfetch" | ||||
| version = "0.2.0" | ||||
| version = "0.3.0" | ||||
| edition = "2021" | ||||
| 
 | ||||
| [dependencies] | ||||
| nix = {version = "0.29", features = ["fs"]} | ||||
| nix = {version = "0.29", features = ["fs", "hostname"]} | ||||
| color-eyre = { version = "0.6", default-features = false } | ||||
| 
 | ||||
| [profile.release] | ||||
|  | @ -13,6 +13,3 @@ opt-level = "z" | |||
| lto = true | ||||
| codegen-units = 1 | ||||
| panic = "abort" | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										35
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										35
									
								
								README.md
									
										
									
									
									
								
							|  | @ -1,16 +1,35 @@ | |||
| # Microfetch | ||||
| 
 | ||||
| A stupidly simple fetch program written in Rust. | ||||
| A stupidly simple fetch tool, written in Rust. Runs in a fraction of a second, | ||||
| displays most nonsense people on r/unixporn care about. Aims to replace | ||||
| fastfetch on my system, but probably not on yours. Though you are more than | ||||
| welcome to use it on your system: it's fast. | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| ## Features | ||||
| 
 | ||||
| Microfetch can reliably detect and display the following: | ||||
| 
 | ||||
| - Hostname/Username | ||||
| - Kernel | ||||
| - Fast | ||||
| - Really fast | ||||
| - Minimal dependencies | ||||
| - Actually very fast | ||||
| - Cool NixOS logo (other, inferior, distros are not supported) | ||||
| - Reliable detection of following info: | ||||
|   - Hostname/Username | ||||
|   - Kernel | ||||
|     - Name | ||||
|     - Version | ||||
|     - Architecture | ||||
| - WM/Compositor and display backend | ||||
| - Memory Usage/Total Memory | ||||
| - Storage Usage/Total Storage (for `/` only) | ||||
|   - Current shell (from $SHELL) | ||||
|   - WM/Compositor and display backend | ||||
|   - Memory Usage/Total Memory | ||||
|   - Storage Usage/Total Storage (for `/` only) | ||||
|   - Shell Colors | ||||
| 
 | ||||
| ## Customizing | ||||
| 
 | ||||
| You can't. | ||||
| 
 | ||||
| ## License | ||||
| 
 | ||||
| Microfetch is licensed under [GPL3](LICENSE). See the license file for details. | ||||
|  |  | |||
|  | @ -4,3 +4,10 @@ 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"; | ||||
| 
 | ||||
| pub fn print_dots() -> Result<String, std::io::Error> { | ||||
|     let colors = format!("{BLUE}  {CYAN}  {GREEN}  {YELLOW}  {RED}  {MAGENTA}  {RESET}"); | ||||
| 
 | ||||
|     Ok(colors) | ||||
| } | ||||
|  |  | |||
							
								
								
									
										33
									
								
								src/main.rs
									
										
									
									
									
								
							
							
						
						
									
										33
									
								
								src/main.rs
									
										
									
									
									
								
							|  | @ -4,13 +4,13 @@ mod release; | |||
| mod system; | ||||
| mod uptime; | ||||
| 
 | ||||
| use color_eyre::{Report, Result}; | ||||
| 
 | ||||
| use crate::colors::{BLUE, CYAN, RESET}; | ||||
| use crate::colors::{print_dots, BLUE, CYAN, RESET}; | ||||
| 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_username_and_hostname}; | ||||
| 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 nix::sys::sysinfo::sysinfo; | ||||
| 
 | ||||
| fn main() -> Result<(), Report> { | ||||
|     color_eyre::install()?; | ||||
|  | @ -18,19 +18,24 @@ fn main() -> Result<(), Report> { | |||
|     let user_info = get_username_and_hostname()?; | ||||
|     let os_name = get_os_pretty_name()?; | ||||
|     let kernel_version = get_system_info()?; | ||||
|     let shell = get_shell()?; | ||||
|     let uptime = get_current()?; | ||||
|     let window_manager = get_desktop_info()?; | ||||
|     let memory_usage = get_memory_usage()?; | ||||
|     let sys_info = sysinfo()?; | ||||
|     let memory_usage = get_memory_usage(sys_info); | ||||
|     let storage = get_root_disk_usage()?; | ||||
|     let colors = print_dots()?; | ||||
| 
 | ||||
|     print_system_info( | ||||
|         &user_info, | ||||
|         &os_name, | ||||
|         &kernel_version, | ||||
|         &shell, | ||||
|         &uptime, | ||||
|         &window_manager, | ||||
|         &memory_usage, | ||||
|         &storage, | ||||
|         &colors, | ||||
|     ); | ||||
| 
 | ||||
|     Ok(()) | ||||
|  | @ -40,20 +45,24 @@ fn print_system_info( | |||
|     user_info: &str, | ||||
|     os_name: &str, | ||||
|     kernel_version: &str, | ||||
|     shell: &str, | ||||
|     uptime: &str, | ||||
|     window_manager: &str, | ||||
|     memory_usage: &str, | ||||
|     storage: &str, | ||||
|     colors: &str, | ||||
| ) { | ||||
|     println!( | ||||
|         " | ||||
| {CYAN}  ▗▄   {BLUE}▗▄ ▄▖         {user_info} ~{RESET} | ||||
| {CYAN} ▄▄🬸█▄▄▄{BLUE}🬸█▛ {CYAN}▃        {CYAN}  {BLUE}System{RESET}        {os_name} | ||||
| {BLUE}   ▟▛    ▜{CYAN}▃▟🬕        {CYAN}  {BLUE}Kernel{RESET}        {kernel_version} | ||||
| {BLUE}🬋🬋🬫█      {CYAN}█🬛🬋🬋       {CYAN}  {BLUE}Uptime{RESET}        {uptime} | ||||
| {BLUE} 🬷▛🮃{CYAN}▙    ▟▛          {CYAN}  {BLUE}WM{RESET}            {window_manager} | ||||
| {BLUE} 🮃 {CYAN}▟█🬴{BLUE}▀▀▀█🬴▀▀        {CYAN}  {BLUE}Memory{RESET}        {memory_usage} | ||||
| {CYAN}  ▝▀ ▀▘   {BLUE}▀▘         {CYAN}  {BLUE}Storage (/){RESET}   {storage} | ||||
|  {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}WM{RESET}            {window_manager} | ||||
|  {BLUE}  ▝█▛  {CYAN}██▖{BLUE}▗▄▄▄▄▄▄▄▄▄▄▄       {CYAN}  {BLUE}Memory{RESET}        {memory_usage} | ||||
|  {BLUE}   ▝  {CYAN}▟█▜█▖{BLUE}▀▀▀▀▀██▛▀▀▘       {CYAN}  {BLUE}Storage (/){RESET}   {storage} | ||||
|  {CYAN}     ▟█▘ ▜█▖    {BLUE}▝█▛          {CYAN}  {BLUE}Colors{RESET}        {colors} | ||||
|     " | ||||
|     ); | ||||
| } | ||||
|  |  | |||
|  | @ -1,38 +1,27 @@ | |||
| use color_eyre::Result; | ||||
| use std::fs::{self, read_to_string}; | ||||
| use std::io::{self, Read}; | ||||
| use std::io; | ||||
| 
 | ||||
| // Try to detect OS type as accurately as possible and without depending on uname.
 | ||||
| // /etc/os-release should generally imply Linux, and /etc/bsd-release would imply BSD system.
 | ||||
| fn detect_os() -> Result<String, io::Error> { | ||||
| fn detect_os() -> Result<&'static str, io::Error> { | ||||
|     if fs::metadata("/etc/os-release").is_ok() || fs::metadata("/usr/lib/os-release").is_ok() { | ||||
|         Ok("Linux".to_string()) | ||||
|         Ok("Linux") | ||||
|     } else if fs::metadata("/etc/rc.conf").is_ok() || fs::metadata("/etc/bsd-release").is_ok() { | ||||
|         Ok("BSD".to_string()) | ||||
|         Ok("BSD") | ||||
|     } else { | ||||
|         Ok("Unknown".to_string()) | ||||
|         Ok("Unknown") | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn get_architecture() -> Result<String, io::Error> { | ||||
|     // Read architecture from /proc/sys/kernel/arch
 | ||||
|     let mut arch = String::new(); | ||||
|     fs::File::open("/proc/sys/kernel/arch")?.read_to_string(&mut arch)?; | ||||
|     let arch = arch.trim().to_string(); | ||||
|     Ok(arch) | ||||
| } | ||||
| 
 | ||||
| pub fn get_system_info() -> Result<String, io::Error> { | ||||
|     let system = detect_os()?; | ||||
| 
 | ||||
|     let mut kernel_release = String::new(); | ||||
|     fs::File::open("/proc/sys/kernel/osrelease")?.read_to_string(&mut kernel_release)?; | ||||
|     let kernel_release = kernel_release.trim().to_string(); | ||||
|     let kernel_release = read_to_string("/proc/sys/kernel/osrelease")?; | ||||
|     let kernel_release = kernel_release.trim(); | ||||
| 
 | ||||
|     let mut cpuinfo = String::new(); | ||||
|     fs::File::open("/proc/cpuinfo")?.read_to_string(&mut cpuinfo)?; | ||||
| 
 | ||||
|     let architecture = get_architecture()?; | ||||
|     let architecture = read_to_string("/proc/sys/kernel/arch")?; | ||||
|     let architecture = architecture.trim(); | ||||
| 
 | ||||
|     let result = format!("{system} {kernel_release} ({architecture})"); | ||||
|     Ok(result) | ||||
|  |  | |||
|  | @ -1,21 +1,29 @@ | |||
| use nix::sys::statvfs::statvfs; | ||||
| use nix::sys::sysinfo::SysInfo; | ||||
| 
 | ||||
| use std::env; | ||||
| use std::fs::File; | ||||
| use std::io::{self, BufRead}; | ||||
| use std::path::Path; | ||||
| use std::process::Command; | ||||
| use std::io::{self}; | ||||
| 
 | ||||
| use crate::colors::{CYAN, GREEN, RED, RESET, YELLOW}; | ||||
| 
 | ||||
| pub fn get_username_and_hostname() -> Result<String, io::Error> { | ||||
|     let username = env::var("USER").unwrap_or_else(|_| "unknown_user".to_string()); | ||||
|     let output = Command::new("hostname").output()?; | ||||
|     let hostname = String::from_utf8_lossy(&output.stdout).trim().to_string(); | ||||
|     let hostname = nix::unistd::gethostname()?; | ||||
|     let hostname = hostname.to_string_lossy(); | ||||
| 
 | ||||
|     Ok(format!("{YELLOW}{username}{RED}@{GREEN}{hostname}")) | ||||
| } | ||||
| 
 | ||||
| pub fn get_shell() -> Result<String, io::Error> { | ||||
|     // In some setups, $SHELL is set to the store path
 | ||||
|     // of the actual shell program. While we can consider
 | ||||
|     // trimming by name, I will leave it to the user to handle
 | ||||
|     // what their SHELL variable is really set to.
 | ||||
|     let shell = env::var("SHELL").unwrap_or_else(|_| "unknown_shell".to_string()); | ||||
| 
 | ||||
|     Ok(shell) | ||||
| } | ||||
| 
 | ||||
| pub fn get_root_disk_usage() -> Result<String, io::Error> { | ||||
|     let vfs = statvfs("/")?; | ||||
|     let block_size = vfs.block_size() as u64; | ||||
|  | @ -34,49 +42,21 @@ pub fn get_root_disk_usage() -> Result<String, io::Error> { | |||
|     )) | ||||
| } | ||||
| 
 | ||||
| pub fn get_memory_usage() -> Result<String, io::Error> { | ||||
|     fn parse_memory_info() -> Result<(f64, f64), io::Error> { | ||||
|         let path = Path::new("/proc/meminfo"); | ||||
|         let file = File::open(path)?; | ||||
|         let reader = io::BufReader::new(file); | ||||
| 
 | ||||
|         let mut total_memory_kb = 0.0; | ||||
|         let mut available_memory_kb = 0.0; | ||||
| 
 | ||||
|         for line in reader.lines() { | ||||
|             let line = line?; | ||||
|             if line.starts_with("MemTotal:") { | ||||
|                 total_memory_kb = line | ||||
|                     .split_whitespace() | ||||
|                     .nth(1) | ||||
|                     .ok_or_else(|| { | ||||
|                         io::Error::new(io::ErrorKind::InvalidData, "Failed to parse MemTotal") | ||||
|                     })? | ||||
|                     .parse::<f64>() | ||||
|                     .unwrap_or(0.0); | ||||
|             } else if line.starts_with("MemAvailable:") { | ||||
|                 available_memory_kb = line | ||||
|                     .split_whitespace() | ||||
|                     .nth(1) | ||||
|                     .ok_or_else(|| { | ||||
|                         io::Error::new(io::ErrorKind::InvalidData, "Failed to parse MemAvailable") | ||||
|                     })? | ||||
|                     .parse::<f64>() | ||||
|                     .unwrap_or(0.0); | ||||
|             } | ||||
|         } | ||||
| pub fn get_memory_usage(info: SysInfo) -> String { | ||||
|     #[inline(always)] | ||||
|     fn parse_memory_info(info: SysInfo) -> (f64, f64) { | ||||
|         let total_memory_kb = (info.ram_total() / 1024) as f64; | ||||
|         let available_memory_kb = (info.ram_unused() / 1024) as f64; | ||||
| 
 | ||||
|         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)) | ||||
|         (used_memory_gb, total_memory_gb) | ||||
|     } | ||||
| 
 | ||||
|     let (used_memory, total_memory) = parse_memory_info()?; | ||||
|     let (used_memory, total_memory) = parse_memory_info(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})" | ||||
|     )) | ||||
|     format!("{used_memory:.2} GiB / {total_memory:.2} GiB ({CYAN}{percentage_used}%{RESET})") | ||||
| } | ||||
|  |  | |||
|  | @ -25,7 +25,7 @@ pub fn get_current() -> Result<String, io::Error> { | |||
|     let hours = (total_minutes % (60 * 24)) / 60; | ||||
|     let minutes = total_minutes % 60; | ||||
| 
 | ||||
|     let mut parts = Vec::new(); | ||||
|     let mut parts = Vec::with_capacity(3); | ||||
|     if days > 0 { | ||||
|         parts.push(format!("{days} days")); | ||||
|     } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue