Skip to content

Allow spreading arguments to commands#11289

Merged
WindSoilder merged 41 commits intonushell:mainfrom
ysthakur:spread-cmd-args
Dec 28, 2023
Merged

Allow spreading arguments to commands#11289
WindSoilder merged 41 commits intonushell:mainfrom
ysthakur:spread-cmd-args

Conversation

@ysthakur
Copy link
Copy Markdown
Member

@ysthakur ysthakur commented Dec 11, 2023

Finishes implementing #10598, which asks for a spread operator in lists, in records, and when calling commands.

Description

This PR will allow spreading arguments to commands (both internal and external). It will also deprecate spreading arguments automatically when passing to external commands.

User-Facing Changes

  • Users will be able to use ... to spread arguments to custom/builtin commands that have rest parameters or allow unknown arguments, or to any external command
    • If a custom command doesn't have a rest parameter and it doesn't allow unknown arguments either, the spread operator will not be allowed
  • Passing lists to external commands without ... will work for now but will cause a deprecation warning saying that it'll stop working in 0.91 (is 2 versions enough time?)

Here's a function to help with demonstrating some behavior:

> def foo [ a, b, c?, d?, ...rest ] { [$a $b $c $d $rest] | to nuon }

You can pass a list of arguments to fill in the rest parameter using ...:

> foo 1 2 3 4 ...[5 6]
[1, 2, 3, 4, [5, 6]]

If you don't use ..., the list [5 6] will be treated as a single argument:

> foo 1 2 3 4 [5 6] # Note the double [[]]
[1, 2, 3, 4, [[5, 6]]]

You can omit optional parameters before the spread arguments:

> foo 1 2 3 ...[4 5] # d is omitted here
[1, 2, 3, null, [4, 5]]

If you have multiple lists, you can spread them all:

> foo 1 2 3 ...[4 5] 6 7 ...[8] ...[]
[1, 2, 3, null, [4, 5, 6, 7, 8]]

Here's the kind of error you get when you try to spread arguments to a command with no rest parameter:
image

And this is the warning you get when you pass a list to an external now (without ...):

image

Tests + Formatting

Added tests to cover the following cases:

  • Spreading arguments to a command that doesn't have a rest parameter (unexpected spread argument error)
  • Spreading arguments to a command that doesn't have a rest parameter but there's also a missing positional argument (missing positional error)
  • Spreading arguments to a command that doesn't have a rest parameter but does allow unknown arguments, such as exec (allowed)
  • Spreading a list literal containing arguments of the wrong type (parse error)
  • Spreading a non-list value, both to internal and external commands
  • Having named arguments in the middle of rest arguments
  • explaining a command call that spreads its arguments

After Submitting

Examples

Suppose you have multiple tables:

let people = [[id name age]; [0 alice 100] [1 bob 200] [2 eve 300]]
let evil_twins = [[id name age]; [0 ecila 100] [-1 bob 200] [-2 eve 300]]

Maybe you often find yourself needing to merge multiple tables and want a utility to do that. You could write a function like this:

def merge_all [ ...tables ] { $tables | reduce { |it, acc| $acc | merge $it } }

Then you can use it like this:

> merge_all ...([$people $evil_twins] | each { |$it| $it | select name age })
╭───┬───────┬─────╮
 # │ name  │ age │
├───┼───────┼─────┤
 0  ecila  100 
 1  bob    200 
 2  eve    300 
╰───┴───────┴─────╯

Except they had duplicate columns, so now you first want to suffix every column with a number to tell you which table the column came from. You can make a command for that:

def select_and_merge [ --cols: list<string>, ...tables ] {
  let renamed_tables = $tables
    | enumerate
    | each { |it|
      $it.item | select $cols | rename ...($cols | each { |col| $col + ($it.index | into string) })
    };
  merge_all ...$renamed_tables
}

And call it like this:

> select_and_merge --cols [name age] $people $evil_twins
╭───┬───────┬──────┬───────┬──────╮
 # │ name0 │ age0 │ name1 │ age1 │
├───┼───────┼──────┼───────┼──────┤
 0  alice   100  ecila   100 
 1  bob     200  bob     200 
 2  eve     300  eve     300 
╰───┴───────┴──────┴───────┴──────╯

Suppose someone's made a command to search for APT packages:

# The main command
def search-pkgs [
    --install                   # Whether to install any packages it finds
    log_level: int              # Pretend it's a good idea to make this a required positional parameter
    exclude?: list<string>      # Packages to exclude
    repositories?: list<string> # Which repositories to look in (searches in all if not given)
    ...pkgs                     # Package names to search for
] {
  { install: $install, log_level: $log_level, exclude: ($exclude | to nuon), repositories: ($repositories | to nuon), pkgs: ($pkgs | to nuon) }
}

It has a lot of parameters to configure it, so you might make your own helper commands to wrap around it for specific cases. Here's one example:

# Only look for packages locally
def search-pkgs-local [
    --install              # Whether to install any packages it finds
    log_level: int
    exclude?: list<string> # Packages to exclude
    ...pkgs                # Package names to search for
] {
  # All required and optional positional parameters are given
  search-pkgs --install=$install $log_level [] ["<local URI or something>"] ...$pkgs
}

And you can run it like this:

> search-pkgs-local --install=false 5 ...["python2.7" "vim"]
╭──────────────┬──────────────────────────────╮
 install       false                        
 log_level     5                            
 exclude       []                           
 repositories  ["<local URI or something>"] 
 pkgs          ["python2.7", vim]           
╰──────────────┴──────────────────────────────╯

One thing I realized when writing this was that if we decide to not allow passing optional arguments using the spread operator, then you can (mis?)use the spread operator to skip optional parameters. Here, I didn't want to give exclude explicitly, so I used a spread operator to pass the packages to install. Without it, I would've needed to do search-pkgs-local --install=false 5 [] "python2.7" "vim" (explicitly pass [] (or null, in the general case) to exclude). There are probably more idiomatic ways to do this, but I just thought it was something interesting.

If you're a virologist of the xkcd kind, another helper command you might make is this:

# Install any packages it finds
def live-dangerously [ ...pkgs ] {
  # One optional argument was given (exclude), while another was not (repositories)
  search-pkgs 0 [] ...$pkgs --install # Flags can go after spread arguments
}

Running it:

> live-dangerously "git" "*vi*" # *vi* because I don't feel like typing out vim and neovim
╭──────────────┬─────────────╮
 install       true        
 log_level     0           
 exclude       []          
 repositories  null        
 pkgs          [git, *vi*] 
╰──────────────┴─────────────╯

Here's an example that uses the spread operator more than once within the same command call:

let extras = [ chrome firefox python java git ]

def search-pkgs-curated [ ...pkgs ] {
  (search-pkgs
      1
      [emacs]
      ["example.com", "foo.com"]
      vim # A must for everyone!
      ...($pkgs | filter { |p| not ($p | str contains "*") }) # Remove packages with globs
      python # Good tool to have
      ...$extras
      --install=false
      python3) # I forget, did I already put Python in extras?
}

Running it:

> search-pkgs-curated "git" "*vi*"
╭──────────────┬───────────────────────────────────────────────────────────────────╮
 install       false                                                             
 log_level     1                                                                 
 exclude       [emacs]                                                           
 repositories  [example.com, foo.com]                                            
 pkgs          [vim, git, python, chrome, firefox, python, java, git, "python3"] 
╰──────────────┴───────────────────────────────────────────────────────────────────╯

@ysthakur
Copy link
Copy Markdown
Member Author

ysthakur commented Dec 14, 2023

A few things I'd like feedback on:

  • I made a helper method inside the impl for Call called rest_iter_flattened that evaluates all of the rest arguments and flattens any spread arguments it sees along the way. Is Call the right place to put such a method, or should it go in eval.rs, eval_base.rs, or someplace else?
  • Rather than representing spread arguments using Expr::Spread, I made an Argument::Spread variant for internal calls. For external calls, I made an ExternalArgument enum with Regular and Spread variants (previously, arguments to external calls were simply Expressions). This feels a little safer than using Expr::Spread, but explicitly handling these Spread variants does mean a little more code. Do you guys want to use Expr::Spread (or something else) instead?
  • Should these Argument::Spread and ExternalArgument::Spread variants also hold the Span of the spread operator itself? Currently, when making a FlatShape for the operator before syntax highlighting, it finds the start of the spread operator's span by subtracting 3 from the argument's span's start. This may break if, in the future, the spread operator's syntax is changed slightly, e.g. whitespace is allowed, * instead of ...
  • I also rewrote a few blocks of code that used call.named_iter() and call.positional_iter() to instead iterate over through call.arguments in a single loop and manually match on each argument. This was just to make it easier to deal with the Argument::Spread variant. Is this fine or should I go back to the previous style and use call.rest_iter() to handle the rest arguments?
  • There's definitely other stuff that I can't remember right now

@ysthakur ysthakur marked this pull request as ready for review December 14, 2023 02:05
@fdncred
Copy link
Copy Markdown
Contributor

fdncred commented Dec 15, 2023

once finished with this pr, it'll be good to get some documentation because i keep confusing myself with what the spread operator is supposed to do, even though i've looked at each pr. maybe equally importantly is to understand what it's not supposed to do.

for now, it seems like it's only used for external commands. is that right?

regular rest arg

def --wrapped mecho [...rest] { echo $rest}
 mecho -h a b d
╭───┬────╮
 0  -h 
 1  a  
 2  b  
 3  d  
╰───┴────╯

rest arg with spread operator

def --wrapped mecho [...rest] { echo ...$rest}
 mecho -h a b d
╭───┬────╮
 0  -h 
 1  a  
 2  b  
 3  d  
╰───┴────╯

rest arg with rest operator with external command

 def --wrapped mecho [...rest] { ^echo ...$rest}
 mecho -h a b d
-h a b d

@ysthakur
Copy link
Copy Markdown
Member Author

once finished with this pr, it'll be good to get some documentation

Good idea, I'll get started on a PR for that right after this one (or in parallel).

for now, it seems like it's only used for external commands. is that right?

No, it should also work for internal commands (although I still haven't gotten around to testing it on commands with named parameters). For example:

❯ def f [a b c? d? ...x] { [$a $b $c $d $x] | to nuon }
❯ f 1 2 3 ...[5 6]
[1, 2, 3, null, [5, 6]]

@ysthakur
Copy link
Copy Markdown
Member Author

Converting to draft because I just realized that if you do export extern foo [] {}, you can still spread (foo ...[bar baz] isn't rejected at parse time)

@ysthakur ysthakur marked this pull request as draft December 23, 2023 00:53
@ysthakur
Copy link
Copy Markdown
Member Author

Oh, it looks like the reason foo ...[bar] is allowed even with export extern foo [] {} is that with export extern, the signature allows unknown arguments. In that case, I guess it's acceptable behavior for arguments to such external commands to be spread?

@kubouch
Copy link
Copy Markdown
Contributor

kubouch commented Dec 26, 2023

I think it's OK to allow spreading for externals because their ...rest is implied.

I wonder if we should unify def and extern to both require --wrapped, because currently --wrapped is implied with extern and doesn't require ...rest. But that's outside of scope for this PR.

One last note: I'd change the error message on the screenshot from This command does not have a rest parameter to This command does not have a ...rest parameter. You can make the ...rest named whatever, for example ...spam, it's the three dots that make it significant. The best would be to give it some name, like This command does not have a multi-positional parameter, such as ...rest (not sure if it's the best term, lol). And to make the error message more actionable: To use the spread argument, the command needs to define a multi-positional parameter in its signature, such as ...rest. This tells the user how to fix their code.

@ysthakur ysthakur marked this pull request as ready for review December 26, 2023 20:54
@kubouch
Copy link
Copy Markdown
Contributor

kubouch commented Dec 27, 2023

OK, error looks better now!

I saw the TODO comments when creating Spans in flatten.rs. I think it's OK as the 3 preceding dots should be guaranteed from the parser, and we'd get crashes when running tests thanks to the debug_assert! in Span::new().

Looks good to me!

@amtoine amtoine linked an issue Dec 27, 2023 that may be closed by this pull request
@WindSoilder
Copy link
Copy Markdown
Contributor

Looks good to me :-) I think we can go and merge it

@WindSoilder WindSoilder merged commit 21b3eee into nushell:main Dec 28, 2023
@ysthakur ysthakur deleted the spread-cmd-args branch December 28, 2023 11:03
fdncred pushed a commit that referenced this pull request Jan 16, 2024
# Description
in #11289, spreading lists into
command invocations was made possible and its implicit version was
deprecated, but not everything was updated accordingly.

# User-Facing Changes
A commented part of the default config no longer throws a deprecation
warning when uncommented


# After Submitting
After #11289, the mention of
carapace in the documentation wasn’t updated. See
nushell/nushell.github.io#1211
amtoine added a commit to nushell/nupm that referenced this pull request Jan 20, 2024
related to
- nushell/nushell#11289

## Description
this should fix the deprecation warning that we get these days
amtoine added a commit to amtoine/nu-git-manager that referenced this pull request Jan 20, 2024
amtoine added a commit to amtoine/nu-git-manager that referenced this pull request Jan 21, 2024
ysthakur added a commit that referenced this pull request Feb 14, 2024
<!--
if this PR closes one or more issues, you can automatically link the PR
with
them by using one of the [*linking
keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword),
e.g.
- this PR should close #xxxx
- fixes #xxxx

you can also mention related issues, PRs or discussions!
-->

# Description
<!--
Thank you for improving Nushell. Please, check our [contributing
guide](../CONTRIBUTING.md) and talk to the core team before making major
changes.

Description of your pull request goes here. **Provide examples and/or
screenshots** if your changes affect the user experience.
-->

Spreading lists automatically when calling externals was deprecated in
0.89 (#11289), and this PR is to remove it in 0.91.

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

The new error message looks like this:

```
>  ^echo [1 2]
Error: nu::shell::cannot_pass_list_to_external

  × Lists are not automatically spread when calling external commands
   ╭─[entry #13:1:8]
 1 │  ^echo [1 2]
   ·        ──┬──
   ·          ╰── Spread operator (...) is necessary to spread lists
   ╰────
  help: Either convert the list to a string or use the spread operator, like so: ...[1 2]
```

The old error message didn't say exactly where to put the `...` and
seemed to confuse a lot of people, so hopefully this helps.

# 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 std testing; testing run-tests --path
crates/nu-std"` 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
> ```
-->

There was one test to check that implicit spread was deprecated before,
updated that to check that it's disallowed now.

# 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.
-->
dmatos2012 pushed a commit to dmatos2012/nushell that referenced this pull request Feb 20, 2024
<!--
if this PR closes one or more issues, you can automatically link the PR
with
them by using one of the [*linking
keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword),
e.g.
- this PR should close #xxxx
- fixes #xxxx

you can also mention related issues, PRs or discussions!
-->

Finishes implementing nushell#10598,
which asks for a spread operator in lists, in records, and when calling
commands.

# Description
<!--
Thank you for improving Nushell. Please, check our [contributing
guide](../CONTRIBUTING.md) and talk to the core team before making major
changes.

Description of your pull request goes here. **Provide examples and/or
screenshots** if your changes affect the user experience.
-->

This PR will allow spreading arguments to commands (both internal and
external). It will also deprecate spreading arguments automatically when
passing to external commands.

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

- Users will be able to use `...` to spread arguments to custom/builtin
commands that have rest parameters or allow unknown arguments, or to any
external command
- If a custom command doesn't have a rest parameter and it doesn't allow
unknown arguments either, the spread operator will not be allowed
- Passing lists to external commands without `...` will work for now but
will cause a deprecation warning saying that it'll stop working in 0.91
(is 2 versions enough time?)

Here's a function to help with demonstrating some behavior:
```nushell
> def foo [ a, b, c?, d?, ...rest ] { [$a $b $c $d $rest] | to nuon }
```

You can pass a list of arguments to fill in the `rest` parameter using
`...`:
```nushell
> foo 1 2 3 4 ...[5 6]
[1, 2, 3, 4, [5, 6]]
```

If you don't use `...`, the list `[5 6]` will be treated as a single
argument:

```nushell
> foo 1 2 3 4 [5 6] # Note the double [[]]
[1, 2, 3, 4, [[5, 6]]]
```

You can omit optional parameters before the spread arguments:
```nushell
> foo 1 2 3 ...[4 5] # d is omitted here
[1, 2, 3, null, [4, 5]]
```

If you have multiple lists, you can spread them all:
```nushell
> foo 1 2 3 ...[4 5] 6 7 ...[8] ...[]
[1, 2, 3, null, [4, 5, 6, 7, 8]]
```

Here's the kind of error you get when you try to spread arguments to a
command with no rest parameter:

![image](https://github.com/nushell/nushell/assets/45539777/93faceae-00eb-4e59-ac3f-17f98436e6e4)

And this is the warning you get when you pass a list to an external now
(without `...`):


![image](https://github.com/nushell/nushell/assets/45539777/d368f590-201e-49fb-8b20-68476ced415e)


# 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 std testing; testing run-tests --path
crates/nu-std"` 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
> ```
-->

Added tests to cover the following cases:
- Spreading arguments to a command that doesn't have a rest parameter
(unexpected spread argument error)
- Spreading arguments to a command that doesn't have a rest parameter
*but* there's also a missing positional argument (missing positional
error)
- Spreading arguments to a command that doesn't have a rest parameter
but does allow unknown arguments, such as `exec` (allowed)
- Spreading a list literal containing arguments of the wrong type (parse
error)
- Spreading a non-list value, both to internal and external commands
- Having named arguments in the middle of rest arguments
- `explain`ing a command call that spreads its arguments

# 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.
-->

# Examples

Suppose you have multiple tables:
```nushell
let people = [[id name age]; [0 alice 100] [1 bob 200] [2 eve 300]]
let evil_twins = [[id name age]; [0 ecila 100] [-1 bob 200] [-2 eve 300]]
```

Maybe you often find yourself needing to merge multiple tables and want
a utility to do that. You could write a function like this:
```nushell
def merge_all [ ...tables ] { $tables | reduce { |it, acc| $acc | merge $it } }
```

Then you can use it like this:
```nushell
> merge_all ...([$people $evil_twins] | each { |$it| $it | select name age })
╭───┬───────┬─────╮
│ # │ name  │ age │
├───┼───────┼─────┤
│ 0 │ ecila │ 100 │
│ 1 │ bob   │ 200 │
│ 2 │ eve   │ 300 │
╰───┴───────┴─────╯
```

Except they had duplicate columns, so now you first want to suffix every
column with a number to tell you which table the column came from. You
can make a command for that:
```nushell
def select_and_merge [ --cols: list<string>, ...tables ] {
  let renamed_tables = $tables
    | enumerate
    | each { |it|
      $it.item | select $cols | rename ...($cols | each { |col| $col + ($it.index | into string) })
    };
  merge_all ...$renamed_tables
}
```
And call it like this:
```nushell
> select_and_merge --cols [name age] $people $evil_twins
╭───┬───────┬──────┬───────┬──────╮
│ # │ name0 │ age0 │ name1 │ age1 │
├───┼───────┼──────┼───────┼──────┤
│ 0 │ alice │  100 │ ecila │  100 │
│ 1 │ bob   │  200 │ bob   │  200 │
│ 2 │ eve   │  300 │ eve   │  300 │
╰───┴───────┴──────┴───────┴──────╯
```

---

Suppose someone's made a command to search for APT packages:

```nushell
# The main command
def search-pkgs [
    --install                   # Whether to install any packages it finds
    log_level: int              # Pretend it's a good idea to make this a required positional parameter
    exclude?: list<string>      # Packages to exclude
    repositories?: list<string> # Which repositories to look in (searches in all if not given)
    ...pkgs                     # Package names to search for
] {
  { install: $install, log_level: $log_level, exclude: ($exclude | to nuon), repositories: ($repositories | to nuon), pkgs: ($pkgs | to nuon) }
}
```

It has a lot of parameters to configure it, so you might make your own
helper commands to wrap around it for specific cases. Here's one
example:
```nushell
# Only look for packages locally
def search-pkgs-local [
    --install              # Whether to install any packages it finds
    log_level: int
    exclude?: list<string> # Packages to exclude
    ...pkgs                # Package names to search for
] {
  # All required and optional positional parameters are given
  search-pkgs --install=$install $log_level [] ["<local URI or something>"] ...$pkgs
}
```
And you can run it like this:
```nushell
> search-pkgs-local --install=false 5 ...["python2.7" "vim"]
╭──────────────┬──────────────────────────────╮
│ install      │ false                        │
│ log_level    │ 5                            │
│ exclude      │ []                           │
│ repositories │ ["<local URI or something>"] │
│ pkgs         │ ["python2.7", vim]           │
╰──────────────┴──────────────────────────────╯
```

One thing I realized when writing this was that if we decide to not
allow passing optional arguments using the spread operator, then you can
(mis?)use the spread operator to skip optional parameters. Here, I
didn't want to give `exclude` explicitly, so I used a spread operator to
pass the packages to install. Without it, I would've needed to do
`search-pkgs-local --install=false 5 [] "python2.7" "vim"` (explicitly
pass `[]` (or `null`, in the general case) to `exclude`). There are
probably more idiomatic ways to do this, but I just thought it was
something interesting.

If you're a virologist of the [xkcd](https://xkcd.com/350/) kind,
another helper command you might make is this:
```nushell
# Install any packages it finds
def live-dangerously [ ...pkgs ] {
  # One optional argument was given (exclude), while another was not (repositories)
  search-pkgs 0 [] ...$pkgs --install # Flags can go after spread arguments
}
```

Running it:
```nushell
> live-dangerously "git" "*vi*" # *vi* because I don't feel like typing out vim and neovim
╭──────────────┬─────────────╮
│ install      │ true        │
│ log_level    │ 0           │
│ exclude      │ []          │
│ repositories │ null        │
│ pkgs         │ [git, *vi*] │
╰──────────────┴─────────────╯
```

Here's an example that uses the spread operator more than once within
the same command call:
```nushell
let extras = [ chrome firefox python java git ]

def search-pkgs-curated [ ...pkgs ] {
  (search-pkgs
      1
      [emacs]
      ["example.com", "foo.com"]
      vim # A must for everyone!
      ...($pkgs | filter { |p| not ($p | str contains "*") }) # Remove packages with globs
      python # Good tool to have
      ...$extras
      --install=false
      python3) # I forget, did I already put Python in extras?
}
```

Running it:
```nushell
> search-pkgs-curated "git" "*vi*"
╭──────────────┬───────────────────────────────────────────────────────────────────╮
│ install      │ false                                                             │
│ log_level    │ 1                                                                 │
│ exclude      │ [emacs]                                                           │
│ repositories │ [example.com, foo.com]                                            │
│ pkgs         │ [vim, git, python, chrome, firefox, python, java, git, "python3"] │
╰──────────────┴───────────────────────────────────────────────────────────────────╯
```
dmatos2012 pushed a commit to dmatos2012/nushell that referenced this pull request Feb 20, 2024
# Description
in nushell#11289, spreading lists into
command invocations was made possible and its implicit version was
deprecated, but not everything was updated accordingly.

# User-Facing Changes
A commented part of the default config no longer throws a deprecation
warning when uncommented


# After Submitting
After nushell#11289, the mention of
carapace in the documentation wasn’t updated. See
nushell/nushell.github.io#1211
dmatos2012 pushed a commit to dmatos2012/nushell that referenced this pull request Feb 20, 2024
…l#11857)

<!--
if this PR closes one or more issues, you can automatically link the PR
with
them by using one of the [*linking
keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword),
e.g.
- this PR should close #xxxx
- fixes #xxxx

you can also mention related issues, PRs or discussions!
-->

# Description
<!--
Thank you for improving Nushell. Please, check our [contributing
guide](../CONTRIBUTING.md) and talk to the core team before making major
changes.

Description of your pull request goes here. **Provide examples and/or
screenshots** if your changes affect the user experience.
-->

Spreading lists automatically when calling externals was deprecated in
0.89 (nushell#11289), and this PR is to remove it in 0.91.

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

The new error message looks like this:

```
>  ^echo [1 2]
Error: nu::shell::cannot_pass_list_to_external

  × Lists are not automatically spread when calling external commands
   ╭─[entry nushell#13:1:8]
 1 │  ^echo [1 2]
   ·        ──┬──
   ·          ╰── Spread operator (...) is necessary to spread lists
   ╰────
  help: Either convert the list to a string or use the spread operator, like so: ...[1 2]
```

The old error message didn't say exactly where to put the `...` and
seemed to confuse a lot of people, so hopefully this helps.

# 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 std testing; testing run-tests --path
crates/nu-std"` 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
> ```
-->

There was one test to check that implicit spread was deprecated before,
updated that to check that it's disallowed now.

# 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.
-->
kik4444 pushed a commit to kik4444/nushell-fork that referenced this pull request Feb 28, 2024
…l#11857)

<!--
if this PR closes one or more issues, you can automatically link the PR
with
them by using one of the [*linking
keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword),
e.g.
- this PR should close #xxxx
- fixes #xxxx

you can also mention related issues, PRs or discussions!
-->

# Description
<!--
Thank you for improving Nushell. Please, check our [contributing
guide](../CONTRIBUTING.md) and talk to the core team before making major
changes.

Description of your pull request goes here. **Provide examples and/or
screenshots** if your changes affect the user experience.
-->

Spreading lists automatically when calling externals was deprecated in
0.89 (nushell#11289), and this PR is to remove it in 0.91.

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

The new error message looks like this:

```
>  ^echo [1 2]
Error: nu::shell::cannot_pass_list_to_external

  × Lists are not automatically spread when calling external commands
   ╭─[entry nushell#13:1:8]
 1 │  ^echo [1 2]
   ·        ──┬──
   ·          ╰── Spread operator (...) is necessary to spread lists
   ╰────
  help: Either convert the list to a string or use the spread operator, like so: ...[1 2]
```

The old error message didn't say exactly where to put the `...` and
seemed to confuse a lot of people, so hopefully this helps.

# 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 std testing; testing run-tests --path
crates/nu-std"` 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
> ```
-->

There was one test to check that implicit spread was deprecated before,
updated that to check that it's disallowed now.

# 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.
-->
a-stevan added a commit to dragoon-rs/komodo that referenced this pull request Nov 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

category:deprecation Related to the deprecation of commands/features/options

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Introduce a spread operator

4 participants