mirror of
https://github.com/nushell/nushell
synced 2025-01-13 05:38:57 +00:00
Refactor to clear role of code segments
This commit is contained in:
parent
32ba2e0cc4
commit
b0aeab9c99
6 changed files with 268 additions and 199 deletions
|
@ -5,7 +5,7 @@ use nu_engine::env_to_string;
|
|||
use nu_path::dots::expand_ndots;
|
||||
use nu_path::{expand_to_real_path, home_dir};
|
||||
#[cfg(windows)]
|
||||
use nu_protocol::engine::expand_pwd;
|
||||
use nu_protocol::engine::pwd_per_drive_helper::os_windows::*; //fs_client::expand_pwd;
|
||||
use nu_protocol::{
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
Span,
|
||||
|
@ -177,8 +177,9 @@ pub fn complete_item(
|
|||
let cleaned_partial = surround_remove(partial);
|
||||
let isdir = cleaned_partial.ends_with(is_separator);
|
||||
#[cfg(windows)]
|
||||
let cleaned_partial =
|
||||
if let Some(absolute_path) = expand_pwd(stack, engine_state, Path::new(&cleaned_partial)) {
|
||||
let cleaned_partial = if let Some(absolute_path) =
|
||||
fs_client::expand_pwd(stack, engine_state, Path::new(&cleaned_partial))
|
||||
{
|
||||
if let Some(abs_path_string) = absolute_path.as_path().to_str() {
|
||||
abs_path_string.to_string()
|
||||
} else {
|
||||
|
|
|
@ -7,7 +7,7 @@ pub mod form;
|
|||
mod helpers;
|
||||
mod path;
|
||||
#[cfg(windows)]
|
||||
pub mod pwd_per_drive;
|
||||
mod pwd_per_drive;
|
||||
mod tilde;
|
||||
mod trailing_slash;
|
||||
|
||||
|
@ -16,9 +16,10 @@ 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::*;
|
||||
// {
|
||||
// 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 tilde::expand_tilde;
|
||||
pub use trailing_slash::{has_trailing_slash, strip_trailing_slash};
|
||||
|
|
|
@ -4,62 +4,6 @@
|
|||
///
|
||||
use std::path::Path;
|
||||
|
||||
/// Helper to check if input path is relative path
|
||||
/// with drive letter, it can be expanded with PWD-per-drive.
|
||||
/// ```
|
||||
/// use nu_path::need_expand;
|
||||
/// assert!(need_expand(r"c:nushell\src"));
|
||||
/// assert!(need_expand("C:src/"));
|
||||
/// assert!(need_expand("a:"));
|
||||
/// assert!(need_expand("z:"));
|
||||
/// // Absolute path does not need expand
|
||||
/// assert!(!need_expand(r"c:\"));
|
||||
/// // Unix path does not need expand
|
||||
/// assert!(!need_expand("/usr/bin"));
|
||||
/// ```
|
||||
pub 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
|
||||
}
|
||||
}
|
||||
|
||||
/// Get windows env var for drive
|
||||
/// ```
|
||||
/// use nu_path::env_var_for_drive;
|
||||
///
|
||||
/// for drive_letter in 'A'..='Z' {
|
||||
/// assert_eq!(env_var_for_drive(drive_letter), format!("={drive_letter}:"));
|
||||
/// }
|
||||
/// for drive_letter in 'a'..='z' {
|
||||
/// assert_eq!(
|
||||
/// env_var_for_drive(drive_letter),
|
||||
/// format!("={}:", drive_letter.to_ascii_uppercase())
|
||||
/// );
|
||||
/// }
|
||||
///
|
||||
/// ```
|
||||
pub fn env_var_for_drive(drive_letter: char) -> String {
|
||||
let drive_letter = drive_letter.to_ascii_uppercase();
|
||||
format!("={}:", drive_letter)
|
||||
}
|
||||
|
||||
/// Helper to extract the drive letter from a path, keep case
|
||||
/// ```
|
||||
/// use nu_path::extract_drive_letter;
|
||||
/// use std::path::Path;
|
||||
///
|
||||
/// assert_eq!(extract_drive_letter(Path::new("C:test")), Some('C'));
|
||||
/// assert_eq!(extract_drive_letter(Path::new(r"d:\temp")), Some('d'));
|
||||
/// ```
|
||||
pub fn extract_drive_letter(path: &Path) -> Option<char> {
|
||||
path.to_str()
|
||||
.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;
|
||||
|
|
|
@ -29,9 +29,9 @@ pub use engine_state::*;
|
|||
pub use error_handler::*;
|
||||
pub use overlay::*;
|
||||
pub use pattern_match::*;
|
||||
pub use pwd_per_drive_helper::expand_path_with;
|
||||
pub use pwd_per_drive_helper::fs_client::*; //expand_path_with
|
||||
#[cfg(windows)]
|
||||
pub use pwd_per_drive_helper::{expand_pwd, set_pwd};
|
||||
pub use pwd_per_drive_helper::os_windows::*; //{expand_pwd, set_pwd};
|
||||
pub use sequence::*;
|
||||
pub use stack::*;
|
||||
pub use stack_out_dest::*;
|
||||
|
|
|
@ -2,47 +2,44 @@ use crate::engine::{EngineState, Stack};
|
|||
#[cfg(windows)]
|
||||
use crate::{Span, Value};
|
||||
#[cfg(windows)]
|
||||
use nu_path::{
|
||||
bash_strip_redundant_quotes, ensure_trailing_delimiter, env_var_for_drive,
|
||||
extract_drive_letter, get_full_path_name_w, need_expand,
|
||||
};
|
||||
use nu_path::{bash_strip_redundant_quotes, ensure_trailing_delimiter, get_full_path_name_w};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn set_pwd(stack: &mut Stack, path: &Path) {
|
||||
pub mod os_windows {
|
||||
use super::*;
|
||||
|
||||
// For maintainer to notify current pwd
|
||||
pub mod maintainer {
|
||||
use super::*;
|
||||
|
||||
/// when user change current directory, maintainer nofity
|
||||
/// PWD-per-drive by calling set_pwd() with current stack and path;
|
||||
pub fn set_pwd(stack: &mut Stack, path: &Path) {
|
||||
use implementation::{env_var_for_drive, extract_drive_letter};
|
||||
|
||||
if let Some(drive) = extract_drive_letter(path) {
|
||||
let value = Value::string(path.to_string_lossy(), Span::unknown());
|
||||
stack.add_env_var(env_var_for_drive(drive), value.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get pwd for drive:
|
||||
// 1. From env_var, if no,
|
||||
// 2. From sys_absolute, if no,
|
||||
// 3. Construct root path to drives
|
||||
#[cfg(windows)]
|
||||
fn get_pwd_on_drive(stack: &Stack, engine_state: &EngineState, drive_letter: char) -> String {
|
||||
let env_var_for_drive = env_var_for_drive(drive_letter);
|
||||
let mut abs_pwd: Option<String> = None;
|
||||
if let Some(pwd) = stack.get_env_var(engine_state, &env_var_for_drive) {
|
||||
if let Ok(pwd_string) = pwd.clone().into_string() {
|
||||
abs_pwd = Some(pwd_string);
|
||||
}
|
||||
}
|
||||
if abs_pwd.is_none() {
|
||||
if let Some(sys_pwd) = get_full_path_name_w(&format!("{}:", drive_letter)) {
|
||||
abs_pwd = Some(sys_pwd);
|
||||
}
|
||||
}
|
||||
if let Some(pwd) = abs_pwd {
|
||||
ensure_trailing_delimiter(&pwd)
|
||||
} else {
|
||||
format!(r"{}:\", drive_letter)
|
||||
}
|
||||
}
|
||||
// For file system command usage
|
||||
pub mod fs_client {
|
||||
use super::*;
|
||||
|
||||
/// file system command implementation can use expand_pwd to expand relate path for a drive
|
||||
/// and strip redundant double or single quote like bash
|
||||
/// expand_pwd(stack, engine_state, Path::new("''C:''nushell''") ->
|
||||
/// Some(PathBuf("C:\\User\\nushell");
|
||||
pub fn expand_pwd(
|
||||
stack: &Stack,
|
||||
engine_state: &EngineState,
|
||||
path: &Path,
|
||||
) -> Option<PathBuf> {
|
||||
use implementation::{extract_drive_letter, get_pwd_on_drive, need_expand};
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn expand_pwd(stack: &Stack, engine_state: &EngineState, path: &Path) -> Option<PathBuf> {
|
||||
if let Some(path_str) = path.to_str() {
|
||||
if let Some(path_string) = bash_strip_redundant_quotes(path_str) {
|
||||
if need_expand(&path_string) {
|
||||
|
@ -61,44 +58,144 @@ pub fn expand_pwd(stack: &Stack, engine_state: &EngineState, path: &Path) -> Opt
|
|||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation for maintainer and fs_client
|
||||
pub(in crate::engine::pwd_per_drive_helper) mod implementation {
|
||||
use super::*;
|
||||
|
||||
// get pwd for drive:
|
||||
// 1. From env_var, if no,
|
||||
// 2. From sys_absolute, if no,
|
||||
// 3. Construct root path to drives
|
||||
pub fn get_pwd_on_drive(
|
||||
stack: &Stack,
|
||||
engine_state: &EngineState,
|
||||
drive_letter: char,
|
||||
) -> String {
|
||||
let env_var_for_drive = env_var_for_drive(drive_letter);
|
||||
let mut abs_pwd: Option<String> = None;
|
||||
if let Some(pwd) = stack.get_env_var(engine_state, &env_var_for_drive) {
|
||||
if let Ok(pwd_string) = pwd.clone().into_string() {
|
||||
abs_pwd = Some(pwd_string);
|
||||
}
|
||||
}
|
||||
if abs_pwd.is_none() {
|
||||
if let Some(sys_pwd) = get_full_path_name_w(&format!("{}:", drive_letter)) {
|
||||
abs_pwd = Some(sys_pwd);
|
||||
}
|
||||
}
|
||||
if let Some(pwd) = abs_pwd {
|
||||
ensure_trailing_delimiter(&pwd)
|
||||
} else {
|
||||
format!(r"{}:\", drive_letter)
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper to check if input path is relative path
|
||||
/// with drive letter, it can be expanded with PWD-per-drive.
|
||||
pub 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
|
||||
}
|
||||
}
|
||||
|
||||
/// Get windows env var for drive
|
||||
pub fn env_var_for_drive(drive_letter: char) -> String {
|
||||
let drive_letter = drive_letter.to_ascii_uppercase();
|
||||
format!("={}:", drive_letter)
|
||||
}
|
||||
|
||||
/// Helper to extract the drive letter from a path, keep case
|
||||
pub fn extract_drive_letter(path: &Path) -> Option<char> {
|
||||
path.to_str()
|
||||
.and_then(|s| s.chars().next())
|
||||
.filter(|c| c.is_ascii_alphabetic())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper stub/proxy for nu_path::expand_path_with::<P, Q>(path, relative_to, expand_tilde)
|
||||
// Facilitates file system commands to easily gain the ability to expand PWD-per-drive
|
||||
pub fn expand_path_with<P, Q>(
|
||||
// For file system command usage
|
||||
pub mod fs_client {
|
||||
use super::*;
|
||||
|
||||
// Helper stub/proxy for nu_path::expand_path_with::<P, Q>(path, relative_to, expand_tilde)
|
||||
// Facilitates file system commands to easily gain the ability to expand PWD-per-drive
|
||||
pub fn expand_path_with<P, Q>(
|
||||
_stack: &Stack,
|
||||
_engine_state: &EngineState,
|
||||
path: P,
|
||||
relative_to: Q,
|
||||
expand_tilde: bool,
|
||||
) -> PathBuf
|
||||
where
|
||||
) -> PathBuf
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
Q: AsRef<Path>,
|
||||
{
|
||||
{
|
||||
#[cfg(windows)]
|
||||
if let Some(abs_path) = expand_pwd(_stack, _engine_state, path.as_ref()) {
|
||||
if let Some(abs_path) =
|
||||
os_windows::fs_client::expand_pwd(_stack, _engine_state, path.as_ref())
|
||||
{
|
||||
return abs_path;
|
||||
}
|
||||
|
||||
nu_path::expand_path_with::<P, Q>(path, relative_to, expand_tilde)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[cfg(test)]
|
||||
#[cfg(test)] // test only for windows
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
mod fs_client_test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_set_pwd() {
|
||||
fn test_fs_client_expand_path_with() {
|
||||
let mut stack = Stack::new();
|
||||
let path_str = r"c:\users\nushell";
|
||||
let path = Path::new(path_str);
|
||||
os_windows::maintainer::set_pwd(&mut stack, path);
|
||||
let engine_state = EngineState::new();
|
||||
|
||||
let rel_path = Path::new("c:.config");
|
||||
let result = format!(r"{path_str}\.config");
|
||||
assert_eq!(
|
||||
Some(result.as_str()),
|
||||
fs_client::expand_path_with(
|
||||
&stack,
|
||||
&engine_state,
|
||||
rel_path,
|
||||
Path::new(path_str),
|
||||
false
|
||||
)
|
||||
.as_path()
|
||||
.to_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
mod os_windows_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_os_windows_maintainer_set_pwd() {
|
||||
let mut stack = Stack::new();
|
||||
let path_str = r"c:\uesrs\nushell";
|
||||
let path = Path::new(path_str);
|
||||
set_pwd(&mut stack, path);
|
||||
os_windows::maintainer::set_pwd(&mut stack, path);
|
||||
let engine_state = EngineState::new();
|
||||
assert_eq!(
|
||||
stack
|
||||
.get_env_var(&engine_state, &env_var_for_drive('c'))
|
||||
.get_env_var(
|
||||
&engine_state,
|
||||
&os_windows::implementation::env_var_for_drive('c')
|
||||
)
|
||||
.unwrap()
|
||||
.clone()
|
||||
.into_string()
|
||||
|
@ -108,50 +205,76 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_pwd_on_drive() {
|
||||
fn test_os_windows_fs_client_expand_pwd() {
|
||||
let mut stack = Stack::new();
|
||||
let path_str = r"c:\users\nushell";
|
||||
let path = Path::new(path_str);
|
||||
set_pwd(&mut stack, path);
|
||||
let engine_state = EngineState::new();
|
||||
let result = format!(r"{path_str}\");
|
||||
assert_eq!(result, get_pwd_on_drive(&stack, &engine_state, 'c'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_expand_pwd() {
|
||||
let mut stack = Stack::new();
|
||||
let path_str = r"c:\users\nushell";
|
||||
let path = Path::new(path_str);
|
||||
set_pwd(&mut stack, path);
|
||||
os_windows::maintainer::set_pwd(&mut stack, path);
|
||||
let engine_state = EngineState::new();
|
||||
|
||||
let rel_path = Path::new("c:.config");
|
||||
let result = format!(r"{path_str}\.config");
|
||||
assert_eq!(
|
||||
Some(result.as_str()),
|
||||
expand_pwd(&stack, &engine_state, rel_path)
|
||||
os_windows::fs_client::expand_pwd(&stack, &engine_state, rel_path)
|
||||
.unwrap()
|
||||
.as_path()
|
||||
.to_str()
|
||||
);
|
||||
}
|
||||
|
||||
mod implementation_test {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_expand_path_with() {
|
||||
fn test_os_windows_implementation_get_pwd_on_drive() {
|
||||
let mut stack = Stack::new();
|
||||
let path_str = r"c:\users\nushell";
|
||||
let path = Path::new(path_str);
|
||||
set_pwd(&mut stack, path);
|
||||
os_windows::maintainer::set_pwd(&mut stack, path);
|
||||
let engine_state = EngineState::new();
|
||||
|
||||
let rel_path = Path::new("c:.config");
|
||||
let result = format!(r"{path_str}\.config");
|
||||
let result = format!(r"{path_str}\");
|
||||
assert_eq!(
|
||||
Some(result.as_str()),
|
||||
expand_path_with(&stack, &engine_state, rel_path, Path::new(path_str), false)
|
||||
.as_path()
|
||||
.to_str()
|
||||
result,
|
||||
os_windows::implementation::get_pwd_on_drive(&stack, &engine_state, 'c')
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_os_windows_implementation_need_expand() {
|
||||
use os_windows::implementation::need_expand;
|
||||
|
||||
assert!(need_expand(r"c:nushell\src"));
|
||||
assert!(need_expand("C:src/"));
|
||||
assert!(need_expand("a:"));
|
||||
assert!(need_expand("z:"));
|
||||
// Absolute path does not need expand
|
||||
assert!(!need_expand(r"c:\"));
|
||||
// Unix path does not need expand
|
||||
assert!(!need_expand("/usr/bin"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_os_windows_implementation_env_var_for_drive() {
|
||||
use os_windows::implementation::env_var_for_drive;
|
||||
|
||||
for drive_letter in 'A'..='Z' {
|
||||
assert_eq!(env_var_for_drive(drive_letter), format!("={drive_letter}:"));
|
||||
}
|
||||
for drive_letter in 'a'..='z' {
|
||||
assert_eq!(
|
||||
env_var_for_drive(drive_letter),
|
||||
format!("={}:", drive_letter.to_ascii_uppercase())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_os_windows_implementation_extract_drive_letter() {
|
||||
use os_windows::implementation::extract_drive_letter;
|
||||
|
||||
assert_eq!(extract_drive_letter(Path::new("C:test")), Some('C'));
|
||||
assert_eq!(extract_drive_letter(Path::new(r"d:\temp")), Some('d'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#[cfg(windows)]
|
||||
use crate::engine::set_pwd;
|
||||
use crate::engine::pwd_per_drive_helper::*;
|
||||
use crate::{
|
||||
engine::{
|
||||
ArgumentStack, EngineState, ErrorHandlerStack, Redirection, StackCallArgGuard,
|
||||
|
@ -764,7 +764,7 @@ impl Stack {
|
|||
let value = Value::string(path.to_string_lossy(), Span::unknown());
|
||||
self.add_env_var("PWD".into(), value);
|
||||
#[cfg(windows)] // Sync with PWD-per-drive
|
||||
set_pwd(self, &path);
|
||||
os_windows::maintainer::set_pwd(self, &path);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue