path.rs•2.86 kB
use dirs::home_dir;
use std::path::{Path, PathBuf};
#[allow(dead_code)]
pub fn expand_tilde(path: &str) -> PathBuf {
    if !path.starts_with('~') {
        return PathBuf::from(path);
    }
    if let Some(home) = home_dir() {
        if path == "~" {
            return home;
        }
        if let Some(rest) = path.strip_prefix("~/") {
            return home.join(rest);
        }
    }
    PathBuf::from(path)
}
#[allow(dead_code)]
pub fn contract_tilde(path: &Path) -> String {
    if let Some(home) = home_dir() {
        let home_str = home.to_string_lossy();
        let path_str = path.to_string_lossy();
        if path_str == home_str {
            return "~".to_string();
        }
        // Create a path object for comparing to handle different path separators
        let path_buf = PathBuf::from(path_str.as_ref());
        // Check if path_buf starts with home directory
        if let Ok(relative) = path_buf.strip_prefix(&home) {
            if relative.as_os_str().is_empty() {
                return "~".to_string();
            } else {
                // Convert to forward slashes for consistency across platforms
                let relative_str = relative.to_string_lossy().replace('\\', "/");
                return format!("~/{}", relative_str);
            }
        }
        path_str.into_owned()
    } else {
        path.to_string_lossy().into_owned()
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    use std::path::PathBuf;
    #[test]
    fn test_expand_tilde_no_tilde() {
        let path = "/usr/bin";
        let expanded = expand_tilde(path);
        assert_eq!(expanded, PathBuf::from("/usr/bin"));
    }
    #[test]
    fn test_expand_tilde_home_only() {
        let expanded = expand_tilde("~");
        let home = home_dir().unwrap();
        assert_eq!(expanded, home);
    }
    #[test]
    fn test_expand_tilde_home_slash() {
        let expanded = expand_tilde("~/Documents");
        let home = home_dir().unwrap();
        assert_eq!(expanded, home.join("Documents"));
    }
    #[test]
    fn test_expand_tilde_user_not_supported() {
        let expanded = expand_tilde("~username/bin");
        assert_eq!(expanded, PathBuf::from("~username/bin"));
    }
    #[test]
    fn test_contract_tilde_outside_home() {
        let path = Path::new("/var/log");
        let contracted = contract_tilde(path);
        assert_eq!(contracted, "/var/log");
    }
    #[test]
    fn test_contract_tilde_exact_home() {
        let home = home_dir().unwrap();
        let contracted = contract_tilde(&home);
        assert_eq!(contracted, "~");
    }
    #[test]
    fn test_contract_tilde_home_subdir() {
        let home = home_dir().unwrap();
        let sub_path = home.join("Pictures");
        let contracted = contract_tilde(&sub_path);
        assert_eq!(contracted, "~/Pictures");
    }
}