From ba9d44274a8014520510c2df73d4cdbd834ce7ad Mon Sep 17 00:00:00 2001 From: Zhenping Zhao Date: Sun, 8 Dec 2024 17:45:48 -0800 Subject: [PATCH] Continue refactoring --- crates/nu-path/src/lib.rs | 6 +- crates/nu-path/src/pwd_per_drive.rs | 125 +---------------- .../src/engine/pwd_per_drive_helper.rs | 130 +++++++++++++++++- 3 files changed, 129 insertions(+), 132 deletions(-) diff --git a/crates/nu-path/src/lib.rs b/crates/nu-path/src/lib.rs index f61c61b954..52cbe8d972 100644 --- a/crates/nu-path/src/lib.rs +++ b/crates/nu-path/src/lib.rs @@ -16,10 +16,6 @@ pub use expansions::{canonicalize_with, expand_path_with, expand_to_real_path, l pub use helpers::{cache_dir, data_dir, home_dir, nu_config_dir}; pub use path::*; #[cfg(windows)] -pub use pwd_per_drive::*; -// { -// bash_strip_redundant_quotes, cmd_strip_all_double_quotes, ensure_trailing_delimiter, -// env_var_for_drive, extract_drive_letter, get_full_path_name_w, need_expand, -// }; +pub use pwd_per_drive::get_full_path_name_w; pub use tilde::expand_tilde; pub use trailing_slash::{has_trailing_slash, strip_trailing_slash}; diff --git a/crates/nu-path/src/pwd_per_drive.rs b/crates/nu-path/src/pwd_per_drive.rs index 5c5345eb02..a8146f00d2 100644 --- a/crates/nu-path/src/pwd_per_drive.rs +++ b/crates/nu-path/src/pwd_per_drive.rs @@ -1,126 +1,3 @@ -/// Usage for pwd_per_drive on windows -/// -/// See nu_protocol::engine::pwd_per_drive_helper; -/// -use std::path::Path; - -/// Ensure a path has a trailing `\\` or '/' -/// ``` -/// use nu_path::ensure_trailing_delimiter; -/// -/// assert_eq!(ensure_trailing_delimiter("E:"), r"E:\"); -/// assert_eq!(ensure_trailing_delimiter(r"e:\"), r"e:\"); -/// assert_eq!(ensure_trailing_delimiter("c:/"), "c:/"); -/// ``` -pub fn ensure_trailing_delimiter(path: &str) -> String { - if !path.ends_with('\\') && !path.ends_with('/') { - format!(r"{}\", path) - } else { - path.to_string() - } -} - -/// Remove leading quote and matching quote at back -/// "D:\\"Music -> D:\\Music -/// ``` -/// use nu_path::bash_strip_redundant_quotes; -/// -/// let input = r#""D:\Music""#; -/// let result = Some(r"D:\Music".to_string()); -/// assert_eq!(result, bash_strip_redundant_quotes(input)); -/// -/// let input = r#"""""D:\Music"""""#; -/// assert_eq!(result, bash_strip_redundant_quotes(input)); -/// -/// let input = r#""D:\Mus"ic"#; -/// assert_eq!(result, bash_strip_redundant_quotes(input)); -/// let input = r#""D:"\Music"#; -/// assert_eq!(result, bash_strip_redundant_quotes(input)); -/// -/// let input = r#""D":\Music"#; -/// assert_eq!(result, bash_strip_redundant_quotes(input)); -/// -/// let input = r#"""D:\Music"#; -/// assert_eq!(result, bash_strip_redundant_quotes(input)); -/// -/// let input = r#"""''"""D:\Mu sic"""''"""#; -/// let result = Some(r#""D:\Mu sic""#.to_string()); -/// assert_eq!(result, bash_strip_redundant_quotes(input)); -/// -/// assert_eq!(bash_strip_redundant_quotes(""), Some("".to_string())); -/// assert_eq!(bash_strip_redundant_quotes("''"), Some("".to_string())); -/// assert_eq!(bash_strip_redundant_quotes("'''"), None); -/// assert_eq!(bash_strip_redundant_quotes("'''M'"), Some("M".to_string())); -/// assert_eq!( -/// bash_strip_redundant_quotes("'''M '"), -/// Some("'M '".to_string()) -/// ); -/// assert_eq!( -/// bash_strip_redundant_quotes(r#"""''"""D:\Mu sic"""''"""#), -/// crate::pwd_per_drive::bash_strip_redundant_quotes(r#""D:\Mu sic""#.to_string()) -/// ); -/// ``` -pub fn bash_strip_redundant_quotes(input: &str) -> Option { - let mut result = String::new(); - let mut i = 0; - let chars: Vec = input.chars().collect(); - - let mut no_quote_start_pos = 0; - while i < chars.len() { - let current_char = chars[i]; - - if current_char == '"' || current_char == '\'' { - if i > no_quote_start_pos { - result.push_str(&input[no_quote_start_pos..i]); - } - - let mut j = i + 1; - let mut has_space = false; - - // Look for the matching quote - while j < chars.len() && chars[j] != current_char { - if chars[j].is_whitespace() { - has_space = true; - } - j += 1; - } - - // Check if the matching quote exists - if j < chars.len() && chars[j] == current_char { - if has_space { - // Push the entire segment including quotes - result.push_str(&input[i..=j]); - } else { - // Push the inner content without quotes - result.push_str(&input[i + 1..j]); - } - i = j + 1; // Move past the closing quote - no_quote_start_pos = i; - continue; - } else { - // No matching quote found, return None - return None; - } - } - i += 1; - } - - if i > no_quote_start_pos + 1 { - result.push_str(&input[no_quote_start_pos..i]); - } - // Return the result if matching quotes are found - Some(result) -} - -/// cmd_strip_all_double_quotes -/// ``` -/// use nu_path::cmd_strip_all_double_quotes; -/// assert_eq!("t t", cmd_strip_all_double_quotes("t\" \"t\"\"")); -/// ``` -pub fn cmd_strip_all_double_quotes(input: &str) -> String { - input.replace("\"", "") -} - /// get_full_path_name_w /// Call windows system API (via omnipath crate) to expand /// absolute path @@ -140,6 +17,8 @@ pub fn cmd_strip_all_double_quotes(input: &str) -> String { /// ``` pub fn get_full_path_name_w(path_str: &str) -> Option { use omnipath::sys_absolute; + use std::path::Path; + if let Ok(path_sys_abs) = sys_absolute(Path::new(path_str)) { Some(path_sys_abs.to_str()?.to_string()) } else { diff --git a/crates/nu-protocol/src/engine/pwd_per_drive_helper.rs b/crates/nu-protocol/src/engine/pwd_per_drive_helper.rs index b3593af669..57d56ac95d 100644 --- a/crates/nu-protocol/src/engine/pwd_per_drive_helper.rs +++ b/crates/nu-protocol/src/engine/pwd_per_drive_helper.rs @@ -1,8 +1,8 @@ use crate::engine::{EngineState, Stack}; #[cfg(windows)] -use crate::{Span, Value}; -#[cfg(windows)] -use nu_path::{bash_strip_redundant_quotes, ensure_trailing_delimiter, get_full_path_name_w}; +use {crate::{Span, Value}, + nu_path::get_full_path_name_w, +}; use std::path::{Path, PathBuf}; #[cfg(windows)] @@ -38,7 +38,7 @@ pub mod os_windows { engine_state: &EngineState, path: &Path, ) -> Option { - use implementation::{extract_drive_letter, get_pwd_on_drive, need_expand}; + use implementation::{bash_strip_redundant_quotes, extract_drive_letter, get_pwd_on_drive, need_expand}; if let Some(path_str) = path.to_str() { if let Some(path_string) = bash_strip_redundant_quotes(path_str) { @@ -116,6 +116,81 @@ pub mod os_windows { .and_then(|s| s.chars().next()) .filter(|c| c.is_ascii_alphabetic()) } + /// Ensure a path has a trailing `\\` or '/' + /// ``` + /// use nu_path::ensure_trailing_delimiter; + /// + /// assert_eq!(ensure_trailing_delimiter("E:"), r"E:\"); + /// assert_eq!(ensure_trailing_delimiter(r"e:\"), r"e:\"); + /// assert_eq!(ensure_trailing_delimiter("c:/"), "c:/"); + /// ``` + pub fn ensure_trailing_delimiter(path: &str) -> String { + if !path.ends_with('\\') && !path.ends_with('/') { + format!(r"{}\", path) + } else { + path.to_string() + } + } + + /// Remove redundant quotes as preprocessor for path + /// #"D:\\"''M''u's 'ic# -> #D:\\Mu's 'ic# + pub fn bash_strip_redundant_quotes(input: &str) -> Option { + let mut result = String::new(); + let mut i = 0; + let chars: Vec = input.chars().collect(); + + let mut no_quote_start_pos = 0; + while i < chars.len() { + let current_char = chars[i]; + + if current_char == '"' || current_char == '\'' { + if i > no_quote_start_pos { + result.push_str(&input[no_quote_start_pos..i]); + } + + let mut j = i + 1; + let mut has_space = false; + + // Look for the matching quote + while j < chars.len() && chars[j] != current_char { + if chars[j].is_whitespace() { + has_space = true; + } + j += 1; + } + + // Check if the matching quote exists + if j < chars.len() && chars[j] == current_char { + if has_space { + // Push the entire segment including quotes + result.push_str(&input[i..=j]); + } else { + // Push the inner content without quotes + result.push_str(&input[i + 1..j]); + } + i = j + 1; // Move past the closing quote + no_quote_start_pos = i; + continue; + } else { + // No matching quote found, return None + return None; + } + } + i += 1; + } + + if i > no_quote_start_pos + 1 { + result.push_str(&input[no_quote_start_pos..i]); + } + // Return the result if matching quotes are found + Some(result) + } + + /// cmd_strip_all_double_quotes + /// assert_eq!("t t", cmd_strip_all_double_quotes("t\" \"t\"\"")); + pub fn cmd_strip_all_double_quotes(input: &str) -> String { + input.replace("\"", "") + } } } @@ -275,6 +350,53 @@ mod tests { assert_eq!(extract_drive_letter(Path::new("C:test")), Some('C')); assert_eq!(extract_drive_letter(Path::new(r"d:\temp")), Some('d')); } + + #[test] + fn test_os_windows_implementation_bash_strip_redundant_quotes() { + use os_windows::implementation::bash_strip_redundant_quotes; + + let input = r#""D:\Music""#; + let result = Some(r"D:\Music".to_string()); + assert_eq!(result, bash_strip_redundant_quotes(input)); + + let input = r#"""""D:\Music"""""#; + assert_eq!(result, bash_strip_redundant_quotes(input)); + + let input = r#""D:\Mus"ic"#; + assert_eq!(result, bash_strip_redundant_quotes(input)); + let input = r#""D:"\Music"#; + assert_eq!(result, bash_strip_redundant_quotes(input)); + + let input = r#""D":\Music"#; + assert_eq!(result, bash_strip_redundant_quotes(input)); + + let input = r#"""D:\Music"#; + assert_eq!(result, bash_strip_redundant_quotes(input)); + + let input = r#"""''"""D:\Mu sic"""''"""#; + let result = Some(r#""D:\Mu sic""#.to_string()); + assert_eq!(result, bash_strip_redundant_quotes(input)); + + assert_eq!(bash_strip_redundant_quotes(""), Some("".to_string())); + assert_eq!(bash_strip_redundant_quotes("''"), Some("".to_string())); + assert_eq!(bash_strip_redundant_quotes("'''"), None); + assert_eq!(bash_strip_redundant_quotes("'''M'"), Some("M".to_string())); + assert_eq!( + bash_strip_redundant_quotes("'''M '"), + Some("'M '".to_string()) + ); + assert_eq!( + bash_strip_redundant_quotes(r#"""''"""D:\Mu sic"""''"""#), + Some(r#""D:\Mu sic""#.to_string()) + ); + } + + #[test] + fn test_os_windows_implementation_cmd_strip_all_double_quotes() { + use os_windows::implementation::cmd_strip_all_double_quotes; + + assert_eq!("t t", cmd_strip_all_double_quotes("t\" \"t\"\"")); + } } } }