Skip to main content

proc_cli/ui/
format.rs

1//! Shared formatting utilities used across commands and output
2//!
3//! Provides common string formatting, truncation, and colorization.
4
5use crate::core::ProcessStatus;
6use colored::*;
7
8/// Format a duration in seconds to a human-readable string.
9///
10/// Examples: "45s", "3m 12s", "2h 15m", "1d 6h"
11pub fn format_duration(secs: u64) -> String {
12    if secs < 60 {
13        format!("{}s", secs)
14    } else if secs < 3600 {
15        format!("{}m {}s", secs / 60, secs % 60)
16    } else if secs < 86400 {
17        format!("{}h {}m", secs / 3600, (secs % 3600) / 60)
18    } else {
19        format!("{}d {}h", secs / 86400, (secs % 86400) / 3600)
20    }
21}
22
23/// Return "es" for plural process counts, "" for singular.
24///
25/// Usage: `format!("{} process{}", n, plural(n))` → "1 process" or "3 processes"
26pub fn plural(n: usize) -> &'static str {
27    if n == 1 {
28        ""
29    } else {
30        "es"
31    }
32}
33
34/// Truncate a string to a maximum length, appending "..." if truncated.
35pub fn truncate_string(s: &str, max_len: usize) -> String {
36    if s.len() <= max_len {
37        s.to_string()
38    } else {
39        format!("{}...", &s[..max_len.saturating_sub(3)])
40    }
41}
42
43/// Truncate a path intelligently — shows the end (most relevant part).
44pub fn truncate_path(path: &str, max_len: usize) -> String {
45    if path.len() <= max_len {
46        path.to_string()
47    } else {
48        let start = path.len().saturating_sub(max_len.saturating_sub(3));
49        format!("...{}", &path[start..])
50    }
51}
52
53/// Format memory in MB to a human-readable string with adaptive units.
54///
55/// Examples: "512KB", "6.0MB", "3.0GB"
56pub fn format_memory(memory_mb: f64) -> String {
57    if memory_mb < 1.0 {
58        format!("{:.0}KB", memory_mb * 1000.0)
59    } else if memory_mb < 1000.0 {
60        format!("{:.1}MB", memory_mb)
61    } else {
62        format!("{:.1}GB", memory_mb / 1000.0)
63    }
64}
65
66/// Colorize a process status string based on the status variant.
67pub fn colorize_status(status: &ProcessStatus, status_str: &str) -> ColoredString {
68    match status {
69        ProcessStatus::Running => status_str.green(),
70        ProcessStatus::Sleeping => status_str.blue(),
71        ProcessStatus::Stopped => status_str.yellow(),
72        ProcessStatus::Zombie => status_str.red(),
73        _ => status_str.white(),
74    }
75}