| 1 | //! Small helpers shared across modules. |
| 2 | |
| 3 | use std::{env, path::PathBuf, time::Duration}; |
| 4 | |
| 5 | /// Replaces a leading `~` with the home directory. |
| 6 | pub fn expand_tilde(path: &str) -> PathBuf { |
| 7 | match path.strip_prefix('~') { |
| 8 | Some(rest) if rest.is_empty() || rest.starts_with('/') => { |
| 9 | env::var_os("HOME").map(PathBuf::from).map_or_else( |
| 10 | || PathBuf::from(path), |
| 11 | |home| home.join(rest.trim_start_matches('/')), |
| 12 | ) |
| 13 | } |
| 14 | _ => PathBuf::from(path), |
| 15 | } |
| 16 | } |
| 17 | |
| 18 | /// `$XDG_CACHE_HOME/rmptui`, falling back to `~/.cache/rmptui`. |
| 19 | pub fn cache_dir() -> PathBuf { |
| 20 | env::var_os("XDG_CACHE_HOME") |
| 21 | .filter(|dir| !dir.is_empty()) |
| 22 | .map(PathBuf::from) |
| 23 | .unwrap_or_else(|| expand_tilde("~/.cache")) |
| 24 | .join("rmptui") |
| 25 | } |
| 26 | |
| 27 | /// Formats a duration as `m:ss` or `h:mm:ss`. |
| 28 | pub fn format_duration(duration: Duration) -> String { |
| 29 | let secs = duration.as_secs(); |
| 30 | let (h, m, s) = (secs / 3600, secs / 60 % 60, secs % 60); |
| 31 | if h > 0 { |
| 32 | format!("{h}:{m:02}:{s:02}") |
| 33 | } else { |
| 34 | format!("{m}:{s:02}") |
| 35 | } |
| 36 | } |
| 37 | |
| 38 | #[cfg(test)] |
| 39 | mod tests { |
| 40 | use super::*; |
| 41 | |
| 42 | #[test] |
| 43 | fn formats_durations() { |
| 44 | assert_eq!(format_duration(Duration::from_secs(5)), "0:05"); |
| 45 | assert_eq!(format_duration(Duration::from_secs(605)), "10:05"); |
| 46 | assert_eq!(format_duration(Duration::from_secs(3725)), "1:02:05"); |
| 47 | } |
| 48 | |
| 49 | #[test] |
| 50 | fn expands_tilde() { |
| 51 | let home = env::var("HOME").unwrap(); |
| 52 | assert_eq!( |
| 53 | expand_tilde("~/music"), |
| 54 | PathBuf::from(format!("{home}/music")) |
| 55 | ); |
| 56 | assert_eq!(expand_tilde("/abs"), PathBuf::from("/abs")); |
| 57 | assert_eq!(expand_tilde("~user/x"), PathBuf::from("~user/x")); |
| 58 | } |
| 59 | } |