Repository: nushell/nushell
File: crates/nu-path/src/pwd_per_drive.rs (Rust)

Code before:
use std::path::{Path, PathBuf};

cfg_if::cfg_if! { if #[cfg(windows)] {


struct Drive2PWDmap {
    map: [Option<String>; 26], // Fixed-size array for A-Z
}

impl Drive2PWDmap {
    pub fn new() -> Self {
        Drive2PWDmap {
            map: Default::default(), // Initialize all to `None`
        }
    }

    /// Set the PWD for the drive letter in the absolute path.
    /// Return String for error description.
    pub fn set_pwd(&mut self, path: &Path) -> Result<(), String> {
        if let (Some(drive_letter), Some(path_str)) = (
            Self::extract_drive_letter(path),
            path.to_str(),
        ) {
            self.map[drive_letter as usize - 'A' as usize] = Some(path_str.to_string());
            return Ok(());
        }
        Err(format!("Invalid path: {}", path.display()))
    }

    /// Get the PWD for drive, if not yet, ask GetFullPathNameW(),
    /// or else return default r"X:\".
    fn get_pwd(&mut self, drive: char) -> Option<String> {
        if drive.is_ascii_alphabetic() {
            let drive = drive.to_ascii_uppercase();
            let index = drive as usize - 'A' as usize;
            Some(self.map[index]
                .clone()
                .unwrap_or_else(||
                    if let Some(system_pwd) = get_full_path_name_w(&format!("{}:", drive)) {
                        self.map[index] = Some(system_pwd.clone());
                        system_pwd
                    } else {
                        format!(r"{}:\", drive)
                    }

Review comment (suggestion):
I'm somewhat unfamiliar with what errors we have in the `nu-path` crate, but returning a `String` is not really ideal. Most of our code uses error enums like `ShellError` that are either miette or thiserror-based.

Code after:
/// Usage for pwd_per_drive on windows
///
/// let mut map = DriveToPwdMap::new();
///
/// Upon change PWD, call map.set_pwd() with absolute path
///
/// Call map.expand_pwd() with relative path to get absolution path
///
/// ```
/// use std::path::{Path, PathBuf};
/// use nu_path::DriveToPwdMap;
///
/// let mut map = DriveToPwdMap::new();
///
/// // Set PWD for drive C
/// assert!(map.set_pwd(Path::new(r"C:\Users\Home")).is_ok());
///
/// // Expand a relative path
/// let expanded = map.expand_pwd(Path::new("c:test"));
/// assert_eq!(expanded, Some(PathBuf::from(r"C:\Users\Home\test")));
///
/// // Will NOT expand an absolute path
/// let expanded = map.expand_pwd(Path::new(r"C:\absolute\path"));
/// assert_eq!(expanded, None);
///
/// // Expand with no drive letter
/// let expanded = map.expand_pwd(Path::new(r"\no_drive"));
/// assert_eq!(expanded, None);
///
/// // Expand with no PWD set for the drive
/// let expanded = map.expand_pwd(Path::new("D:test"));
/// assert!(expanded.is_some());
/// let abs_path = expanded.unwrap().as_path().to_str().expect("OK").to_string();
/// assert!(abs_path.starts_with(r"D:\"));
/// assert!(abs_path.ends_with(r"\test"));
///
/// // Get env vars for child process
/// use std::collections::HashMap;
/// let mut env = HashMap::<String, String>::new();
/// map.get_env_vars(&mut env);
/// assert_eq!(env.get("=C:").unwrap(), r"C:\Users\Home");
/// ```
use std::collections::HashMap;
use std::path::{Path, PathBuf};