use colored::Colorize;
pub fn print_title(title: &str) {
println!("\n{}", title.bold().underline().blue());
}
pub fn print_section(name: &str) {
println!(" {}", name.cyan().bold());
}
pub fn print_field(name: &str, value: &str) {
println!(" {}: {}", name.yellow(), value);
}
pub fn print_field_with_raw(name: &str, human: &str, raw: &str) {
println!(
" {}: {} ({})",
name.yellow(),
human.green(),
raw.dimmed()
);
}
pub fn print_field_desc(name: &str, value: &str, desc: &str) {
println!(
" {}: {} - {}",
name.yellow(),
value.green(),
desc.dimmed()
);
}
pub fn print_address(name: &str, addr: u64) {
println!(" {}: {:#018X}", name.yellow(), addr);
}
pub fn print_size(name: &str, size: u64) {
let human = humanize_size(size);
println!(
" {}: {} ({})",
name.yellow(),
format!("{}", size).cyan(),
human.dimmed()
);
}
pub fn print_file_info(path: &str, size: usize, format_desc: &str) {
println!("{}: {}", "File".bold(), path.white().bold());
println!("{}: {} bytes", "Size".bold(), size.to_string().cyan());
println!("{}: {}", "Format".bold(), format_desc.green());
}
pub fn print_separator() {
println!("{}", "─".repeat(60).dimmed());
}
pub fn print_table_header(columns: &[(&str, usize)]) {
let mut line = String::from(" ");
for (name, width) in columns {
line.push_str(&format!("{:width$} ", name, width = width));
}
println!("{}", line.cyan().bold());
let mut underline = String::from(" ");
for (_, width) in columns {
underline.push_str(&format!("{} ", "─".repeat(*width)));
}
println!("{}", underline.dimmed());
}
pub fn print_table_row(values: &[(&str, usize)]) {
let mut line = String::from(" ");
for (value, width) in values {
line.push_str(&format!("{:width$} ", value, width = width));
}
println!("{}", line);
}
pub fn print_indexed_item(index: usize, name: &str) {
println!(
" {} {}",
format!("[{:3}]", index).cyan(),
name.white().bold()
);
}
pub fn print_error(message: &str) {
eprintln!("{}: {}", "Error".red().bold(), message);
}
pub fn print_warning(message: &str) {
eprintln!("{}: {}", "Warning".yellow().bold(), message);
}
fn humanize_size(bytes: u64) -> String {
const KB: u64 = 1024;
const MB: u64 = KB * 1024;
const GB: u64 = MB * 1024;
if bytes >= GB {
format!("{:.2} GB", bytes as f64 / GB as f64)
} else if bytes >= MB {
format!("{:.2} MB", bytes as f64 / MB as f64)
} else if bytes >= KB {
format!("{:.2} KB", bytes as f64 / KB as f64)
} else {
format!("{} bytes", bytes)
}
}
pub fn format_flags(read: bool, write: bool, exec: bool) -> String {
let mut flags = String::with_capacity(3);
flags.push(if read { 'R' } else { '-' });
flags.push(if write { 'W' } else { '-' });
flags.push(if exec { 'X' } else { '-' });
flags
}