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:
WindSoilder
2024-01-21 23:22:25 +08:00
committed by GitHub
parent 64f34e0287
commit c59d6d31bc
26 changed files with 310 additions and 60 deletions

View File

@ -115,6 +115,7 @@ pub fn value_to_json_value(v: &Value) -> Result<nu_json::Value, ShellError> {
Value::Int { val, .. } => nu_json::Value::I64(*val),
Value::Nothing { .. } => nu_json::Value::Null,
Value::String { val, .. } => nu_json::Value::String(val.to_string()),
Value::QuotedString { val, .. } => nu_json::Value::String(val.to_string()),
Value::CellPath { val, .. } => nu_json::Value::Array(
val.members
.iter()

View File

@ -279,6 +279,7 @@ pub fn value_to_string(
// All strings outside data structures are quoted because they are in 'command position'
// (could be mistaken for commands by the Nu parser)
Value::String { val, .. } => Ok(escape_quote_string(val)),
Value::QuotedString { val, .. } => Ok(escape_quote_string(val)),
}
}

View File

@ -127,6 +127,7 @@ fn local_into_string(value: Value, separator: &str, config: &Config) -> String {
)
}
Value::String { val, .. } => val,
Value::QuotedString { val, .. } => val,
Value::List { vals: val, .. } => val
.into_iter()
.map(|x| local_into_string(x, ", ", config))

View File

@ -54,7 +54,9 @@ fn helper(engine_state: &EngineState, v: &Value) -> Result<toml::Value, ShellErr
Value::Date { val, .. } => toml::Value::String(val.to_string()),
Value::Range { .. } => toml::Value::String("<Range>".to_string()),
Value::Float { val, .. } => toml::Value::Float(*val),
Value::String { val, .. } => toml::Value::String(val.clone()),
Value::String { val, .. } | Value::QuotedString { val, .. } => {
toml::Value::String(val.clone())
}
Value::Record { val, .. } => {
let mut m = toml::map::Map::new();
for (k, v) in val {

View File

@ -52,7 +52,9 @@ pub fn value_to_yaml_value(v: &Value) -> Result<serde_yaml::Value, ShellError> {
Value::Date { val, .. } => serde_yaml::Value::String(val.to_string()),
Value::Range { .. } => serde_yaml::Value::Null,
Value::Float { val, .. } => serde_yaml::Value::Number(serde_yaml::Number::from(*val)),
Value::String { val, .. } => serde_yaml::Value::String(val.clone()),
Value::String { val, .. } | Value::QuotedString { val, .. } => {
serde_yaml::Value::String(val.clone())
}
Value::Record { val, .. } => {
let mut m = serde_yaml::Mapping::new();
for (k, v) in val {