feat: halfway there?

This commit is contained in:
neoarz
2026-01-05 20:42:12 -05:00
parent 136b77644c
commit a1b7e755b2
11 changed files with 420 additions and 2 deletions

50
src/helpers/cursor.rs Normal file
View File

@@ -0,0 +1,50 @@
// https://github.com/fastfetch-cli/fastfetch/blob/dev/src/detection/cursor/cursor_apple.m
use plist::Value;
use std::env;
use std::path::PathBuf;
fn format_color(dict: &plist::dictionary::Dictionary) -> String {
let r = (dict.get("red").and_then(|v| v.as_real()).unwrap_or(0.0) * 255.0 + 0.5) as u32;
let g = (dict.get("green").and_then(|v| v.as_real()).unwrap_or(0.0) * 255.0 + 0.5) as u32;
let b = (dict.get("blue").and_then(|v| v.as_real()).unwrap_or(0.0) * 255.0 + 0.5) as u32;
let a = (dict.get("alpha").and_then(|v| v.as_real()).unwrap_or(1.0) * 255.0 + 0.5) as u32;
let color_hex = (r << 24) | (g << 16) | (b << 8) | a;
match color_hex {
0x000000FF => "Black".to_string(),
0xFFFFFFFF => "White".to_string(),
0xFF2600FF => "Red".to_string(),
0x0433FFFF => "Blue".to_string(),
0x00F900FF => "Green".to_string(),
0xFFFB00FF => "Yellow".to_string(),
_ => format!("#{:08X}", color_hex),
}
}
pub fn get_cursor_info() -> String {
let mut path = PathBuf::from(env::var("HOME").unwrap_or_default());
path.push("Library/Preferences/com.apple.universalaccess.plist");
let mut fill = "Black".to_string();
let mut outline = "White".to_string();
let mut size = "32".to_string();
if let Ok(value) = Value::from_file(path) {
if let Some(dict) = value.as_dictionary() {
if let Some(f_dict) = dict.get("cursorFill").and_then(|v| v.as_dictionary()) {
fill = format_color(f_dict);
}
if let Some(o_dict) = dict.get("cursorOutline").and_then(|v| v.as_dictionary()) {
outline = format_color(o_dict);
}
if let Some(s_val) = dict.get("mouseDriverCursorSize").and_then(|v| v.as_real()) {
size = format!("{:.0}", s_val * 32.0);
}
}
}
format!("Fill - {}, Outline - {} ({}px)", fill, outline, size)
}

View File

@@ -0,0 +1,22 @@
// https://github.com/fastfetch-cli/fastfetch/blob/dev/src/detection/theme/theme_apple.c
use sysinfo::System;
pub fn get_desktop_env_info() -> String {
let os_version = System::os_version().unwrap_or_else(|| "0.0.0".to_string());
let major_version: u32 = os_version
.split('.')
.next()
.and_then(|s| s.parse().ok())
.unwrap_or(0);
if major_version > 15 {
"Liquid Glass".to_string()
} else if major_version < 10 && major_version != 0 {
"Platinum".to_string()
} else if major_version >= 10 {
"Aqua".to_string()
} else {
"Unknown".to_string()
}
}

25
src/helpers/font.rs Normal file
View File

@@ -0,0 +1,25 @@
// https://github.com/fastfetch-cli/fastfetch/blob/dev/src/detection/font/font_apple.m
use objc2_app_kit::NSFont;
use objc2_foundation::MainThreadMarker;
pub fn get_font_info() -> String {
let _mtm = MainThreadMarker::new().expect("Must be on the main thread to query fonts");
let sys_font = NSFont::systemFontOfSize(12.0);
let sys_name = sys_font
.familyName()
.expect("System font must have a family name")
.to_string();
let user_font = NSFont::userFontOfSize(12.0);
let user_name = match user_font {
Some(font) => font
.familyName()
.map(|name| name.to_string())
.unwrap_or_else(|| "Helvetica".to_string()),
None => "Helvetica".to_string(),
};
format!("{} [System], {} [User]", sys_name, user_name)
}

View File

@@ -1,4 +1,11 @@
pub mod cursor;
pub mod desktop_env;
pub mod display;
pub mod font;
pub mod packages;
pub mod shell;
pub mod terminal;
pub mod terminal_font;
pub mod uptime;
pub mod wm;
pub mod wm_theme;

38
src/helpers/terminal.rs Normal file
View File

@@ -0,0 +1,38 @@
use std::env;
use sysinfo::System;
pub fn get_terminal_info() -> String {
let term_env = env::var("TERM_PROGRAM")
.or_else(|_| env::var("TERM"))
.unwrap_or_default();
let term_ver = env::var("TERM_PROGRAM_VERSION").unwrap_or_default();
if !term_env.is_empty() && term_env != "xterm-256color" && term_env != "xterm" {
let clean_name = term_env
.replace("com.apple.", "") // Apple Terminal
.replace("com.mitchellh.", "") // Ghostty
.replace(".app", "");
return if term_ver.is_empty() {
clean_name
} else {
format!("{} {}", clean_name, term_ver)
};
}
let mut sys = System::new();
sys.refresh_processes(sysinfo::ProcessesToUpdate::All, true);
let my_pid = sysinfo::get_current_pid().unwrap_or(sysinfo::Pid::from(0));
if let Some(process) = sys.process(my_pid) {
if let Some(parent_pid) = process.parent() {
if let Some(parent_proc) = sys.process(parent_pid) {
return parent_proc.name().to_string_lossy().replace(".app", "");
}
}
}
"unknown".to_string()
}

View File

@@ -0,0 +1,32 @@
// https://github.com/fastfetch-cli/fastfetch/blob/dev/src/detection/terminalfont/terminalfont.c
use std::process::Command;
pub fn get_terminal_font_info() -> String {
let output = Command::new("ghostty").arg("+show-config").output();
let mut font_family = String::new();
let mut font_size = String::new();
if let Ok(out) = output {
let stdout = String::from_utf8_lossy(&out.stdout);
for line in stdout.lines() {
if line.starts_with("font-family =") && font_family.is_empty() {
font_family = line.replace("font-family =", "").trim().to_string();
}
if line.starts_with("font-size =") && font_size.is_empty() {
font_size = line.replace("font-size =", "").trim().to_string();
}
}
}
if font_family.is_empty() {
font_family = "JetBrainsMono Nerd Font".to_string();
}
if font_size.is_empty() {
font_size = "13".to_string();
}
format!("{} Regular ({}pt)", font_family, font_size)
}

47
src/helpers/wm.rs Normal file
View File

@@ -0,0 +1,47 @@
// https://github.com/fastfetch-cli/fastfetch/blob/dev/src/detection/displayserver/displayserver_apple.c
use plist::Value;
use std::path::Path;
pub struct DisplayServerResult {
pub wm_pretty_name: String,
}
pub fn get_window_manager_info() -> DisplayServerResult {
let mut result = DisplayServerResult {
wm_pretty_name: "Quartz Compositor".to_string(),
};
if cfg!(target_os = "macos") {
let plist_path = "/System/Library/CoreServices/WindowManager.app/Contents/version.plist";
if Path::new(plist_path).exists() {
if let Ok(value) = Value::from_file(plist_path) {
if let Some(dict) = value.as_dictionary() {
if let Some(raw_version) = dict.get("SourceVersion").and_then(|v| v.as_string())
{
// Apple format: AAAABBBCCDDDDDD (Major, Minor, Patch, Build)
if raw_version.len() >= 8 && raw_version.chars().all(|c| c.is_numeric()) {
let major =
raw_version[..raw_version.len() - 12].trim_start_matches('0');
let minor = raw_version[raw_version.len() - 12..raw_version.len() - 9]
.trim_start_matches('0');
let patch = raw_version[raw_version.len() - 9..raw_version.len() - 7]
.trim_start_matches('0');
let m = if minor.is_empty() { "0" } else { minor };
let p = if patch.is_empty() { "0" } else { patch };
result.wm_pretty_name =
format!("Quartz Compositor {}.{}.{}", major, m, p);
} else {
result.wm_pretty_name = format!("Quartz Compositor {}", raw_version);
}
}
}
}
}
}
result
}

40
src/helpers/wm_theme.rs Normal file
View File

@@ -0,0 +1,40 @@
// https://github.com/fastfetch-cli/fastfetch/blob/dev/src/detection/wmtheme/wmtheme_apple.m
use plist::Value;
use std::env;
use std::path::PathBuf;
pub fn get_wm_theme_info() -> String {
let mut path = PathBuf::from(env::var("HOME").unwrap_or_else(|_| "".to_string()));
path.push("Library/Preferences/.GlobalPreferences.plist");
let mut accent_name = "Multicolor".to_string();
let mut appearance = "Light".to_string();
if let Ok(value) = Value::from_file(path) {
if let Some(dict) = value.as_dictionary() {
if let Some(accent_val) = dict
.get("AppleAccentColor")
.and_then(|v| v.as_signed_integer())
{
accent_name = match accent_val {
-1 => "Graphite".to_string(),
0 => "Red".to_string(),
1 => "Orange".to_string(),
2 => "Yellow".to_string(),
3 => "Green".to_string(),
4 => "Blue".to_string(),
5 => "Purple".to_string(),
6 => "Pink".to_string(),
_ => "Multicolor".to_string(),
};
}
if let Some(style) = dict.get("AppleInterfaceStyle").and_then(|v| v.as_string()) {
appearance = style.to_string(); // Usually "Dark"
}
}
}
format!("{} ({})", accent_name, appearance)
}

View File

@@ -2,7 +2,6 @@
// neo64fetch - "jarvis, rewrite this project in rust"
// use colored::*;
use display_info::DisplayInfo;
use std::env;
use sysinfo::System;
mod helpers;
@@ -19,8 +18,15 @@ struct Stats {
packages: String,
shell: String,
display: String,
desktop_env: String,
window_manager: String,
window_manager_theme: String,
font: String,
cursor: String,
terminal: String,
terminal_font: String,
// Extra fields which are usually appended
// Extra fields
architecture: String,
}
@@ -41,8 +47,16 @@ fn main() {
packages: helpers::packages::get_brew_info(),
shell: helpers::shell::get_shell_info(),
display: helpers::display::get_display_info(),
desktop_env: helpers::desktop_env::get_desktop_env_info(),
window_manager: helpers::wm::get_window_manager_info().wm_pretty_name,
window_manager_theme: helpers::wm_theme::get_wm_theme_info(),
font: helpers::font::get_font_info(),
cursor: helpers::cursor::get_cursor_info(),
terminal: helpers::terminal::get_terminal_info(),
terminal_font: helpers::terminal_font::get_terminal_font_info(),
};
// TODO: Add ascii art support later
// Testing each component separately; going to comment out at the end
{
println!("{}", stats.username);
@@ -55,5 +69,12 @@ fn main() {
println!("{}", stats.packages);
println!("{}", stats.shell);
println!("{}", stats.display);
println!("{}", stats.desktop_env);
println!("{}", stats.window_manager);
println!("{}", stats.window_manager_theme);
println!("{}", stats.font);
println!("{}", stats.cursor);
println!("{}", stats.terminal);
println!("{}", stats.terminal_font);
}
}