Follow review comments, and adjust expectation on test results for windows. Hide env_vars for PWD-per-drive from being collected by auto completion.

This commit is contained in:
Zhenping Zhao 2024-12-13 13:39:31 -08:00
parent ed848615ac
commit 795230f36b
7 changed files with 60 additions and 24 deletions

1
Cargo.lock generated
View file

@ -3256,6 +3256,7 @@ dependencies = [
"nu-utils", "nu-utils",
"percent-encoding", "percent-encoding",
"reedline", "reedline",
"regex",
"rstest", "rstest",
"sysinfo 0.32.0", "sysinfo 0.32.0",
"tempfile", "tempfile",

View file

@ -42,6 +42,8 @@ sysinfo = { workspace = true }
unicode-segmentation = { workspace = true } unicode-segmentation = { workspace = true }
uuid = { workspace = true, features = ["v4"] } uuid = { workspace = true, features = ["v4"] }
which = { workspace = true } which = { workspace = true }
#[cfg(windows)]
regex = { workspace = true }
[features] [features]
plugin = ["nu-plugin-engine"] plugin = ["nu-plugin-engine"]

View file

@ -46,7 +46,17 @@ impl Completer for VariableCompletion {
if !var_str.is_empty() { if !var_str.is_empty() {
// Completion for $env.<tab> // Completion for $env.<tab>
if var_str == "$env" { if var_str == "$env" {
#[cfg(not(windows))]
let env_vars = stack.get_env_vars(working_set.permanent_state); let env_vars = stack.get_env_vars(working_set.permanent_state);
#[cfg(windows)]
let mut env_vars = stack.get_env_vars(working_set.permanent_state);
#[cfg(windows)]
{
// Hide env_vars for PWD-per-drive from being listed in completion selection
if let Ok(pattern) = regex::Regex::new(r"^=[a-zA-Z]:$") {
env_vars.retain(|key, _| !pattern.is_match(key));
}
}
// Return nested values // Return nested values
if sublevels_count > 0 { if sublevels_count > 0 {

View file

@ -1414,10 +1414,7 @@ fn variables_completions() {
// Test completions for $env // Test completions for $env
let suggestions = completer.complete("$env.", 5); let suggestions = completer.complete("$env.", 5);
#[cfg(not(windows))]
assert_eq!(3, suggestions.len()); assert_eq!(3, suggestions.len());
#[cfg(windows)]
assert_eq!(4, suggestions.len());
#[cfg(windows)] #[cfg(windows)]
let expected: Vec<String> = vec!["Path".into(), "PWD".into(), "TEST".into()]; let expected: Vec<String> = vec!["Path".into(), "PWD".into(), "TEST".into()];
@ -1425,14 +1422,7 @@ fn variables_completions() {
let expected: Vec<String> = vec!["PATH".into(), "PWD".into(), "TEST".into()]; let expected: Vec<String> = vec!["PATH".into(), "PWD".into(), "TEST".into()];
// Match results // Match results
#[cfg(not(windows))]
match_suggestions(&expected, &suggestions); match_suggestions(&expected, &suggestions);
#[cfg(windows)]
{
let mut suggestions = suggestions;
let _ = suggestions.remove(0);
match_suggestions(&expected, &suggestions);
}
// Test completions for $env // Test completions for $env
let suggestions = completer.complete("$env.T", 6); let suggestions = completer.complete("$env.T", 6);

View file

@ -1,4 +1,6 @@
use crate::engine::{EngineState, Stack}; use crate::engine::{EngineState, Stack};
#[cfg(windows)]
use omnipath::sys_absolute;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
// For file system command usage // For file system command usage
@ -40,28 +42,34 @@ pub mod windows {
fn maintain(&mut self, key: String, value: Value); fn maintain(&mut self, key: String, value: Value);
} }
macro_rules! impl_env_maintainer { impl EnvMaintainer for EngineState {
($type:ty) => { fn maintain(&mut self, key: String, value: Value) {
impl EnvMaintainer for $type { self.add_env_var(key, value);
fn maintain(&mut self, key: String, value: Value) { }
self.add_env_var(key, value);
}
}
};
} }
impl_env_maintainer!(Stack); impl EnvMaintainer for Stack {
impl_env_maintainer!(EngineState); fn maintain(&mut self, key: String, value: Value) {
self.add_env_var(key, value);
}
}
/// For maintainer to notify PWD /// For maintainer to notify PWD
/// When user changes current directory, maintainer calls set_pwd() /// When user changes current directory, maintainer calls set_pwd()
/// and PWD-per-drive call maintainer back to store it for the /// and PWD-per-drive call maintainer back to store it for the
/// env_var_for_drive. /// env_var_for_drive.
/// TBD: If value can't be converted to String or the value is not valid for
/// windows path on a drive, should 'cd' or 'auto_cd' get warning message
/// that PWD-per-drive can't process the path value?
pub fn set_pwd<T: EnvMaintainer>(maintainer: &mut T, value: Value) { pub fn set_pwd<T: EnvMaintainer>(maintainer: &mut T, value: Value) {
if let Ok(path_string) = String::from_value(value.clone()) { if let Ok(path_string) = String::from_value(value.clone()) {
if let Some(drive) = extract_drive_letter(&path_string) { if let Some(drive) = extract_drive_letter(&path_string) {
maintainer.maintain(env_var_for_drive(drive), value); maintainer.maintain(env_var_for_drive(drive), value);
} else {
log::trace!("PWD-per-drive can't find drive of {}", path_string);
} }
} else if let Err(e) = value.into_string() {
log::trace!("PWD-per-drive can't keep this path value: {}", e);
} }
} }
@ -154,9 +162,6 @@ pub mod windows {
/// Call Windows system API (via omnipath crate) to expand /// Call Windows system API (via omnipath crate) to expand
/// absolute path /// absolute path
fn get_full_path_name_w(path_str: &str) -> Option<String> { 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)) { if let Ok(path_sys_abs) = sys_absolute(Path::new(path_str)) {
Some(path_sys_abs.to_str()?.to_string()) Some(path_sys_abs.to_str()?.to_string())
} else { } else {

View file

@ -100,6 +100,13 @@ fn canonicalize_dot() {
let actual = canonicalize_with(".", expected.as_path()).expect("Failed to canonicalize"); let actual = canonicalize_with(".", expected.as_path()).expect("Failed to canonicalize");
// Once my windows gives the current directory for different case
// Actual "E:\\Study", got "E:\\study"
#[cfg(windows)]
let actual = std::path::PathBuf::from(actual.to_str().unwrap().to_ascii_uppercase());
#[cfg(windows)]
let expected = std::path::PathBuf::from(expected.to_str().unwrap().to_ascii_uppercase());
assert_eq!(actual, expected); assert_eq!(actual, expected);
} }
@ -110,6 +117,13 @@ fn canonicalize_many_dots() {
let actual = canonicalize_with("././/.//////./././//.///", expected.as_path()) let actual = canonicalize_with("././/.//////./././//.///", expected.as_path())
.expect("Failed to canonicalize"); .expect("Failed to canonicalize");
// Once my windows gives the current directory for different case
// Actual "E:\\Study", got "E:\\study"
#[cfg(windows)]
let actual = std::path::PathBuf::from(actual.to_str().unwrap().to_ascii_uppercase());
#[cfg(windows)]
let expected = std::path::PathBuf::from(expected.to_str().unwrap().to_ascii_uppercase());
assert_eq!(actual, expected); assert_eq!(actual, expected);
} }
@ -148,6 +162,13 @@ fn canonicalize_double_dot() {
.parent() .parent()
.expect("Could not get parent of current directory"); .expect("Could not get parent of current directory");
// Once my windows gives the current directory for different case
// Actual "E:\\Study", got "E:\\study"
#[cfg(windows)]
let actual = std::path::PathBuf::from(actual.to_str().unwrap().to_ascii_uppercase());
#[cfg(windows)]
let expected = std::path::PathBuf::from(expected.to_str().unwrap().to_ascii_uppercase());
assert_eq!(actual, expected); assert_eq!(actual, expected);
} }

View file

@ -49,7 +49,14 @@ fn get_current_dir() {
cwd.chars().next().unwrap().to_ascii_uppercase(), cwd.chars().next().unwrap().to_ascii_uppercase(),
result.out.chars().next().unwrap().to_ascii_uppercase() result.out.chars().next().unwrap().to_ascii_uppercase()
); );
assert_eq!(cwd[1..], result.out[1..]); // Once my windows gives the current directory for different case
// Actual "E:\\Study", got "E:\\study"
//left: ":\\study\\nushell\\tests"
//right: ":\\Study\\nushell\\tests"
assert_eq!(
cwd[1..].to_ascii_uppercase(),
result.out[1..].to_ascii_uppercase()
);
} }
} }