Compare commits

...

9 Commits

Author SHA1 Message Date
be8c1dc006 Fix run_external::expand_glob() to return paths that are PWD-relative but reflect the original intent (#13028)
# Description

Fix #13021

This changes the `expand_glob()` function to use
`nu_engine::glob_from()` so that absolute paths are actually preserved,
rather than being made relative to the provided parent. This preserves
the intent of whoever wrote the original path/glob, and also makes it so
that tilde always produces absolute paths.

I also made `expand_glob()` handle Ctrl-C so that it can be interrupted.

cc @YizhePKU

# Tests + Formatting
No additional tests here... but that might be a good idea.
2024-06-03 10:38:55 +03:00
b50903cf58 Fix external command name parsing with backslashes, and add tests (#13027)
# Description

Fixes #13016 and adds tests for many variations of external call
parsing.

I just realized @kubouch took a crack at this too (#13022) so really
whichever is better, but I think the
tests are a good addition.
2024-06-03 10:28:45 +03:00
6635b74d9d Bump version to 0.94.2 (#13014)
Version bump after 0.94.1 patch release.
2024-06-03 10:28:35 +03:00
f3cf693ec7 Disallow more characters in arguments for internal cmd commands (#13009)
# Description
Makes `run-external` error if arguments to `cmd.exe` internal commands
contain newlines or a percent sign. This is because the percent sign can
expand environment variables, potentially? allowing command injection.
Newlines I think will truncate the rest of the arguments and should
probably be disallowed to be safe.

# After Submitting
- If the user calls `cmd.exe` directly, then this bypasses our
handling/checking for internal `cmd` commands. Instead, we use the
handling from the Rust std lib which, in this case, does not do special
handling and is potentially unsafe. Then again, it could be the user's
specific intention to run `cmd` with whatever trusted input. The problem
is that since we use the std lib handling, it assumes the exe uses the C
runtime escaping rules and will perform some unwanted escaping. E.g., it
will add backslashes to the quotes in `cmd echo /c '""'`.
- If `cmd` is called indirectly via a `.bat` or `.cmd` file, then we use
the Rust std lib which has separate handling for bat files that should
be safe, but will reject some inputs.
- ~~I'm not sure how we handle `PATHEXT`, that can also cause a file
without an extension to be run as a bat file. If so, I don't know where
the handling, if any, is done for that.~~ It looks like we use the
`which` crate to do the lookup using `PATHEXT`. Then, we pass the exe
path from that to the Rust std lib `Command`, which should be safe
(except for the first `cmd.exe` note).

So, in the future we need to unify and/or fix these different
implementations, including our own special handling for internal `cmd`
commands that this PR tries to fix.
2024-05-30 19:24:48 +00:00
31f3d2f664 Restore path type behavior (#13006)
# Description
Restores `path type` to return an empty string on error like it did pre
0.94.0.
2024-05-30 13:42:22 +00:00
40772fea15 fix do closure with both required, options, and rest args (#13002)
# Description
Fixes: #12985

`val_iter` has already handle required positional and optional
positional arguments, it not skip them again while handling rest
arguments.

# User-Facing Changes
Makes `do {|a, ...b| echo $a ...$b} 1 2 3 4` output the following again:
```nushell
╭───┬───╮
│ 0 │ 1 │
│ 1 │ 2 │
│ 2 │ 3 │
│ 3 │ 4 │
╰───┴───╯
```

# Tests + Formatting
Added some test cases
2024-05-30 08:29:46 -05:00
0e1553026e Restore tilde expansion on external command names (#13001)
# Description

Fix a regression introduced by #12921, where tilde expansion was no
longer done on the external command name, breaking things like

```nushell
> ~/.cargo/bin/exa
```

This properly handles quoted strings, so they don't expand:

```nushell
> ^"~/.cargo/bin/exa"
Error: nu:🐚:external_command

  × External command failed
   ╭─[entry #1:1:2]
 1 │ ^"~/.cargo/bin/exa"
   ·  ─────────┬────────
   ·           ╰── Command `~/.cargo/bin/exa` not found
   ╰────
  help: `~/.cargo/bin/exa` is neither a Nushell built-in or a known external command

```

This required a change to the parser, so the command name is also parsed
in the same way the arguments are - i.e. the quotes on the outside
remain in the expression. Hopefully that doesn't break anything else. 🤞

Fixes #13000. Should include in patch release 0.94.1

cc @YizhePKU

# User-Facing Changes
- Tilde expansion now works again for external commands
- The `command` of `run-external` will now have its quotes removed like
the other arguments if it is a literal string
- The parser is changed to include quotes in the command expression of
`ExternalCall` if they were present

# Tests + Formatting
I would like to add a regression test for this, but it's complicated
because we need a well-known binary within the home directory, which
just isn't a thing. We could drop one there, but that's kind of a bad
behavior for a test to do. I also considered changing the home directory
for the test, but that's so platform-specific - potentially could get it
working on specific platforms though. Changing `HOME` env on Linux
definitely works as far as tilde expansion works.

- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`
2024-05-29 18:48:29 -07:00
6a2996251c fixes a bug in OSC9;9 execution (#12994)
# Description

This fixes a bug in the `OSC 9;9` functionality where the path wasn't
being constructed properly and therefore wasn't getting set right for
things like "Duplicate Tab" in Windows Terminal. Thanks to @Araxeus for
finding it.

Related to https://github.com/nushell/nushell/issues/10166

# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->

# Tests + Formatting
<!--
Don't forget to add tests that cover your changes.

Make sure you've run and fixed any issues with these commands:

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to
check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use toolkit.nu; toolkit test stdlib"` to run the
tests for the standard library

> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-05-29 18:06:47 -05:00
f3991f2080 Bump version to 0.94.1 (#12988)
Merge this PR before merging any other PRs.
2024-05-28 22:41:23 +00:00
49 changed files with 624 additions and 304 deletions

72
Cargo.lock generated
View File

@ -2770,7 +2770,7 @@ dependencies = [
[[package]]
name = "nu"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"assert_cmd",
"crossterm",
@ -2823,7 +2823,7 @@ dependencies = [
[[package]]
name = "nu-cli"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"chrono",
"crossterm",
@ -2858,7 +2858,7 @@ dependencies = [
[[package]]
name = "nu-cmd-base"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"indexmap",
"miette",
@ -2870,7 +2870,7 @@ dependencies = [
[[package]]
name = "nu-cmd-extra"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"fancy-regex",
"heck 0.5.0",
@ -2895,7 +2895,7 @@ dependencies = [
[[package]]
name = "nu-cmd-lang"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"itertools 0.12.1",
"nu-engine",
@ -2907,7 +2907,7 @@ dependencies = [
[[package]]
name = "nu-cmd-plugin"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"itertools 0.12.1",
"nu-engine",
@ -2918,7 +2918,7 @@ dependencies = [
[[package]]
name = "nu-color-config"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"nu-ansi-term",
"nu-engine",
@ -2930,7 +2930,7 @@ dependencies = [
[[package]]
name = "nu-command"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"alphanumeric-sort",
"base64 0.22.1",
@ -3039,7 +3039,7 @@ dependencies = [
[[package]]
name = "nu-engine"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"nu-glob",
"nu-path",
@ -3049,7 +3049,7 @@ dependencies = [
[[package]]
name = "nu-explore"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"ansi-str",
"anyhow",
@ -3074,14 +3074,14 @@ dependencies = [
[[package]]
name = "nu-glob"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"doc-comment",
]
[[package]]
name = "nu-json"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"linked-hash-map",
"num-traits",
@ -3091,7 +3091,7 @@ dependencies = [
[[package]]
name = "nu-lsp"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"assert-json-diff",
"crossbeam-channel",
@ -3112,7 +3112,7 @@ dependencies = [
[[package]]
name = "nu-parser"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"bytesize",
"chrono",
@ -3128,7 +3128,7 @@ dependencies = [
[[package]]
name = "nu-path"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"dirs-next",
"omnipath",
@ -3137,7 +3137,7 @@ dependencies = [
[[package]]
name = "nu-plugin"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"log",
"nix",
@ -3152,7 +3152,7 @@ dependencies = [
[[package]]
name = "nu-plugin-core"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"interprocess",
"log",
@ -3166,7 +3166,7 @@ dependencies = [
[[package]]
name = "nu-plugin-engine"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"log",
"nu-engine",
@ -3181,7 +3181,7 @@ dependencies = [
[[package]]
name = "nu-plugin-protocol"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"bincode",
"nu-protocol",
@ -3193,7 +3193,7 @@ dependencies = [
[[package]]
name = "nu-plugin-test-support"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"nu-ansi-term",
"nu-cmd-lang",
@ -3211,7 +3211,7 @@ dependencies = [
[[package]]
name = "nu-pretty-hex"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"heapless",
"nu-ansi-term",
@ -3220,7 +3220,7 @@ dependencies = [
[[package]]
name = "nu-protocol"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"brotli 5.0.0",
"byte-unit",
@ -3251,7 +3251,7 @@ dependencies = [
[[package]]
name = "nu-std"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"log",
"miette",
@ -3262,7 +3262,7 @@ dependencies = [
[[package]]
name = "nu-system"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"chrono",
"itertools 0.12.1",
@ -3280,7 +3280,7 @@ dependencies = [
[[package]]
name = "nu-table"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"fancy-regex",
"nu-ansi-term",
@ -3294,7 +3294,7 @@ dependencies = [
[[package]]
name = "nu-term-grid"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"nu-utils",
"unicode-width",
@ -3302,7 +3302,7 @@ dependencies = [
[[package]]
name = "nu-test-support"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"nu-glob",
"nu-path",
@ -3314,7 +3314,7 @@ dependencies = [
[[package]]
name = "nu-utils"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"crossterm_winapi",
"log",
@ -3340,7 +3340,7 @@ dependencies = [
[[package]]
name = "nu_plugin_example"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"nu-cmd-lang",
"nu-plugin",
@ -3350,7 +3350,7 @@ dependencies = [
[[package]]
name = "nu_plugin_formats"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"eml-parser",
"ical",
@ -3363,7 +3363,7 @@ dependencies = [
[[package]]
name = "nu_plugin_gstat"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"git2",
"nu-plugin",
@ -3372,7 +3372,7 @@ dependencies = [
[[package]]
name = "nu_plugin_inc"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"nu-plugin",
"nu-protocol",
@ -3381,7 +3381,7 @@ dependencies = [
[[package]]
name = "nu_plugin_polars"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"chrono",
"chrono-tz 0.9.0",
@ -3412,7 +3412,7 @@ dependencies = [
[[package]]
name = "nu_plugin_query"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"gjson",
"nu-plugin",
@ -3424,7 +3424,7 @@ dependencies = [
[[package]]
name = "nu_plugin_stress_internals"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"interprocess",
"serde",
@ -3550,7 +3550,7 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "nuon"
version = "0.94.0"
version = "0.94.2"
dependencies = [
"chrono",
"fancy-regex",

View File

@ -11,7 +11,7 @@ license = "MIT"
name = "nu"
repository = "https://github.com/nushell/nushell"
rust-version = "1.77.2"
version = "0.94.0"
version = "0.94.2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -174,22 +174,22 @@ windows = "0.54"
winreg = "0.52"
[dependencies]
nu-cli = { path = "./crates/nu-cli", version = "0.94.0" }
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.94.0" }
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.94.0" }
nu-cmd-plugin = { path = "./crates/nu-cmd-plugin", version = "0.94.0", optional = true }
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.94.0" }
nu-command = { path = "./crates/nu-command", version = "0.94.0" }
nu-engine = { path = "./crates/nu-engine", version = "0.94.0" }
nu-explore = { path = "./crates/nu-explore", version = "0.94.0" }
nu-lsp = { path = "./crates/nu-lsp/", version = "0.94.0" }
nu-parser = { path = "./crates/nu-parser", version = "0.94.0" }
nu-path = { path = "./crates/nu-path", version = "0.94.0" }
nu-plugin-engine = { path = "./crates/nu-plugin-engine", optional = true, version = "0.94.0" }
nu-protocol = { path = "./crates/nu-protocol", version = "0.94.0" }
nu-std = { path = "./crates/nu-std", version = "0.94.0" }
nu-system = { path = "./crates/nu-system", version = "0.94.0" }
nu-utils = { path = "./crates/nu-utils", version = "0.94.0" }
nu-cli = { path = "./crates/nu-cli", version = "0.94.2" }
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.94.2" }
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.94.2" }
nu-cmd-plugin = { path = "./crates/nu-cmd-plugin", version = "0.94.2", optional = true }
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.94.2" }
nu-command = { path = "./crates/nu-command", version = "0.94.2" }
nu-engine = { path = "./crates/nu-engine", version = "0.94.2" }
nu-explore = { path = "./crates/nu-explore", version = "0.94.2" }
nu-lsp = { path = "./crates/nu-lsp/", version = "0.94.2" }
nu-parser = { path = "./crates/nu-parser", version = "0.94.2" }
nu-path = { path = "./crates/nu-path", version = "0.94.2" }
nu-plugin-engine = { path = "./crates/nu-plugin-engine", optional = true, version = "0.94.2" }
nu-protocol = { path = "./crates/nu-protocol", version = "0.94.2" }
nu-std = { path = "./crates/nu-std", version = "0.94.2" }
nu-system = { path = "./crates/nu-system", version = "0.94.2" }
nu-utils = { path = "./crates/nu-utils", version = "0.94.2" }
reedline = { workspace = true, features = ["bashisms", "sqlite"] }
@ -218,9 +218,9 @@ nix = { workspace = true, default-features = false, features = [
] }
[dev-dependencies]
nu-test-support = { path = "./crates/nu-test-support", version = "0.94.0" }
nu-plugin-protocol = { path = "./crates/nu-plugin-protocol", version = "0.94.0" }
nu-plugin-core = { path = "./crates/nu-plugin-core", version = "0.94.0" }
nu-test-support = { path = "./crates/nu-test-support", version = "0.94.2" }
nu-plugin-protocol = { path = "./crates/nu-plugin-protocol", version = "0.94.2" }
nu-plugin-core = { path = "./crates/nu-plugin-core", version = "0.94.2" }
assert_cmd = "2.0"
dirs-next = { workspace = true }
tango-bench = "0.5"

View File

@ -5,27 +5,27 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cli"
edition = "2021"
license = "MIT"
name = "nu-cli"
version = "0.94.0"
version = "0.94.2"
[lib]
bench = false
[dev-dependencies]
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.0" }
nu-command = { path = "../nu-command", version = "0.94.0" }
nu-test-support = { path = "../nu-test-support", version = "0.94.0" }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.2" }
nu-command = { path = "../nu-command", version = "0.94.2" }
nu-test-support = { path = "../nu-test-support", version = "0.94.2" }
rstest = { workspace = true, default-features = false }
tempfile = { workspace = true }
[dependencies]
nu-cmd-base = { path = "../nu-cmd-base", version = "0.94.0" }
nu-engine = { path = "../nu-engine", version = "0.94.0" }
nu-path = { path = "../nu-path", version = "0.94.0" }
nu-parser = { path = "../nu-parser", version = "0.94.0" }
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.94.0", optional = true }
nu-protocol = { path = "../nu-protocol", version = "0.94.0" }
nu-utils = { path = "../nu-utils", version = "0.94.0" }
nu-color-config = { path = "../nu-color-config", version = "0.94.0" }
nu-cmd-base = { path = "../nu-cmd-base", version = "0.94.2" }
nu-engine = { path = "../nu-engine", version = "0.94.2" }
nu-path = { path = "../nu-path", version = "0.94.2" }
nu-parser = { path = "../nu-parser", version = "0.94.2" }
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.94.2", optional = true }
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
nu-utils = { path = "../nu-utils", version = "0.94.2" }
nu-color-config = { path = "../nu-color-config", version = "0.94.2" }
nu-ansi-term = { workspace = true }
reedline = { workspace = true, features = ["bashisms", "sqlite"] }

View File

@ -1110,9 +1110,9 @@ fn run_shell_integration_osc9_9(engine_state: &EngineState, stack: &mut Stack, u
let start_time = Instant::now();
// Otherwise, communicate the path as OSC 9;9 from ConEmu (often used for spawning new tabs in the same dir)
// This is helpful in Windows Terminal with Duplicate Tab
run_ansi_sequence(&format!(
"\x1b]9;9;{}{}\x1b\\",
if path.starts_with('/') { "" } else { "/" },
"\x1b]9;9;{}\x1b\\",
percent_encoding::utf8_percent_encode(&path, percent_encoding::CONTROLS)
));

View File

@ -5,15 +5,15 @@ edition = "2021"
license = "MIT"
name = "nu-cmd-base"
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-base"
version = "0.94.0"
version = "0.94.2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
nu-engine = { path = "../nu-engine", version = "0.94.0" }
nu-parser = { path = "../nu-parser", version = "0.94.0" }
nu-path = { path = "../nu-path", version = "0.94.0" }
nu-protocol = { path = "../nu-protocol", version = "0.94.0" }
nu-engine = { path = "../nu-engine", version = "0.94.2" }
nu-parser = { path = "../nu-parser", version = "0.94.2" }
nu-path = { path = "../nu-path", version = "0.94.2" }
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
indexmap = { workspace = true }
miette = { workspace = true }

View File

@ -5,7 +5,7 @@ edition = "2021"
license = "MIT"
name = "nu-cmd-extra"
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-extra"
version = "0.94.0"
version = "0.94.2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -13,13 +13,13 @@ version = "0.94.0"
bench = false
[dependencies]
nu-cmd-base = { path = "../nu-cmd-base", version = "0.94.0" }
nu-engine = { path = "../nu-engine", version = "0.94.0" }
nu-json = { version = "0.94.0", path = "../nu-json" }
nu-parser = { path = "../nu-parser", version = "0.94.0" }
nu-pretty-hex = { version = "0.94.0", path = "../nu-pretty-hex" }
nu-protocol = { path = "../nu-protocol", version = "0.94.0" }
nu-utils = { path = "../nu-utils", version = "0.94.0" }
nu-cmd-base = { path = "../nu-cmd-base", version = "0.94.2" }
nu-engine = { path = "../nu-engine", version = "0.94.2" }
nu-json = { version = "0.94.2", path = "../nu-json" }
nu-parser = { path = "../nu-parser", version = "0.94.2" }
nu-pretty-hex = { version = "0.94.2", path = "../nu-pretty-hex" }
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
nu-utils = { path = "../nu-utils", version = "0.94.2" }
# Potential dependencies for extras
heck = { workspace = true }
@ -37,6 +37,6 @@ extra = ["default"]
default = []
[dev-dependencies]
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.0" }
nu-command = { path = "../nu-command", version = "0.94.0" }
nu-test-support = { path = "../nu-test-support", version = "0.94.0" }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.2" }
nu-command = { path = "../nu-command", version = "0.94.2" }
nu-test-support = { path = "../nu-test-support", version = "0.94.2" }

View File

@ -6,16 +6,16 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-lang"
edition = "2021"
license = "MIT"
name = "nu-cmd-lang"
version = "0.94.0"
version = "0.94.2"
[lib]
bench = false
[dependencies]
nu-engine = { path = "../nu-engine", version = "0.94.0" }
nu-parser = { path = "../nu-parser", version = "0.94.0" }
nu-protocol = { path = "../nu-protocol", version = "0.94.0" }
nu-utils = { path = "../nu-utils", version = "0.94.0" }
nu-engine = { path = "../nu-engine", version = "0.94.2" }
nu-parser = { path = "../nu-parser", version = "0.94.2" }
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
nu-utils = { path = "../nu-utils", version = "0.94.2" }
itertools = { workspace = true }
shadow-rs = { version = "0.28", default-features = false }

View File

@ -298,9 +298,7 @@ fn bind_args_to(
if let Some(rest_positional) = &signature.rest_positional {
let mut rest_items = vec![];
for result in
val_iter.skip(signature.required_positional.len() + signature.optional_positional.len())
{
for result in val_iter {
rest_items.push(result);
}

View File

@ -5,15 +5,15 @@ edition = "2021"
license = "MIT"
name = "nu-cmd-plugin"
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-plugin"
version = "0.94.0"
version = "0.94.2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
nu-engine = { path = "../nu-engine", version = "0.94.0" }
nu-path = { path = "../nu-path", version = "0.94.0" }
nu-protocol = { path = "../nu-protocol", version = "0.94.0", features = ["plugin"] }
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.94.0" }
nu-engine = { path = "../nu-engine", version = "0.94.2" }
nu-path = { path = "../nu-path", version = "0.94.2" }
nu-protocol = { path = "../nu-protocol", version = "0.94.2", features = ["plugin"] }
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.94.2" }
itertools = { workspace = true }

View File

@ -5,18 +5,18 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-color-confi
edition = "2021"
license = "MIT"
name = "nu-color-config"
version = "0.94.0"
version = "0.94.2"
[lib]
bench = false
[dependencies]
nu-protocol = { path = "../nu-protocol", version = "0.94.0" }
nu-engine = { path = "../nu-engine", version = "0.94.0" }
nu-json = { path = "../nu-json", version = "0.94.0" }
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
nu-engine = { path = "../nu-engine", version = "0.94.2" }
nu-json = { path = "../nu-json", version = "0.94.2" }
nu-ansi-term = { workspace = true }
serde = { workspace = true, features = ["derive"] }
[dev-dependencies]
nu-test-support = { path = "../nu-test-support", version = "0.94.0" }
nu-test-support = { path = "../nu-test-support", version = "0.94.2" }

View File

@ -5,7 +5,7 @@ edition = "2021"
license = "MIT"
name = "nu-command"
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-command"
version = "0.94.0"
version = "0.94.2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -13,21 +13,21 @@ version = "0.94.0"
bench = false
[dependencies]
nu-cmd-base = { path = "../nu-cmd-base", version = "0.94.0" }
nu-color-config = { path = "../nu-color-config", version = "0.94.0" }
nu-engine = { path = "../nu-engine", version = "0.94.0" }
nu-glob = { path = "../nu-glob", version = "0.94.0" }
nu-json = { path = "../nu-json", version = "0.94.0" }
nu-parser = { path = "../nu-parser", version = "0.94.0" }
nu-path = { path = "../nu-path", version = "0.94.0" }
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.94.0" }
nu-protocol = { path = "../nu-protocol", version = "0.94.0" }
nu-system = { path = "../nu-system", version = "0.94.0" }
nu-table = { path = "../nu-table", version = "0.94.0" }
nu-term-grid = { path = "../nu-term-grid", version = "0.94.0" }
nu-utils = { path = "../nu-utils", version = "0.94.0" }
nu-cmd-base = { path = "../nu-cmd-base", version = "0.94.2" }
nu-color-config = { path = "../nu-color-config", version = "0.94.2" }
nu-engine = { path = "../nu-engine", version = "0.94.2" }
nu-glob = { path = "../nu-glob", version = "0.94.2" }
nu-json = { path = "../nu-json", version = "0.94.2" }
nu-parser = { path = "../nu-parser", version = "0.94.2" }
nu-path = { path = "../nu-path", version = "0.94.2" }
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.94.2" }
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
nu-system = { path = "../nu-system", version = "0.94.2" }
nu-table = { path = "../nu-table", version = "0.94.2" }
nu-term-grid = { path = "../nu-term-grid", version = "0.94.2" }
nu-utils = { path = "../nu-utils", version = "0.94.2" }
nu-ansi-term = { workspace = true }
nuon = { path = "../nuon", version = "0.94.0" }
nuon = { path = "../nuon", version = "0.94.2" }
alphanumeric-sort = { workspace = true }
base64 = { workspace = true }
@ -137,8 +137,8 @@ trash-support = ["trash"]
which-support = []
[dev-dependencies]
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.0" }
nu-test-support = { path = "../nu-test-support", version = "0.94.0" }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.2" }
nu-test-support = { path = "../nu-test-support", version = "0.94.2" }
dirs-next = { workspace = true }
mockito = { workspace = true, default-features = false }

View File

@ -104,10 +104,9 @@ If nothing is found, an empty string will be returned."#
fn path_type(path: &Path, span: Span, args: &Arguments) -> Value {
let path = nu_path::expand_path_with(path, &args.pwd, true);
match std::fs::symlink_metadata(path) {
Ok(metadata) => Value::string(get_file_type(&metadata), span),
Err(err) => Value::error(err.into(), span),
}
let meta = path.symlink_metadata();
let ty = meta.as_ref().map(get_file_type).unwrap_or("");
Value::string(ty, span)
}
fn get_file_type(md: &std::fs::Metadata) -> &str {

View File

@ -4,7 +4,7 @@ use nu_protocol::{
ast::{Expr, Expression},
did_you_mean,
process::ChildProcess,
ByteStream, OutDest,
ByteStream, NuGlob, OutDest,
};
use nu_system::ForegroundChild;
use nu_utils::IgnoreCaseExt;
@ -13,7 +13,7 @@ use std::{
io::Write,
path::{Path, PathBuf},
process::Stdio,
sync::Arc,
sync::{atomic::AtomicBool, Arc},
thread,
};
@ -46,15 +46,36 @@ impl Command for External {
) -> Result<PipelineData, ShellError> {
let cwd = engine_state.cwd(Some(stack))?;
// Evaluate the command name in the same way the arguments are evaluated. Since this isn't
// a spread, it should return a one-element vec.
let name_expr = call
.positional_nth(0)
.ok_or_else(|| ShellError::MissingParameter {
param_name: "command".into(),
span: call.head,
})?;
let name = eval_argument(engine_state, stack, name_expr, false)?
.pop()
.expect("eval_argument returned zero-element vec")
.into_spanned(name_expr.span);
// Find the absolute path to the executable. On Windows, set the
// executable to "cmd.exe" if it's is a CMD internal command. If the
// command is not found, display a helpful error message.
let name: Spanned<String> = call.req(engine_state, stack, 0)?;
let executable = if cfg!(windows) && is_cmd_internal_command(&name.item) {
PathBuf::from("cmd.exe")
} else {
// Expand tilde on the name if it's a bare string (#13000)
let expanded_name = if is_bare_string(name_expr) {
expand_tilde(&name.item)
} else {
name.item.clone()
};
// Determine the PATH to be used and then use `which` to find it - though this has no
// effect if it's an absolute path already
let paths = nu_engine::env::path_str(engine_state, stack, call.head)?;
let Some(executable) = which(&name.item, &paths, &cwd) else {
let Some(executable) = which(&expanded_name, &paths, &cwd) else {
return Err(command_not_found(
&name.item,
call.head,
@ -134,6 +155,9 @@ impl Command for External {
}
};
// Log the command we're about to run in case it's useful for debugging purposes.
log::trace!("run-external spawning: {command:?}");
// Spawn the child process. On Unix, also put the child process to
// foreground if we're in an interactive session.
#[cfg(windows)]
@ -211,6 +235,7 @@ pub fn eval_arguments_from_call(
stack: &mut Stack,
call: &Call,
) -> Result<Vec<Spanned<String>>, ShellError> {
let ctrlc = &engine_state.ctrlc;
let cwd = engine_state.cwd(Some(stack))?;
let mut args: Vec<Spanned<String>> = vec![];
for (expr, spread) in call.rest_iter(1) {
@ -219,7 +244,7 @@ pub fn eval_arguments_from_call(
// glob-expansion, and inner-quotes-removal, in that order.
for arg in eval_argument(engine_state, stack, expr, spread)? {
let tilde_expanded = expand_tilde(&arg);
for glob_expanded in expand_glob(&tilde_expanded, &cwd, expr.span)? {
for glob_expanded in expand_glob(&tilde_expanded, &cwd, expr.span, ctrlc)? {
let inner_quotes_removed = remove_inner_quotes(&glob_expanded);
args.push(inner_quotes_removed.into_owned().into_spanned(expr.span));
}
@ -300,37 +325,75 @@ fn expand_tilde(arg: &str) -> String {
///
/// Note: This matches the default behavior of Bash, but is known to be
/// error-prone. We might want to change this behavior in the future.
fn expand_glob(arg: &str, cwd: &Path, span: Span) -> Result<Vec<String>, ShellError> {
let Ok(paths) = nu_glob::glob_with_parent(arg, nu_glob::MatchOptions::default(), cwd) else {
fn expand_glob(
arg: &str,
cwd: &Path,
span: Span,
interrupt: &Option<Arc<AtomicBool>>,
) -> Result<Vec<String>, ShellError> {
const GLOB_CHARS: &[char] = &['*', '?', '['];
// Don't expand something that doesn't include the GLOB_CHARS
if !arg.contains(GLOB_CHARS) {
return Ok(vec![arg.into()]);
}
// We must use `nu_engine::glob_from` here, in order to ensure we get paths from the correct
// dir
let glob = NuGlob::Expand(arg.to_owned()).into_spanned(span);
let Ok((_prefix, paths)) = nu_engine::glob_from(&glob, cwd, span, None) else {
// If an error occurred, return the original input
return Ok(vec![arg.into()]);
};
let mut result = vec![];
for path in paths {
let path = path.map_err(|err| ShellError::IOErrorSpanned {
msg: format!("{}: {:?}", err.path().display(), err.error()),
span,
})?;
// Strip PWD from the resulting paths if possible.
let path_stripped = if let Ok(remainder) = path.strip_prefix(cwd) {
// If stripping PWD results in an empty path, return `.` instead.
if remainder.components().next().is_none() {
Path::new(".")
} else {
remainder
// If the first component of the original `arg` string path was '.', that should be preserved
let relative_to_dot = Path::new(arg).starts_with(".");
let paths = paths
// Skip over glob failures. These are usually just inaccessible paths.
.flat_map(|path_result| match path_result {
Ok(path) => Some(path),
Err(err) => {
// But internally log them just in case we need to debug this.
log::warn!("Error in run_external::expand_glob(): {}", err);
None
}
} else {
&path
};
let path_string = path_stripped.to_string_lossy().to_string();
result.push(path_string);
}
})
// Make the paths relative to the cwd
.map(|path| {
path.strip_prefix(cwd)
.map(|path| path.to_owned())
.unwrap_or(path)
})
// Add './' to relative paths if the original pattern had it
.map(|path| {
if relative_to_dot && path.is_relative() {
Path::new(".").join(path)
} else {
path
}
})
// Convert the paths returned to UTF-8 strings.
//
// FIXME: this fails to return the correct results for non-UTF-8 paths, but we don't support
// those in Nushell yet.
.map(|path| path.to_string_lossy().into_owned())
// Abandon if ctrl-c is pressed
.map(|path| {
if !nu_utils::ctrl_c::was_pressed(interrupt) {
Ok(path)
} else {
Err(ShellError::InterruptedByUser { span: Some(span) })
}
})
.collect::<Result<Vec<String>, ShellError>>()?;
if result.is_empty() {
result.push(arg.to_string());
if !paths.is_empty() {
Ok(paths)
} else {
// If we failed to match, return the original input
Ok(vec![arg.into()])
}
Ok(result)
}
/// Transforms `--option="value"` into `--option=value`. `value` can be quoted
@ -544,12 +607,20 @@ fn has_cmd_special_character(s: &str) -> bool {
SPECIAL_CHARS.iter().any(|c| s.contains(*c))
}
/// Escape an argument for CMD internal commands. The result can be safely
/// passed to `raw_arg()`.
/// Escape an argument for CMD internal commands. The result can be safely passed to `raw_arg()`.
#[cfg(windows)]
fn escape_cmd_argument(arg: &Spanned<String>) -> Result<Cow<'_, str>, ShellError> {
let Spanned { item: arg, span } = arg;
if arg.contains('"') {
if arg.contains(['\r', '\n', '%']) {
// \r and \n trunacte the rest of the arguments and % can expand environment variables
Err(ShellError::ExternalCommand {
label:
"Arguments to CMD internal commands cannot contain new lines or percent signs '%'"
.into(),
help: "some characters currently cannot be securely escaped".into(),
span: *span,
})
} else if arg.contains('"') {
// If `arg` is already quoted by double quotes, confirm there's no
// embedded double quotes, then leave it as is.
if arg.chars().filter(|c| *c == '"').count() == 2
@ -561,7 +632,7 @@ fn escape_cmd_argument(arg: &Spanned<String>) -> Result<Cow<'_, str>, ShellError
Err(ShellError::ExternalCommand {
label: "Arguments to CMD internal commands cannot contain embedded double quotes"
.into(),
help: "CMD doesn't support escaping double quotes inside double quotes".into(),
help: "this case currently cannot be securely handled".into(),
span: *span,
})
}
@ -569,6 +640,7 @@ fn escape_cmd_argument(arg: &Spanned<String>) -> Result<Cow<'_, str>, ShellError
// If `arg` contains space or special characters, quote the entire argument by double quotes.
Ok(Cow::Owned(format!("\"{arg}\"")))
} else {
// FIXME?: what if `arg.is_empty()`?
Ok(Cow::Borrowed(arg))
}
}
@ -577,6 +649,7 @@ fn escape_cmd_argument(arg: &Spanned<String>) -> Result<Cow<'_, str>, ShellError
mod test {
use super::*;
use nu_protocol::ast::ListItem;
use nu_test_support::{fs::Stub, playground::Playground};
#[test]
fn test_remove_quotes() {
@ -639,26 +712,38 @@ mod test {
#[test]
fn test_expand_glob() {
let tempdir = tempfile::tempdir().unwrap();
let cwd = tempdir.path();
std::fs::File::create(cwd.join("a.txt")).unwrap();
std::fs::File::create(cwd.join("b.txt")).unwrap();
Playground::setup("test_expand_glob", |dirs, play| {
play.with_files(&[Stub::EmptyFile("a.txt"), Stub::EmptyFile("b.txt")]);
let actual = expand_glob("*.txt", cwd, Span::unknown()).unwrap();
let expected = &["a.txt", "b.txt"];
assert_eq!(actual, expected);
let cwd = dirs.test();
let actual = expand_glob("'*.txt'", cwd, Span::unknown()).unwrap();
let expected = &["'*.txt'"];
assert_eq!(actual, expected);
let actual = expand_glob("*.txt", cwd, Span::unknown(), &None).unwrap();
let expected = &["a.txt", "b.txt"];
assert_eq!(actual, expected);
let actual = expand_glob(cwd.to_str().unwrap(), cwd, Span::unknown()).unwrap();
let expected = &["."];
assert_eq!(actual, expected);
let actual = expand_glob("./*.txt", cwd, Span::unknown(), &None).unwrap();
let expected = vec![
Path::new(".").join("a.txt").to_string_lossy().into_owned(),
Path::new(".").join("b.txt").to_string_lossy().into_owned(),
];
assert_eq!(actual, expected);
let actual = expand_glob("[*.txt", cwd, Span::unknown()).unwrap();
let expected = &["[*.txt"];
assert_eq!(actual, expected);
let actual = expand_glob("'*.txt'", cwd, Span::unknown(), &None).unwrap();
let expected = &["'*.txt'"];
assert_eq!(actual, expected);
let actual = expand_glob(".", cwd, Span::unknown(), &None).unwrap();
let expected = &["."];
assert_eq!(actual, expected);
let actual = expand_glob("./a.txt", cwd, Span::unknown(), &None).unwrap();
let expected = &["./a.txt"];
assert_eq!(actual, expected);
let actual = expand_glob("[*.txt", cwd, Span::unknown(), &None).unwrap();
let expected = &["[*.txt"];
assert_eq!(actual, expected);
})
}
#[test]

View File

@ -5,16 +5,16 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-engine"
edition = "2021"
license = "MIT"
name = "nu-engine"
version = "0.94.0"
version = "0.94.2"
[lib]
bench = false
[dependencies]
nu-protocol = { path = "../nu-protocol", features = ["plugin"], version = "0.94.0" }
nu-path = { path = "../nu-path", version = "0.94.0" }
nu-glob = { path = "../nu-glob", version = "0.94.0" }
nu-utils = { path = "../nu-utils", version = "0.94.0" }
nu-protocol = { path = "../nu-protocol", features = ["plugin"], version = "0.94.2" }
nu-path = { path = "../nu-path", version = "0.94.2" }
nu-glob = { path = "../nu-glob", version = "0.94.2" }
nu-utils = { path = "../nu-utils", version = "0.94.2" }
[features]
plugin = []

View File

@ -5,21 +5,21 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-explore"
edition = "2021"
license = "MIT"
name = "nu-explore"
version = "0.94.0"
version = "0.94.2"
[lib]
bench = false
[dependencies]
nu-protocol = { path = "../nu-protocol", version = "0.94.0" }
nu-parser = { path = "../nu-parser", version = "0.94.0" }
nu-color-config = { path = "../nu-color-config", version = "0.94.0" }
nu-engine = { path = "../nu-engine", version = "0.94.0" }
nu-table = { path = "../nu-table", version = "0.94.0" }
nu-json = { path = "../nu-json", version = "0.94.0" }
nu-utils = { path = "../nu-utils", version = "0.94.0" }
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
nu-parser = { path = "../nu-parser", version = "0.94.2" }
nu-color-config = { path = "../nu-color-config", version = "0.94.2" }
nu-engine = { path = "../nu-engine", version = "0.94.2" }
nu-table = { path = "../nu-table", version = "0.94.2" }
nu-json = { path = "../nu-json", version = "0.94.2" }
nu-utils = { path = "../nu-utils", version = "0.94.2" }
nu-ansi-term = { workspace = true }
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.94.0" }
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.94.2" }
anyhow = { workspace = true }
log = { workspace = true }

View File

@ -1,6 +1,6 @@
[package]
name = "nu-glob"
version = "0.94.0"
version = "0.94.2"
authors = ["The Nushell Project Developers", "The Rust Project Developers"]
license = "MIT/Apache-2.0"
description = """

View File

@ -5,7 +5,7 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-json"
edition = "2021"
license = "MIT"
name = "nu-json"
version = "0.94.0"
version = "0.94.2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -23,5 +23,5 @@ serde = { workspace = true }
serde_json = { workspace = true }
[dev-dependencies]
# nu-path = { path="../nu-path", version = "0.94.0" }
# nu-path = { path="../nu-path", version = "0.94.2" }
# serde_json = "1.0"

View File

@ -3,14 +3,14 @@ authors = ["The Nushell Project Developers"]
description = "Nushell's integrated LSP server"
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-lsp"
name = "nu-lsp"
version = "0.94.0"
version = "0.94.2"
edition = "2021"
license = "MIT"
[dependencies]
nu-cli = { path = "../nu-cli", version = "0.94.0" }
nu-parser = { path = "../nu-parser", version = "0.94.0" }
nu-protocol = { path = "../nu-protocol", version = "0.94.0" }
nu-cli = { path = "../nu-cli", version = "0.94.2" }
nu-parser = { path = "../nu-parser", version = "0.94.2" }
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
reedline = { workspace = true }
@ -23,8 +23,8 @@ serde = { workspace = true }
serde_json = { workspace = true }
[dev-dependencies]
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.0" }
nu-command = { path = "../nu-command", version = "0.94.0" }
nu-test-support = { path = "../nu-test-support", version = "0.94.0" }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.2" }
nu-command = { path = "../nu-command", version = "0.94.2" }
nu-test-support = { path = "../nu-test-support", version = "0.94.2" }
assert-json-diff = "2.0"

View File

@ -5,17 +5,17 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-parser"
edition = "2021"
license = "MIT"
name = "nu-parser"
version = "0.94.0"
version = "0.94.2"
exclude = ["/fuzz"]
[lib]
bench = false
[dependencies]
nu-engine = { path = "../nu-engine", version = "0.94.0" }
nu-path = { path = "../nu-path", version = "0.94.0" }
nu-plugin-engine = { path = "../nu-plugin-engine", optional = true, version = "0.94.0" }
nu-protocol = { path = "../nu-protocol", version = "0.94.0" }
nu-engine = { path = "../nu-engine", version = "0.94.2" }
nu-path = { path = "../nu-path", version = "0.94.2" }
nu-plugin-engine = { path = "../nu-plugin-engine", optional = true, version = "0.94.2" }
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
bytesize = { workspace = true }
chrono = { default-features = false, features = ['std'], workspace = true }

View File

@ -16,6 +16,7 @@ use nu_protocol::{
IN_VARIABLE_ID,
};
use std::{
borrow::Cow,
collections::{HashMap, HashSet},
num::ParseIntError,
str,
@ -241,15 +242,10 @@ fn parse_external_arg(working_set: &mut StateWorkingSet, span: Span) -> External
))
} else {
// Eval stage trims the quotes, so we don't have to do the same thing when parsing.
let contents = if contents.starts_with(b"\"") {
let (contents, err) = unescape_string(contents, span);
if let Some(err) = err {
working_set.error(err)
}
String::from_utf8_lossy(&contents).to_string()
} else {
String::from_utf8_lossy(contents).to_string()
};
let (contents, err) = unescape_string_preserving_quotes(contents, span);
if let Some(err) = err {
working_set.error(err);
}
ExternalArgument::Regular(Expression {
expr: Expr::String(contents),
@ -278,7 +274,8 @@ pub fn parse_external_call(working_set: &mut StateWorkingSet, spans: &[Span]) ->
let arg = parse_expression(working_set, &[head_span]);
Box::new(arg)
} else {
let (contents, err) = unescape_unquote_string(&head_contents, head_span);
// Eval stage will unquote the string, so we don't bother with that here
let (contents, err) = unescape_string_preserving_quotes(&head_contents, head_span);
if let Some(err) = err {
working_set.error(err)
}
@ -2698,6 +2695,23 @@ pub fn unescape_unquote_string(bytes: &[u8], span: Span) -> (String, Option<Pars
}
}
/// XXX: This is here temporarily as a patch, but we should replace this with properly representing
/// the quoted state of a string in the AST
fn unescape_string_preserving_quotes(bytes: &[u8], span: Span) -> (String, Option<ParseError>) {
let (bytes, err) = if bytes.starts_with(b"\"") {
let (bytes, err) = unescape_string(bytes, span);
(Cow::Owned(bytes), err)
} else {
(Cow::Borrowed(bytes), None)
};
// The original code for args used lossy conversion here, even though that's not what we
// typically use for strings. Revisit whether that's actually desirable later, but don't
// want to introduce a breaking change for this patch.
let token = String::from_utf8_lossy(&bytes).into_owned();
(token, err)
}
pub fn parse_string(working_set: &mut StateWorkingSet, span: Span) -> Expression {
trace!("parsing: string");

View File

@ -694,6 +694,221 @@ pub fn parse_call_missing_req_flag() {
));
}
#[rstest]
#[case("foo-external-call", "foo-external-call", "bare word")]
#[case("^foo-external-call", "foo-external-call", "bare word with caret")]
#[case(
"foo/external-call",
"foo/external-call",
"bare word with forward slash"
)]
#[case(
"^foo/external-call",
"foo/external-call",
"bare word with forward slash and caret"
)]
#[case(r"foo\external-call", r"foo\external-call", "bare word with backslash")]
#[case(
r"^foo\external-call",
r"foo\external-call",
"bare word with backslash and caret"
)]
#[case(
"^'foo external call'",
"'foo external call'",
"single quote with caret"
)]
#[case(
"^'foo/external call'",
"'foo/external call'",
"single quote with forward slash and caret"
)]
#[case(
r"^'foo\external call'",
r"'foo\external call'",
"single quote with backslash and caret"
)]
#[case(
r#"^"foo external call""#,
r#""foo external call""#,
"double quote with caret"
)]
#[case(
r#"^"foo/external call""#,
r#""foo/external call""#,
"double quote with forward slash and caret"
)]
#[case(
r#"^"foo\\external call""#,
r#""foo\external call""#,
"double quote with backslash and caret"
)]
#[case("`foo external call`", "`foo external call`", "backtick quote")]
#[case(
"^`foo external call`",
"`foo external call`",
"backtick quote with caret"
)]
#[case(
"`foo/external call`",
"`foo/external call`",
"backtick quote with forward slash"
)]
#[case(
"^`foo/external call`",
"`foo/external call`",
"backtick quote with forward slash and caret"
)]
#[case(
r"^`foo\external call`",
r"`foo\external call`",
"backtick quote with backslash"
)]
#[case(
r"^`foo\external call`",
r"`foo\external call`",
"backtick quote with backslash and caret"
)]
fn test_external_call_name(#[case] input: &str, #[case] expected: &str, #[case] tag: &str) {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let block = parse(&mut working_set, None, input.as_bytes(), true);
assert!(
working_set.parse_errors.is_empty(),
"{tag}: errors: {:?}",
working_set.parse_errors
);
let pipeline = &block.pipelines[0];
assert_eq!(1, pipeline.len());
let element = &pipeline.elements[0];
match &element.expr.expr {
Expr::ExternalCall(name, args) => {
match &name.expr {
Expr::String(string) => {
assert_eq!(expected, string);
}
other => {
panic!("{tag}: Unexpected expression in command name position: {other:?}");
}
}
assert_eq!(0, args.len());
}
other => {
panic!("{tag}: Unexpected expression in pipeline: {other:?}");
}
}
}
#[rstest]
#[case("^foo bar-baz", "bar-baz", "bare word")]
#[case("^foo bar/baz", "bar/baz", "bare word with forward slash")]
#[case(r"^foo bar\baz", r"bar\baz", "bare word with backslash")]
#[case("^foo 'bar baz'", "'bar baz'", "single quote")]
#[case("foo 'bar/baz'", "'bar/baz'", "single quote with forward slash")]
#[case(r"foo 'bar\baz'", r"'bar\baz'", "single quote with backslash")]
#[case(r#"^foo "bar baz""#, r#""bar baz""#, "double quote")]
#[case(r#"^foo "bar/baz""#, r#""bar/baz""#, "double quote with forward slash")]
#[case(r#"^foo "bar\\baz""#, r#""bar\baz""#, "double quote with backslash")]
#[case("^foo `bar baz`", "`bar baz`", "backtick quote")]
#[case("^foo `bar/baz`", "`bar/baz`", "backtick quote with forward slash")]
#[case(r"^foo `bar\baz`", r"`bar\baz`", "backtick quote with backslash")]
fn test_external_call_argument_regular(
#[case] input: &str,
#[case] expected: &str,
#[case] tag: &str,
) {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let block = parse(&mut working_set, None, input.as_bytes(), true);
assert!(
working_set.parse_errors.is_empty(),
"{tag}: errors: {:?}",
working_set.parse_errors
);
let pipeline = &block.pipelines[0];
assert_eq!(1, pipeline.len());
let element = &pipeline.elements[0];
match &element.expr.expr {
Expr::ExternalCall(name, args) => {
match &name.expr {
Expr::String(string) => {
assert_eq!("foo", string, "{tag}: incorrect name");
}
other => {
panic!("{tag}: Unexpected expression in command name position: {other:?}");
}
}
assert_eq!(1, args.len());
match &args[0] {
ExternalArgument::Regular(expr) => match &expr.expr {
Expr::String(string) => {
assert_eq!(expected, string, "{tag}: incorrect arg");
}
other => {
panic!("Unexpected expression in command arg position: {other:?}")
}
},
other @ ExternalArgument::Spread(..) => {
panic!("Unexpected external spread argument in command arg position: {other:?}")
}
}
}
other => {
panic!("{tag}: Unexpected expression in pipeline: {other:?}");
}
}
}
#[test]
fn test_external_call_argument_spread() {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let block = parse(&mut working_set, None, b"^foo ...[a b c]", true);
assert!(
working_set.parse_errors.is_empty(),
"errors: {:?}",
working_set.parse_errors
);
let pipeline = &block.pipelines[0];
assert_eq!(1, pipeline.len());
let element = &pipeline.elements[0];
match &element.expr.expr {
Expr::ExternalCall(name, args) => {
match &name.expr {
Expr::String(string) => {
assert_eq!("foo", string, "incorrect name");
}
other => {
panic!("Unexpected expression in command name position: {other:?}");
}
}
assert_eq!(1, args.len());
match &args[0] {
ExternalArgument::Spread(expr) => match &expr.expr {
Expr::List(items) => {
assert_eq!(3, items.len());
// that's good enough, don't really need to go so deep into it...
}
other => {
panic!("Unexpected expression in command arg position: {other:?}")
}
},
other @ ExternalArgument::Regular(..) => {
panic!(
"Unexpected external regular argument in command arg position: {other:?}"
)
}
}
}
other => {
panic!("Unexpected expression in pipeline: {other:?}");
}
}
}
#[test]
fn test_nothing_comparison_eq() {
let engine_state = EngineState::new();

View File

@ -5,7 +5,7 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-path"
edition = "2021"
license = "MIT"
name = "nu-path"
version = "0.94.0"
version = "0.94.2"
exclude = ["/fuzz"]
[lib]

View File

@ -5,14 +5,14 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-plugin-core
edition = "2021"
license = "MIT"
name = "nu-plugin-core"
version = "0.94.0"
version = "0.94.2"
[lib]
bench = false
[dependencies]
nu-protocol = { path = "../nu-protocol", version = "0.94.0" }
nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.94.0", default-features = false }
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.94.2", default-features = false }
rmp-serde = { workspace = true }
serde = { workspace = true }

View File

@ -5,17 +5,17 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-plugin-engi
edition = "2021"
license = "MIT"
name = "nu-plugin-engine"
version = "0.94.0"
version = "0.94.2"
[lib]
bench = false
[dependencies]
nu-engine = { path = "../nu-engine", version = "0.94.0" }
nu-protocol = { path = "../nu-protocol", version = "0.94.0" }
nu-system = { path = "../nu-system", version = "0.94.0" }
nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.94.0" }
nu-plugin-core = { path = "../nu-plugin-core", version = "0.94.0", default-features = false }
nu-engine = { path = "../nu-engine", version = "0.94.2" }
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
nu-system = { path = "../nu-system", version = "0.94.2" }
nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.94.2" }
nu-plugin-core = { path = "../nu-plugin-core", version = "0.94.2", default-features = false }
serde = { workspace = true }
log = { workspace = true }

View File

@ -5,14 +5,14 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-plugin-prot
edition = "2021"
license = "MIT"
name = "nu-plugin-protocol"
version = "0.94.0"
version = "0.94.2"
[lib]
bench = false
[dependencies]
nu-protocol = { path = "../nu-protocol", version = "0.94.0", features = ["plugin"] }
nu-utils = { path = "../nu-utils", version = "0.94.0" }
nu-protocol = { path = "../nu-protocol", version = "0.94.2", features = ["plugin"] }
nu-utils = { path = "../nu-utils", version = "0.94.2" }
bincode = "1.3"
serde = { workspace = true, features = ["derive"] }

View File

@ -1,6 +1,6 @@
[package]
name = "nu-plugin-test-support"
version = "0.94.0"
version = "0.94.2"
edition = "2021"
license = "MIT"
description = "Testing support for Nushell plugins"
@ -12,14 +12,14 @@ bench = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
nu-engine = { path = "../nu-engine", version = "0.94.0", features = ["plugin"] }
nu-protocol = { path = "../nu-protocol", version = "0.94.0", features = ["plugin"] }
nu-parser = { path = "../nu-parser", version = "0.94.0", features = ["plugin"] }
nu-plugin = { path = "../nu-plugin", version = "0.94.0" }
nu-plugin-core = { path = "../nu-plugin-core", version = "0.94.0" }
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.94.0" }
nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.94.0" }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.0" }
nu-engine = { path = "../nu-engine", version = "0.94.2", features = ["plugin"] }
nu-protocol = { path = "../nu-protocol", version = "0.94.2", features = ["plugin"] }
nu-parser = { path = "../nu-parser", version = "0.94.2", features = ["plugin"] }
nu-plugin = { path = "../nu-plugin", version = "0.94.2" }
nu-plugin-core = { path = "../nu-plugin-core", version = "0.94.2" }
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.94.2" }
nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.94.2" }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.2" }
nu-ansi-term = { workspace = true }
similar = "2.5"

View File

@ -5,16 +5,16 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-plugin"
edition = "2021"
license = "MIT"
name = "nu-plugin"
version = "0.94.0"
version = "0.94.2"
[lib]
bench = false
[dependencies]
nu-engine = { path = "../nu-engine", version = "0.94.0" }
nu-protocol = { path = "../nu-protocol", version = "0.94.0" }
nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.94.0" }
nu-plugin-core = { path = "../nu-plugin-core", version = "0.94.0", default-features = false }
nu-engine = { path = "../nu-engine", version = "0.94.2" }
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.94.2" }
nu-plugin-core = { path = "../nu-plugin-core", version = "0.94.2", default-features = false }
log = { workspace = true }
thiserror = "1.0"

View File

@ -5,7 +5,7 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-pretty-hex"
edition = "2021"
license = "MIT"
name = "nu-pretty-hex"
version = "0.94.0"
version = "0.94.2"
[lib]
doctest = false

View File

@ -5,7 +5,7 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-protocol"
edition = "2021"
license = "MIT"
name = "nu-protocol"
version = "0.94.0"
version = "0.94.2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -13,9 +13,9 @@ version = "0.94.0"
bench = false
[dependencies]
nu-utils = { path = "../nu-utils", version = "0.94.0" }
nu-path = { path = "../nu-path", version = "0.94.0" }
nu-system = { path = "../nu-system", version = "0.94.0" }
nu-utils = { path = "../nu-utils", version = "0.94.2" }
nu-path = { path = "../nu-path", version = "0.94.2" }
nu-system = { path = "../nu-system", version = "0.94.2" }
brotli = { workspace = true, optional = true }
byte-unit = { version = "5.1", features = [ "serde" ] }
@ -45,7 +45,7 @@ plugin = [
serde_json = { workspace = true }
strum = "0.26"
strum_macros = "0.26"
nu-test-support = { path = "../nu-test-support", version = "0.94.0" }
nu-test-support = { path = "../nu-test-support", version = "0.94.2" }
pretty_assertions = { workspace = true }
rstest = { workspace = true }
tempfile = { workspace = true }

View File

@ -5,12 +5,12 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-std"
edition = "2021"
license = "MIT"
name = "nu-std"
version = "0.94.0"
version = "0.94.2"
[dependencies]
nu-parser = { version = "0.94.0", path = "../nu-parser" }
nu-protocol = { version = "0.94.0", path = "../nu-protocol" }
nu-engine = { version = "0.94.0", path = "../nu-engine" }
nu-parser = { version = "0.94.2", path = "../nu-parser" }
nu-protocol = { version = "0.94.2", path = "../nu-protocol" }
nu-engine = { version = "0.94.2", path = "../nu-engine" }
miette = { workspace = true, features = ["fancy-no-backtrace"] }
log = "0.4"

View File

@ -3,7 +3,7 @@ authors = ["The Nushell Project Developers", "procs creators"]
description = "Nushell system querying"
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-system"
name = "nu-system"
version = "0.94.0"
version = "0.94.2"
edition = "2021"
license = "MIT"

View File

@ -5,20 +5,20 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-table"
edition = "2021"
license = "MIT"
name = "nu-table"
version = "0.94.0"
version = "0.94.2"
[lib]
bench = false
[dependencies]
nu-protocol = { path = "../nu-protocol", version = "0.94.0" }
nu-utils = { path = "../nu-utils", version = "0.94.0" }
nu-engine = { path = "../nu-engine", version = "0.94.0" }
nu-color-config = { path = "../nu-color-config", version = "0.94.0" }
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
nu-utils = { path = "../nu-utils", version = "0.94.2" }
nu-engine = { path = "../nu-engine", version = "0.94.2" }
nu-color-config = { path = "../nu-color-config", version = "0.94.2" }
nu-ansi-term = { workspace = true }
once_cell = { workspace = true }
fancy-regex = { workspace = true }
tabled = { workspace = true, features = ["color"], default-features = false }
[dev-dependencies]
# nu-test-support = { path="../nu-test-support", version = "0.94.0" }
# nu-test-support = { path="../nu-test-support", version = "0.94.2" }

View File

@ -5,12 +5,12 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-term-grid"
edition = "2021"
license = "MIT"
name = "nu-term-grid"
version = "0.94.0"
version = "0.94.2"
[lib]
bench = false
[dependencies]
nu-utils = { path = "../nu-utils", version = "0.94.0" }
nu-utils = { path = "../nu-utils", version = "0.94.2" }
unicode-width = { workspace = true }

View File

@ -5,16 +5,16 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-test-suppor
edition = "2021"
license = "MIT"
name = "nu-test-support"
version = "0.94.0"
version = "0.94.2"
[lib]
doctest = false
bench = false
[dependencies]
nu-path = { path = "../nu-path", version = "0.94.0" }
nu-glob = { path = "../nu-glob", version = "0.94.0" }
nu-utils = { path = "../nu-utils", version = "0.94.0" }
nu-path = { path = "../nu-path", version = "0.94.2" }
nu-glob = { path = "../nu-glob", version = "0.94.2" }
nu-utils = { path = "../nu-utils", version = "0.94.2" }
num-format = { workspace = true }
which = { workspace = true }

View File

@ -5,7 +5,7 @@ edition = "2021"
license = "MIT"
name = "nu-utils"
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-utils"
version = "0.94.0"
version = "0.94.2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[[bin]]

View File

@ -1,6 +1,6 @@
# Nushell Config File
#
# version = "0.94.0"
# version = "0.94.2"
# For more information on defining custom themes, see
# https://www.nushell.sh/book/coloring_and_theming.html

View File

@ -1,6 +1,6 @@
# Nushell Environment Config File
#
# version = "0.94.0"
# version = "0.94.2"
def create_left_prompt [] {
let dir = match (do --ignore-shell-errors { $env.PWD | path relative-to $nu.home-path }) {

View File

@ -10,10 +10,10 @@ name = "nu_plugin_custom_values"
bench = false
[dependencies]
nu-plugin = { path = "../nu-plugin", version = "0.94.0" }
nu-protocol = { path = "../nu-protocol", version = "0.94.0", features = ["plugin"] }
nu-plugin = { path = "../nu-plugin", version = "0.94.2" }
nu-protocol = { path = "../nu-protocol", version = "0.94.2", features = ["plugin"] }
serde = { workspace = true, default-features = false }
typetag = "0.2"
[dev-dependencies]
nu-plugin-test-support = { path = "../nu-plugin-test-support", version = "0.94.0" }
nu-plugin-test-support = { path = "../nu-plugin-test-support", version = "0.94.2" }

View File

@ -5,7 +5,7 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_exam
edition = "2021"
license = "MIT"
name = "nu_plugin_example"
version = "0.94.0"
version = "0.94.2"
[[bin]]
name = "nu_plugin_example"
@ -15,9 +15,9 @@ bench = false
bench = false
[dependencies]
nu-plugin = { path = "../nu-plugin", version = "0.94.0" }
nu-protocol = { path = "../nu-protocol", version = "0.94.0", features = ["plugin"] }
nu-plugin = { path = "../nu-plugin", version = "0.94.2" }
nu-protocol = { path = "../nu-protocol", version = "0.94.2", features = ["plugin"] }
[dev-dependencies]
nu-plugin-test-support = { path = "../nu-plugin-test-support", version = "0.94.0" }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.0" }
nu-plugin-test-support = { path = "../nu-plugin-test-support", version = "0.94.2" }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.2" }

View File

@ -5,12 +5,12 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_form
edition = "2021"
license = "MIT"
name = "nu_plugin_formats"
version = "0.94.0"
version = "0.94.2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
nu-plugin = { path = "../nu-plugin", version = "0.94.0" }
nu-protocol = { path = "../nu-protocol", version = "0.94.0", features = ["plugin"] }
nu-plugin = { path = "../nu-plugin", version = "0.94.2" }
nu-protocol = { path = "../nu-protocol", version = "0.94.2", features = ["plugin"] }
indexmap = { workspace = true }
eml-parser = "0.1"
@ -18,4 +18,4 @@ ical = "0.11"
rust-ini = "0.21.0"
[dev-dependencies]
nu-plugin-test-support = { path = "../nu-plugin-test-support", version = "0.94.0" }
nu-plugin-test-support = { path = "../nu-plugin-test-support", version = "0.94.2" }

View File

@ -5,7 +5,7 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_gsta
edition = "2021"
license = "MIT"
name = "nu_plugin_gstat"
version = "0.94.0"
version = "0.94.2"
[lib]
doctest = false
@ -16,7 +16,7 @@ name = "nu_plugin_gstat"
bench = false
[dependencies]
nu-plugin = { path = "../nu-plugin", version = "0.94.0" }
nu-protocol = { path = "../nu-protocol", version = "0.94.0" }
nu-plugin = { path = "../nu-plugin", version = "0.94.2" }
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
git2 = "0.18"

View File

@ -5,7 +5,7 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_inc"
edition = "2021"
license = "MIT"
name = "nu_plugin_inc"
version = "0.94.0"
version = "0.94.2"
[lib]
doctest = false
@ -16,7 +16,7 @@ name = "nu_plugin_inc"
bench = false
[dependencies]
nu-plugin = { path = "../nu-plugin", version = "0.94.0" }
nu-protocol = { path = "../nu-protocol", version = "0.94.0", features = ["plugin"] }
nu-plugin = { path = "../nu-plugin", version = "0.94.2" }
nu-protocol = { path = "../nu-protocol", version = "0.94.2", features = ["plugin"] }
semver = "1.0"

View File

@ -6,7 +6,7 @@
# it also allows us to test the plugin interface with something manually implemented in a scripting
# language without adding any extra dependencies to our tests.
const NUSHELL_VERSION = "0.94.0"
const NUSHELL_VERSION = "0.94.2"
def main [--stdio] {
if ($stdio) {

View File

@ -5,7 +5,7 @@ edition = "2021"
license = "MIT"
name = "nu_plugin_polars"
repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_polars"
version = "0.94.0"
version = "0.94.2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -17,9 +17,9 @@ bench = false
bench = false
[dependencies]
nu-protocol = { path = "../nu-protocol", version = "0.94.0" }
nu-plugin = { path = "../nu-plugin", version = "0.94.0" }
nu-path = { path = "../nu-path", version = "0.94.0" }
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
nu-plugin = { path = "../nu-plugin", version = "0.94.2" }
nu-path = { path = "../nu-path", version = "0.94.2" }
# Potential dependencies for extras
chrono = { workspace = true, features = ["std", "unstable-locales"], default-features = false }
@ -73,9 +73,9 @@ optional = false
version = "0.39"
[dev-dependencies]
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.0" }
nu-engine = { path = "../nu-engine", version = "0.94.0" }
nu-parser = { path = "../nu-parser", version = "0.94.0" }
nu-command = { path = "../nu-command", version = "0.94.0" }
nu-plugin-test-support = { path = "../nu-plugin-test-support", version = "0.94.0" }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.2" }
nu-engine = { path = "../nu-engine", version = "0.94.2" }
nu-parser = { path = "../nu-parser", version = "0.94.2" }
nu-command = { path = "../nu-command", version = "0.94.2" }
nu-plugin-test-support = { path = "../nu-plugin-test-support", version = "0.94.2" }
tempfile.workspace = true

View File

@ -27,7 +27,7 @@ import sys
import json
NUSHELL_VERSION = "0.94.0"
NUSHELL_VERSION = "0.94.2"
def signatures():

View File

@ -5,7 +5,7 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_quer
edition = "2021"
license = "MIT"
name = "nu_plugin_query"
version = "0.94.0"
version = "0.94.2"
[lib]
doctest = false
@ -16,8 +16,8 @@ name = "nu_plugin_query"
bench = false
[dependencies]
nu-plugin = { path = "../nu-plugin", version = "0.94.0" }
nu-protocol = { path = "../nu-protocol", version = "0.94.0" }
nu-plugin = { path = "../nu-plugin", version = "0.94.2" }
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
gjson = "0.8"
scraper = { default-features = false, version = "0.19" }

View File

@ -5,7 +5,7 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_stre
edition = "2021"
license = "MIT"
name = "nu_plugin_stress_internals"
version = "0.94.0"
version = "0.94.2"
[[bin]]
name = "nu_plugin_stress_internals"

View File

@ -5,14 +5,14 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nuon"
edition = "2021"
license = "MIT"
name = "nuon"
version = "0.94.0"
version = "0.94.2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
nu-parser = { path = "../nu-parser", version = "0.94.0" }
nu-protocol = { path = "../nu-protocol", version = "0.94.0" }
nu-engine = { path = "../nu-engine", version = "0.94.0" }
nu-parser = { path = "../nu-parser", version = "0.94.2" }
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
nu-engine = { path = "../nu-engine", version = "0.94.2" }
once_cell = { workspace = true }
fancy-regex = { workspace = true }

View File

@ -539,6 +539,15 @@ fn dynamic_closure_optional_arg() {
fn dynamic_closure_rest_args() {
let actual = nu!(r#"let closure = {|...args| $args | str join ""}; do $closure 1 2 3"#);
assert_eq!(actual.out, "123");
let actual = nu!(
r#"let closure = {|required, ...args| $"($required), ($args | str join "")"}; do $closure 1 2 3"#
);
assert_eq!(actual.out, "1, 23");
let actual = nu!(
r#"let closure = {|required, optional?, ...args| $"($required), ($optional), ($args | str join "")"}; do $closure 1 2 3"#
);
assert_eq!(actual.out, "1, 2, 3");
}
#[cfg(feature = "which-support")]