mirror of
https://github.com/nushell/nushell.git
synced 2025-08-10 20:06:18 +02:00
CWDperDrive
This commit is contained in:
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -3352,7 +3352,10 @@ version = "0.100.1"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"dirs",
|
"dirs",
|
||||||
"omnipath",
|
"omnipath",
|
||||||
|
"once_cell",
|
||||||
"pwd",
|
"pwd",
|
||||||
|
"winapi",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -321,3 +321,6 @@ bench = false
|
|||||||
[[bench]]
|
[[bench]]
|
||||||
name = "benchmarks"
|
name = "benchmarks"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
incremental = true
|
||||||
|
@ -114,7 +114,19 @@ impl Command for Cd {
|
|||||||
//FIXME: this only changes the current scope, but instead this environment variable
|
//FIXME: this only changes the current scope, but instead this environment variable
|
||||||
//should probably be a block that loads the information from the state in the overlay
|
//should probably be a block that loads the information from the state in the overlay
|
||||||
PermissionResult::PermissionOk => {
|
PermissionResult::PermissionOk => {
|
||||||
|
let path_for_scd = path.clone();
|
||||||
stack.set_cwd(path)?;
|
stack.set_cwd(path)?;
|
||||||
|
use nu_path::state_driver_pwd::get_drive_pwd_map;
|
||||||
|
get_drive_pwd_map().lock().unwrap().set_pwd(path_for_scd.as_path())
|
||||||
|
.map_err(|_e| {
|
||||||
|
Err(ShellError::GenericError{
|
||||||
|
error: "Set PWD for drive failed".into(),
|
||||||
|
msg: "System error".into(),
|
||||||
|
span: None,
|
||||||
|
help: None,
|
||||||
|
inner: vec![],
|
||||||
|
})
|
||||||
|
})?;
|
||||||
Ok(PipelineData::empty())
|
Ok(PipelineData::empty())
|
||||||
}
|
}
|
||||||
PermissionResult::PermissionDenied(reason) => Err(ShellError::IOError {
|
PermissionResult::PermissionDenied(reason) => Err(ShellError::IOError {
|
||||||
|
@ -16,6 +16,9 @@ dirs = { workspace = true }
|
|||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
omnipath = { workspace = true }
|
omnipath = { workspace = true }
|
||||||
|
once_cell = "1.20.1"
|
||||||
|
winapi = { version = "0.3.9", features = ["fileapi"] }
|
||||||
|
windows-sys = { workspace = true, features = ["Win32_System_Environment"] }
|
||||||
|
|
||||||
[target.'cfg(all(unix, not(target_os = "macos"), not(target_os = "android")))'.dependencies]
|
[target.'cfg(all(unix, not(target_os = "macos"), not(target_os = "android")))'.dependencies]
|
||||||
pwd = { workspace = true }
|
pwd = { workspace = true }
|
||||||
|
@ -8,6 +8,7 @@ mod helpers;
|
|||||||
mod path;
|
mod path;
|
||||||
mod tilde;
|
mod tilde;
|
||||||
mod trailing_slash;
|
mod trailing_slash;
|
||||||
|
pub mod state_driver_pwd;
|
||||||
|
|
||||||
pub use components::components;
|
pub use components::components;
|
||||||
pub use expansions::{canonicalize_with, expand_path_with, expand_to_real_path, locate_in_dirs};
|
pub use expansions::{canonicalize_with, expand_path_with, expand_to_real_path, locate_in_dirs};
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
use std::path::Path;
|
use std::path::{ Path, PathBuf };
|
||||||
|
|
||||||
pub struct DrivePwdMap {
|
pub struct DrivePwdMap {
|
||||||
map: [Option<String>; 26], // Fixed-size array for A-Z
|
map: [Option<String>; 26], // Fixed-size array for A-Z
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DrivePwdMap {
|
impl DrivePwdMap {
|
||||||
/// Create a new DrivePwdMap
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
DrivePwdMap {
|
DrivePwdMap {
|
||||||
map: Default::default(), // Initialize all to `None`
|
map: Default::default(), // Initialize all to `None`
|
||||||
@ -16,7 +15,8 @@ impl DrivePwdMap {
|
|||||||
pub fn set_pwd(&mut self, path: &Path) -> Result<(), String> {
|
pub fn set_pwd(&mut self, path: &Path) -> Result<(), String> {
|
||||||
if let Some(drive_letter) = Self::extract_drive_letter(path) {
|
if let Some(drive_letter) = Self::extract_drive_letter(path) {
|
||||||
if let Some(index) = Self::drive_to_index(drive_letter) {
|
if let Some(index) = Self::drive_to_index(drive_letter) {
|
||||||
self.map[index] = Some(path.to_string_lossy().into_owned());
|
let normalized = Self::normalize_path(path);
|
||||||
|
self.map[index] = Some(normalized.to_string_lossy().into_owned());
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(format!("Invalid drive letter: {}", drive_letter))
|
Err(format!("Invalid drive letter: {}", drive_letter))
|
||||||
@ -27,7 +27,6 @@ impl DrivePwdMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current working directory for a drive letter
|
/// Get the current working directory for a drive letter
|
||||||
/// If no PWD is set, return the root of the drive (e.g., `C:\`)
|
|
||||||
pub fn get_pwd(&self, drive: char) -> Option<String> {
|
pub fn get_pwd(&self, drive: char) -> Option<String> {
|
||||||
Self::drive_to_index(drive).map(|index| {
|
Self::drive_to_index(drive).map(|index| {
|
||||||
self.map[index]
|
self.map[index]
|
||||||
@ -43,10 +42,10 @@ impl DrivePwdMap {
|
|||||||
let is_absolute = path_str.contains(":\\") || path_str.starts_with("\\");
|
let is_absolute = path_str.contains(":\\") || path_str.starts_with("\\");
|
||||||
if is_absolute {
|
if is_absolute {
|
||||||
// Already an absolute path
|
// Already an absolute path
|
||||||
Some(PathBuf::from(path_str))
|
Some(PathBuf::from(Self::ensure_trailing_separator(path_str)))
|
||||||
} else if let Some(pwd) = self.get_pwd(drive_letter) {
|
} else if let Some(pwd) = self.get_pwd(drive_letter) {
|
||||||
// Combine current PWD with the relative path
|
// Combine current PWD with the relative path
|
||||||
let mut base = PathBuf::from(pwd);
|
let mut base = PathBuf::from(Self::ensure_trailing_separator(&pwd));
|
||||||
base.push(path_str.split_at(2).1); // Skip the "C:" part of the relative path
|
base.push(path_str.split_at(2).1); // Skip the "C:" part of the relative path
|
||||||
Some(base)
|
Some(base)
|
||||||
} else {
|
} else {
|
||||||
@ -67,17 +66,35 @@ impl DrivePwdMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract the drive letter from a path (e.g., `C:\Users` -> `C`)
|
/// Extract the drive letter from a path (e.g., `C:test` -> `C`)
|
||||||
fn extract_drive_letter(path: &Path) -> Option<char> {
|
fn extract_drive_letter(path: &Path) -> Option<char> {
|
||||||
path.to_str()
|
path.to_str()
|
||||||
.and_then(|s| s.chars().next())
|
.and_then(|s| s.chars().next())
|
||||||
.filter(|c| c.is_ascii_alphabetic())
|
.filter(|c| c.is_ascii_alphabetic())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Normalize a path by removing any trailing `\` or `/`
|
||||||
|
fn normalize_path(path: &Path) -> PathBuf {
|
||||||
|
let mut normalized = path.to_path_buf();
|
||||||
|
while normalized.to_string_lossy().ends_with(&['\\', '/'][..]) {
|
||||||
|
normalized.pop();
|
||||||
|
}
|
||||||
|
normalized
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ensure a path has a trailing `\`
|
||||||
|
fn ensure_trailing_separator(path: &str) -> String {
|
||||||
|
if !path.ends_with('\\') && !path.ends_with('/') {
|
||||||
|
format!("{}\\", path)
|
||||||
|
} else {
|
||||||
|
path.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use crate::ShellError;
|
//use nu_protocol::errors::shell_error::ShellError;
|
||||||
|
|
||||||
/// Global singleton instance of DrivePwdMap
|
/// Global singleton instance of DrivePwdMap
|
||||||
static DRIVE_PWD_MAP: Lazy<Mutex<DrivePwdMap>> = Lazy::new(|| Mutex::new(DrivePwdMap::new()));
|
static DRIVE_PWD_MAP: Lazy<Mutex<DrivePwdMap>> = Lazy::new(|| Mutex::new(DrivePwdMap::new()));
|
||||||
@ -192,12 +209,11 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod current_directory_specific {
|
pub mod current_directory_specific {
|
||||||
use crate::ShellError;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
fn need_expand_current_directory(path: &Path) -> bool {
|
pub fn need_expand_current_directory_per_drive(path: &Path) -> bool {
|
||||||
if let Some(path_str) = path.to_str() {
|
if let Some(path_str) = path.to_str() {
|
||||||
let chars: Vec<char> = path_str.chars().collect();
|
let chars: Vec<char> = path_str.chars().collect();
|
||||||
if chars.len() >= 2 {
|
if chars.len() >= 2 {
|
||||||
@ -208,12 +224,12 @@ mod current_directory_specific {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
fn need_expand_current_directory(path: &Path) -> bool {
|
pub fn need_expand_current_directory(path: &Path) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
fn get_windows_absolute_path(path: &Path) -> Option<String> {
|
pub fn get_windows_absolute_path(path: &Path) -> Option<String> {
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::os::windows::ffi::OsStringExt;
|
use std::os::windows::ffi::OsStringExt;
|
||||||
use std::os::windows::ffi::OsStrExt;
|
use std::os::windows::ffi::OsStrExt;
|
||||||
@ -247,12 +263,16 @@ mod current_directory_specific {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum DrivePwdError {
|
||||||
|
InvalidPath,
|
||||||
|
SystemError,
|
||||||
|
}
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
fn get_windows_absolute_path(path: &Path) -> Option<String> {
|
fn get_windows_absolute_path(path: &Path) -> Option<String> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub fn set_current_directory_windows(path: &Path) -> Result<(), ShellError> {
|
pub fn set_current_directory_windows(path: &Path) -> Result<(), DrivePwdError> {
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::os::windows::ffi::OsStrExt;
|
use std::os::windows::ffi::OsStrExt;
|
||||||
use windows_sys::Win32::System::Environment::SetCurrentDirectoryW;
|
use windows_sys::Win32::System::Environment::SetCurrentDirectoryW;
|
||||||
@ -266,27 +286,16 @@ mod current_directory_specific {
|
|||||||
return Ok(())
|
return Ok(())
|
||||||
} else {
|
} else {
|
||||||
return
|
return
|
||||||
Err(ShellError::GenericError {
|
Err(DrivePwdError::SystemError)
|
||||||
error: "Failed to set current directory".into(),
|
|
||||||
msg: "SetCurrentDirectoryW() failed".into(),
|
|
||||||
span: None,
|
|
||||||
help: None,
|
|
||||||
inner: vec![],
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(ShellError::GenericError {
|
Err(DrivePwdError::InvalidPath)
|
||||||
error: "Failed to set current directory".into(),
|
|
||||||
msg: "Invalid path".into(),
|
|
||||||
span: None,
|
|
||||||
help: None,
|
|
||||||
inner: vec![],
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
pub fn set_current_directory_windows(_path: &Path) -> Result<(), ShellError>{
|
pub fn set_current_directory_windows(_path: &Path) -> Result<(), Error>{
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -21,17 +21,21 @@ fn expand_tilde_with_home(path: impl AsRef<Path>, home: Option<PathBuf>) -> Path
|
|||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
|
|
||||||
if !path.starts_with("~") {
|
if !path.starts_with("~") {
|
||||||
use nu_protocol::engine::state_driver_pwd:: {
|
use crate::state_driver_pwd:: {
|
||||||
need_expand_current_directory,
|
current_directory_specific::need_expand_current_directory_per_drive,
|
||||||
get_windows_absolute_path,
|
//current_directory_specific::get_windows_absolute_path,
|
||||||
|
get_drive_pwd_map
|
||||||
};
|
};
|
||||||
if need_expand_current_directory(path) {
|
if need_expand_current_directory_per_drive(path) {
|
||||||
if let Some(current_dir) = get_windows_absolute_path(path) {
|
if let Some(expanded_dir) = get_drive_pwd_map().lock().unwrap().expand_path(path) {
|
||||||
//println!("Absolute path for {} is: {}", path.display(), current_dir);
|
return PathBuf::from(&expanded_dir)
|
||||||
return PathBuf::from(¤t_dir)
|
|
||||||
} else {
|
|
||||||
println!("Failed to get absolute path for {}", path.display());
|
|
||||||
}
|
}
|
||||||
|
// if let Some(current_dir) = get_windows_absolute_path(path) {
|
||||||
|
// //println!("Absolute path for {} is: {}", path.display(), current_dir);
|
||||||
|
// return PathBuf::from(¤t_dir)
|
||||||
|
// } else {
|
||||||
|
// println!("Failed to get absolute path for {}", path.display());
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
let string = path.to_string_lossy();
|
let string = path.to_string_lossy();
|
||||||
let mut path_as_string = string.as_ref().bytes();
|
let mut path_as_string = string.as_ref().bytes();
|
||||||
|
Reference in New Issue
Block a user