You've already forked neo64fetch
mirror of
https://github.com/neoarz/neo64fetch.git
synced 2026-02-08 22:33:26 +01:00
chore: clippy & fmt
This commit is contained in:
@@ -45,19 +45,19 @@ pub fn get_battery_info() -> (String, String) {
|
|||||||
let value = value_part.trim_matches(';').trim();
|
let value = value_part.trim_matches(';').trim();
|
||||||
is_charging = value == "Yes";
|
is_charging = value == "Yes";
|
||||||
}
|
}
|
||||||
} else if line.contains("\"AvgTimeToEmpty\"") {
|
} else if line.contains("\"AvgTimeToEmpty\"")
|
||||||
if let Some(equals_pos) = line.find('=') {
|
&& let Some(equals_pos) = line.find('=')
|
||||||
let value_part = &line[equals_pos + 1..].trim();
|
{
|
||||||
let value = value_part.trim_matches(';').trim();
|
let value_part = &line[equals_pos + 1..].trim();
|
||||||
if let Ok(time) = value.parse::<i32>() {
|
let value = value_part.trim_matches(';').trim();
|
||||||
avg_time_to_empty = Some(time);
|
if let Ok(time) = value.parse::<i32>() {
|
||||||
}
|
avg_time_to_empty = Some(time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let percentage = if let Some(capacity) = current_capacity {
|
let percentage = if let Some(capacity) = current_capacity {
|
||||||
if capacity >= 0 && capacity <= 100 {
|
if (0..=100).contains(&capacity) {
|
||||||
capacity as u32
|
capacity as u32
|
||||||
} else {
|
} else {
|
||||||
return (format!("({})", device_name), "<unknown>".to_string());
|
return (format!("({})", device_name), "<unknown>".to_string());
|
||||||
@@ -76,20 +76,21 @@ pub fn get_battery_info() -> (String, String) {
|
|||||||
|
|
||||||
let mut result = crate::output::colors::battery_percent(percentage);
|
let mut result = crate::output::colors::battery_percent(percentage);
|
||||||
|
|
||||||
if !external_connected && !is_charging {
|
if !external_connected
|
||||||
if let Some(time_mins) = avg_time_to_empty {
|
&& !is_charging
|
||||||
if time_mins > 0 && time_mins < 0xFFFF {
|
&& let Some(time_mins) = avg_time_to_empty
|
||||||
let hours = time_mins / 60;
|
&& time_mins > 0
|
||||||
let mins = time_mins % 60;
|
&& time_mins < 0xFFFF
|
||||||
|
{
|
||||||
|
let hours = time_mins / 60;
|
||||||
|
let mins = time_mins % 60;
|
||||||
|
|
||||||
if hours > 0 && mins > 0 {
|
if hours > 0 && mins > 0 {
|
||||||
result.push_str(&format!(" ({} hours, {} mins remaining)", hours, mins));
|
result.push_str(&format!(" ({} hours, {} mins remaining)", hours, mins));
|
||||||
} else if hours > 0 {
|
} else if hours > 0 {
|
||||||
result.push_str(&format!(" ({} hours remaining)", hours));
|
result.push_str(&format!(" ({} hours remaining)", hours));
|
||||||
} else if mins > 0 {
|
} else if mins > 0 {
|
||||||
result.push_str(&format!(" ({} mins remaining)", mins));
|
result.push_str(&format!(" ({} mins remaining)", mins));
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,4 +98,3 @@ pub fn get_battery_info() -> (String, String) {
|
|||||||
|
|
||||||
(format!("({})", device_name), result)
|
(format!("({})", device_name), result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,45 +12,53 @@ pub fn get_cursor_info() -> String {
|
|||||||
let mut outline = "White".to_string();
|
let mut outline = "White".to_string();
|
||||||
let mut size = "32".to_string();
|
let mut size = "32".to_string();
|
||||||
|
|
||||||
if let Ok(value) = Value::from_file(path) {
|
if let Ok(value) = Value::from_file(path)
|
||||||
if let Some(dict) = value.as_dictionary() {
|
&& let Some(dict) = value.as_dictionary()
|
||||||
if let Some(f_dict) = dict.get("cursorFill").and_then(|v| v.as_dictionary()) {
|
{
|
||||||
let r = (f_dict.get("red").and_then(|v| v.as_real()).unwrap_or(0.0) * 255.0 + 0.5) as u32;
|
if let Some(f_dict) = dict.get("cursorFill").and_then(|v| v.as_dictionary()) {
|
||||||
let g = (f_dict.get("green").and_then(|v| v.as_real()).unwrap_or(0.0) * 255.0 + 0.5) as u32;
|
let r =
|
||||||
let b = (f_dict.get("blue").and_then(|v| v.as_real()).unwrap_or(0.0) * 255.0 + 0.5) as u32;
|
(f_dict.get("red").and_then(|v| v.as_real()).unwrap_or(0.0) * 255.0 + 0.5) as u32;
|
||||||
let a = (f_dict.get("alpha").and_then(|v| v.as_real()).unwrap_or(1.0) * 255.0 + 0.5) as u32;
|
let g =
|
||||||
let color_hex = (r << 24) | (g << 16) | (b << 8) | a;
|
(f_dict.get("green").and_then(|v| v.as_real()).unwrap_or(0.0) * 255.0 + 0.5) as u32;
|
||||||
fill = match color_hex {
|
let b =
|
||||||
0x000000FF => "Black".to_string(),
|
(f_dict.get("blue").and_then(|v| v.as_real()).unwrap_or(0.0) * 255.0 + 0.5) as u32;
|
||||||
0xFFFFFFFF => "White".to_string(),
|
let a =
|
||||||
0xFF2600FF => "Red".to_string(),
|
(f_dict.get("alpha").and_then(|v| v.as_real()).unwrap_or(1.0) * 255.0 + 0.5) as u32;
|
||||||
0x0433FFFF => "Blue".to_string(),
|
let color_hex = (r << 24) | (g << 16) | (b << 8) | a;
|
||||||
0x00F900FF => "Green".to_string(),
|
fill = match color_hex {
|
||||||
0xFFFB00FF => "Yellow".to_string(),
|
0x000000FF => "Black".to_string(),
|
||||||
_ => format!("#{:08X}", color_hex),
|
0xFFFFFFFF => "White".to_string(),
|
||||||
};
|
0xFF2600FF => "Red".to_string(),
|
||||||
}
|
0x0433FFFF => "Blue".to_string(),
|
||||||
|
0x00F900FF => "Green".to_string(),
|
||||||
|
0xFFFB00FF => "Yellow".to_string(),
|
||||||
|
_ => format!("#{:08X}", color_hex),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(o_dict) = dict.get("cursorOutline").and_then(|v| v.as_dictionary()) {
|
if let Some(o_dict) = dict.get("cursorOutline").and_then(|v| v.as_dictionary()) {
|
||||||
let r = (o_dict.get("red").and_then(|v| v.as_real()).unwrap_or(0.0) * 255.0 + 0.5) as u32;
|
let r =
|
||||||
let g = (o_dict.get("green").and_then(|v| v.as_real()).unwrap_or(0.0) * 255.0 + 0.5) as u32;
|
(o_dict.get("red").and_then(|v| v.as_real()).unwrap_or(0.0) * 255.0 + 0.5) as u32;
|
||||||
let b = (o_dict.get("blue").and_then(|v| v.as_real()).unwrap_or(0.0) * 255.0 + 0.5) as u32;
|
let g =
|
||||||
let a = (o_dict.get("alpha").and_then(|v| v.as_real()).unwrap_or(1.0) * 255.0 + 0.5) as u32;
|
(o_dict.get("green").and_then(|v| v.as_real()).unwrap_or(0.0) * 255.0 + 0.5) as u32;
|
||||||
let color_hex = (r << 24) | (g << 16) | (b << 8) | a;
|
let b =
|
||||||
outline = match color_hex {
|
(o_dict.get("blue").and_then(|v| v.as_real()).unwrap_or(0.0) * 255.0 + 0.5) as u32;
|
||||||
0x000000FF => "Black".to_string(),
|
let a =
|
||||||
0xFFFFFFFF => "White".to_string(),
|
(o_dict.get("alpha").and_then(|v| v.as_real()).unwrap_or(1.0) * 255.0 + 0.5) as u32;
|
||||||
0xFF2600FF => "Red".to_string(),
|
let color_hex = (r << 24) | (g << 16) | (b << 8) | a;
|
||||||
0x0433FFFF => "Blue".to_string(),
|
outline = match color_hex {
|
||||||
0x00F900FF => "Green".to_string(),
|
0x000000FF => "Black".to_string(),
|
||||||
0xFFFB00FF => "Yellow".to_string(),
|
0xFFFFFFFF => "White".to_string(),
|
||||||
_ => format!("#{:08X}", color_hex),
|
0xFF2600FF => "Red".to_string(),
|
||||||
};
|
0x0433FFFF => "Blue".to_string(),
|
||||||
}
|
0x00F900FF => "Green".to_string(),
|
||||||
|
0xFFFB00FF => "Yellow".to_string(),
|
||||||
|
_ => format!("#{:08X}", color_hex),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(s_val) = dict.get("mouseDriverCursorSize").and_then(|v| v.as_real()) {
|
if let Some(s_val) = dict.get("mouseDriverCursorSize").and_then(|v| v.as_real()) {
|
||||||
size = format!("{:.0}", s_val * 32.0);
|
size = format!("{:.0}", s_val * 32.0);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,10 +18,20 @@ pub fn get_display_info() -> String {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if display_count > 1 {
|
if display_count > 1 {
|
||||||
let name = if main.name.is_empty() { "Color LCD" } else { &main.name };
|
let name = if main.name.is_empty() {
|
||||||
|
"Color LCD"
|
||||||
|
} else {
|
||||||
|
&main.name
|
||||||
|
};
|
||||||
format!(
|
format!(
|
||||||
"({}) {}x{} @ {}x in {}\", {} Hz {}",
|
"({}) {}x{} @ {}x in {}\", {} Hz {}",
|
||||||
name, p_width, p_height, main.scale_factor as u32, inches, main.frequency as u32, tag
|
name,
|
||||||
|
p_width,
|
||||||
|
p_height,
|
||||||
|
main.scale_factor as u32,
|
||||||
|
inches,
|
||||||
|
main.frequency as u32,
|
||||||
|
tag
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
format!(
|
format!(
|
||||||
|
|||||||
@@ -20,9 +20,7 @@ pub fn get_gpu_info() -> String {
|
|||||||
.nth(1)
|
.nth(1)
|
||||||
.unwrap_or("")
|
.unwrap_or("")
|
||||||
.trim()
|
.trim()
|
||||||
.replace('"', "")
|
.replace(['"', '<', '>'], "");
|
||||||
.replace('<', "")
|
|
||||||
.replace('>', "");
|
|
||||||
}
|
}
|
||||||
if line.contains("\"gpu-core-count\"") {
|
if line.contains("\"gpu-core-count\"") {
|
||||||
cores = line.split('=').nth(1).unwrap_or("").trim().to_string();
|
cores = line.split('=').nth(1).unwrap_or("").trim().to_string();
|
||||||
|
|||||||
@@ -11,13 +11,16 @@ pub fn get_host_info() -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn model_to_name(model: &str) -> Option<String> {
|
fn model_to_name(model: &str) -> Option<String> {
|
||||||
let version = if model.starts_with("Mac") && !model.starts_with("MacBook") && !model.starts_with("Macmini") && !model.starts_with("MacPro") {
|
let version = if model.starts_with("Mac")
|
||||||
|
&& !model.starts_with("MacBook")
|
||||||
|
&& !model.starts_with("Macmini")
|
||||||
|
&& !model.starts_with("MacPro")
|
||||||
|
{
|
||||||
Some(model.strip_prefix("Mac")?)
|
Some(model.strip_prefix("Mac")?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Database stolen from https://github.com/fastfetch-cli/fastfetch/blob/dev/src/detection/host/host_mac.c
|
// Database stolen from https://github.com/fastfetch-cli/fastfetch/blob/dev/src/detection/host/host_mac.c
|
||||||
// Macbook Pro: https://support.apple.com/en-us/HT201300
|
// Macbook Pro: https://support.apple.com/en-us/HT201300
|
||||||
// Macbook Air: https://support.apple.com/en-us/HT201862
|
// Macbook Air: https://support.apple.com/en-us/HT201862
|
||||||
@@ -26,80 +29,86 @@ fn model_to_name(model: &str) -> Option<String> {
|
|||||||
// Mac Pro: https://support.apple.com/en-us/HT202888
|
// Mac Pro: https://support.apple.com/en-us/HT202888
|
||||||
// Mac Studio: https://support.apple.com/en-us/HT213073
|
// Mac Studio: https://support.apple.com/en-us/HT213073
|
||||||
if let Some(v) = version {
|
if let Some(v) = version {
|
||||||
return Some(match v {
|
return Some(
|
||||||
// MacBook Air
|
match v {
|
||||||
"16,13" => "MacBook Air (15-inch, M4, 2025)",
|
// MacBook Air
|
||||||
"16,12" => "MacBook Air (13-inch, M4, 2025)",
|
"16,13" => "MacBook Air (15-inch, M4, 2025)",
|
||||||
"15,13" => "MacBook Air (15-inch, M3, 2024)",
|
"16,12" => "MacBook Air (13-inch, M4, 2025)",
|
||||||
"15,12" => "MacBook Air (13-inch, M3, 2024)",
|
"15,13" => "MacBook Air (15-inch, M3, 2024)",
|
||||||
"14,15" => "MacBook Air (15-inch, M2, 2023)",
|
"15,12" => "MacBook Air (13-inch, M3, 2024)",
|
||||||
"14,2" => "MacBook Air (M2, 2022)",
|
"14,15" => "MacBook Air (15-inch, M2, 2023)",
|
||||||
// MacBook Pro
|
"14,2" => "MacBook Air (M2, 2022)",
|
||||||
"16,8" => "MacBook Pro (16-inch, M4 Max, 2024)",
|
// MacBook Pro
|
||||||
"16,7" => "MacBook Pro (16-inch, M4 Pro, 2024)",
|
"16,8" => "MacBook Pro (16-inch, M4 Max, 2024)",
|
||||||
"16,6" => "MacBook Pro (14-inch, M4 Max, 2024)",
|
"16,7" => "MacBook Pro (16-inch, M4 Pro, 2024)",
|
||||||
"16,5" => "MacBook Pro (14-inch, M4 Pro, 2024)",
|
"16,6" => "MacBook Pro (14-inch, M4 Max, 2024)",
|
||||||
"16,1" => "MacBook Pro (14-inch, M4, 2024)",
|
"16,5" => "MacBook Pro (14-inch, M4 Pro, 2024)",
|
||||||
"15,11" => "MacBook Pro (16-inch, M3 Max, 2023)",
|
"16,1" => "MacBook Pro (14-inch, M4, 2024)",
|
||||||
"15,9" => "MacBook Pro (16-inch, M3 Pro, 2023)",
|
"15,11" => "MacBook Pro (16-inch, M3 Max, 2023)",
|
||||||
"15,10" => "MacBook Pro (14-inch, M3 Max, 2023)",
|
"15,9" => "MacBook Pro (16-inch, M3 Pro, 2023)",
|
||||||
"15,8" => "MacBook Pro (14-inch, M3 Pro, 2023)",
|
"15,10" => "MacBook Pro (14-inch, M3 Max, 2023)",
|
||||||
"15,6" | "15,7" => "MacBook Pro (16-inch, M2 Max, 2023)",
|
"15,8" => "MacBook Pro (14-inch, M3 Pro, 2023)",
|
||||||
"15,3" => "MacBook Pro (14-inch, M2 Max, 2023)",
|
"15,6" | "15,7" => "MacBook Pro (16-inch, M2 Max, 2023)",
|
||||||
"14,10" | "14,6" => "MacBook Pro (16-inch, M2 Pro/Max, 2023)",
|
"15,3" => "MacBook Pro (14-inch, M2 Max, 2023)",
|
||||||
"14,9" | "14,5" => "MacBook Pro (14-inch, M2 Pro/Max, 2023)",
|
"14,10" | "14,6" => "MacBook Pro (16-inch, M2 Pro/Max, 2023)",
|
||||||
"14,7" => "MacBook Pro (13-inch, M2, 2022)",
|
"14,9" | "14,5" => "MacBook Pro (14-inch, M2 Pro/Max, 2023)",
|
||||||
// Mac Studio
|
"14,7" => "MacBook Pro (13-inch, M2, 2022)",
|
||||||
"14,14" => "Mac Studio (M2 Ultra, 2023)",
|
// Mac Studio
|
||||||
"14,13" => "Mac Studio (M2 Max, 2023)",
|
"14,14" => "Mac Studio (M2 Ultra, 2023)",
|
||||||
"13,2" => "Mac Studio (M1 Ultra, 2022)",
|
"14,13" => "Mac Studio (M2 Max, 2023)",
|
||||||
"13,1" => "Mac Studio (M1 Max, 2022)",
|
"13,2" => "Mac Studio (M1 Ultra, 2022)",
|
||||||
// Mac mini
|
"13,1" => "Mac Studio (M1 Max, 2022)",
|
||||||
"16,10" => "Mac mini (M4, 2024)",
|
// Mac mini
|
||||||
"16,3" => "Mac mini (M4 Pro, 2024)",
|
"16,10" => "Mac mini (M4, 2024)",
|
||||||
"14,12" => "Mac mini (M2 Pro, 2023)",
|
"16,3" => "Mac mini (M4 Pro, 2024)",
|
||||||
"14,3" => "Mac mini (M2, 2023)",
|
"14,12" => "Mac mini (M2 Pro, 2023)",
|
||||||
// Mac Pro
|
"14,3" => "Mac mini (M2, 2023)",
|
||||||
"14,8" => "Mac Pro (M2 Ultra, 2023)",
|
// Mac Pro
|
||||||
// iMac
|
"14,8" => "Mac Pro (M2 Ultra, 2023)",
|
||||||
"16,2" => "iMac (24-inch, M4, 2024)",
|
// iMac
|
||||||
"15,4" | "15,5" => "iMac (24-inch, M3, 2023)",
|
"16,2" => "iMac (24-inch, M4, 2024)",
|
||||||
_ => return None,
|
"15,4" | "15,5" => "iMac (24-inch, M3, 2023)",
|
||||||
}.to_string());
|
_ => return None,
|
||||||
|
}
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Older Macs with specific prefixes
|
// Older Macs with specific prefixes
|
||||||
Some(match model {
|
Some(
|
||||||
// MacBook Air (Intel/M1)
|
match model {
|
||||||
"MacBookAir10,1" => "MacBook Air (M1, 2020)",
|
// MacBook Air (Intel/M1)
|
||||||
"MacBookAir9,1" => "MacBook Air (Retina, 13-inch, 2020)",
|
"MacBookAir10,1" => "MacBook Air (M1, 2020)",
|
||||||
"MacBookAir8,2" => "MacBook Air (Retina, 13-inch, 2019)",
|
"MacBookAir9,1" => "MacBook Air (Retina, 13-inch, 2020)",
|
||||||
"MacBookAir8,1" => "MacBook Air (Retina, 13-inch, 2018)",
|
"MacBookAir8,2" => "MacBook Air (Retina, 13-inch, 2019)",
|
||||||
// MacBook Pro (Intel/M1)
|
"MacBookAir8,1" => "MacBook Air (Retina, 13-inch, 2018)",
|
||||||
"MacBookPro18,4" => "MacBook Pro (14-inch, M1 Max, 2021)",
|
// MacBook Pro (Intel/M1)
|
||||||
"MacBookPro18,3" => "MacBook Pro (14-inch, M1 Pro, 2021)",
|
"MacBookPro18,4" => "MacBook Pro (14-inch, M1 Max, 2021)",
|
||||||
"MacBookPro18,2" => "MacBook Pro (16-inch, M1 Max, 2021)",
|
"MacBookPro18,3" => "MacBook Pro (14-inch, M1 Pro, 2021)",
|
||||||
"MacBookPro18,1" => "MacBook Pro (16-inch, M1 Pro, 2021)",
|
"MacBookPro18,2" => "MacBook Pro (16-inch, M1 Max, 2021)",
|
||||||
"MacBookPro17,1" => "MacBook Pro (13-inch, M1, 2020)",
|
"MacBookPro18,1" => "MacBook Pro (16-inch, M1 Pro, 2021)",
|
||||||
"MacBookPro16,4" => "MacBook Pro (16-inch, 2019)",
|
"MacBookPro17,1" => "MacBook Pro (13-inch, M1, 2020)",
|
||||||
"MacBookPro16,3" => "MacBook Pro (13-inch, 2020, Two Thunderbolt 3 ports)",
|
"MacBookPro16,4" => "MacBook Pro (16-inch, 2019)",
|
||||||
"MacBookPro16,2" => "MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports)",
|
"MacBookPro16,3" => "MacBook Pro (13-inch, 2020, Two Thunderbolt 3 ports)",
|
||||||
"MacBookPro16,1" => "MacBook Pro (16-inch, 2019)",
|
"MacBookPro16,2" => "MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports)",
|
||||||
"MacBookPro15,4" => "MacBook Pro (13-inch, 2019, Two Thunderbolt 3 ports)",
|
"MacBookPro16,1" => "MacBook Pro (16-inch, 2019)",
|
||||||
"MacBookPro15,3" => "MacBook Pro (15-inch, 2019)",
|
"MacBookPro15,4" => "MacBook Pro (13-inch, 2019, Two Thunderbolt 3 ports)",
|
||||||
"MacBookPro15,2" => "MacBook Pro (13-inch, 2018/2019, Four Thunderbolt 3 ports)",
|
"MacBookPro15,3" => "MacBook Pro (15-inch, 2019)",
|
||||||
"MacBookPro15,1" => "MacBook Pro (15-inch, 2018/2019)",
|
"MacBookPro15,2" => "MacBook Pro (13-inch, 2018/2019, Four Thunderbolt 3 ports)",
|
||||||
// Mac mini
|
"MacBookPro15,1" => "MacBook Pro (15-inch, 2018/2019)",
|
||||||
"Macmini9,1" => "Mac mini (M1, 2020)",
|
// Mac mini
|
||||||
"Macmini8,1" => "Mac mini (2018)",
|
"Macmini9,1" => "Mac mini (M1, 2020)",
|
||||||
// iMac
|
"Macmini8,1" => "Mac mini (2018)",
|
||||||
"iMac21,2" | "iMac21,1" => "iMac (24-inch, M1, 2021)",
|
// iMac
|
||||||
"iMac20,2" | "iMac20,1" => "iMac (Retina 5K, 27-inch, 2020)",
|
"iMac21,2" | "iMac21,1" => "iMac (24-inch, M1, 2021)",
|
||||||
"iMac19,2" => "iMac (Retina 4K, 21.5-inch, 2019)",
|
"iMac20,2" | "iMac20,1" => "iMac (Retina 5K, 27-inch, 2020)",
|
||||||
"iMac19,1" => "iMac (Retina 5K, 27-inch, 2019)",
|
"iMac19,2" => "iMac (Retina 4K, 21.5-inch, 2019)",
|
||||||
// Mac Pro
|
"iMac19,1" => "iMac (Retina 5K, 27-inch, 2019)",
|
||||||
"MacPro7,1" => "Mac Pro (2019)",
|
// Mac Pro
|
||||||
"MacPro6,1" => "Mac Pro (Late 2013)",
|
"MacPro7,1" => "Mac Pro (2019)",
|
||||||
_ => return None,
|
"MacPro6,1" => "Mac Pro (Late 2013)",
|
||||||
}.to_string())
|
_ => return None,
|
||||||
|
}
|
||||||
|
.to_string(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,25 +3,21 @@ use std::process::Command;
|
|||||||
pub fn get_ip_info() -> String {
|
pub fn get_ip_info() -> String {
|
||||||
let mut interface = "en0".to_string();
|
let mut interface = "en0".to_string();
|
||||||
|
|
||||||
let route_output = Command::new("route")
|
let route_output = Command::new("route").args(["get", "default"]).output();
|
||||||
.args(["get", "default"])
|
|
||||||
.output();
|
|
||||||
|
|
||||||
if let Ok(output) = route_output {
|
if let Ok(output) = route_output {
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
for line in stdout.lines() {
|
for line in stdout.lines() {
|
||||||
if line.trim().starts_with("interface:") {
|
if line.trim().starts_with("interface:")
|
||||||
if let Some(iface) = line.split_whitespace().nth(1) {
|
&& let Some(iface) = line.split_whitespace().nth(1)
|
||||||
interface = iface.to_string();
|
{
|
||||||
break;
|
interface = iface.to_string();
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let ifconfig_output = Command::new("ifconfig")
|
let ifconfig_output = Command::new("ifconfig").arg(&interface).output();
|
||||||
.arg(&interface)
|
|
||||||
.output();
|
|
||||||
|
|
||||||
if let Ok(output) = ifconfig_output {
|
if let Ok(output) = ifconfig_output {
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
@@ -32,15 +28,15 @@ pub fn get_ip_info() -> String {
|
|||||||
let ip = parts[1];
|
let ip = parts[1];
|
||||||
let mut ip_with_cidr = ip.to_string();
|
let mut ip_with_cidr = ip.to_string();
|
||||||
|
|
||||||
if let Some(netmask_idx) = parts.iter().position(|&x| x == "netmask") {
|
if let Some(netmask_idx) = parts.iter().position(|&x| x == "netmask")
|
||||||
if netmask_idx + 1 < parts.len() {
|
&& netmask_idx + 1 < parts.len()
|
||||||
let netmask_hex = parts[netmask_idx + 1];
|
{
|
||||||
if netmask_hex.starts_with("0x") {
|
let netmask_hex = parts[netmask_idx + 1];
|
||||||
if let Ok(num) = u32::from_str_radix(&netmask_hex[2..], 16) {
|
if netmask_hex.starts_with("0x")
|
||||||
let cidr = num.count_ones();
|
&& let Ok(num) = u32::from_str_radix(&netmask_hex[2..], 16)
|
||||||
ip_with_cidr = format!("{}/{}", ip, cidr);
|
{
|
||||||
}
|
let cidr = num.count_ones();
|
||||||
}
|
ip_with_cidr = format!("{}/{}", ip, cidr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,4 +48,3 @@ pub fn get_ip_info() -> String {
|
|||||||
|
|
||||||
"<unknown>".to_string()
|
"<unknown>".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
pub fn get_locale_info() -> String {
|
pub fn get_locale_info() -> String {
|
||||||
if let Ok(locale) = env::var("LC_ALL") {
|
if let Ok(locale) = env::var("LC_ALL")
|
||||||
if !locale.is_empty() {
|
&& !locale.is_empty()
|
||||||
return locale;
|
{
|
||||||
}
|
return locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(locale) = env::var("LANG") {
|
if let Ok(locale) = env::var("LANG")
|
||||||
if !locale.is_empty() {
|
&& !locale.is_empty()
|
||||||
return locale;
|
{
|
||||||
}
|
return locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
"<unknown>".to_string()
|
"<unknown>".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,8 @@ pub fn get_memory_info() -> String {
|
|||||||
|
|
||||||
format!(
|
format!(
|
||||||
"{:.2} GiB / {:.2} GiB ({})",
|
"{:.2} GiB / {:.2} GiB ({})",
|
||||||
used_gib, total_gib, crate::output::colors::percent(percentage)
|
used_gib,
|
||||||
|
total_gib,
|
||||||
|
crate::output::colors::percent(percentage)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,9 @@ use std::process::Command;
|
|||||||
|
|
||||||
pub fn get_shell_info() -> String {
|
pub fn get_shell_info() -> String {
|
||||||
let shell_path = env::var("SHELL").unwrap_or_else(|_| "unknown".to_string());
|
let shell_path = env::var("SHELL").unwrap_or_else(|_| "unknown".to_string());
|
||||||
let shell_name = shell_path.split('/').last().unwrap_or("unknown");
|
let shell_name = shell_path.split('/').next_back().unwrap_or("unknown");
|
||||||
let version = Command::new(&shell_path)
|
|
||||||
|
Command::new(&shell_path)
|
||||||
.arg("--version")
|
.arg("--version")
|
||||||
.output()
|
.output()
|
||||||
.map(|output| {
|
.map(|output| {
|
||||||
@@ -16,7 +17,5 @@ pub fn get_shell_info() -> String {
|
|||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(" ")
|
.join(" ")
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|_| shell_name.to_string());
|
.unwrap_or_else(|_| shell_name.to_string())
|
||||||
|
|
||||||
version
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// https://github.com/fastfetch-cli/fastfetch/blob/dev/src/detection/disk/disk.c
|
// https://github.com/fastfetch-cli/fastfetch/blob/dev/src/detection/disk/disk.c
|
||||||
|
|
||||||
use libc::{c_int, c_char};
|
use libc::{c_char, c_int};
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
@@ -79,7 +79,9 @@ pub fn get_storage_info() -> String {
|
|||||||
|
|
||||||
let mut result = format!(
|
let mut result = format!(
|
||||||
"{:.2} GiB / {:.2} GiB ({})",
|
"{:.2} GiB / {:.2} GiB ({})",
|
||||||
used_gib, total_gib, crate::output::colors::percent(percentage)
|
used_gib,
|
||||||
|
total_gib,
|
||||||
|
crate::output::colors::percent(percentage)
|
||||||
);
|
);
|
||||||
|
|
||||||
if !filesystem.is_empty() {
|
if !filesystem.is_empty() {
|
||||||
@@ -97,4 +99,3 @@ pub fn get_storage_info() -> String {
|
|||||||
|
|
||||||
"<unknown>".to_string()
|
"<unknown>".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ pub fn get_swap_info() -> String {
|
|||||||
let mut used_mb = 0.0;
|
let mut used_mb = 0.0;
|
||||||
|
|
||||||
for part in stdout.split_whitespace() {
|
for part in stdout.split_whitespace() {
|
||||||
if let Some(val) = part.strip_suffix('M') {
|
if let Some(val) = part.strip_suffix('M')
|
||||||
if let Ok(num) = val.parse::<f64>() {
|
&& let Ok(num) = val.parse::<f64>()
|
||||||
if stdout.contains(&format!("total = {}", part)) {
|
{
|
||||||
total_mb = num;
|
if stdout.contains(&format!("total = {}", part)) {
|
||||||
} else if stdout.contains(&format!("used = {}", part)) {
|
total_mb = num;
|
||||||
used_mb = num;
|
} else if stdout.contains(&format!("used = {}", part)) {
|
||||||
}
|
used_mb = num;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -33,7 +33,9 @@ pub fn get_swap_info() -> String {
|
|||||||
|
|
||||||
return format!(
|
return format!(
|
||||||
"{:.2} GiB / {:.2} GiB ({})",
|
"{:.2} GiB / {:.2} GiB ({})",
|
||||||
used_gib, total_gib, crate::output::colors::percent(percentage)
|
used_gib,
|
||||||
|
total_gib,
|
||||||
|
crate::output::colors::percent(percentage)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,12 +26,11 @@ pub fn get_terminal_info() -> String {
|
|||||||
|
|
||||||
let my_pid = sysinfo::get_current_pid().unwrap_or(sysinfo::Pid::from(0));
|
let my_pid = sysinfo::get_current_pid().unwrap_or(sysinfo::Pid::from(0));
|
||||||
|
|
||||||
if let Some(process) = sys.process(my_pid) {
|
if let Some(process) = sys.process(my_pid)
|
||||||
if let Some(parent_pid) = process.parent() {
|
&& let Some(parent_pid) = process.parent()
|
||||||
if let Some(parent_proc) = sys.process(parent_pid) {
|
&& let Some(parent_proc) = sys.process(parent_pid)
|
||||||
return parent_proc.name().to_string_lossy().replace(".app", "");
|
{
|
||||||
}
|
return parent_proc.name().to_string_lossy().replace(".app", "");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
"unknown".to_string()
|
"unknown".to_string()
|
||||||
|
|||||||
@@ -15,30 +15,25 @@ pub fn get_window_manager_info() -> DisplayServerResult {
|
|||||||
if cfg!(target_os = "macos") {
|
if cfg!(target_os = "macos") {
|
||||||
let plist_path = "/System/Library/CoreServices/WindowManager.app/Contents/version.plist";
|
let plist_path = "/System/Library/CoreServices/WindowManager.app/Contents/version.plist";
|
||||||
|
|
||||||
if Path::new(plist_path).exists() {
|
if Path::new(plist_path).exists()
|
||||||
if let Ok(value) = Value::from_file(plist_path) {
|
&& let Ok(value) = Value::from_file(plist_path)
|
||||||
if let Some(dict) = value.as_dictionary() {
|
&& let Some(dict) = value.as_dictionary()
|
||||||
if let Some(raw_version) = dict.get("SourceVersion").and_then(|v| v.as_string())
|
&& let Some(raw_version) = dict.get("SourceVersion").and_then(|v| v.as_string())
|
||||||
{
|
{
|
||||||
// Apple format: AAAABBBCCDDDDDD (Major, Minor, Patch, Build)
|
// Apple format: AAAABBBCCDDDDDD (Major, Minor, Patch, Build)
|
||||||
if raw_version.len() >= 8 && raw_version.chars().all(|c| c.is_numeric()) {
|
if raw_version.len() >= 8 && raw_version.chars().all(|c| c.is_numeric()) {
|
||||||
let major =
|
let major = raw_version[..raw_version.len() - 12].trim_start_matches('0');
|
||||||
raw_version[..raw_version.len() - 12].trim_start_matches('0');
|
let minor = raw_version[raw_version.len() - 12..raw_version.len() - 9]
|
||||||
let minor = raw_version[raw_version.len() - 12..raw_version.len() - 9]
|
.trim_start_matches('0');
|
||||||
.trim_start_matches('0');
|
let patch = raw_version[raw_version.len() - 9..raw_version.len() - 7]
|
||||||
let patch = raw_version[raw_version.len() - 9..raw_version.len() - 7]
|
.trim_start_matches('0');
|
||||||
.trim_start_matches('0');
|
|
||||||
|
|
||||||
let m = if minor.is_empty() { "0" } else { minor };
|
let m = if minor.is_empty() { "0" } else { minor };
|
||||||
let p = if patch.is_empty() { "0" } else { patch };
|
let p = if patch.is_empty() { "0" } else { patch };
|
||||||
|
|
||||||
result.wm_pretty_name =
|
result.wm_pretty_name = format!("Quartz Compositor {}.{}.{}", major, m, p);
|
||||||
format!("Quartz Compositor {}.{}.{}", major, m, p);
|
} else {
|
||||||
} else {
|
result.wm_pretty_name = format!("Quartz Compositor {}", raw_version);
|
||||||
result.wm_pretty_name = format!("Quartz Compositor {}", raw_version);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,28 +11,28 @@ pub fn get_wm_theme_info() -> String {
|
|||||||
let mut accent_name = "Multicolor".to_string();
|
let mut accent_name = "Multicolor".to_string();
|
||||||
let mut appearance = "Light".to_string();
|
let mut appearance = "Light".to_string();
|
||||||
|
|
||||||
if let Ok(value) = Value::from_file(path) {
|
if let Ok(value) = Value::from_file(path)
|
||||||
if let Some(dict) = value.as_dictionary() {
|
&& let Some(dict) = value.as_dictionary()
|
||||||
if let Some(accent_val) = dict
|
{
|
||||||
.get("AppleAccentColor")
|
if let Some(accent_val) = dict
|
||||||
.and_then(|v| v.as_signed_integer())
|
.get("AppleAccentColor")
|
||||||
{
|
.and_then(|v| v.as_signed_integer())
|
||||||
accent_name = match accent_val {
|
{
|
||||||
-1 => "Graphite".to_string(),
|
accent_name = match accent_val {
|
||||||
0 => "Red".to_string(),
|
-1 => "Graphite".to_string(),
|
||||||
1 => "Orange".to_string(),
|
0 => "Red".to_string(),
|
||||||
2 => "Yellow".to_string(),
|
1 => "Orange".to_string(),
|
||||||
3 => "Green".to_string(),
|
2 => "Yellow".to_string(),
|
||||||
4 => "Blue".to_string(),
|
3 => "Green".to_string(),
|
||||||
5 => "Purple".to_string(),
|
4 => "Blue".to_string(),
|
||||||
6 => "Pink".to_string(),
|
5 => "Purple".to_string(),
|
||||||
_ => "Multicolor".to_string(),
|
6 => "Pink".to_string(),
|
||||||
};
|
_ => "Multicolor".to_string(),
|
||||||
}
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(style) = dict.get("AppleInterfaceStyle").and_then(|v| v.as_string()) {
|
if let Some(style) = dict.get("AppleInterfaceStyle").and_then(|v| v.as_string()) {
|
||||||
appearance = style.to_string(); // Usually "Dark"
|
appearance = style.to_string(); // Usually "Dark"
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
25
src/main.rs
25
src/main.rs
@@ -1,7 +1,6 @@
|
|||||||
// neoarz
|
// neoarz
|
||||||
// neo64fetch - "jarvis, rewrite this project in rust"
|
// neo64fetch - "jarvis, rewrite this project in rust"
|
||||||
|
|
||||||
use std::env;
|
|
||||||
use sysinfo::System;
|
use sysinfo::System;
|
||||||
|
|
||||||
mod helpers;
|
mod helpers;
|
||||||
@@ -41,7 +40,6 @@ struct Stats {
|
|||||||
architecture: String, // appended to os
|
architecture: String, // appended to os
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn get_system_stats() -> Stats {
|
fn get_system_stats() -> Stats {
|
||||||
let mut sys = System::new_all();
|
let mut sys = System::new_all();
|
||||||
sys.refresh_all();
|
sys.refresh_all();
|
||||||
@@ -82,7 +80,6 @@ fn get_system_stats() -> Stats {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn print_stats(stats: &Stats, offset: usize) {
|
fn print_stats(stats: &Stats, offset: usize) {
|
||||||
let mut lines = Vec::new();
|
let mut lines = Vec::new();
|
||||||
|
|
||||||
@@ -90,10 +87,15 @@ fn print_stats(stats: &Stats, offset: usize) {
|
|||||||
lines.push(colors::title(&stats.username, &stats.hostname));
|
lines.push(colors::title(&stats.username, &stats.hostname));
|
||||||
|
|
||||||
// separator
|
// separator
|
||||||
lines.push(colors::separator(stats.username.len() + stats.hostname.len() + 1));
|
lines.push(colors::separator(
|
||||||
|
stats.username.len() + stats.hostname.len() + 1,
|
||||||
|
));
|
||||||
|
|
||||||
// info
|
// info
|
||||||
lines.push(colors::info("OS", &format!("{} {}", stats.os, stats.architecture)));
|
lines.push(colors::info(
|
||||||
|
"OS",
|
||||||
|
&format!("{} {}", stats.os, stats.architecture),
|
||||||
|
));
|
||||||
lines.push(colors::info("Host", &stats.host));
|
lines.push(colors::info("Host", &stats.host));
|
||||||
lines.push(colors::info("Kernel", &stats.kernel));
|
lines.push(colors::info("Kernel", &stats.kernel));
|
||||||
lines.push(colors::info("Uptime", &stats.uptime));
|
lines.push(colors::info("Uptime", &stats.uptime));
|
||||||
@@ -113,7 +115,10 @@ fn print_stats(stats: &Stats, offset: usize) {
|
|||||||
lines.push(colors::info("Swap", &stats.swap));
|
lines.push(colors::info("Swap", &stats.swap));
|
||||||
lines.push(colors::info("Disk (/)", &stats.storage));
|
lines.push(colors::info("Disk (/)", &stats.storage));
|
||||||
// lines.push(colors::info("Local IP", &stats.ip));
|
// lines.push(colors::info("Local IP", &stats.ip));
|
||||||
lines.push(colors::info(&format!("Battery {}", stats.battery.0), &stats.battery.1));
|
lines.push(colors::info(
|
||||||
|
&format!("Battery {}", stats.battery.0),
|
||||||
|
&stats.battery.1,
|
||||||
|
));
|
||||||
// lines.push(colors::info("Locale", &stats.locale));
|
// lines.push(colors::info("Locale", &stats.locale));
|
||||||
|
|
||||||
// color blocks
|
// color blocks
|
||||||
@@ -127,12 +132,10 @@ fn print_stats(stats: &Stats, offset: usize) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let stats = get_system_stats();
|
let stats = get_system_stats();
|
||||||
let (offset, img_rows) = image::print_image_and_setup("assets/logo.png", 700);
|
let (offset, img_rows) = image::print_image_and_setup("assets/logo.png", 700);
|
||||||
// ^^^ size of the image change it here
|
// ^^^ size of the image change it here
|
||||||
print_stats(&stats, offset);
|
print_stats(&stats, offset);
|
||||||
image::finish_printing(offset, 24, img_rows);
|
image::finish_printing(offset, 24, img_rows);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
// Kitty Graphics Protocol implementation for terminal image display
|
// Kitty Graphics Protocol implementation for terminal image display
|
||||||
//
|
//
|
||||||
// Inspired ~~stolen~~ by swiftfetch's implementation:
|
// Inspired ~~stolen~~ by swiftfetch's implementation:
|
||||||
// https://github.com/Ly-sec/swiftfetch/blob/main/src/display.rs
|
// https://github.com/Ly-sec/swiftfetch/blob/main/src/display.rs
|
||||||
//
|
//
|
||||||
// Images are base64-encoded and chunked copying what swiftfetch does
|
// Images are base64-encoded and chunked copying what swiftfetch does
|
||||||
// Compatible terminals: Any terminals which use Kitty protocol, like Ghostty, Kitty, Wezterm
|
// Compatible terminals: Any terminals which use Kitty protocol, like Ghostty, Kitty, Wezterm
|
||||||
|
|
||||||
use base64::{engine::general_purpose::STANDARD as BASE64, Engine};
|
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
|
||||||
use image::{GenericImageView, ImageFormat};
|
use image::{GenericImageView, ImageFormat};
|
||||||
use libc::{ioctl, winsize, STDOUT_FILENO, TIOCGWINSZ};
|
use libc::{STDOUT_FILENO, TIOCGWINSZ, ioctl, winsize};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::io::{Cursor, Write};
|
use std::io::{Cursor, Write};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
@@ -27,11 +27,11 @@ const DEFAULT_GAP_COLUMNS: usize = 2;
|
|||||||
// See: https://github.com/Ly-sec/swiftfetch/blob/main/src/display.rs#L557
|
// See: https://github.com/Ly-sec/swiftfetch/blob/main/src/display.rs#L557
|
||||||
const CHUNK_SIZE: usize = 4096;
|
const CHUNK_SIZE: usize = 4096;
|
||||||
|
|
||||||
// Detects Kitty Graphics Protocol support via environment variables.
|
// Detects Kitty Graphics Protocol support via environment variables.
|
||||||
//
|
//
|
||||||
// See: https://github.com/Ly-sec/swiftfetch/blob/main/src/display.rs#L422-L460
|
// See: https://github.com/Ly-sec/swiftfetch/blob/main/src/display.rs#L422-L460
|
||||||
//
|
//
|
||||||
// Returns false for unsupported terminals
|
// Returns false for unsupported terminals
|
||||||
// Right now it just doenst print anything
|
// Right now it just doenst print anything
|
||||||
pub fn terminal_supports_kitty() -> bool {
|
pub fn terminal_supports_kitty() -> bool {
|
||||||
if matches!(
|
if matches!(
|
||||||
@@ -41,8 +41,12 @@ pub fn terminal_supports_kitty() -> bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if env::var("KITTY_WINDOW_ID").is_ok() { return true; }
|
if env::var("KITTY_WINDOW_ID").is_ok() {
|
||||||
if env::var("WEZTERM_PANE").is_ok() { return true; }
|
return true;
|
||||||
|
}
|
||||||
|
if env::var("WEZTERM_PANE").is_ok() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if let Ok(term_program) = env::var("TERM_PROGRAM") {
|
if let Ok(term_program) = env::var("TERM_PROGRAM") {
|
||||||
let t = term_program.to_lowercase();
|
let t = term_program.to_lowercase();
|
||||||
@@ -51,22 +55,26 @@ pub fn terminal_supports_kitty() -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(term) = env::var("TERM") {
|
if let Ok(term) = env::var("TERM")
|
||||||
if term.to_lowercase().contains("kitty") { return true; }
|
&& term.to_lowercase().contains("kitty")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Queries terminal for character cell dimensions using ioctl(TIOCGWINSZ).
|
// Queries terminal for character cell dimensions using ioctl(TIOCGWINSZ).
|
||||||
//
|
//
|
||||||
// See: https://github.com/Ly-sec/swiftfetch/blob/main/src/display.rs#L462-L477
|
// See: https://github.com/Ly-sec/swiftfetch/blob/main/src/display.rs#L462-L477
|
||||||
fn terminal_cell_metrics() -> (f32, f32) {
|
fn terminal_cell_metrics() -> (f32, f32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut ws: winsize = mem::zeroed();
|
let mut ws: winsize = mem::zeroed();
|
||||||
if ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut ws) == 0
|
if ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut ws) == 0
|
||||||
&& ws.ws_col > 0 && ws.ws_row > 0
|
&& ws.ws_col > 0
|
||||||
&& ws.ws_xpixel > 0 && ws.ws_ypixel > 0
|
&& ws.ws_row > 0
|
||||||
|
&& ws.ws_xpixel > 0
|
||||||
|
&& ws.ws_ypixel > 0
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
ws.ws_xpixel as f32 / ws.ws_col as f32,
|
ws.ws_xpixel as f32 / ws.ws_col as f32,
|
||||||
@@ -80,13 +88,13 @@ fn terminal_cell_metrics() -> (f32, f32) {
|
|||||||
// Loads, resizes, and displays an image via Kitty Graphics Protocol.
|
// Loads, resizes, and displays an image via Kitty Graphics Protocol.
|
||||||
// Loading Logic:
|
// Loading Logic:
|
||||||
// See: https://github.com/Ly-sec/swiftfetch/blob/main/src/display.rs#L479-L527
|
// See: https://github.com/Ly-sec/swiftfetch/blob/main/src/display.rs#L479-L527
|
||||||
//
|
//
|
||||||
// Resize logic:
|
// Resize logic:
|
||||||
// See: https://github.com/Ly-sec/swiftfetch/blob/main/src/display.rs#L530-L545
|
// See: https://github.com/Ly-sec/swiftfetch/blob/main/src/display.rs#L530-L545
|
||||||
//
|
//
|
||||||
// Transmission logic:
|
// Transmission logic:
|
||||||
// See: https://github.com/Ly-sec/swiftfetch/blob/main/src/display.rs#L547-L578
|
// See: https://github.com/Ly-sec/swiftfetch/blob/main/src/display.rs#L547-L578
|
||||||
//
|
//
|
||||||
// Returns (column_offset, total_rows) for side-by-side text printing.
|
// Returns (column_offset, total_rows) for side-by-side text printing.
|
||||||
// Returns (0, 0) on failure; unsupported terminal or image load error (skill issue)
|
// Returns (0, 0) on failure; unsupported terminal or image load error (skill issue)
|
||||||
pub fn print_image_and_setup(path: &str, target_height: u32) -> (usize, usize) {
|
pub fn print_image_and_setup(path: &str, target_height: u32) -> (usize, usize) {
|
||||||
@@ -109,7 +117,10 @@ pub fn print_image_and_setup(path: &str, target_height: u32) -> (usize, usize) {
|
|||||||
// Kitty protocol requires PNG format, even for JPEG/WebP sources
|
// Kitty protocol requires PNG format, even for JPEG/WebP sources
|
||||||
// See: https://github.com/Ly-sec/swiftfetch/blob/main/src/display.rs#L495-L501
|
// See: https://github.com/Ly-sec/swiftfetch/blob/main/src/display.rs#L495-L501
|
||||||
let mut png_bytes = Vec::new();
|
let mut png_bytes = Vec::new();
|
||||||
if image.write_to(&mut Cursor::new(&mut png_bytes), ImageFormat::Png).is_err() {
|
if image
|
||||||
|
.write_to(&mut Cursor::new(&mut png_bytes), ImageFormat::Png)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
return (0, 0);
|
return (0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +135,10 @@ pub fn print_image_and_setup(path: &str, target_height: u32) -> (usize, usize) {
|
|||||||
let more = if end < encoded.len() { 1 } else { 0 };
|
let more = if end < encoded.len() { 1 } else { 0 };
|
||||||
|
|
||||||
if first {
|
if first {
|
||||||
output.push_str(&format!("\x1b_Ga=T,f=100,s={},v={},m={};", width, height, more));
|
output.push_str(&format!(
|
||||||
|
"\x1b_Ga=T,f=100,s={},v={},m={};",
|
||||||
|
width, height, more
|
||||||
|
));
|
||||||
first = false;
|
first = false;
|
||||||
} else {
|
} else {
|
||||||
output.push_str(&format!("\x1b_Gm={};", more));
|
output.push_str(&format!("\x1b_Gm={};", more));
|
||||||
@@ -150,38 +164,42 @@ pub fn print_image_and_setup(path: &str, target_height: u32) -> (usize, usize) {
|
|||||||
// use cursor positioning to place image
|
// use cursor positioning to place image
|
||||||
// swiftfetch uses a different approach with save/restore but lowk didnt work for me
|
// swiftfetch uses a different approach with save/restore but lowk didnt work for me
|
||||||
// https://github.com/Ly-sec/swiftfetch/blob/main/src/display.rs#L225-L253
|
// https://github.com/Ly-sec/swiftfetch/blob/main/src/display.rs#L225-L253
|
||||||
print!("\x1b[{}A", total_rows);
|
print!("\x1b[{}A", total_rows);
|
||||||
|
|
||||||
if padding_top > 0 {
|
if padding_top > 0 {
|
||||||
print!("\x1b[{}B", padding_top);
|
print!("\x1b[{}B", padding_top);
|
||||||
}
|
}
|
||||||
|
|
||||||
print!("\x1b[s");
|
print!("\x1b[s");
|
||||||
print!("{}", output);
|
print!("{}", output);
|
||||||
std::io::stdout().flush().ok();
|
std::io::stdout().flush().ok();
|
||||||
|
|
||||||
// just a silly caption lolol
|
// just a silly caption lolol
|
||||||
let image_width_cols = cols - DEFAULT_GAP_COLUMNS;
|
let image_width_cols = cols - DEFAULT_GAP_COLUMNS;
|
||||||
|
|
||||||
let text = "a creeper made this";
|
let text = "a creeper made this";
|
||||||
let text_len = 16;
|
let text_len = 16;
|
||||||
let pad = if image_width_cols > text_len { (image_width_cols - text_len) / 2 } else { 0 };
|
let pad = if image_width_cols > text_len {
|
||||||
|
(image_width_cols - text_len) / 2
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
print!("\x1b[{}B", rows);
|
print!("\x1b[{}B", rows);
|
||||||
print!("\r\x1b[{}C{}", pad, text);
|
print!("\r\x1b[{}C{}", pad, text);
|
||||||
|
|
||||||
|
print!("\x1b[u");
|
||||||
|
|
||||||
print!("\x1b[u");
|
|
||||||
|
|
||||||
if padding_top > 0 {
|
if padding_top > 0 {
|
||||||
print!("\x1b[{}A", padding_top);
|
print!("\x1b[{}A", padding_top);
|
||||||
}
|
}
|
||||||
std::io::stdout().flush().ok();
|
std::io::stdout().flush().ok();
|
||||||
|
|
||||||
(cols, total_rows + caption_rows)
|
(cols, total_rows + caption_rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prints text at a horizontal offset for side-by-side layout with image.
|
// Prints text at a horizontal offset for side-by-side layout with image.
|
||||||
//
|
//
|
||||||
// swiftfetch uses space padding instead of cursor movement:
|
// swiftfetch uses space padding instead of cursor movement:
|
||||||
// See: https://github.com/Ly-sec/swiftfetch/blob/main/src/display.rs#L236-L245
|
// See: https://github.com/Ly-sec/swiftfetch/blob/main/src/display.rs#L236-L245
|
||||||
pub fn print_with_offset(offset: usize, text: &str) {
|
pub fn print_with_offset(offset: usize, text: &str) {
|
||||||
if offset > 0 {
|
if offset > 0 {
|
||||||
@@ -192,7 +210,7 @@ pub fn print_with_offset(offset: usize, text: &str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fills remaining vertical space if text is shorter than image height.
|
// Fills remaining vertical space if text is shorter than image height.
|
||||||
//
|
//
|
||||||
// Called after all info lines are printed to make sure the image is not cut off.
|
// Called after all info lines are printed to make sure the image is not cut off.
|
||||||
// See: https://github.com/Ly-sec/swiftfetch/blob/main/src/display.rs#L338-L348
|
// See: https://github.com/Ly-sec/swiftfetch/blob/main/src/display.rs#L338-L348
|
||||||
pub fn finish_printing(offset: usize, lines_printed: usize, image_rows: usize) {
|
pub fn finish_printing(offset: usize, lines_printed: usize, image_rows: usize) {
|
||||||
|
|||||||
Reference in New Issue
Block a user