mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 09:25:38 +02:00
do not attempt to glob expand if the file path is wrapped in quotes (#11569)
# Description Fixes: #11455 ### For arguments which is annotated with `:path/:directory/:glob` To fix the issue, we need to have a way to know if a path is originally quoted during runtime. So the information needed to be added at several levels: * parse time (from user input to expression) We need to add quoted information into `Expr::Filepath`, `Expr::Directory`, `Expr::GlobPattern` * eval time When convert from `Expr::Filepath`, `Expr::Directory`, `Expr::GlobPattern` to `Value::String` during runtime, we won't auto expanded the path if it's quoted ### For `ls` It's really special, because it accepts a `String` as a pattern, and it generates `glob` expression inside the command itself. So the idea behind the change is introducing a special SyntaxShape to ls: `SyntaxShape::LsGlobPattern`. So we can track if the pattern is originally quoted easier, and we don't auto expand the path either. Then when constructing a glob pattern inside ls, we check if input pattern is quoted, if so: we escape the input pattern, so we can run `ls a[123]b`, because it's already escaped. Finally, to accomplish the checking process, we also need to introduce a new value type called `Value::QuotedString` to differ from `Value::String`, it's used to generate an enum called `NuPath`, which is finally used in `ls` function. `ls` learned from `NuPath` to know if user input is quoted. # User-Facing Changes Actually it contains several changes ### For arguments which is annotated with `:path/:directory/:glob` #### Before ```nushell > def foo [p: path] { echo $p }; print (foo "~/a"); print (foo '~/a') /home/windsoilder/a /home/windsoilder/a > def foo [p: directory] { echo $p }; print (foo "~/a"); print (foo '~/a') /home/windsoilder/a /home/windsoilder/a > def foo [p: glob] { echo $p }; print (foo "~/a"); print (foo '~/a') /home/windsoilder/a /home/windsoilder/a ``` #### After ```nushell > def foo [p: path] { echo $p }; print (foo "~/a"); print (foo '~/a') ~/a ~/a > def foo [p: directory] { echo $p }; print (foo "~/a"); print (foo '~/a') ~/a ~/a > def foo [p: glob] { echo $p }; print (foo "~/a"); print (foo '~/a') ~/a ~/a ``` ### For ls command `touch '[uwu]'` #### Before ``` ❯ ls -D "[uwu]" Error: × No matches found for [uwu] ╭─[entry #6:1:1] 1 │ ls -D "[uwu]" · ───┬─── · ╰── Pattern, file or folder not found ╰──── help: no matches found ``` #### After ``` ❯ ls -D "[uwu]" ╭───┬───────┬──────┬──────┬──────────╮ │ # │ name │ type │ size │ modified │ ├───┼───────┼──────┼──────┼──────────┤ │ 0 │ [uwu] │ file │ 0 B │ now │ ╰───┴───────┴──────┴──────┴──────────╯ ``` # Tests + Formatting Done # After Submitting NaN
This commit is contained in:
@ -387,7 +387,7 @@ fn eval_element_with_input(
|
||||
Expr::String(_)
|
||||
| Expr::FullCellPath(_)
|
||||
| Expr::StringInterpolation(_)
|
||||
| Expr::Filepath(_) => {
|
||||
| Expr::Filepath(_, _) => {
|
||||
let exit_code = match &mut input {
|
||||
PipelineData::ExternalStream { exit_code, .. } => exit_code.take(),
|
||||
_ => None,
|
||||
@ -485,11 +485,11 @@ fn eval_element_with_input(
|
||||
Expr::String(_)
|
||||
| Expr::FullCellPath(_)
|
||||
| Expr::StringInterpolation(_)
|
||||
| Expr::Filepath(_),
|
||||
| Expr::Filepath(_, _),
|
||||
Expr::String(_)
|
||||
| Expr::FullCellPath(_)
|
||||
| Expr::StringInterpolation(_)
|
||||
| Expr::Filepath(_),
|
||||
| Expr::Filepath(_, _),
|
||||
) => {
|
||||
if let Some(save_command) = engine_state.find_decl(b"save", &[]) {
|
||||
let exit_code = match &mut input {
|
||||
@ -917,22 +917,30 @@ impl Eval for EvalRuntime {
|
||||
engine_state: Self::State<'_>,
|
||||
stack: &mut Self::MutState,
|
||||
path: String,
|
||||
quoted: bool,
|
||||
span: Span,
|
||||
) -> Result<Value, ShellError> {
|
||||
let cwd = current_dir_str(engine_state, stack)?;
|
||||
let path = expand_path_with(path, cwd);
|
||||
if quoted {
|
||||
Ok(Value::string(path, span))
|
||||
} else {
|
||||
let cwd = current_dir_str(engine_state, stack)?;
|
||||
let path = expand_path_with(path, cwd);
|
||||
|
||||
Ok(Value::string(path.to_string_lossy(), span))
|
||||
Ok(Value::string(path.to_string_lossy(), span))
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_directory(
|
||||
engine_state: Self::State<'_>,
|
||||
stack: &mut Self::MutState,
|
||||
path: String,
|
||||
quoted: bool,
|
||||
span: Span,
|
||||
) -> Result<Value, ShellError> {
|
||||
if path == "-" {
|
||||
Ok(Value::string("-", span))
|
||||
} else if quoted {
|
||||
Ok(Value::string(path, span))
|
||||
} else {
|
||||
let cwd = current_dir_str(engine_state, stack)?;
|
||||
let path = expand_path_with(path, cwd);
|
||||
@ -1163,12 +1171,17 @@ impl Eval for EvalRuntime {
|
||||
engine_state: Self::State<'_>,
|
||||
stack: &mut Self::MutState,
|
||||
pattern: String,
|
||||
quoted: bool,
|
||||
span: Span,
|
||||
) -> Result<Value, ShellError> {
|
||||
let cwd = current_dir_str(engine_state, stack)?;
|
||||
let path = expand_path_with(pattern, cwd);
|
||||
if quoted {
|
||||
Ok(Value::string(pattern, span))
|
||||
} else {
|
||||
let cwd = current_dir_str(engine_state, stack)?;
|
||||
let path = expand_path_with(pattern, cwd);
|
||||
|
||||
Ok(Value::string(path.to_string_lossy(), span))
|
||||
Ok(Value::string(path.to_string_lossy(), span))
|
||||
}
|
||||
}
|
||||
|
||||
fn unreachable(expr: &Expression) -> Result<Value, ShellError> {
|
||||
|
Reference in New Issue
Block a user