mirror of
https://github.com/nushell/nushell
synced 2025-01-27 12:25:19 +00:00
Refactor path handling in DriveToPwdMap
- Updated `need_expand` function to accept a string instead of a Path reference, simplifying the logic for checking relative paths with drive letters. - Enhanced `expand_pwd` method to handle leading quotes in paths, ensuring proper path expansion and returning dequoted paths when necessary. - Introduced a new helper function `remove_leading_quotes` to clean up input paths by removing matching leading and trailing quotes. - Added unit tests for the new functionality, ensuring robust handling of quoted paths and correct expansion behavior. This refactor improves the clarity and functionality of path handling in the DriveToPwdMap implementation.
This commit is contained in:
parent
a332712275
commit
6ca1628dce
1 changed files with 109 additions and 16 deletions
|
@ -51,14 +51,13 @@ pub enum PathError {
|
|||
|
||||
/// Helper to check if input path is relative path
|
||||
/// with drive letter, it can be expanded with PWD-per-drive.
|
||||
fn need_expand(path: &Path) -> bool {
|
||||
if let Some(path_str) = path.to_str() {
|
||||
let chars: Vec<char> = path_str.chars().collect();
|
||||
if chars.len() >= 2 {
|
||||
return chars[1] == ':' && (chars.len() == 2 || (chars[2] != '/' && chars[2] != '\\'));
|
||||
}
|
||||
fn need_expand(path: &str) -> bool {
|
||||
let chars: Vec<char> = path.chars().collect();
|
||||
if chars.len() >= 2 {
|
||||
chars[1] == ':' && (chars.len() == 2 || (chars[2] != '/' && chars[2] != '\\'))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -145,17 +144,23 @@ impl DriveToPwdMap {
|
|||
/// of absolute path.
|
||||
/// Return None if path is not valid or can't get drive letter.
|
||||
pub fn expand_pwd(&self, path: &Path) -> Option<PathBuf> {
|
||||
if need_expand(path) {
|
||||
let path_str = path.to_str()?;
|
||||
if let Some(drive_letter) = Self::extract_drive_letter(path) {
|
||||
if let Ok(pwd) = self.get_pwd(drive_letter) {
|
||||
// Combine current PWD with the relative path
|
||||
let mut base = PathBuf::from(Self::ensure_trailing_delimiter(&pwd));
|
||||
// need_expand() and extract_drive_letter() all ensure path_str.len() >= 2
|
||||
base.push(&path_str[2..]); // Join PWD with path parts after "C:"
|
||||
return Some(base);
|
||||
if let Some(path_str) = path.to_str() {
|
||||
let path_string = Self::remove_leading_quotes(path_str);
|
||||
if need_expand(&path_string) {
|
||||
let path = Path::new(&path_string);
|
||||
if let Some(drive_letter) = Self::extract_drive_letter(path) {
|
||||
if let Ok(pwd) = self.get_pwd(drive_letter) {
|
||||
// Combine current PWD with the relative path
|
||||
let mut base = PathBuf::from(Self::ensure_trailing_delimiter(&pwd));
|
||||
// need_expand() and extract_drive_letter() all ensure path_str.len() >= 2
|
||||
base.push(&path_string[2..]); // Join PWD with path parts after "C:"
|
||||
return Some(base);
|
||||
}
|
||||
}
|
||||
}
|
||||
if path_string != path_str {
|
||||
return Some(PathBuf::from(&path_string));
|
||||
}
|
||||
}
|
||||
None // Invalid path or has no drive letter
|
||||
}
|
||||
|
@ -176,6 +181,27 @@ impl DriveToPwdMap {
|
|||
path.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove leading quote and matching quote at back
|
||||
/// "D:\\"Music -> D:\\Music
|
||||
fn remove_leading_quotes(input: &str) -> String {
|
||||
let mut result = input.to_string(); // Convert to a String for mutability
|
||||
while let Some(first_char) = result.chars().next() {
|
||||
if first_char == '"' || first_char == '\'' {
|
||||
// Find the matching quote from the reverse order
|
||||
if let Some(pos) = result.rfind(first_char) {
|
||||
// Remove the quotes but keep the content after the matching character
|
||||
result = format!("{}{}", &result[1..pos], &result[pos + 1..]);
|
||||
} else {
|
||||
// No matching quote found, stop
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
fn get_full_path_name_w(path_str: &str) -> Option<String> {
|
||||
|
@ -328,4 +354,71 @@ mod tests {
|
|||
// Invalid drive letter (non-alphabetic)
|
||||
assert_eq!(drive_map.get_pwd('1'), Err(PathError::InvalidDriveLetter));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remove_leading_quotes()
|
||||
{
|
||||
let input = r#""D:\Music""#;
|
||||
assert_eq!(r"D:\Music", DriveToPwdMap::remove_leading_quotes(input));
|
||||
|
||||
let input = r#"""""D:\Music"""""#;
|
||||
assert_eq!(r"D:\Music", DriveToPwdMap::remove_leading_quotes(input));
|
||||
|
||||
let input = r#""''""D:\Music""''""#;
|
||||
assert_eq!(r"D:\Music", DriveToPwdMap::remove_leading_quotes(input));
|
||||
|
||||
let input = r#""D:\Mus"ic"#;
|
||||
assert_eq!(r"D:\Music", DriveToPwdMap::remove_leading_quotes(input));
|
||||
let input = r#""D:"\Music"#;
|
||||
assert_eq!(r"D:\Music", DriveToPwdMap::remove_leading_quotes(input));
|
||||
|
||||
let input = r#""D":\Music"#;
|
||||
assert_eq!(r"D:\Music", DriveToPwdMap::remove_leading_quotes(input));
|
||||
|
||||
let input = r#"""D:\Music"#;
|
||||
assert_eq!(r"D:\Music", DriveToPwdMap::remove_leading_quotes(input));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_expand_with_leading_quotes()
|
||||
{
|
||||
let mut drive_map = DriveToPwdMap::new();
|
||||
|
||||
// Set PWD for drive 'Q:'
|
||||
assert_eq!(drive_map.set_pwd(Path::new(r"q:\Users\Home")), Ok(()));
|
||||
|
||||
let input = r#""q:Music""#;
|
||||
let result = r"Q:\Users\Home\Music";
|
||||
assert_eq!(result, drive_map.expand_pwd(Path::new(input)).unwrap().as_path().to_str().unwrap());
|
||||
|
||||
let input = r#"""""q:Music"""""#;
|
||||
assert_eq!(result, drive_map.expand_pwd(Path::new(input)).unwrap().as_path().to_str().unwrap());
|
||||
|
||||
let input = r#""''""q:Music""''""#;
|
||||
assert_eq!(result, drive_map.expand_pwd(Path::new(input)).unwrap().as_path().to_str().unwrap());
|
||||
|
||||
let input = r#""''""q:Mus""ic''""#;
|
||||
assert_eq!(result, drive_map.expand_pwd(Path::new(input)).unwrap().as_path().to_str().unwrap());
|
||||
|
||||
let input = r#""''""q:""Mu''sic""#;
|
||||
assert_eq!(result, drive_map.expand_pwd(Path::new(input)).unwrap().as_path().to_str().unwrap());
|
||||
|
||||
// For quoted absolute path, return dequoted absolute path
|
||||
let input = r#"""""q:\Music"""""#;
|
||||
let result = DriveToPwdMap::remove_leading_quotes(input);
|
||||
assert_eq!(r"q:\Music", result);
|
||||
assert_eq!(result, drive_map.expand_pwd(Path::new(input)).unwrap().as_path().to_str().unwrap());
|
||||
|
||||
let input = r#""q:\Mus"ic"#;
|
||||
assert_eq!(result, drive_map.expand_pwd(Path::new(input)).unwrap().as_path().to_str().unwrap());
|
||||
|
||||
let input = r#""q:"\Music"#;
|
||||
assert_eq!(result, drive_map.expand_pwd(Path::new(input)).unwrap().as_path().to_str().unwrap());
|
||||
|
||||
let input = r#""q":\Music"#;
|
||||
assert_eq!(result, drive_map.expand_pwd(Path::new(input)).unwrap().as_path().to_str().unwrap());
|
||||
|
||||
let input = r#"""q:\Music"#;
|
||||
assert_eq!(result, drive_map.expand_pwd(Path::new(input)).unwrap().as_path().to_str().unwrap());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue