Remove extra mods

This commit is contained in:
Zhao Zhenping 2024-12-09 12:13:35 -08:00
parent f8e01d8401
commit 338fa8400f
9 changed files with 271 additions and 332 deletions

View file

@ -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::os_windows;
use nu_protocol::engine::expand_pwd;
use nu_protocol::{
engine::{EngineState, Stack, StateWorkingSet},
Span,
@ -177,17 +177,16 @@ 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) =
os_windows::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()
let cleaned_partial =
if let Some(absolute_path) = 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 {
absolute_path.display().to_string()
}
} else {
absolute_path.display().to_string()
}
} else {
cleaned_partial
};
cleaned_partial
};
let expanded_partial = expand_ndots(Path::new(&cleaned_partial));
let should_collapse_dots = expanded_partial != Path::new(&cleaned_partial);
let mut partial = expanded_partial.to_string_lossy().to_string();

View file

@ -23,7 +23,7 @@ use nu_engine::{convert_env_values, current_dir_str, env_to_strings};
use nu_parser::{lex, parse, trim_quotes_str};
use nu_protocol::{
config::NuCursorShape,
engine::{fs_client, EngineState, Stack, StateWorkingSet},
engine::{expand_path_with, EngineState, Stack, StateWorkingSet},
report_shell_error, HistoryConfig, HistoryFileFormat, PipelineData, ShellError, Span, Spanned,
Value,
};
@ -824,7 +824,7 @@ fn parse_operation(
orig = trim_quotes_str(&orig).to_string()
}
let path = fs_client::expand_path_with(stack, engine_state, &orig, &cwd, true);
let path = expand_path_with(stack, engine_state, &orig, &cwd, true);
if looks_like_path(&orig) && is_dir(&path) && tokens.0.len() == 1 {
Ok(ReplOperation::AutoCd {
cwd,

View file

@ -1,7 +1,7 @@
#[allow(deprecated)]
use nu_engine::{command_prelude::*, current_dir};
use nu_protocol::{
engine::{fs_client, StateWorkingSet},
engine::{expand_path_with, StateWorkingSet},
PluginRegistryFile,
};
use std::{
@ -19,7 +19,7 @@ fn get_plugin_registry_file_path(
let cwd = current_dir(engine_state, stack)?;
if let Some(ref custom_path) = custom_path {
Ok(fs_client::expand_path_with(
Ok(expand_path_with(
stack,
engine_state,
&custom_path.item,
@ -130,7 +130,7 @@ pub(crate) fn canonicalize_possible_filename_arg(
// This results in the best possible chance of a match with the plugin item
#[allow(deprecated)]
if let Ok(cwd) = nu_engine::current_dir(engine_state, stack) {
let path = fs_client::expand_path_with(stack, engine_state, arg, &cwd, true);
let path = expand_path_with(stack, engine_state, arg, &cwd, true);
// Try to canonicalize
nu_path::locate_in_dirs(&path, &cwd, || get_plugin_dirs(engine_state, stack))
// If we couldn't locate it, return the expanded path alone

View file

@ -1,5 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::engine::fs_client;
use nu_protocol::engine::expand_path_with;
use nu_utils::filesystem::{have_permission, PermissionResult};
#[derive(Clone)]
@ -88,13 +88,8 @@ impl Command for Cd {
});
}
} else {
let path = fs_client::expand_path_with(
stack,
engine_state,
path_no_whitespace,
&cwd,
true,
);
let path =
expand_path_with(stack, engine_state, path_no_whitespace, &cwd, true);
if !path.exists() {
return Err(ShellError::DirectoryNotFound {
dir: path_no_whitespace.to_string(),

View file

@ -5,7 +5,7 @@ use nu_path::AbsolutePathBuf;
use nu_protocol::{
ast::{Assignment, Block, Call, Expr, Expression, ExternalArgument, PathMember},
debugger::DebugContext,
engine::{fs_client, Closure, EngineState, Stack},
engine::{expand_path_with, Closure, EngineState, Stack},
eval_base::Eval,
BlockId, Config, DataSource, IntoPipelineData, PipelineData, PipelineMetadata, ShellError,
Span, Type, Value, VarId, ENV_VARIABLE_ID,
@ -425,7 +425,7 @@ impl Eval for EvalRuntime {
Ok(Value::string(path, span))
} else {
let cwd = engine_state.cwd(Some(stack))?;
let path = fs_client::expand_path_with(stack, engine_state, path, cwd, true);
let path = expand_path_with(stack, engine_state, path, cwd, true);
Ok(Value::string(path.to_string_lossy(), span))
}
@ -447,7 +447,7 @@ impl Eval for EvalRuntime {
.cwd(Some(stack))
.map(AbsolutePathBuf::into_std_path_buf)
.unwrap_or_default();
let path = fs_client::expand_path_with(stack, engine_state, path, cwd, true);
let path = expand_path_with(stack, engine_state, path, cwd, true);
Ok(Value::string(path.to_string_lossy(), span))
}

View file

@ -5,8 +5,8 @@ use nu_protocol::{
ast::{Bits, Block, Boolean, CellPath, Comparison, Math, Operator},
debugger::DebugContext,
engine::{
fs_client, Argument, Closure, EngineState, ErrorHandler, Matcher, Redirection, Stack,
StateWorkingSet,
expand_path_with, Argument, Closure, EngineState, ErrorHandler, Matcher, Redirection,
Stack, StateWorkingSet,
},
ir::{Call, DataSlice, Instruction, IrAstRef, IrBlock, Literal, RedirectMode},
DataSource, DeclId, ErrSpan, Flag, IntoPipelineData, IntoSpanned, ListStream, OutDest,
@ -871,8 +871,7 @@ fn literal_value(
Value::string(path, span)
} else {
let cwd = ctx.engine_state.cwd(Some(ctx.stack))?;
let path =
fs_client::expand_path_with(ctx.stack, ctx.engine_state, path, cwd, true);
let path = expand_path_with(ctx.stack, ctx.engine_state, path, cwd, true);
Value::string(path.to_string_lossy(), span)
}
@ -892,8 +891,7 @@ fn literal_value(
.cwd(Some(ctx.stack))
.map(AbsolutePathBuf::into_std_path_buf)
.unwrap_or_default();
let path =
fs_client::expand_path_with(ctx.stack, ctx.engine_state, path, cwd, true);
let path = expand_path_with(ctx.stack, ctx.engine_state, path, cwd, true);
Value::string(path.to_string_lossy(), span)
}
@ -1407,7 +1405,7 @@ enum RedirectionStream {
/// Open a file for redirection
fn open_file(ctx: &EvalContext<'_>, path: &Value, append: bool) -> Result<Arc<File>, ShellError> {
let path_expanded = fs_client::expand_path_with(
let path_expanded = expand_path_with(
ctx.stack,
ctx.engine_state,
path.as_str()?,

View file

@ -29,7 +29,7 @@ pub use engine_state::*;
pub use error_handler::*;
pub use overlay::*;
pub use pattern_match::*;
pub use pwd_per_drive::*; //fs_client::expand_path_with
pub use pwd_per_drive::*;
pub use sequence::*;
pub use stack::*;
pub use stack_out_dest::*;

View file

@ -4,181 +4,153 @@ use crate::{Span, Value};
use std::path::{Path, PathBuf};
// For file system command usage
pub mod fs_client {
use super::*;
/// Proxy/Wrapper for
/// nu_path::expand_path_with<P, Q>(path, relative_to, expand_tilde);
///
/// Usually if a command opens one file or directory, it uses
/// nu_path::expand_path_with::<P, Q>(p, r, t) to expand '~','.' etc.; replacing it with
/// nu_protocol::engine::fs_client::expand_path_with(stack, engine_state, p, r t) will
/// first check if the path is relative for a drive;
/// Commands that accept multiple files/directories as parameters usually depend on Glob,
/// after near future revised Glob collection implementation done, all file system commands
/// will support 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
P: AsRef<Path>,
Q: AsRef<Path>,
{
#[cfg(windows)]
if let Some(abs_path) = expand_pwd(_stack, _engine_state, path.as_ref()) {
return abs_path;
}
/// Proxy/Wrapper for
/// nu_path::expand_path_with<P, Q>(path, relative_to, expand_tilde);
///
/// Usually if a command opens one file or directory, it uses
/// nu_path::expand_path_with::<P, Q>(p, r, t) to expand '~','.' etc.; replacing it with
/// nu_protocol::engine::fs_client::expand_path_with(stack, engine_state, p, r t) will
/// first check if the path is relative for a drive;
/// Commands that accept multiple files/directories as parameters usually depend on Glob,
/// after near future revised Glob collection implementation done, all file system commands
/// will support 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
P: AsRef<Path>,
Q: AsRef<Path>,
{
#[cfg(windows)]
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)
}
/// For maintainer to notify current pwd
/// When user change current directory, maintainer notifies
/// PWD-per-drive by calling set_pwd() with current stack and path;
#[cfg(windows)]
pub fn set_pwd(stack: &mut Stack, path: &Path) {
if let Some(path_str) = path.to_str() {
if let Some(drive) = extract_drive_letter(path_str) {
stack.add_env_var(
env_var_for_drive(drive),
Value::string(path_str, Span::unknown()).clone(),
);
}
nu_path::expand_path_with::<P, Q>(path, relative_to, expand_tilde)
}
}
/// For file system command usage
/// File system command implementation can also directly use expand_pwd
/// to expand relate path for a drive and strip redundant double or
/// single quote like bash.
/// cd "''C:''nushell''"
/// C:\Users\nushell>
#[cfg(windows)]
pub mod os_windows {
use super::*;
/// For maintainer to notify current pwd
pub mod maintainer {
use super::*;
/// When user change current directory, maintainer notifies
/// 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(path_str) = path.to_str() {
if let Some(drive) = extract_drive_letter(path_str) {
stack.add_env_var(
env_var_for_drive(drive),
Value::string(path_str, Span::unknown()).clone(),
);
}
}
pub fn expand_pwd(stack: &Stack, engine_state: &EngineState, path: &Path) -> Option<PathBuf> {
if let Some(path_str) = path.to_str() {
if let Some(drive_letter) = need_expand(path_str) {
let mut base = PathBuf::from(get_pwd_on_drive(stack, engine_state, drive_letter));
// need_expand() ensures path_str.len() >= 2
base.push(&path_str[2..]); // Join PWD with path parts after "C:"
return Some(base);
}
}
None
}
/// For file system command usage
pub mod fs_client {
use super::*;
/// Implementation for maintainer and fs_client
/// Windows env var for drive
/// essential for integration with windows native shell CMD/PowerShell
/// and the core mechanism for supporting PWD-per-drive with nushell's
/// powerful layered environment system.
/// Returns uppercased "=X:".
#[cfg(windows)]
pub fn env_var_for_drive(drive_letter: char) -> String {
let drive_letter = drive_letter.to_ascii_uppercase();
format!("={}:", drive_letter)
}
/// File system command implementation can also directly use expand_pwd
/// to expand relate path for a drive and strip redundant double or
/// single quote like bash.
/// cd "''C:''nushell''"
/// C:\Users\nushell>
pub fn expand_pwd(
stack: &Stack,
engine_state: &EngineState,
path: &Path,
) -> Option<PathBuf> {
use implementation::{get_pwd_on_drive, need_expand};
if let Some(path_str) = path.to_str() {
if let Some(drive_letter) = need_expand(path_str) {
let mut base =
PathBuf::from(get_pwd_on_drive(stack, engine_state, drive_letter));
// need_expand() ensures path_str.len() >= 2
base.push(&path_str[2..]); // Join PWD with path parts after "C:"
return Some(base);
}
}
None
/// get pwd for drive:
/// 1. From env_var, if no,
/// 2. From sys_absolute, if no,
/// 3. Construct root path to drives
#[cfg(windows)]
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);
}
}
/// Implementation for maintainer and fs_client
pub(in crate::engine::pwd_per_drive) mod implementation {
use super::*;
/// Windows env var for drive
/// essential for integration with windows native shell CMD/PowerShell
/// and the core mechanism for supporting PWD-per-drive with nushell's
/// powerful layered environment system.
/// Returns uppercased "=X:".
pub fn env_var_for_drive(drive_letter: char) -> String {
let drive_letter = drive_letter.to_ascii_uppercase();
format!("={}:", drive_letter)
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)
}
}
/// 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)
}
}
/// Check if input path is relative path for drive letter,
/// which should be expanded with PWD-per-drive.
/// Returns Some(drive_letter) or None, drive_letter is upper case.
#[cfg(windows)]
pub fn need_expand(path: &str) -> Option<char> {
let chars: Vec<char> = path.chars().collect();
if chars.len() == 2 || (chars.len() > 2 && chars[2] != '/' && chars[2] != '\\') {
extract_drive_letter(path)
} else {
None
}
}
/// Check if input path is relative path for drive letter,
/// which should be expanded with PWD-per-drive.
/// Returns Some(drive_letter) or None, drive_letter is upper case.
pub fn need_expand(path: &str) -> Option<char> {
let chars: Vec<char> = path.chars().collect();
if chars.len() == 2 || (chars.len() > 2 && chars[2] != '/' && chars[2] != '\\') {
extract_drive_letter(path)
} else {
None
}
}
/// Extract the drive letter from a path, return uppercased
/// drive letter or None
#[cfg(windows)]
pub fn extract_drive_letter(path: &str) -> Option<char> {
let chars: Vec<char> = path.chars().collect();
if chars.len() >= 2 && chars[0].is_ascii_alphabetic() && chars[1] == ':' {
Some(chars[0].to_ascii_uppercase())
} else {
None
}
}
/// Extract the drive letter from a path, return uppercased
/// drive letter or None
pub fn extract_drive_letter(path: &str) -> Option<char> {
let chars: Vec<char> = path.chars().collect();
if chars.len() >= 2 && chars[0].is_ascii_alphabetic() && chars[1] == ':' {
Some(chars[0].to_ascii_uppercase())
} else {
None
}
}
/// Ensure a path has a trailing `\\` or '/'
#[cfg(windows)]
pub fn ensure_trailing_delimiter(path: &str) -> String {
if !path.ends_with('\\') && !path.ends_with('/') {
format!(r"{}\", path)
} else {
path.to_string()
}
}
/// Ensure a path has a trailing `\\` or '/'
pub fn ensure_trailing_delimiter(path: &str) -> String {
if !path.ends_with('\\') && !path.ends_with('/') {
format!(r"{}\", path)
} else {
path.to_string()
}
}
/// get_full_path_name_w
/// Call Windows system API (via omnipath crate) to expand
/// absolute path
#[cfg(windows)]
pub fn get_full_path_name_w(path_str: &str) -> Option<String> {
use omnipath::sys_absolute;
use std::path::Path;
/// get_full_path_name_w
/// Call windows system API (via omnipath crate) to expand
/// absolute path
pub fn get_full_path_name_w(path_str: &str) -> Option<String> {
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 {
None
}
}
if let Ok(path_sys_abs) = sys_absolute(Path::new(path_str)) {
Some(path_sys_abs.to_str()?.to_string())
} else {
None
}
}
@ -187,158 +159,133 @@ pub mod os_windows {
mod tests {
use super::*;
mod fs_client_test {
use super::*;
#[test]
fn test_expand_path_with() {
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();
#[test]
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()
);
}
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,
#[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);
let engine_state = EngineState::new();
assert_eq!(
stack
.get_env_var(
&engine_state,
rel_path,
Path::new(path_str),
false
&os_windows::implementation::env_var_for_drive('c')
)
.unwrap()
.clone()
.into_string()
.unwrap(),
path_str.to_string()
);
}
#[test]
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 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)
.unwrap()
.as_path()
.to_str()
);
}
#[test]
fn test_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())
);
}
}
mod os_windows_tests {
use super::*;
#[test]
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);
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_os_windows_maintainer_set_pwd() {
let mut stack = Stack::new();
let path_str = r"c:\uesrs\nushell";
let path = Path::new(path_str);
os_windows::maintainer::set_pwd(&mut stack, path);
let engine_state = EngineState::new();
assert_eq!(
stack
.get_env_var(
&engine_state,
&os_windows::implementation::env_var_for_drive('c')
)
.unwrap()
.clone()
.into_string()
.unwrap(),
path_str.to_string()
);
}
#[test]
fn test_os_windows_implementation_need_expand() {
assert_eq!(need_expand(r"c:nushell\src"), Some('C'));
assert_eq!(need_expand("C:src/"), Some('C'));
assert_eq!(need_expand("a:"), Some('A'));
assert_eq!(need_expand("z:"), Some('Z'));
// Absolute path does not need expand
assert_eq!(need_expand(r"c:\"), None);
// Unix path does not need expand
assert_eq!(need_expand("/usr/bin"), None);
// Invalid path on drive
assert_eq!(need_expand("1:usr/bin"), None);
}
#[test]
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);
os_windows::maintainer::set_pwd(&mut stack, path);
let engine_state = EngineState::new();
#[test]
fn test_os_windows_implementation_extract_drive_letter() {
assert_eq!(extract_drive_letter("C:test"), Some('C'));
assert_eq!(extract_drive_letter(r"d:\temp"), Some('D'));
assert_eq!(extract_drive_letter(r"1:temp"), None);
}
let rel_path = Path::new("c:.config");
let result = format!(r"{path_str}\.config");
assert_eq!(
Some(result.as_str()),
os_windows::fs_client::expand_pwd(&stack, &engine_state, rel_path)
.unwrap()
.as_path()
.to_str()
);
}
#[test]
fn test_os_windows_implementation_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:/");
}
mod implementation_test {
use super::*;
#[test]
fn test_os_windows_implementation_get_full_path_name_w() {
let result = get_full_path_name_w("C:");
assert!(result.is_some());
let path = result.unwrap();
assert!(path.starts_with(r"C:\"));
#[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_get_pwd_on_drive() {
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 result = format!(r"{path_str}\");
assert_eq!(
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_eq!(need_expand(r"c:nushell\src"), Some('C'));
assert_eq!(need_expand("C:src/"), Some('C'));
assert_eq!(need_expand("a:"), Some('A'));
assert_eq!(need_expand("z:"), Some('Z'));
// Absolute path does not need expand
assert_eq!(need_expand(r"c:\"), None);
// Unix path does not need expand
assert_eq!(need_expand("/usr/bin"), None);
// Invalid path on drive
assert_eq!(need_expand("1:usr/bin"), None);
}
#[test]
fn test_os_windows_implementation_extract_drive_letter() {
use os_windows::implementation::extract_drive_letter;
assert_eq!(extract_drive_letter("C:test"), Some('C'));
assert_eq!(extract_drive_letter(r"d:\temp"), Some('D'));
assert_eq!(extract_drive_letter(r"1:temp"), None);
}
#[test]
fn test_os_windows_implementation_ensure_trailing_delimiter() {
use os_windows::implementation::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:/");
}
#[test]
fn test_os_windows_implementation_get_full_path_name_w() {
use os_windows::implementation::get_full_path_name_w;
let result = get_full_path_name_w("C:");
assert!(result.is_some());
let path = result.unwrap();
assert!(path.starts_with(r"C:\"));
let result = get_full_path_name_w(r"c:nushell\src");
assert!(result.is_some());
let path = result.unwrap();
assert!(path.starts_with(r"C:\") || path.starts_with(r"c:\"));
assert!(path.ends_with(r"nushell\src"));
}
}
let result = get_full_path_name_w(r"c:nushell\src");
assert!(result.is_some());
let path = result.unwrap();
assert!(path.starts_with(r"C:\") || path.starts_with(r"c:\"));
assert!(path.ends_with(r"nushell\src"));
}
}

View file

@ -1,5 +1,5 @@
#[cfg(windows)]
use crate::engine::pwd_per_drive::*;
use crate::engine::pwd_per_drive;
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
os_windows::maintainer::set_pwd(self, &path);
pwd_per_drive::set_pwd(self, &path);
Ok(())
}
}