1
Fork 0
mirror of https://github.com/RGBCube/superfreq synced 2025-07-27 17:07:44 +00:00

core: improve formatting & display for info command

This commit is contained in:
NotAShelf 2025-05-14 02:05:12 +03:00
parent 166dc5a6a5
commit fad56e6e1e
No known key found for this signature in database
GPG key ID: 29D95B64378DB4BF
4 changed files with 457 additions and 80 deletions

View file

@ -69,10 +69,7 @@ pub fn run_daemon(mut config: AppConfig, verbose: bool) -> Result<(), Box<dyn st
Some(path)
} else {
// Check standard config paths
let default_paths = [
"/etc/superfreq/config.toml",
"/etc/superfreq.toml",
];
let default_paths = ["/etc/superfreq/config.toml", "/etc/superfreq.toml"];
default_paths
.iter()
@ -80,24 +77,26 @@ pub fn run_daemon(mut config: AppConfig, verbose: bool) -> Result<(), Box<dyn st
.map(|path| (*path).to_string())
};
let mut config_watcher = if let Some(path) = config_file_path { match ConfigWatcher::new(&path) {
Ok(watcher) => {
log_message(
&effective_log_level,
LogLevel::Info,
&format!("Watching config file: {path}"),
);
Some(watcher)
let mut config_watcher = if let Some(path) = config_file_path {
match ConfigWatcher::new(&path) {
Ok(watcher) => {
log_message(
&effective_log_level,
LogLevel::Info,
&format!("Watching config file: {path}"),
);
Some(watcher)
}
Err(e) => {
log_message(
&effective_log_level,
LogLevel::Warning,
&format!("Failed to initialize config file watcher: {e}"),
);
None
}
}
Err(e) => {
log_message(
&effective_log_level,
LogLevel::Warning,
&format!("Failed to initialize config file watcher: {e}"),
);
None
}
} } else {
} else {
log_message(
&effective_log_level,
LogLevel::Warning,

View file

@ -91,89 +91,237 @@ fn main() {
};
let command_result = match cli.command {
// TODO: This will be moved to a different module in the future.
Some(Commands::Info) => match monitor::collect_system_report(&config) {
Ok(report) => {
println!("--- System Information ---");
println!("CPU Model: {}", report.system_info.cpu_model);
println!("Architecture: {}", report.system_info.architecture);
// Format section headers with proper centering
let format_section = |title: &str| {
let title_len = title.len();
let total_width = title_len + 8; // 8 is for padding (4 on each side)
let separator = "".repeat(total_width);
println!("\n{}", separator);
// Calculate centering
println!("{}", title);
println!("{}", separator);
};
format_section("System Information");
println!("CPU Model: {}", report.system_info.cpu_model);
println!("Architecture: {}", report.system_info.architecture);
println!(
"Linux Distribution: {}",
report.system_info.linux_distribution
);
println!("Timestamp: {:?}", report.timestamp);
println!("\n--- CPU Global Info ---");
println!("Current Governor: {:?}", report.cpu_global.current_governor);
// Format timestamp in a readable way
println!(
"Available Governors: {:?}",
"Current Time: {}",
chrono::Local::now().format("%Y-%m-%d %H:%M:%S")
);
format_section("CPU Global Info");
println!(
"Current Governor: {}",
report
.cpu_global
.current_governor
.as_deref()
.unwrap_or("N/A")
);
println!(
"Available Governors: {}",
report.cpu_global.available_governors.join(", ")
);
println!("Turbo Status: {:?}", report.cpu_global.turbo_status);
println!("EPP: {:?}", report.cpu_global.epp);
println!("EPB: {:?}", report.cpu_global.epb);
println!("Platform Profile: {:?}", report.cpu_global.platform_profile);
println!(
"Average CPU Temperature: {}",
"Turbo Status: {}",
match report.cpu_global.turbo_status {
Some(true) => "Enabled",
Some(false) => "Disabled",
None => "Unknown",
}
);
println!(
"EPP: {}",
report.cpu_global.epp.as_deref().unwrap_or("N/A")
);
println!(
"EPB: {}",
report.cpu_global.epb.as_deref().unwrap_or("N/A")
);
println!(
"Platform Profile: {}",
report
.cpu_global
.platform_profile
.as_deref()
.unwrap_or("N/A")
);
println!(
"CPU Temperature: {}",
report.cpu_global.average_temperature_celsius.map_or_else(
|| "N/A (CPU temperature sensor not detected)".to_string(),
|t| format!("{t:.1}°C")
|| "N/A (No sensor detected)".to_string(),
|t| format!("{:.1}°C", t)
)
);
println!("\n--- CPU Core Info ---");
for core_info in report.cpu_cores {
format_section("CPU Core Info");
// Get max core ID length for padding
let max_core_id_len = report
.cpu_cores
.last()
.map_or(1, |core| core.core_id.to_string().len());
// Table headers
println!(
" {:>width$} │ {:^10} │ {:^10} │ {:^10} │ {:^7} │ {:^9}",
"Core",
"Current",
"Min",
"Max",
"Usage",
"Temp",
width = max_core_id_len + 4
);
println!(
" {:─>width$}──┼─{:─^10}─┼─{:─^10}─┼─{:─^10}─┼─{:─^7}─┼─{:─^9}",
"",
"",
"",
"",
"",
"",
width = max_core_id_len + 4
);
for core_info in &report.cpu_cores {
// Format frequencies: if current > max, show in a special way
let current_freq = match core_info.current_frequency_mhz {
Some(freq) => {
let max_freq = core_info.max_frequency_mhz.unwrap_or(0);
if freq > max_freq && max_freq > 0 {
// Special format for boosted frequencies
format!("{}*", freq)
} else {
format!("{}", freq)
}
}
None => "N/A".to_string(),
};
// CPU core display
println!(
" Core {}: Current Freq: {:?} MHz, Min Freq: {:?} MHz, Max Freq: {:?} MHz, Usage: {:?}%, Temp: {:?}°C",
" Core {:<width$} │ {:>10} │ {:>10} │ {:>10} │ {:>7} │ {:>9}",
core_info.core_id,
core_info
.current_frequency_mhz
.map_or_else(|| "N/A".to_string(), |f| f.to_string()),
core_info
.min_frequency_mhz
.map_or_else(|| "N/A".to_string(), |f| f.to_string()),
core_info
.max_frequency_mhz
.map_or_else(|| "N/A".to_string(), |f| f.to_string()),
core_info
.usage_percent
.map_or_else(|| "N/A".to_string(), |f| format!("{f:.1}")),
core_info
.temperature_celsius
.map_or_else(|| "N/A".to_string(), |f| format!("{f:.1}"))
format!("{} MHz", current_freq),
format!(
"{} MHz",
core_info
.min_frequency_mhz
.map_or_else(|| "N/A".to_string(), |f| f.to_string())
),
format!(
"{} MHz",
core_info
.max_frequency_mhz
.map_or_else(|| "N/A".to_string(), |f| f.to_string())
),
format!(
"{}%",
core_info
.usage_percent
.map_or_else(|| "N/A".to_string(), |f| format!("{:.1}", f))
),
format!(
"{}°C",
core_info
.temperature_celsius
.map_or_else(|| "N/A".to_string(), |f| format!("{:.1}", f))
),
width = max_core_id_len
);
}
println!("\n--- Battery Info ---");
if report.batteries.is_empty() {
println!(" No batteries found or all are ignored.");
} else {
for battery_info in report.batteries {
println!(
" Battery {}: AC Connected: {}, State: {:?}, Capacity: {:?}%, Power Rate: {:?} W, Charge Thresholds: {:?}-{:?}",
battery_info.name,
battery_info.ac_connected,
battery_info.charging_state.as_deref().unwrap_or("N/A"),
battery_info
.capacity_percent
.map_or_else(|| "N/A".to_string(), |c| c.to_string()),
battery_info
.power_rate_watts
.map_or_else(|| "N/A".to_string(), |p| format!("{p:.2}")),
battery_info
.charge_start_threshold
.map_or_else(|| "N/A".to_string(), |t| t.to_string()),
battery_info
.charge_stop_threshold
.map_or_else(|| "N/A".to_string(), |t| t.to_string())
);
// Only display battery info for systems that have real batteries
// Skip this section entirely on desktop systems
if !report.batteries.is_empty() {
let has_real_batteries = report.batteries.iter().any(|b| {
// Check if any battery has actual battery data
// (as opposed to peripherals like wireless mice)
b.capacity_percent.is_some() || b.power_rate_watts.is_some()
});
if has_real_batteries {
format_section("Battery Info");
for battery_info in &report.batteries {
// Check if this appears to be a real system battery
if battery_info.capacity_percent.is_some()
|| battery_info.power_rate_watts.is_some()
{
let power_status = if battery_info.ac_connected {
"Connected to AC"
} else {
"Running on Battery"
};
println!("Battery {}:", battery_info.name);
println!(" Power Status: {power_status}");
println!(
" State: {}",
battery_info.charging_state.as_deref().unwrap_or("Unknown")
);
if let Some(capacity) = battery_info.capacity_percent {
println!(" Capacity: {capacity}%");
}
if let Some(power) = battery_info.power_rate_watts {
let direction = if power >= 0.0 {
"charging"
} else {
"discharging"
};
println!(
" Power Rate: {:.2} W ({})",
power.abs(),
direction
);
}
// Display charge thresholds if available
if battery_info.charge_start_threshold.is_some()
|| battery_info.charge_stop_threshold.is_some()
{
println!(
" Charge Thresholds: {}-{}",
battery_info
.charge_start_threshold
.map_or_else(|| "N/A".to_string(), |t| t.to_string()),
battery_info
.charge_stop_threshold
.map_or_else(|| "N/A".to_string(), |t| t.to_string())
);
}
}
}
}
}
println!("\n--- System Load ---");
format_section("System Load");
println!(
"Load Average (1m, 5m, 15m): {:.2}, {:.2}, {:.2}",
report.system_load.load_avg_1min,
report.system_load.load_avg_5min,
"Load Average (1m): {:.2}",
report.system_load.load_avg_1min
);
println!(
"Load Average (5m): {:.2}",
report.system_load.load_avg_5min
);
println!(
"Load Average (15m): {:.2}",
report.system_load.load_avg_15min
);
Ok(())