Compare commits

...

127 Commits

Author SHA1 Message Date
3016d7a64c Bump version for 0.91.0 release (#12070) 2024-03-05 21:28:40 +01:00
9a07b41c9d Pin reedline to 0.30.0 release (#12081)
https://github.com/nushell/reedline/releases/tag/v0.30.0
2024-03-05 21:13:57 +01:00
565c6409d9 Bump mio from 0.8.10 to 0.8.11 (#12077) 2024-03-05 09:46:11 +00:00
27793e7452 Bump crate-ci/typos from 1.18.2 to 1.19.0 (#12059) 2024-03-04 13:13:08 +00:00
7066cc5004 fix --table-name parameter for into sqlite (#12068)
# Description

This PR fixes the typo in the parameter `--table-name` instead of
`--table_name` in the `into sqlite` command.

fixes #12067

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

# 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-03-04 05:55:40 -06:00
71aacf5032 Adjust examples in date commands (#12055)
Hello! This is my first PR to nushell, as I was looking at things for
#5066. The usage text for the date commands seemed fine to me, so this
is just a bit of a tidy up of the examples, mostly the description text.

# Description

- Remove two incorrect examples for `date to-record` and `date to-table`
where nothing was piped in (which causes an error in actual use).

- Fix misleading descriptions in `date to-timezone` which erroneously
referred to Hawaii's time zone.

- Standardise on "time zone" in written descriptions.

- Generally tidy up example descriptions and improve consistency.

# User-Facing Changes

Only in related help text showing examples.
2024-03-03 15:10:50 -06:00
3ee2fc60f9 Fix typos in comments (#12052)
<!--
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.
-->

Fix typos in comments

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

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

Signed-off-by: geekvest <cuimoman@sohu.com>
2024-03-03 06:28:56 -06:00
669659f974 Improve sleep resolution (#12049)
# Description
This improves the resolution of the sleep commands by simply not
clamping to the default 100ms ctrl+c signal checking loop if the
passed-in duration is shorter.

# User-Facing Changes
You can use smaller values in sleep.

```
# Before
timeit { 0..100 | each { |row| print $row; sleep 10ms; } } # +10sec

# After
timeit { 0..100 | each { |row| print $row; sleep 10ms; } } # +1sec
```

It still depends on the internal behavior of thread::sleep and the OS
timers. In windows it doesn't seem to go much lower than 15 or 10ms, or
0 if you asked for that.

# After Submitting
Sleep didn't have anything documenting its minimum value, so this should
be more in line with its standard procedure. It will still never sleep
for less time than allocated.

Did you know `sleep` can take multiple durations, and it'll add them up?
I didn't
2024-03-02 14:03:56 -06:00
4cda183103 Canonicalize default-config-dir and plugin-path (#11999)
<!--
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.
-->

This PR makes sure `$nu.default-config-dir` and `$nu.plugin-path` are
canonicalized.

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

`$nu.default-config-dir` (and `$nu.plugin-path`) will now give canonical
paths, with symlinks and whatnot resolved.

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

I've added a couple of tests to check that even if the config folder
and/or any of the config files within are symlinks, the `$nu.*`
variables are properly canonicalized. These tests unfortunately only run
on Linux and MacOS, because I couldn't figure out how to change the
config directory on Windows. Also, given that they involve creating
files, I'm not sure if they're excessive, so I could remove one or two
of them.

# 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-03-02 11:15:31 -06:00
9a9fdd7a35 add examples for adding paths to PATH, and to load from a custom file in default_env.nu (#12032)
# Description
Show an example of loading from a custom file, and an example of adding
multiple entry to PATH. Loading from a custom file will hopefully allow
for greater modularity of configuration files out of the box for new
users. Adding multiple paths to PATH is very common, and will help new
users to.

Adds this:
```
# To add multiple paths to PATH this may be simpler:
# use std "path add"
# $env.PATH = ($env.PATH | split row (char esep))
# path add /some/path
# path add ($env.CARGO_HOME | path join "bin")
# path add ($env.HOME | path join ".local" "bin")
# $env.PATH = ($env.PATH | uniq)

# To load from a custom file you can use:
# source ($nu.default-config-dir | path join 'custom.nu')
```

---------

Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2024-03-02 11:14:42 -06:00
626d597527 Replace panics with errors in thread spawning (#12040)
# Description
Replace panics with errors in thread spawning.

Also adds `IntoSpanned` trait for easily constructing `Spanned`, and an
implementation of `From<Spanned<std::io::Error>>` for `ShellError`,
which is used to provide context for the error wherever there was a span
conveniently available. In general this should make it more convenient
to do the right thing with `std::io::Error` and always add a span to it
when it's possible to do so.

# User-Facing Changes
Fewer panics!

# Tests + Formatting
- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`
2024-03-02 11:14:02 -06:00
8c112c9efd fix: allow view source to view aliases again (#12048)
# Description

This PR allows `view source` to view aliases again. It looks like it's
been half broken for a while now.

fixes #12044

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

# 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-03-02 07:50:36 -06:00
98525043ed Fix const string interpolation test (#12038)
<!--
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.
-->

Currently, in the test for interpolating strings at parse-time, the
formatted string includes `(X years ago)` (from formatting a date) (test
came from https://github.com/nushell/nushell/pull/11562). I didn't
realize when I was writing it that it would have to be updated every
year. This PR uses regex to check the output instead.

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

# 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-03-01 16:35:07 -08:00
872aa78373 Add interleave command for reading multiple streams in parallel (#11955)
<!--
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.
-->

This command mixes input from multiple sources and sends items to the
final stream as soon as they're available. It can be called as part of a
pipeline with input, or it can take multiple closures and mix them that
way.

See `crates/nu-command/tests/commands/interleave.rs` for a practical
example. I imagine this will be most often used to run multiple commands
in parallel and print their outputs line-by-line. A stdlib command could
potentially use `interleave` to make this particular use case easier.

It's quite common to wish that nushell had a command for running things
in the background, and instead of providing job control, this provides
an alternative to some use cases for that by just allowing multiple
commands to run simultaneously and direct their output to the same
place.

This enables certain things that are not possible with `par-each` - for
example, you may wish to run `make` across several projects in parallel:

```nushell
(ls projects).name | par-each { |project| cd $project; make }
```

This works well enough, but the output will only be available after each
`make` command finishes. `interleave` allows you to get each line:

```nushell
interleave ...(
  (ls projects).name | each { |project|
    {
      cd $project
      make | lines | each { |line| {project: $project, out: $line} }
    }
  }
)
```

The result of this is a stream that you could process further - for
example, by saving to a text file.

Note that the closures themselves are not run in parallel. The initial
execution happens serially, and then the streams are consumed in
parallel.

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

Adds a new command.

# 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
> ```
-->
- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`

# 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-03-01 16:56:37 -06:00
8948c350d4 fix: start command should break on the first succeeded command result (#12021)
<!--
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.
-->
Fixes #12020 

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

# 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-03-01 13:48:04 -06:00
9ff92c6878 replace Criterion with Divan (#12000)
<!--
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.
--> 
This is a test of changing out the current criterion microbenchmark tool
to [Divan](https://nikolaivazquez.com/blog/divan/), a new and more
straightforward microbenchmark suit.
Itself states it is robust to noise, and even allow it to be used in CI
settings. It by default has no external dependencies and is very fast to
run, the sampling method allows it to be a lot faster compared to
criterion requiring less samples.
The output is also nicely displayed and easy to get a quick overview of
the performance.


![image](https://github.com/nushell/nushell/assets/17986183/587a1fb1-1da3-402c-b668-a27fde9a0657)


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

# 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-03-01 10:09:21 -08:00
38a42905ae Fix touch to allow changing timestamps on directories, remake from #11760 (#12005)
<!--
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!
-->

Based off of #11760 to be mergable without conflicts.

# 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.
-->
Fix for #11757.
The main issue in #11757 is I tried to copy the timestamp from one
directory to another only to realize that did not work whereas the
coreutils `^touch` had no problems. I thought `--reference` just did not
work, but apparently the whole `touch` command could not work on
directories because
`OpenOptions::new().write(true).create(true).open(&item)` tries to
create `touch`'s target in advance and then modify its timestamps. But
if the target is a directory that already exists then this would fail
even though the crate used for working with timestamps, `filetime`,
already works on directories.

# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->
I don't believe this should change any existing valid behaviors. It just
changes a non-working behavior.

# 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
> ```
-->
~~I only could not run `cargo test` because I get compilation errors on
the latest main branch~~
All tests pass with `cargo test --features=sqlite`

# 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-03-01 07:23:03 -06:00
39cf43ef06 Fix: string_to_table in ssv.rs now filters comments. (issue #11997) (#12035)
- Fixes #11997

# Description
Fixes the issue that comments are not ignored in SSV formatted data.
![Fix
image](https://github.com/nushell/nushell/assets/64328283/1c1bd7dd-ced8-4276-8c21-b50e1c0dba53)

# User-Facing Changes
If you have a comment in the beginning of SSV formatted data it is now
not included in the SSV table.

# Tests + Formatting
The PR adds one test in the ssv.rs file. All previous test-cases are
still passing. Clippy and Fmt have been ran.
2024-03-01 07:11:13 -06:00
262914cf92 remove old mv command in favor of umv (renamed to mv) (#12022)
# Description

This PR removes our old nushell `mv` command in favor of the
uutils/coreutils `uu_mv` crate's `mv` command which we integrated in
0.90.1.

# User-Facing Changes

# Tests + Formatting

# After Submitting
2024-03-01 09:37:23 +08:00
4c4609d646 Plugin StreamReader: fuse the iterator after an error (#12027)
# Description

This patches `StreamReader`'s iterator implementation to not return any
values after an I/O error has been encountered.

Without this, it's possible for a protocol error to cause the channel to
disconnect, in which case every call to `recv()` returns an error, which
causes the iterator to produce error values infinitely. There are some
commands that don't immediately stop after receiving an error so it's
possible that they just get stuck in an infinite error. This fixes that
so the error is only produced once, and then the stream ends
artificially.
2024-02-29 23:39:17 +01:00
65e5abaa3e deprecate str escape-glob command (#12018)
# Description
After some iteration on globbing rules, I don't think `str escape-glob`
is needed

# User-Facing Changes
```nushell
❯ let f = "[ab]*.nu"
❯ $f | str escape-glob
Error:   × str escape-glob is deprecated
   ╭─[entry #1:1:6]
 1 │ $f | str escape-glob
   ·      ───────┬───────
   ·             ╰── if you are trying to escape a variable, you don't need to do it now
   ╰────
  help: Remove `str escape-glob` call

[[]ab[]][*].nu
```

# Tests + Formatting
NaN

# After Submitting
NaN
2024-02-29 20:29:56 +08:00
f24877ba08 fix: process empty headers in to md command (#12012)
<!--
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!
-->
fixes #12006

# 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.
-->
Process empty headers as well in `to md` command.

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

# 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-02-28 20:44:11 -06:00
ab08328a30 Add Goodbye message to ensure plugins exit when they are no longer needed (#12014)
# Description

This fixes a race condition where all interfaces to a plugin might have
been dropped, but both sides are still expecting input, and the
`PluginInterfaceManager` doesn't get a chance to see that the interfaces
have been dropped and stop trying to consume input.

As the manager needs to hold on to a writer, we can't automatically
close the stream, but we also can't interrupt it if it's in a waiting to
read. So the best solution is to send a message to the plugin that we
are no longer going to be sending it any plugin calls, so that it knows
that it can exit when it's done.

This race condition is a little bit tricky to trigger as-is, but can be
more noticeable when running plugins in a tight loop. If too many plugin
processes are spawned at one time, Nushell can start to encounter "too
many open files" errors, and not be very useful.


# User-Facing Changes


# Tests + Formatting
- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`

# After Submitting

I will need to add `Goodbye` to the protocol docs
2024-02-28 20:41:22 -06:00
345edbbe10 add is-not-empty command as a QOL improvement (#11991)
# Description

This PR adds `is-not-empty` as a counterpart to `is-empty`. It's the
same code but negates the results. This command has been asked for many
times. So, I thought it would be nice for our community to add it just
as a quality-of-life improvement. This allows people to stop writing
their `def is-not-empty [] { not ($in | is-empty) }` custom commands.

I'm sure there will be some who disagree with adding this, I just think
it's like we have `in` and `not-in` and helps fill out the language and
makes it a little easier to use.

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

# 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-02-28 17:11:44 -06:00
e69a02d379 Add tee command for operating on copies of streams (#11928)
<!--
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!
-->

[Related conversation on
Discord](https://discord.com/channels/601130461678272522/615329862395101194/1209951539901366292)

# 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 is inspired by the Unix tee command, but significantly more
powerful. Rather than just writing to a file, you can do any kind of
stream operation that Nushell supports within the closure.

The equivalent of Unix `tee -a file.txt` would be, for example, `command
| tee { save -a file.txt }` - but of course this is Nushell, and you can
do the same with structured data to JSON objects, or even just run any
other command on the system with it.

A `--stderr` flag is provided for operating on the stderr stream from
external programs. This may produce unexpected results if the stderr
stream is not then also printed by something else - nushell currently
doesn't. See #11929 for the fix for that.

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

If someone was using the system `tee` command, they might be surprised
to find that it's different.

# 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
> ```
-->
- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`


# 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-02-28 17:08:31 -06:00
0126620c19 Disable flaky network tests (#12010)
# Description
Ignores some network tests that sometimes fail in CI. E.g., in
[11953](https://github.com/nushell/nushell/pull/11953#issuecomment-1962275863)
and
[11654](https://github.com/nushell/nushell/pull/11654#issuecomment-1968404551).
2024-02-28 16:28:33 +00:00
387328fe73 Glob: don't allow implicit casting between glob and string (#11992)
# Description
As title, currently on latest main, nushell confused user if it allows
implicit casting between glob and string:
```nushell
let x = "*.txt"
def glob-test [g: glob] { open $g } 
glob-test $x
```
It always expand the glob although `$x` is defined as a string.
This pr implements a solution from @kubouch :
> We could make it really strict and disallow all autocasting between
globs and strings because that's what's causing the "magic" confusion.
Then, modify all builtins that accept globs to accept oneof(glob,
string) and the rules would be that globs always expand and strings
never expand

# User-Facing Changes
After this pr, user needs to use `into glob` to invoke `glob-test`, if
user pass a string variable:
```nushell
let x = "*.txt"
def glob-test [g: glob] { open $g } 
glob-test ($x | into glob)
```
Or else nushell will return an error.
```
 3 │ glob-test $x
   ·           ─┬
   ·            ╰── can't convert string to glob
```

# Tests + Formatting
Done

# After Submitting
Nan
2024-02-28 23:05:35 +08:00
eaedb30a8c Don't expanding globs if user pass variables. (#11946)
# Description
Fixes: #11912

# User-Facing Changes
After this change: 
```
let x = '*.nu'; ^echo $x
```
will no longer expand glob.
If users still want to expand glob, there are also 3 ways to do this:
```
# 1. use spread operation with `glob` command
let x = '*.nu'; ^echo ...(glob $x)
```
# Tests + Formatting
Done

# After Submitting
NaN
2024-02-28 23:05:09 +08:00
c6cb406a53 Allow clear command to clear terminal's history (#12008)
This PR should close #11693.

# Description

This PR just adds a '--all' flag to the `clear` command in order to
clear the terminal and its history.

By default, the `clear` command only scrolls down.
In some cases, clearing the history as well can be useful.

Default behavior does not change.

Even if the `clear` command can be extended form within nushell, having
it in out of the box would allow to use it raw, without any
customization required.
Last but not least, it is pretty easy to implement as it is already
supported by the crate which is used to clear the terminal
(`crossterm`).

Providing relevant screenshot is pretty difficult because the result is
the same.
In the `clear --all` case, you just cannot scroll back anymore.

# User-Facing Changes

`clear` just scrolls down as usual without wiping the history of the
terminal.

` clear --all` scrolls down and wipe the terminal's history which means
scrolling back is no more possible.

# Tests + Formatting

General formatting and tests pass and have been executed on Linux only.
I don't have any way to test it on other systems.
There are no specific tests for the `clear` command so I didn't add any
(and I am not sure how to do if I had to).
Clear command is just a wrapper of the `crossterm` crate Clear command.

I would be more than happy if someone else was able to test it in other
context (even if it may be good as we rely on the crossterm crate).

# After Submitting

PR for documentation has been drafted:
https://github.com/nushell/nushell.github.io/pull/1266.
I'll update it with version if this PR is merged.

---------

Co-authored-by: Stefan Holderbach <sholderbach@users.noreply.github.com>
2024-02-28 07:49:41 -06:00
d3895d71db add binary data handling to bits commands (#11854)
# Description
- enables `bits` commands to operate on binary data, where both inputs
are binary and can vary in length
- adds an `--endian` flag to `bits and`, `or`, `xor` for specifying
endianness (for binary values of different lengths)

# User-Facing Changes
- `bits` commands will no longer error for non-int inputs
- the default for `--number-bytes` is now `auto` (infer int size;
changed from 8)

# Tests + Formatting
> addendum: first PR, please inform if any changes are needed
2024-02-28 20:43:50 +08:00
7b95e37bbe Making coreutils umkdir as the default mkdir (#12007)
<!--
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.
-->
`umkdir` was added in #10785, I think it's time to replace the default
one.

# After Submitting

Remove the old `mkdir` command and making coreutils' `umkdir` as the
default
2024-02-28 06:27:10 -06:00
bf425874b8 Add upsert example (#12001)
# Description
Adds one example to `help upsert` that indirectly uses the `$in` value
in a closure.
2024-02-27 17:54:29 -06:00
f6e248f343 Benchmark changes (#11998)
<!--
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.
-->

This PR does a total of 3 things,
1. It fixes an error when running the `cargo bench` suit where nushell
constants where not set correctly ending in an error when running the
code.
2. It removes 2 redundant benchmark runs as these where duplicates of
existing ones.
3. It reduced encoding and decoding benchmark suit future, only having 4
benches instead of the previous 8.

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

# 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-02-27 11:55:26 -06:00
ecaed7f0ae add --signed flag for binary into int conversions (#11902)
<!--
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.
-->
- adds a `--signed` flag to `into int` to allow parsing binary values as
signed integers, the integer size depends on the length of the binary
value

# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->
- attempting to convert binary values larger than 8 bytes into integers
now throws an error, with or without `--signed`

# 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
> ```
-->
- wrote 3 tests and 1 example for `into int --signed` usage
- added an example for unsigned binary `into int`

# 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.
-->
- will add examples from this PR to `into int` documentation
2024-02-27 15:05:26 +00:00
0aae485395 Fixes test 1 year more. (#11994)
<!--
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.
-->
The test checks the time that has passed, bumped year by 1.


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

# 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-02-27 08:55:37 -06:00
523d57b2d8 bump reedline to test ExecuteHostCommand changes (#11993)
# Description

This PR bumps reedline to the latest main which has the
`executehostcommand` changes
https://github.com/nushell/reedline/pull/758 which essentially allows
reedline/nushell to call `executehostcommand` in key bindings and
rewrite the commandline buffer without inserting a newline.

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

# 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-02-27 08:43:14 -06:00
2a721bad52 Add columns to dataframe that are present in the schema but not present the Dataframe when applying schema. (#11987) 2024-02-26 17:22:33 -06:00
f4d9ddd3ad Fix completions for directories with hidden files (#11921)
# Description
Attempting to complete a directory with hidden files could cause a
variety of issues. When Rust parses the partial path to be completed
into components, it removes the trailing `.` since it interprets this to
mean "the current directory", but in the case of the completer we
actually want to treat the trailling `.` as a literal `.`. This PR fixes
this by adding a `.` back into the Path components if the last character
of the path is a `.` AND the path is longer than 1 character (eg., not
just a ".", since that correctly gets interpreted as Component::CurDir).

Here are some things this fixes:
- Panic when tab completing for hidden files in a directory with hidden
files (ex. `ls test/.`)
- Panic when tab completing a directory with only hidden files (since
the common prefix ends with a `.`, causing the previous issue)
- Mishandling of tab completing hidden files in directory (ex. `ls
~/.<TAB>` lists all files instead of just hidden files)
- Trailing `.` being inexplicably removed when tab completing a
directory without hidden files

While testing for this PR I also noticed there is a similar issue when
completing with `..` (ex. `ls ~/test/..<TAB>`) which is not fixed by
this PR (edit: see #11922).

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

# 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 a hidden-files-within-directories test to the `file_completions`
test.

# 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-02-26 12:14:19 -06:00
daeb56fe90 Fix Windows msvc *.msi builds (#11986)
Try to fix the nightly build failure here:
https://github.com/nushell/nushell/actions/runs/8041856942
2024-02-26 08:34:25 -06:00
43687207b4 allow current day to be highlighted (#11954)
# Description

This PR tweaks the built-in `cal` command so that it's still nushell-y
but looks closer to the "expected" cal by abbreviating the name of the
days. I also added the ability to color the current day with the current
"header" color.

### Before

![image](https://github.com/nushell/nushell/assets/343840/c7ad3017-d872-4d39-926d-cc99b097d934)

### After

![image](https://github.com/nushell/nushell/assets/343840/735c4f2e-9867-4cd7-ae3b-397dd02059d7)



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

# 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-02-26 08:31:46 -06:00
c0ff0f12f0 Add ConfigDirNotFound error (#11849)
<!--
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.
-->

Currently, there's multiple places that look for a config directory, and
each of them has different error messages when it can't be found. This
PR makes a `ConfigDirNotFound` error to standardize the error message
for all of these cases.

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

Previously, the errors in `create_nu_constant()` would say which config
file Nushell was trying to get when it couldn't find the config
directory. Now it doesn't. However, I think that's fine, given that it
doesn't matter whether it couldn't find the config directory while
looking for `login.nu` or `env.nu`, it only matters that it couldn't
find it.

This is what the error looks like:


![image](https://github.com/nushell/nushell/assets/45539777/52298ed4-f9e9-4900-bb94-1154d389efa7)

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

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

---------

Co-authored-by: Antoine Stevan <44101798+amtoine@users.noreply.github.com>
2024-02-26 15:42:20 +08:00
2697ea9a25 Bump mockito from 1.2.0 to 1.3.0 (#11976)
Bumps [mockito](https://github.com/lipanski/mockito) from 1.2.0 to
1.3.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/lipanski/mockito/releases">mockito's
releases</a>.</em></p>
<blockquote>
<h2>1.3.0</h2>
<ul>
<li><a
href="3e2d4662eb">Introduced</a>
<code>Server::new_with_opts</code>,
<code>Server::new_with_opts_async</code> and the <code>ServerOpts</code>
struct to allow configuring the server host, port and enabling
auto-asserts (see next item)</li>
<li><a
href="3e2d4662eb">Added</a>
the <code>assert_on_drop</code> server option that allows you to
automatically call <code>assert()</code> whenever your mocks go out of
scope (defaults to false)</li>
<li><a
href="2ed230b5e9">Expose</a>
<code>Server::socket_address()</code> to return the raw server
<code>SocketAddr</code></li>
<li><a
href="efc7da13c5">Use</a>
only required features for dependencies</li>
<li><a
href="bcdcb2a154">Accept</a>
<code>hyper::header::HeaderValue</code> as a <code>match_header()</code>
value</li>
</ul>
<p>Thanks to <a
href="https://github.com/andrewtoth"><code>@​andrewtoth</code></a> <a
href="https://github.com/alexander-jackson"><code>@​alexander-jackson</code></a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="a09f1f0009"><code>a09f1f0</code></a>
Bump to 1.3.0</li>
<li><a
href="0be6d7a184"><code>0be6d7a</code></a>
Merge pull request <a
href="https://redirect.github.com/lipanski/mockito/issues/191">#191</a>
from lipanski/server-opts</li>
<li><a
href="3e2d4662eb"><code>3e2d466</code></a>
Allow configuring the mock server (host, port, assert_on_drop)</li>
<li><a
href="12cb5d0786"><code>12cb5d0</code></a>
Add sponsor button</li>
<li><a
href="3cce903c0f"><code>3cce903</code></a>
Merge pull request <a
href="https://redirect.github.com/lipanski/mockito/issues/186">#186</a>
from alexander-jackson/feat/return-raw-socket-address</li>
<li><a
href="2ed230b5e9"><code>2ed230b</code></a>
feat: return raw socket address</li>
<li><a
href="496f26da87"><code>496f26d</code></a>
Merge pull request <a
href="https://redirect.github.com/lipanski/mockito/issues/185">#185</a>
from andrewtoth/less-deps</li>
<li><a
href="40138fe979"><code>40138fe</code></a>
Merge pull request <a
href="https://redirect.github.com/lipanski/mockito/issues/184">#184</a>
from andrewtoth/into-headername</li>
<li><a
href="efc7da13c5"><code>efc7da1</code></a>
Use only required features for dependencies</li>
<li><a
href="10d1081d80"><code>10d1081</code></a>
Add impl IntoHeaderName for &amp;HeaderName</li>
<li>Additional commits viewable in <a
href="https://github.com/lipanski/mockito/compare/1.2.0...1.3.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=mockito&package-manager=cargo&previous-version=1.2.0&new-version=1.3.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-26 15:38:29 +08:00
55b67e17bb Bump tempfile from 3.9.0 to 3.10.0 (#11977)
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.9.0 to
3.10.0.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md">tempfile's
changelog</a>.</em></p>
<blockquote>
<h2>3.10.0</h2>
<ul>
<li>Drop <code>redox_syscall</code> dependency, we now use
<code>rustix</code> for Redox.</li>
<li>Add <code>Builder::permissions</code> for setting the permissions on
temporary files and directories (thanks to <a
href="https://github.com/Byron"><code>@​Byron</code></a>).</li>
<li>Update rustix to 0.38.31.</li>
<li>Update fastrand to 2.0.1.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="61531eae61"><code>61531ea</code></a>
chore: release v3.10.0</li>
<li><a
href="e246c4a004"><code>e246c4a</code></a>
chore: update deps (<a
href="https://redirect.github.com/Stebalien/tempfile/issues/275">#275</a>)</li>
<li><a
href="4a05e47d3b"><code>4a05e47</code></a>
feat: Add <code>Builder::permissions()</code> method. (<a
href="https://redirect.github.com/Stebalien/tempfile/issues/273">#273</a>)</li>
<li><a
href="184ab8f5ca"><code>184ab8f</code></a>
fix: drop redox_syscall dependency (<a
href="https://redirect.github.com/Stebalien/tempfile/issues/272">#272</a>)</li>
<li>See full diff in <a
href="https://github.com/Stebalien/tempfile/compare/v3.9.0...v3.10.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=tempfile&package-manager=cargo&previous-version=3.9.0&new-version=3.10.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-26 15:38:11 +08:00
123547444c Bump strum_macros from 0.25.3 to 0.26.1 (#11979)
Bumps [strum_macros](https://github.com/Peternator7/strum) from 0.25.3
to 0.26.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/Peternator7/strum/releases">strum_macros's
releases</a>.</em></p>
<blockquote>
<h2>v0.26.1</h2>
<h2>0.26.1</h2>
<ul>
<li><a
href="https://redirect.github.com/Peternator7/strum/pull/325">#325</a>:
use <code>core</code> instead of <code>std</code> in VariantArray.</li>
</ul>
<h2>0.26.0</h2>
<h3>Breaking Changes</h3>
<ul>
<li>The <code>EnumVariantNames</code> macro has been renamed
<code>VariantNames</code>. The deprecation warning should steer you in
the right direction for fixing the warning.</li>
<li>The Iterator struct generated by EnumIter now has new bounds on it.
This shouldn't break code unless you manually
added the implementation in your code.</li>
<li><code>Display</code> now supports format strings using named fields
in the enum variant. This should be a no-op for most code.
However, if you were outputting a string like <code>&quot;Hello
{field}&quot;</code>, this will now be interpretted as a format
string.</li>
<li>EnumDiscriminant now inherits the repr and discriminant values from
your main enum. This makes the discriminant type
closer to a mirror of the original and that's always the goal.</li>
</ul>
<h3>New features</h3>
<ul>
<li>
<p>The <code>VariantArray</code> macro has been added. This macro adds
an associated constant <code>VARIANTS</code> to your enum. The constant
is a <code>&amp;'static [Self]</code> slice so that you can access all
the variants of your enum. This only works on enums that only
have unit variants.</p>
<pre lang="rust"><code>use strum::VariantArray;
<p>#[derive(Debug, VariantArray)]
enum Color {
Red,
Blue,
Green,
}</p>
<p>fn main() {
println!(&quot;{:?}&quot;, Color::VARIANTS); // prints:
[&quot;Red&quot;, &quot;Blue&quot;, &quot;Green&quot;]
}
</code></pre></p>
</li>
<li>
<p>The <code>EnumTable</code> macro has been <em>experimentally</em>
added. This macro adds a new type that stores an item for each variant
of the enum. This is useful for storing a value for each variant of an
enum. This is an experimental feature because
I'm not convinced the current api surface area is correct.</p>
<pre lang="rust"><code>use strum::EnumTable;
<p>#[derive(Copy, Clone, Debug, EnumTable)]
enum Color {
Red,
Blue,
</code></pre></p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/Peternator7/strum/blob/master/CHANGELOG.md">strum_macros's
changelog</a>.</em></p>
<blockquote>
<h2>0.26.1</h2>
<ul>
<li><a
href="https://redirect.github.com/Peternator7/strum/pull/325">#325</a>:
use <code>core</code> instead of <code>std</code> in VariantArray.</li>
</ul>
<h2>0.26.0</h2>
<h3>Breaking Changes</h3>
<ul>
<li>The <code>EnumVariantNames</code> macro has been renamed
<code>VariantNames</code>. The deprecation warning should steer you in
the right direction for fixing the warning.</li>
<li>The Iterator struct generated by EnumIter now has new bounds on it.
This shouldn't break code unless you manually
added the implementation in your code.</li>
<li><code>Display</code> now supports format strings using named fields
in the enum variant. This should be a no-op for most code.
However, if you were outputting a string like <code>&quot;Hello
{field}&quot;</code>, this will now be interpretted as a format
string.</li>
<li>EnumDiscriminant now inherits the repr and discriminant values from
your main enum. This makes the discriminant type
closer to a mirror of the original and that's always the goal.</li>
</ul>
<h3>New features</h3>
<ul>
<li>
<p>The <code>VariantArray</code> macro has been added. This macro adds
an associated constant <code>VARIANTS</code> to your enum. The constant
is a <code>&amp;'static [Self]</code> slice so that you can access all
the variants of your enum. This only works on enums that only
have unit variants.</p>
<pre lang="rust"><code>use strum::VariantArray;
<p>#[derive(Debug, VariantArray)]
enum Color {
Red,
Blue,
Green,
}</p>
<p>fn main() {
println!(&quot;{:?}&quot;, Color::VARIANTS); // prints:
[&quot;Red&quot;, &quot;Blue&quot;, &quot;Green&quot;]
}
</code></pre></p>
</li>
<li>
<p>The <code>EnumTable</code> macro has been <em>experimentally</em>
added. This macro adds a new type that stores an item for each variant
of the enum. This is useful for storing a value for each variant of an
enum. This is an experimental feature because
I'm not convinced the current api surface area is correct.</p>
<pre lang="rust"><code>use strum::EnumTable;
<p>#[derive(Copy, Clone, Debug, EnumTable)]
enum Color {
Red,
Blue,
Green,
</code></pre></p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/Peternator7/strum/commits/v0.26.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=strum_macros&package-manager=cargo&previous-version=0.25.3&new-version=0.26.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-26 15:37:38 +08:00
88f1f386bb Bidirectional communication and streams for plugins (#11911) 2024-02-25 16:32:50 -06:00
461f69ac5d Rename spans in the serialized form of Value (#11972)
[Discord
context](https://discord.com/channels/601130461678272522/615962413203718156/1211158641793695744)

<!--
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.
-->
Span fields were previously renamed to `internal_span` to discourage
their use in Rust code, but this change also affected the serde I/O for
Value. I don't believe the Python plugin was ever updated to reflect
this change.

This effectively changes it back, but just for the serialized form.
There are good reasons for doing this:

1. `internal_span` is a much longer name, and would be one of the most
common strings found in serialized Value data, probably bulking up the
plugin I/O

2. This change was never really meant to have implications for plugins,
and was just meant to be a hint that `.span()` should be used instead in
Rust code.

When Span refactoring is complete, the serialized form of Value will
probably change again in some significant way, so I think for now it's
best that it's left like this.

This has implications for #11911, particularly for documentation and for
the Python plugin as that was already updated in that PR to reflect
`internal_span`. If this is merged first, I will update that PR.

This would probably be considered a breaking change as it would break
plugin I/O compatibility (but not Rust code). I think it can probably go
in any major release though - all things considered, it's pretty minor,
and users are already expected to recompile plugins for new major
versions. However, it may also be worth holding off to do it together
with #11911 as that PR makes breaking changes in general a little bit
friendlier.

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

Requires plugin recompile.

# 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
> ```
-->
- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`

Nothing outside of `Value` itself had to be changed to make tests pass.
I did not check the Python plugin and whether it works now, but it was
broken before. It may work again as I think the main incompatibility it
had was expecting to use `span`

# 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-02-25 15:49:10 -06:00
e09b4817e1 Fix future lint by truncate(false) in touch (#11863)
The following clippy lint on nightly would complain:
- https://rust-lang.github.io/rust-clippy/master/#/suspicious_open

We don't want to alter the content in `touch` or truncate by not
writing. While not fully applicable, may be good practice for
platforms/filesystems we are not aware of.
2024-02-25 00:02:48 +01:00
96744e3155 Fix cargo b -p nu-command --tests (#11939)
The feature `sqlite` is not active by default on `nu-command`.
Only when building `cargo b --all --tests` would the feature be
activated via `nu`'s feature requirements.

Make the tests conditional

Saw this when double checking the removals from #11938.
Making sure each crate still compiles individually, ensures both that
you can run subcrate tests independently and that the `cargo publish`
run will succeed to build the crate with the default feature set (see
the problems occurring for the `0.90.0` release.
2024-02-25 00:01:29 +01:00
4372d00ea9 Move typos config to repo root (#11949)
# Description
Moves the `typos` config to the repository root directory. This allows
one to run `typos` locally and have the config used automatically.
Currently, one has to instead run `typos -c .github/.typos.toml`.
2024-02-24 20:29:57 +00:00
7884de1941 Remove some unnecessary static Vecs (#11947)
Avoid unnecessary allocations or larger iterator structs

- Turn static `Vec`s into arrays when possible
- Use `std::iter::once`/`empty` where applicable
- Use `bool::then_some` in `detect column` `.chain`
- Drop in the bucket: de-vec-ing tests
2024-02-24 20:58:01 +01:00
098527b263 Print stderr streams to stderr in pipeline_data::print_if_stream() (#11929)
<!--
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!
-->

Related to #11928 - `tee --stderr` doesn't really work as expected
without it

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

Print stderr streams to stderr in `pipeline_data::print_if_stream()`

This corrects unexpected behavior if a stream from an external program
is transformed while still preserving its stderr output. Before this
change, that output is just drained and discarded. Worse, it's drained
to a buffer, which could be really slow and memory hungry if there's a
lot of output on stderr.

This is needed to make `tee --stderr` function in a non-surprising way.
See #11928

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

A script that was erroneously not producing stderr output before might
now, but I can't think of a lot of examples of an external stream being
transformed without being converted.

# 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
> ```
-->
- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`


# 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-02-24 15:32:39 +00:00
995989dad4 Handling errors instead of killing the REPL (#11953)
Handle all errors that happen within the REPL loop, display warning or
error messages, and return defaults where necessary.

This addresses @IanManske [Comment Item
1](https://github.com/nushell/nushell/pull/11860#issuecomment-1959947240)
in #11860

---------

Co-authored-by: Jack Wright <jack.wright@disqo.com>
2024-02-24 15:26:06 +00:00
67a63162b2 Add date support in from xlsx (#11952)
<!--
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.
-->

This PR add date support when using the `open` command on a xlsx file,
and the using `from xlsx` on a xlsx file.
 
# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->

Currently dates in xlsx files are read as nulls, after this PR this
would be regular dates.

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

# 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-02-24 07:25:51 -06:00
6be91a68f3 nu-table: Improve table -a (#11905)
Hi there;

Sorry took that long to respond.

I guess it's good?
It will consume the whole stream whether possible.
I do believe it will be faster in WSL in general too (in a sense of
whole buffer output), but its interesting issue probably needed to be
separated. It was not very well explained as well.

```nushell
> 0..2000 | table -a 2
╭───┬──────╮
│ 0 │    0 │
│ 1 │    1 │
│ 2 │ ...  │
│ 3 │ 1999 │
│ 4 │ 2000 │
╰───┴──────╯
```

Take care

fix: #11845

cc: @fdncred
2024-02-23 19:12:10 -06:00
f7d647ac3c open, rm, umv, cp, rm and du: Don't globs if inputs are variables or string interpolation (#11886)
# Description
This is a follow up to
https://github.com/nushell/nushell/pull/11621#issuecomment-1937484322

Also Fixes: #11838 

## About the code change
It applys the same logic when we pass variables to external commands:


0487e9ffcb/crates/nu-command/src/system/run_external.rs (L162-L170)

That is: if user input dynamic things(like variables, sub-expression, or
string interpolation), it returns a quoted `NuPath`, then user input
won't be globbed
 
# User-Facing Changes
Given two input files: `a*c.txt`, `abc.txt`

* `let f = "a*c.txt"; rm $f` will remove one file: `a*c.txt`. 
~* `let f = "a*c.txt"; rm --glob $f` will remove `a*c.txt` and
`abc.txt`~
* `let f: glob = "a*c.txt"; rm $f` will remove `a*c.txt` and `abc.txt`

## Rules about globbing with *variable*
Given two files: `a*c.txt`, `abc.txt`
| Cmd Type | example | Result |
| ----- | ------------------ | ------ |
| builtin | let f = "a*c.txt"; rm $f | remove `a*c.txt` |
| builtin | let f: glob = "a*c.txt"; rm $f | remove `a*c.txt` and
`abc.txt`
| builtin | let f = "a*c.txt"; rm ($f \| into glob) | remove `a*c.txt`
and `abc.txt`
| custom | def crm [f: glob] { rm $f }; let f = "a*c.txt"; crm $f |
remove `a*c.txt` and `abc.txt`
| custom | def crm [f: glob] { rm ($f \| into string) }; let f =
"a*c.txt"; crm $f | remove `a*c.txt`
| custom | def crm [f: string] { rm $f }; let f = "a*c.txt"; crm $f |
remove `a*c.txt`
| custom | def crm [f: string] { rm $f }; let f = "a*c.txt"; crm ($f \|
into glob) | remove `a*c.txt` and `abc.txt`

In general, if a variable is annotated with `glob` type, nushell will
expand glob pattern. Or else, we need to use `into | glob` to expand
glob pattern

# Tests + Formatting
Done

# After Submitting
I think `str glob-escape` command will be no-longer required. We can
remove it.
2024-02-23 09:17:09 +08:00
a2a1c1656f remove unused dependencies (#11938)
# Description

This PR removes unused dependencies. The `cargo machete --with-metadata`
tool was used to determine what is unused and then I recompiled. Putting
this up here to see what happens in MacOS and Linux in the CI and see if
anything breaks.

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

# 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-02-22 16:31:37 -06:00
99ba365c4a Handle configuration panics (#11935)
Use the default configuration on panic.

Adding a line that panics to any configuration:
```nushell
# Nushell Config File
#
# version = "0.86.0"
"2031-13-31" | into datetime
```

An error message will be displayed and the shell will continue:
<img width="1016" alt="Screenshot 2024-02-22 at 10 14 25"
src="https://github.com/nushell/nushell/assets/56345/8ccff001-300a-4caf-b131-bf7b114a06e3">

Co-authored-by: Jack Wright <jack.wright@disqo.com>
2024-02-22 16:25:55 -06:00
28f58057b6 Replace debug_assert! with assert! in Signature::check_names (#11937)
<!--
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.
-->

Debug assertions don't run at release, which means that `cargo test
--release` fails because the tests for name checks don't run properly.
These checks are not really expensive, and there shouldn't be any
noticeable difference to startup time, so there isn't much reason not to
just leave them in.

It's valuable to be able to run `cargo test --release`, as that can
expose race conditions and dependencies on undefined behavior that
aren't exposed in debug builds.

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

This shouldn't affect anything. Any violations of this rule were being
caught with debug tests, which are run by the CI.

# 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
> ```
-->
- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`


# 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-02-22 16:17:06 -06:00
f17f857b1f wrapping run_repl with catch_unwind and restarting the repl on panic (#11860)
Provides the ability to cleanly recover from panics, falling back to the
last known good state of EngineState and Stack. This pull request also
utilizes miette's panic handler for better formatting of panics.

<img width="642" alt="Screenshot 2024-02-21 at 08 34 35"
src="https://github.com/nushell/nushell/assets/56345/f81efaba-aa45-4e47-991c-1a2cf99e06ff">

---------

Co-authored-by: Jack Wright <jack.wright@disqo.com>
2024-02-22 12:14:10 -06:00
cf68334fa0 Add support for the argument to zip being a closure (#11924)
<!--
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!
-->

[Related conversation on
Discord](https://discord.com/channels/601130461678272522/615329862395101194/1209951539901366292)

# 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 allows `zip` to consume two streams at the same time without having
to choose to fully consume one of them. Helpful for combining infinite
streams, or just large ones.

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

Provides a way to consume another (possibly infinite) stream in `zip`,
rather than that being limited to open ranges.

# 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
> ```
-->
- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`

# 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-02-22 06:35:00 -06:00
6ff3a4180b Specify which file not found in error (#11868)
# Description
Currently, `ShellError::FileNotFound` shows the span where the error
occurred but doesn't say which file wasn't found. This PR makes it so
the help includes that (like the `DirectoryNotFound` error).

# User-Facing Changes
No breaking changes, it's just that when a file can't be found, the help
will say which file couldn't be found:


![image](https://github.com/nushell/nushell/assets/45539777/e52f1e65-55c1-4cd2-8108-a4ccc334a66f)
2024-02-21 21:27:13 +08:00
1058707a29 make stderr works for failed external command (#11914)
# Description
Fixes: #11913

When running external command, nushell shouldn't consumes stderr
messages, if user want to redirect stderr.

# User-Facing Changes
NaN

# Tests + Formatting
Done

# After Submitting
NaN
2024-02-21 21:15:05 +08:00
6e590fe0a2 Remove unused Index(Mut) impls on AST types (#11903)
# Description
Both `Block` and `Pipeline` had `Index`/`IndexMut` implementations to
access their elements, that are currently unused.
Explicit helpers or iteration would generally be preferred anyways but
in the current state the inner containers are `pub` and are liberally
used. (Sometimes with potentially panicking indexing or also iteration)

As it is potentially unclear what the meaning of the element from a
block or pipeline queried by a usize is, let's remove it entirely until
we come up with a better API.

# User-Facing Changes
None

Plugin authors shouldn't dig into AST internals
2024-02-21 18:02:30 +08:00
b23fe30530 fixes debug info not populating process information (#11909)
# Description

This PR fixes #11901. For some reason `debug info` stopped reporting
information. This hopefully fixes it. I think something changes in the
`sysinfo` crate that stopped it from working.

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

# 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-02-20 13:34:11 -06:00
123bf2d736 fix format date based on users locale (#11908)
<!--
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
Hi, 

Fixes #10838, where before the `date` would be formatted incorrectly,
and was not picking `LC_TIME` for time formatting, but it picked the
first locale returned by the `sys-locale` crate instead. Now it will
format time based on `LC_TIME`. For example,

```
// my locale `nl_NL.UTF-8`
❯ date now | format date '%x %X'
20-02-24 17:17:12

$env.LC_TIME = "en_US.UTF-8"

❯ date now | format date '%x %X'
02/20/2024 05:16:28 PM
```
Note that I also changed the `default_env.nu` as otherwise the Time will
show AM/PM twice. Also reason for the `chrono` update is because this
relies on a fix to upstream repo, which i initially submitted an
[issue](https://github.com/chronotope/chrono/issues/1349#event-11765363286)

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

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

- [X] `cargo fmt --all -- --check` to check standard code formatting
(`cargo fmt --all` applies these changes)
- [X] `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used`
to check that you're using the standard code style
- [X] `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))
- [X] `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
> ```


# 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-02-20 11:08:49 -06:00
7c1eb6b0c8 move-Command Tests, Refactor, Fix (#11904)
fixes #11783 

# Description
Firstly Tests for the `move` Command have been added. Afterwards some
duplicate Code has been removed and finally an error-message has been
added for when a column is tried to be moved based on itself. This
should fix #11783 .

To reiterate, the example of the initial issue now plays out as follows:
```shell
> {a: 1} | move a --after a                             
Error: nu:🐚:incompatible_parameters

  × Incompatible parameters.
   ╭─[entry #1:1:15]
 1 │ {a: 1} | move a --after a
   ·               ┬         ┬
   ·               │         ╰── relative to itself
   ·               ╰── Column cannot be moved
   ╰────
``` 

# User-Facing Changes
The error message shown above.

# Tests + Formatting
I added some Tests for the behavior of the command. If I should add
more, please let me know but I added everything that came to mind when
thinking about the command.

---------

Co-authored-by: dannou812 <dannou281@gmail.com>
2024-02-20 07:23:46 -06:00
63ccc62a24 allow last to work with ranges (#11906)
# Description

This PR allows `last` to work with ranges in the same way that `first`
does. It also adds a couple examples demonstrating it.

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

# 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-02-20 06:28:50 -06:00
c0bac5a440 style: correct keybinding name and improve formatting in default_config.nu (#11889)
<!--
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.
-->
This PR addresses a minor mismatch in a keybinding name within the
`default_config.nu` file. Additionally, it applies formatting for
consistency.
# 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 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
> ```
-->

# 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-02-18 20:50:50 -06:00
68a3d7c430 Bump trash from 3.2.1 to 3.3.1 (#11894)
Bumps [trash](https://github.com/ArturKovacs/trash) from 3.2.1 to 3.3.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/ArturKovacs/trash/releases">trash's
releases</a>.</em></p>
<blockquote>
<h2>v3.3.1</h2>
<h3>Bug Fixes</h3>
<ul>
<li>Use <code>AtomicI32</code> instead of I64 for compatibility with
<code>armel</code></li>
</ul>
<h3>Commit Statistics</h3>
<ul>
<li>1 commit contributed to the release.</li>
<li>2 days passed between releases.</li>
<li>1 commit was understood as <a
href="https://www.conventionalcommits.org">conventional</a>.</li>
<li>1 unique issue was worked on: <a
href="https://redirect.github.com/ArturKovacs/trash/issues/99">#99</a></li>
</ul>
<h3>Commit Details</h3>
<!-- raw HTML omitted -->
<!-- raw HTML omitted -->
<ul>
<li><strong><a
href="https://redirect.github.com/ArturKovacs/trash/issues/99">#99</a></strong>
<ul>
<li>Use <code>AtomicI32</code> instead of I64 for compatibility with
<code>armel</code> (98049f1)</li>
</ul>
</li>
</ul>
<!-- raw HTML omitted -->
<h2>v3.3.0</h2>
<h3>New Features</h3>
<ul>
<li>improved error granularity
Inform about operating-system specific errors more clearly, thus avoid
degenerating error information.</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>Use <code>AtomicI32</code> in tests for compatibility with
<code>armel</code> platform</li>
</ul>
<h3>Commit Statistics</h3>
<ul>
<li>5 commits contributed to the release over the course of 5 calendar
days.</li>
<li>25 days passed between releases.</li>
<li>2 commits were understood as <a
href="https://www.conventionalcommits.org">conventional</a>.</li>
<li>1 unique issue was worked on: <a
href="https://redirect.github.com/ArturKovacs/trash/issues/99">#99</a></li>
</ul>
<h3>Commit Details</h3>
<!-- raw HTML omitted -->
<!-- raw HTML omitted -->
<ul>
<li><strong><a
href="https://redirect.github.com/ArturKovacs/trash/issues/99">#99</a></strong>
<ul>
<li>Use <code>AtomicI32</code> in tests for compatibility with
<code>armel</code> platform (920ff0c)</li>
</ul>
</li>
<li><strong>Uncategorized</strong>
<ul>
<li>Improved error granularity (452be83)</li>
<li>Removed tracing. (2b1c9fa)</li>
</ul>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/Byron/trash-rs/blob/master/CHANGELOG.md">trash's
changelog</a>.</em></p>
<blockquote>
<h2>3.3.1 (2024-02-12)</h2>
<h3>Bug Fixes</h3>
<ul>
<li><!-- raw HTML omitted --> Use <code>AtomicI32</code> instead of I64
for compatibility with <code>armel</code></li>
</ul>
<h3>Commit Statistics</h3>
<!-- raw HTML omitted -->
<ul>
<li>1 commit contributed to the release.</li>
<li>2 days passed between releases.</li>
<li>1 commit was understood as <a
href="https://www.conventionalcommits.org">conventional</a>.</li>
<li>1 unique issue was worked on: <a
href="https://redirect.github.com/Byron/trash-rs/issues/99">#99</a></li>
</ul>
<h3>Commit Details</h3>
<!-- raw HTML omitted -->
<!-- raw HTML omitted -->
<ul>
<li><strong><a
href="https://redirect.github.com/Byron/trash-rs/issues/99">#99</a></strong>
<ul>
<li>Use <code>AtomicI32</code> instead of I64 for compatibility with
<code>armel</code> (<a
href="98049f1316"><code>98049f1</code></a>)</li>
</ul>
</li>
</ul>
<!-- raw HTML omitted -->
<h2>3.3.0 (2024-02-10)</h2>
<h3>New Features</h3>
<ul>
<li><!-- raw HTML omitted --> improved error granularity
Inform about operating-system specific errors more clearly, thus avoid
degenerating error information.</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li><!-- raw HTML omitted --> Use <code>AtomicI32</code> in tests for
compatibility with <code>armel</code> platform</li>
</ul>
<h3>Commit Statistics</h3>
<!-- raw HTML omitted -->
<ul>
<li>6 commits contributed to the release over the course of 5 calendar
days.</li>
<li>25 days passed between releases.</li>
<li>2 commits were understood as <a
href="https://www.conventionalcommits.org">conventional</a>.</li>
<li>1 unique issue was worked on: <a
href="https://redirect.github.com/Byron/trash-rs/issues/99">#99</a></li>
</ul>
<h3>Commit Details</h3>
<!-- raw HTML omitted -->
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="b6e2d6c57f"><code>b6e2d6c</code></a>
Release trash v3.3.1</li>
<li><a
href="98049f1316"><code>98049f1</code></a>
fix: Use <code>AtomicI32</code> instead of I64 for compatibility with
<code>armel</code> (<a
href="https://redirect.github.com/ArturKovacs/trash/issues/99">#99</a>)</li>
<li><a
href="d0d8f26030"><code>d0d8f26</code></a>
Release trash v3.3.0</li>
<li><a
href="920ff0c69f"><code>920ff0c</code></a>
fix: Use <code>AtomicI32</code> in tests for compatibility with
<code>armel</code> platform (<a
href="https://redirect.github.com/ArturKovacs/trash/issues/99">#99</a>)</li>
<li><a
href="452be8303c"><code>452be83</code></a>
feat: improved error granularity</li>
<li><a
href="2b1c9fa2a9"><code>2b1c9fa</code></a>
Removed tracing.</li>
<li><a
href="b238938d7d"><code>b238938</code></a>
Bug fix for macOS.</li>
<li><a
href="671cef91f4"><code>671cef9</code></a>
Enhanced error reporting.</li>
<li>See full diff in <a
href="https://github.com/ArturKovacs/trash/compare/v3.2.1...v3.3.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=trash&package-manager=cargo&previous-version=3.2.1&new-version=3.3.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-19 10:21:46 +08:00
d11080e9ab Bump JasonEtco/create-an-issue from 2.9.1 to 2.9.2 (#11895)
Bumps
[JasonEtco/create-an-issue](https://github.com/jasonetco/create-an-issue)
from 2.9.1 to 2.9.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/jasonetco/create-an-issue/releases">JasonEtco/create-an-issue's
releases</a>.</em></p>
<blockquote>
<h2>v2.9.2</h2>
<h2>What's Changed</h2>
<ul>
<li>readme: actions/checkout@ v2 -&gt; v3 by <a
href="https://github.com/IdiosApps"><code>@​IdiosApps</code></a> in <a
href="https://redirect.github.com/JasonEtco/create-an-issue/pull/147">JasonEtco/create-an-issue#147</a></li>
<li>Update actions version in readme and workflow file by <a
href="https://github.com/saerosV"><code>@​saerosV</code></a> in <a
href="https://redirect.github.com/JasonEtco/create-an-issue/pull/151">JasonEtco/create-an-issue#151</a></li>
<li>Use node20 by <a
href="https://github.com/parkerbxyz"><code>@​parkerbxyz</code></a> in <a
href="https://redirect.github.com/JasonEtco/create-an-issue/pull/176">JasonEtco/create-an-issue#176</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/IdiosApps"><code>@​IdiosApps</code></a>
made their first contribution in <a
href="https://redirect.github.com/JasonEtco/create-an-issue/pull/147">JasonEtco/create-an-issue#147</a></li>
<li><a href="https://github.com/saerosV"><code>@​saerosV</code></a> made
their first contribution in <a
href="https://redirect.github.com/JasonEtco/create-an-issue/pull/151">JasonEtco/create-an-issue#151</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/JasonEtco/create-an-issue/compare/v2.9.1...v2.9.2">https://github.com/JasonEtco/create-an-issue/compare/v2.9.1...v2.9.2</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="1b14a70e4d"><code>1b14a70</code></a>
Automatic compilation</li>
<li><a
href="56fdd2d6f9"><code>56fdd2d</code></a>
Merge pull request <a
href="https://redirect.github.com/jasonetco/create-an-issue/issues/176">#176</a>
from parkerbxyz/node20</li>
<li><a
href="c92e5306fc"><code>c92e530</code></a>
<code>@tsconfig/node-lts</code> →
<code>@tsconfig/recommended</code></li>
<li><a
href="d2f7266772"><code>d2f7266</code></a>
Update TSConfig to use node-lts</li>
<li><a
href="d0732be86a"><code>d0732be</code></a>
Update ci.yml to use node20</li>
<li><a
href="c0e947f6a6"><code>c0e947f</code></a>
Update action.yml to use node20</li>
<li><a
href="ee46187b30"><code>ee46187</code></a>
Merge pull request <a
href="https://redirect.github.com/jasonetco/create-an-issue/issues/151">#151</a>
from saerosV/main</li>
<li><a
href="6d783382d3"><code>6d78338</code></a>
Update setup-node action version</li>
<li><a
href="f6aae5d93f"><code>f6aae5d</code></a>
Update Checkout action version</li>
<li><a
href="bf328b8b59"><code>bf328b8</code></a>
Merge pull request <a
href="https://redirect.github.com/jasonetco/create-an-issue/issues/147">#147</a>
from IdiosApps/patch-1</li>
<li>Additional commits viewable in <a
href="https://github.com/jasonetco/create-an-issue/compare/v2.9.1...v2.9.2">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=JasonEtco/create-an-issue&package-manager=github_actions&previous-version=2.9.1&new-version=2.9.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-19 10:05:16 +08:00
a4ef7c1ac4 Bump fancy-regex from 0.12.0 to 0.13.0 (#11893)
[//]: # (dependabot-start)
⚠️  **Dependabot is rebasing this PR** ⚠️ 

Rebasing might not happen immediately, so don't worry if this takes some
time.

Note: if you make any changes to this PR yourself, they will take
precedence over the rebase.

---

[//]: # (dependabot-end)

Bumps [fancy-regex](https://github.com/fancy-regex/fancy-regex) from
0.12.0 to 0.13.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/fancy-regex/fancy-regex/releases">fancy-regex's
releases</a>.</em></p>
<blockquote>
<h2>0.13.0</h2>
<h3>Added</h3>
<ul>
<li>Support for relative backreferences using <code>\k&lt;-1&gt;</code>
(-1 references the
previous group) (<a
href="https://redirect.github.com/fancy-regex/fancy-regex/issues/121">#121</a>)</li>
<li>Add <code>try_replacen</code> to <code>Regex</code> which returns a
<code>Result</code> instead of panicking
when matching errors (<a
href="https://redirect.github.com/fancy-regex/fancy-regex/issues/130">#130</a>)</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Switch from regex crate to regex-automata and regex-syntax (lower
level APIs)
to simplify internals (<a
href="https://redirect.github.com/fancy-regex/fancy-regex/issues/121">#121</a>)</li>
<li>Allow escaping some letters in character classes, e.g.
<code>[\A]</code> used to error
but now matches the same as <code>[A]</code> (for compatibility with
Oniguruma)</li>
<li>MSRV (minimum supported Rust version) is now 1.66.1 (from
1.61.0)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Fix index out of bounds panic when parsing unclosed <code>(?(</code>
(<a
href="https://redirect.github.com/fancy-regex/fancy-regex/issues/125">#125</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/fancy-regex/fancy-regex/blob/main/CHANGELOG.md">fancy-regex's
changelog</a>.</em></p>
<blockquote>
<h2>[0.13.0] - 2023-12-22</h2>
<h3>Added</h3>
<ul>
<li>Support for relative backreferences using <code>\k&lt;-1&gt;</code>
(-1 references the
previous group) (<a
href="https://redirect.github.com/fancy-regex/fancy-regex/issues/121">#121</a>)</li>
<li>Add <code>try_replacen</code> to <code>Regex</code> which returns a
<code>Result</code> instead of panicking
when matching errors (<a
href="https://redirect.github.com/fancy-regex/fancy-regex/issues/130">#130</a>)</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Switch from regex crate to regex-automata and regex-syntax (lower
level APIs)
to simplify internals (<a
href="https://redirect.github.com/fancy-regex/fancy-regex/issues/121">#121</a>)</li>
<li>Allow escaping some letters in character classes, e.g.
<code>[\A]</code> used to error
but now matches the same as <code>[A]</code> (for compatibility with
Oniguruma)</li>
<li>MSRV (minimum supported Rust version) is now 1.66.1 (from
1.61.0)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Fix index out of bounds panic when parsing unclosed <code>(?(</code>
(<a
href="https://redirect.github.com/fancy-regex/fancy-regex/issues/125">#125</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="bf2c807447"><code>bf2c807</code></a>
Version 0.13.0</li>
<li><a
href="7b4ad1178d"><code>7b4ad11</code></a>
Merge pull request <a
href="https://redirect.github.com/fancy-regex/fancy-regex/issues/129">#129</a>
from fancy-regex/changelog-0.13</li>
<li><a
href="8d8ea4fcf9"><code>8d8ea4f</code></a>
Document how to check matching in Oniguruma</li>
<li><a
href="1fab2c7e0b"><code>1fab2c7</code></a>
Add character class escaping change</li>
<li><a
href="2d6339584d"><code>2d63395</code></a>
Add try_replacen</li>
<li><a
href="6deb4fc1b2"><code>6deb4fc</code></a>
Prepare CHANGELOG for next release</li>
<li><a
href="c0e701f821"><code>c0e701f</code></a>
Merge pull request <a
href="https://redirect.github.com/fancy-regex/fancy-regex/issues/130">#130</a>
from kevinhu/try_replacen</li>
<li><a
href="55f6549bec"><code>55f6549</code></a>
Add try_replacen</li>
<li><a
href="8ab3a44053"><code>8ab3a44</code></a>
Merge branch 'fancy-regex:main' into main</li>
<li><a
href="494cd931c3"><code>494cd93</code></a>
Merge pull request <a
href="https://redirect.github.com/fancy-regex/fancy-regex/issues/126">#126</a>
from robertknight/patch-1</li>
<li>Additional commits viewable in <a
href="https://github.com/fancy-regex/fancy-regex/compare/0.12.0...0.13.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=fancy-regex&package-manager=cargo&previous-version=0.12.0&new-version=0.13.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-19 09:54:37 +08:00
6a1691f378 Bump miette from 7.0.0 to 7.1.0 (#11892)
Bumps [miette](https://github.com/zkat/miette) from 7.0.0 to 7.1.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/zkat/miette/releases">miette's
releases</a>.</em></p>
<blockquote>
<h2>v7.1.0</h2>
<h3>Features</h3>
<ul>
<li><strong>derive:</strong> enable more boxed types to be
#[diagnostic_source] (<a
href="https://redirect.github.com/zkat/miette/issues/338">#338</a>) (<a
href="c2f06f6cca">c2f06f6c</a>)</li>
<li><strong>source:</strong> derive common traits for NamedSource,
SourceSpan, and SourceOffset (<a
href="https://redirect.github.com/zkat/miette/issues/340">#340</a>) (<a
href="6f09250cca">6f09250c</a>)</li>
<li><strong>collection:</strong> add support for collection of labels
(<a href="https://redirect.github.com/zkat/miette/issues/341">#341</a>)
(<a
href="03060245d8">03060245</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li><strong>tests:</strong> revert test-breaking changes of e5c7ae4 (<a
href="https://redirect.github.com/zkat/miette/issues/339">#339</a>) (<a
href="6e829f8c0c">6e829f8c</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/zkat/miette/blob/main/CHANGELOG.md">miette's
changelog</a>.</em></p>
<blockquote>
<h2>7.1.0 (2024-02-16)</h2>
<h3>Features</h3>
<ul>
<li><strong>derive:</strong> enable more boxed types to be
#[diagnostic_source] (<a
href="https://redirect.github.com/zkat/miette/issues/338">#338</a>) (<a
href="c2f06f6cca">c2f06f6c</a>)</li>
<li><strong>source:</strong> derive common traits for NamedSource,
SourceSpan, and SourceOffset (<a
href="https://redirect.github.com/zkat/miette/issues/340">#340</a>) (<a
href="6f09250cca">6f09250c</a>)</li>
<li><strong>collection:</strong> add support for collection of labels
(<a href="https://redirect.github.com/zkat/miette/issues/341">#341</a>)
(<a
href="03060245d8">03060245</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li><strong>tests:</strong> revert test-breaking changes of e5c7ae4 (<a
href="https://redirect.github.com/zkat/miette/issues/339">#339</a>) (<a
href="6e829f8c0c">6e829f8c</a>)</li>
</ul>
<p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="a18a6444d9"><code>a18a644</code></a>
chore: Release</li>
<li><a
href="dc77b0cb5b"><code>dc77b0c</code></a>
docs: update changelog</li>
<li><a
href="03060245d8"><code>0306024</code></a>
feat(collection): add support for collection of labels (<a
href="https://redirect.github.com/zkat/miette/issues/341">#341</a>)</li>
<li><a
href="6f09250cca"><code>6f09250</code></a>
feat(source): derive common traits for NamedSource, SourceSpan, and
SourceOff...</li>
<li><a
href="c2f06f6cca"><code>c2f06f6</code></a>
feat(derive): enable more boxed types to be #[diagnostic_source] (<a
href="https://redirect.github.com/zkat/miette/issues/338">#338</a>)</li>
<li><a
href="6e829f8c0c"><code>6e829f8</code></a>
fix(tests): revert test-breaking changes of e5c7ae4 (<a
href="https://redirect.github.com/zkat/miette/issues/339">#339</a>)</li>
<li>See full diff in <a
href="https://github.com/zkat/miette/compare/miette-derive-v7.0.0...miette-derive-v7.1.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=miette&package-manager=cargo&previous-version=7.0.0&new-version=7.1.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-19 09:54:08 +08:00
a71abdaf15 Bump serial_test from 2.0.0 to 3.0.0 (#11890)
Bumps [serial_test](https://github.com/palfrey/serial_test) from 2.0.0
to 3.0.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/palfrey/serial_test/releases">serial_test's
releases</a>.</em></p>
<blockquote>
<h2>v3.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Multi key support <a
href="https://redirect.github.com/palfrey/serial_test/pull/102">palfrey/serial_test#102</a>
<ul>
<li>Attributes like <code>#[serial(one, two)]</code> are now supported
(for all attributes)</li>
<li>This is a breaking change, as <code>file_serial</code> paths now
need to be done separately <code>#[file_serial(key, path =&gt;
&quot;/tmp/foo&quot;)]</code></li>
</ul>
</li>
<li>Attributes at a mod-level <a
href="https://redirect.github.com/palfrey/serial_test/pull/104">palfrey/serial_test#104</a>
<ul>
<li>You can set any of the attributes on a <code>mod</code> and all
<code>#[test]</code> fn's in that mod will have the attribute
applied.</li>
</ul>
</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/palfrey/serial_test/compare/v2.0.0...v3.0.0">https://github.com/palfrey/serial_test/compare/v2.0.0...v3.0.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="bba3db847f"><code>bba3db8</code></a>
3.0.0</li>
<li><a
href="ae14645ea1"><code>ae14645</code></a>
Merge pull request <a
href="https://redirect.github.com/palfrey/serial_test/issues/104">#104</a>
from palfrey/serial-for-mod</li>
<li><a
href="0dec256fe1"><code>0dec256</code></a>
Merge branch 'main' into serial-for-mod</li>
<li><a
href="cee1dc17db"><code>cee1dc1</code></a>
Add testing and parallel to package keywords</li>
<li><a
href="2a4b641ea9"><code>2a4b641</code></a>
Merge branch 'main' into serial-for-mod</li>
<li><a
href="288d933b77"><code>288d933</code></a>
Merge pull request <a
href="https://redirect.github.com/palfrey/serial_test/issues/105">#105</a>
from palfrey/upgrade-rustix</li>
<li><a
href="cf9d7fef62"><code>cf9d7fe</code></a>
Upgrade rustix</li>
<li><a
href="a8d985d9fd"><code>a8d985d</code></a>
Replace a single-use match with if let</li>
<li><a
href="67d22ff9ee"><code>67d22ff</code></a>
Fix some clippy issues</li>
<li><a
href="ff2890d91b"><code>ff2890d</code></a>
Update docs for mod-level functionality</li>
<li>Additional commits viewable in <a
href="https://github.com/palfrey/serial_test/compare/v2.0.0...v3.0.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=serial_test&package-manager=cargo&previous-version=2.0.0&new-version=3.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-19 09:36:41 +08:00
1350f1eff7 Bump unicode-segmentation from 1.10.1 to 1.11.0 (#11891)
Bumps
[unicode-segmentation](https://github.com/unicode-rs/unicode-segmentation)
from 1.10.1 to 1.11.0.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="8b894ca626"><code>8b894ca</code></a>
Bump to 1.11.0</li>
<li><a
href="184277a5f2"><code>184277a</code></a>
Merge pull request <a
href="https://redirect.github.com/unicode-rs/unicode-segmentation/issues/130">#130</a>
from syvb/rm_old_docs</li>
<li><a
href="bfe98e4642"><code>bfe98e4</code></a>
Remove outdated documentation link in Cargo.toml</li>
<li><a
href="062c264acf"><code>062c264</code></a>
Merge pull request <a
href="https://redirect.github.com/unicode-rs/unicode-segmentation/issues/128">#128</a>
from ryanavella/master</li>
<li><a
href="6375d1e431"><code>6375d1e</code></a>
Adding missing size_hint implementations.</li>
<li><a
href="e718ec3132"><code>e718ec3</code></a>
Merge pull request <a
href="https://redirect.github.com/unicode-rs/unicode-segmentation/issues/127">#127</a>
from nicolasmendoza/docs/update-changelogs-from-v1.9....</li>
<li><a
href="e9104b117d"><code>e9104b1</code></a>
Fix: Remove duplicate changelog</li>
<li><a
href="30a3e6bab2"><code>30a3e6b</code></a>
docs: Update changelog for versions 1.9.0 to 1.10.1</li>
<li><a
href="eb794dda07"><code>eb794dd</code></a>
docs: Update changelog for versions 1.9.0 to 1.10.1</li>
<li><a
href="8d165c5842"><code>8d165c5</code></a>
Merge pull request <a
href="https://redirect.github.com/unicode-rs/unicode-segmentation/issues/126">#126</a>
from nicolasmendoza/docs/update-changelogs</li>
<li>Additional commits viewable in <a
href="https://github.com/unicode-rs/unicode-segmentation/compare/v1.10.1...v1.11.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=unicode-segmentation&package-manager=cargo&previous-version=1.10.1&new-version=1.11.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-19 09:36:31 +08:00
752d25b004 separate commandline into subcommands (#11877)
<!--
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.
-->
Related issue and PR, #11825 #11864 
This improves the signature of `commandline`.

## Before

`commandline` returns different types depending on the flags and an
aurgument.

| command | input | output | description |

|-----------------------------|---------|---------|----------------------------------------|
| `commandline` | nothing | string | get current cursor line |
| `commandline arg` | nothing | nothing | replace the cursor line with
`arg` |
| `commandline --append arg` | nothing | nothing | append `arg` to the
end of cursor line |
| `commandline --insert arg` | nothing | nothing | insert `arg` to the
position of cursor |
| `commandline --replace arg` | nothing | nothing | replace the cursor
line with `arg` |
| `commandline --cursor` | nothing | int | get current cursor position |
| `commandline --cursor pos` | nothing | nothing | set cursor position
to pos |
| `commandline --cursor-end` | nothing | nothing | set cursor position
to end |

`help commandline` shows that `commandline` accepts string as pipeline
input, but `commandline` ignores pipeline input.

```
Input/output types:
  ╭───┬─────────┬─────────╮
  │ # │  input  │ output  │
  ├───┼─────────┼─────────┤
  │ 0 │ nothing │ nothing │
  │ 1 │ string  │ string  │
  ╰───┴─────────┴─────────╯
```

671bd08bcd/crates/nu-cli/src/commands/commandline.rs (L70)

This is misleading.

Due to the change #11864 , typecheck does not work well.
https://github.com/nushell/nushell/pull/11864#discussion_r1491814054

## After

Separate `commandline` into subcommands so that each subcommands returns
the same type for the same input type.

| command | input | output | description |

|----------------------------------|---------|---------|----------------------------------------|
| `commandline` | nothing | string | get current cursor line |
| `commandline edit arg` | nothing | nothing | replace the cursor line
with `arg` |
| `commandline edit --append arg` | nothing | nothing | append `arg` to
the end of cursor line |
| `commandline edit --insert arg` | nothing | nothing | insert `arg` to
the position of cursor |
| `commandline edit --replace arg` | nothing | nothing | replace the
cursor line with `arg` |
| `commandline get-cursor` | nothing | int | get current cursor position
|
| `commandline set-cursor pos` | nothing | nothing | set cursor position
to pos |
| `commandline set-cursor --end` | nothing | nothing | set cursor
position to end |

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

# 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-02-18 16:15:59 -06:00
68fcd71898 Add Value::coerce_str (#11885)
# Description
Following #11851, this PR adds one final conversion function for
`Value`. `Value::coerce_str` takes a `&Value` and converts it to a
`Cow<str>`, creating an owned `String` for types that needed converting.
Otherwise, it returns a borrowed `str` for `String` and `Binary`
`Value`s which avoids a clone/allocation. Where possible, `coerce_str`
and `coerce_into_string` should be used instead of `coerce_string`,
since `coerce_string` always allocates a new `String`.
2024-02-18 17:47:10 +01:00
fb4251aba7 Remove Record::from_raw_cols_vals_unchecked (#11810)
# Description
Follows from #11718 and replaces all usages of
`Record::from_raw_cols_vals_unchecked` with iterator or `record!`
equivalents.
2024-02-18 14:20:22 +02:00
28f0f32ae7 Prune unused ShellError variants (#11883)
# Description
Same procedure as #11881

Remove unused variants to avoid confusion and foster better practices
around error variants.

- Remove `SE::PermissionDeniedError`
- Remove `SE::OutOfMemoryError`
- Remove `SE::DirectoryNotFoundCustom`
- Remove `SE::MoveNotPossibleSingle`
- Remove `SE::NonUnicodeInput`

# User-Facing Changes
Plugin authors may have matched against or emitted those variants
2024-02-18 15:31:36 +08:00
06c590d894 Prune unused ParseError variants (#11881)
# Description
Error variants never raised should be removed to avoid confusion and
make sure we choose the proper variants in the future

- Remove unused `ParseError::InvalidModuleFileName`
- Remove unused `ParseError::NotFound`
- Remove unused `ParseError::MissingImportPattern`
- Remove unused `ParseError::ReadingFile`


# User-Facing Changes
None for users.
Insignificant for plugin authors as they interact only with `ShellError`
2024-02-18 15:31:02 +08:00
0487e9ffcb FreeBSD compatibility patches (#11869)
# Description

nushell is verified to work on FreeBSD 14 with these patches.

What isn't supported on FreeBSD:
* the crate 'procfs' doesn't support FreeBSD yet, all functionality
depending on procfs is disabled
* several RLIMIT_* values aren't supported on FreeBSD - functions
related to these are disabled




# User-Facing Changes
n/a

# Tests + Formatting
n/a

# After Submitting
n/a

---------

Co-authored-by: sholderbach <sholderbach@users.noreply.github.com>
2024-02-17 20:04:59 +01:00
1c49ca503a Name the Value conversion functions more clearly (#11851)
# Description
This PR renames the conversion functions on `Value` to be more consistent.
It follows the Rust [API guidelines](https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv) for ad-hoc conversions.
The conversion functions on `Value` now come in a few forms:
- `coerce_{type}` takes a `&Value` and attempts to convert the value to
`type` (e.g., `i64` are converted to `f64`). This is the old behavior of
some of the `as_{type}` functions -- these functions have simply been
renamed to better reflect what they do.
- The new `as_{type}` functions take a `&Value` and returns an `Ok`
result only if the value is of `type` (no conversion is attempted). The
returned value will be borrowed if `type` is non-`Copy`, otherwise an
owned value is returned.
- `into_{type}` exists for non-`Copy` types, but otherwise does not
attempt conversion just like `as_type`. It takes an owned `Value` and
always returns an owned result.
- `coerce_into_{type}` has the same relationship with `coerce_{type}` as
`into_{type}` does with `as_{type}`.
- `to_{kind}_string`: conversion to different string formats (debug,
abbreviated, etc.). Only two of the old string conversion functions were
removed, the rest have been renamed only.
- `to_{type}`: other conversion functions. Currently, only `to_path`
exists. (And `to_string` through `Display`.)

This table summaries the above:
| Form | Cost | Input Ownership | Output Ownership | Converts `Value`
case/`type` |
| ---------------------------- | ----- | --------------- |
---------------- | -------- |
| `as_{type}` | Cheap | Borrowed | Borrowed/Owned | No |
| `into_{type}` | Cheap | Owned | Owned | No |
| `coerce_{type}` | Cheap | Borrowed | Borrowed/Owned | Yes |
| `coerce_into_{type}` | Cheap | Owned | Owned | Yes |
| `to_{kind}_string` | Expensive | Borrowed | Owned | Yes |
| `to_{type}` | Expensive | Borrowed | Owned | Yes |

# User-Facing Changes
Breaking API change for `Value` in `nu-protocol` which is exposed as
part of the plugin API.
2024-02-17 18:14:16 +00:00
360ebeb0bc update to the latest reedline and rusqlite (#11878)
# Description

This updates nushell to the latest reedline and rusqlite dependencies.

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

# 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-02-17 09:32:17 -06:00
7f1e025cc9 Bump roxmltree to 0.19 (#11876)
Manual changes to adapt to new error variants. Error text adapted from
docs.

Supersedes #11605
2024-02-17 09:07:50 -06:00
1b220815b9 Bump calamine to 0.24 (#11874)
# Description
Update `DataType` to `Data` enum due to breaking change
Supersedes #11834

# User-Facing Changes
None obvious
2024-02-17 09:05:55 -06:00
671bd08bcd Remove unnecessary engine state clone (#11872)
<!--
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.
-->

Just randomly found a redundant clone. Seems to work just fine without
it.

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

# 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-02-17 11:34:11 +02:00
bce2627e45 Fix panic in seq date (#11871)
<!--
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
Fix #11732 

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

# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->
Invalid output format causes an error, not a panic.
```nu
❯ seq date --output-format '%H-%M-%S'
Error:   × Invalid output format
   ╭─[entry #1:1:1]
 1 │ seq date --output-format '%H-%M-%S'
   · ────┬───
   ·     ╰── an error occurred when formatting an argument
   ╰────
```
# 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
> ```
-->

# 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-02-17 10:51:20 +02:00
903afda6d9 Remove required positional arg for some file system commands (#11858)
# Description
Fixes (most of) #11796. Some filesystem commands have a required
positional argument which hinders spreading rest args. This PR removes
the required positional arg from `rm`, `open`, and `touch` to be
consistent with other filesystem commands that already only have a
single rest arg (`mkdir` and `cp`).

# User-Facing Changes
`rm`, `open`, and `touch` might no longer error when they used to, but
otherwise there should be no noticeable changes.
2024-02-15 17:25:50 +00:00
317653d5d2 Bump which from 5.0.0 to 6.0.0 (#11832) 2024-02-15 14:43:56 +00:00
a20b24a712 Fix commandline --cursor to return int (#11864)
<!--
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.
-->
Fix #11825 

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

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

# 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-02-15 08:17:38 -06:00
74d62581b9 Remove list of cell path support for select and reject (#11859)
# Description
Requires each of the rest args for `select` and `reject` to be a cell
path instead of the current `oneof(cellpath, list<cellpath>`. This
simplifies the command signatures and code for `select` and `reject`.
Users can now spread lists into the rest arguments instead of providing
them as is.

For example,
```nushell
ls | select [name size]
```
must now be
```nushell
ls | select ...[name size]
```

# User-Facing Changes
Breaking change for the `select` and `reject` command signatures.
2024-02-15 07:49:48 -06:00
c68324762d Upgrade openssl-src to fix riscv64 target building error (#11861)
Upgrade openssl-src to fix riscv64 target building error
Workflow Test:
https://github.com/nushell/nightly/actions/runs/7914366860
2024-02-15 21:05:50 +08:00
525acf9d9e Ability to cast a dataframe's column to a different dtype (#11803)
Provides the ability to cast columns in dataframes, lazy dataframes, and
expressions.

<img width="587" alt="Screenshot 2024-02-14 at 13 53 01"
src="https://github.com/nushell/nushell/assets/56345/b894f746-0e37-472e-9fb0-eb6f71f2bf27">

<img width="616" alt="Screenshot 2024-02-14 at 13 52 37"
src="https://github.com/nushell/nushell/assets/56345/cf10efa7-d89c-4189-ab71-d368b2354d19">

<img width="626" alt="Screenshot 2024-02-14 at 13 54 58"
src="https://github.com/nushell/nushell/assets/56345/cd57cdf0-5096-41dd-8ab5-46e3d1e061b8">

---------

Co-authored-by: Jack Wright <jack.wright@disqo.com>
2024-02-14 18:15:00 -06:00
cb67de675e Disallow spreading lists automatically when calling externals (#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 (#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:🐚: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.
-->
2024-02-14 18:16:19 -05:00
fd7eef1499 refactor: move du from platform to filesystem (#11852)
# Description
`du` command shouldn't belong to `platform`, so I think we should move
it to `filesystem` directory
2024-02-15 06:55:21 +08:00
a603b067e5 update default_config with new defaults (#11856)
# Description

Update a few defaults.
1. use_ls_colors_completeions defaults to true.
2. make ide_menu only offer 10 completions at a time with
`max_completion_height = 10` instead of taking the entire screen.

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

# 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-02-14 13:01:27 -06:00
b0600449e5 Fixed to/from toml date format (#11846)
With this PR i try to resolve #11751 

# Description
I am rather new to Rust so if anything is not the way it should be
please let me know.

As described in the title I just fixed the date conversion in the to and
from toml commands as i thought it would be a good first issue. The
example of the original issue will now work as follows:

```
~> {date: 2024-02-02} | to toml
date = "2024-02-02T00:00:00+00:00"
~> "dob = 1979-05-27T07:32:00-08:00" | from toml
╭─────┬───────────────────────────╮
│ dob │ 44 years ago              |
╰─────┴───────────────────────────╯
```

The `from toml` command now returns a nushell date which is displayed as
`44 years ago` in this case.

# User-Facing Changes
none

# Tests + Formatting
all tests pass and formatting has been applied

---------

Co-authored-by: dannou812 <dannou281@gmail.com>
Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2024-02-14 12:13:33 -06:00
4073783d6e Fix workspace.members for dependabot (#11855)
Missed `nu-test-support` with #11387

Saw the issue on https://github.com/nushell/nushell/pull/11832/files
where `which` was not updated for `nu-test-support`
2024-02-14 17:48:46 +01:00
779a3c075e Fix error message for headers (#11809)
# Description
Fixes #11780: `headers`: incorrect error
2024-02-14 00:14:23 +00:00
d77eeeb5dd Prevent duplicate keys for lazy make (#11808)
# Description
Fixes #11755: `lazy make` also allows duplicate record keys
2024-02-14 00:00:52 +00:00
7a181960b7 Prevent duplicate records keys when decoding from nuon (#11807)
# Description
Fixes #11749: `from nuon` allows duplicate record keys
2024-02-13 23:59:14 +00:00
1bf016bae3 Simplify prompt tilde substitution (#11822)
# Description

Simplify the tilde substitution in `create_left_prompt` by using `path
relative-to`.

# User-Facing Changes

The default `env.nu` is simpler.

# Tests

I've been happily using this formulation in my prompt command for a
while now.
2024-02-13 06:28:52 -06:00
da4c918392 Bump polars from 0.36 to 0.37 (#11848)
# Description
Bump polars from 0.36 to 0.37

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

# 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-02-13 06:27:30 -06:00
db4b3a561d update to latest reedline (#11844)
# Description

This fixes a panic with the text selection.

Reference
https://github.com/nushell/reedline/pull/751
https://github.com/nushell/reedline/issues/750
https://github.com/nushell/reedline/pull/689#issuecomment-1934813606


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

# 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-02-12 13:44:09 -06:00
d74c59eace Bump libgit2-sys from 0.16.1+1.7.1 to 0.16.2+1.7.2 (#11841) 2024-02-12 16:07:12 +00:00
06b0bea77f update to latest reedline (#11840)
# Description

There have been some PRs landed in reedline so it's good to test them
and keep nushell up to date.

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

# 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-02-12 08:30:41 -06:00
3ec0655577 Bump crate-ci/typos from 1.18.0 to 1.18.2 (#11831) 2024-02-12 01:20:04 +00:00
pin
005b8b02b2 Allow building on NetBSD (#11823)
Fixes https://github.com/nushell/nushell/issues/11814
2024-02-11 08:03:17 -06:00
5042f19d1b colored file-like completions (#11702)
<!--
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.
-->

`ls` and other file completions uses `LS_COLORS`.

![maim-2024 01 31 21 34
31](https://github.com/nushell/nushell/assets/15631555/d5c3813f-77b5-4391-aa0b-4b2125e5aca5)


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

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

---------

Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2024-02-08 14:29:28 -06:00
bacc1f6317 bump cargo.toml to rust-version 1.74.1 2024-02-08 13:29:36 -06:00
5536c9c7bc bump rust toolchain to 1.74.1 (#11804)
# Description

Today rust version 1.76.0 was released so we bump nushell to 1.74.1.

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

# 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-02-08 13:25:00 -06:00
58c6fea60b Support redirect stderr and stdout+stderr with a pipe (#11708)
# Description
Close: #9673
Close: #8277
Close: #10944

This pr introduces the following syntax:
1. `e>|`, pipe stderr to next command. Example: `$env.FOO=bar nu
--testbin echo_env_stderr FOO e>| str length`
2. `o+e>|` and `e+o>|`, pipe both stdout and stderr to next command,
example: `$env.FOO=bar nu --testbin echo_env_mixed out-err FOO FOO e+o>|
str length`

Note: it only works for external commands. ~There is no different for
internal commands, that is, the following three commands do the same
things:~ Edit: it raises errors if we want to pipes for internal
commands
``` 
❯ ls e>| str length
Error:   × `e>|` only works with external streams
   ╭─[entry #1:1:1]
 1 │ ls e>| str length
   ·    ─┬─
   ·     ╰── `e>|` only works on external streams
   ╰────

❯ ls e+o>| str length
Error:   × `o+e>|` only works with external streams
   ╭─[entry #2:1:1]
 1 │ ls e+o>| str length
   ·    ──┬──
   ·      ╰── `o+e>|` only works on external streams
   ╰────
```

This can help us to avoid some strange issues like the following:

`$env.FOO=bar (nu --testbin echo_env_stderr FOO) e>| str length`

Which is hard to understand and hard to explain to users.

# User-Facing Changes
Nan

# Tests + Formatting
To be done

# After Submitting
Maybe update documentation about these syntax.
2024-02-09 01:30:46 +08:00
e7f1bf8535 Bump indexmap from 2.1.0 to 2.2.2 (#11746) 2024-02-08 12:31:41 +00:00
84517138bc Bump miette from 5.10.0 to 7.0.0 (#11788)
<!--
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

Bump miette from 5.10.0 to 7.0.0

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

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

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2024-02-07 19:26:18 -06:00
fb7f6fc08b Fix a panic when parsing empty file (#11314)
The previous implementation presumed that if files were given, they had
contents. The change makes the fallback to permanent files uniform.

Fix #11256
2024-02-07 18:47:44 -06:00
3633772d52 Upgrade hustcer/setup-nu action to v3.9 and Nu to v0.90.1 for workflows (#11792) 2024-02-08 08:41:05 +08:00
4de9a3eb34 Apply clippy fixes (#11770)
# Description
Clippy fixes for
[items_after_test_module](https://rust-lang.github.io/rust-clippy/master/index.html#/items_after_test_module)

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

# 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-02-07 18:31:03 -06:00
b2092df27e Upgrade to ratatui 0.26 (#11742)
# Description
Upgrade `ratatui` to 0.26

# User-Facing Changes
n/a
2024-02-08 08:15:45 +08:00
09f513bb53 Allow comments in match blocks (#11717)
<!--
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.
-->
Fix #9878 

# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->
Writing comments in match blocks will be allowed.

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

# 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-02-08 07:22:42 +08:00
857c522808 Fix #11750: LazyRecord error message (#11772)
# Description
Makes `LazyRecord`s have the same error message as regular `Records` for
`Value::follow_cell_path`. Fixes #11750.
2024-02-08 07:22:15 +08:00
9fa2b77611 Allow specifying a cellpath in input list to get the value to display (#11748)
# Description
When using a table (or a list of records) as input to `input list`,
allow specifying a cellpath for the field/column to use as the display
value.

For instance, at the moment, using a table as input results in the
following:

```
❯ [[name price]; [Banana 12] [Kiwi 4] [Pear 7]] | input list
> {name: Banana, price: 12}
  {name: Kiwi, price: 4}
  {name: Pear, price: 7}
```

With the new `--display` flag introduced by this PR, you can do the
following:

```
❯ [[name price]; [Banana 12] [Kiwi 4] [Pear 7]] | input list -d name
> Banana
  Kiwi
  Pear
```

Note that it doesn't change what gets returned after selecting an item:
the full row/record is still returned.

# User-Facing Changes
A new optional flag is allowed.

# Tests + Formatting

# After Submitting
2024-02-08 07:21:47 +08:00
f8a8eca836 Record cleanup (#11726)
# Description
Does a little cleanup in `record.rs`:
- Makes the `record!` macro more hygienic.
- Converts regular comments to doc comments from #11718.
- Converts the `Record` iterators to new types.
2024-02-08 06:43:12 +08:00
20aa59085b Fix file completions which contains glob pattern (#11766)
# Description
Fixes: https://github.com/nushell/nushell/issues/11762

The auto-completion is somehow annoying if a path contains a glob
pattern, let's say if user type `ls` and it auto-completes to <code>ls
`[a] bc.txt`</code>, and user can't list the file because it's backtick
quoted.

This pr is going to fix it.

# User-Facing Changes
### Before
```
❯ | ls
`[a] bc.txt`        `a bc`
```
### After
```
❯ | ls
"[a] bc.txt"        `a bc`
```
# Tests + Formatting
Done

# After Submitting
NaN
2024-02-08 06:42:50 +08:00
4b91ed57dd Enforce call stack depth limit for all calls (#11729)
# Description
Previously, only direcly-recursive calls were checked for recursion
depth. But most recursive calls in nushell are mutually recursive since
expressions like `for`, `where`, `try` and `do` all execute a separte
block.

```nushell
def f [] {
    do { f }
}
```
Calling `f` would crash nushell with a stack overflow.

I think the only general way to prevent such a stack overflow is to
enforce a maximum call stack depth instead of only disallowing directly
recursive calls.

This commit also moves that logic into `eval_call()` instead of
`eval_block()` because the recursion limit is tracked in the `Stack`,
but not all blocks are evaluated in a new stack. Incrementing the
recursion depth of the caller's stack would permanently increment that
for all future calls.

Fixes #11667

# User-Facing Changes
Any function call can now fail with `recursion_limit_reached` instead of
just directly recursive calls. Mutually-recursive calls no longer crash
nushell.

# 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-02-08 06:42:24 +08:00
366348dea0 make char command const (#11771)
# Description

This PR makes the `char` command a `const` command. The only real
changes are to get the arguments different and I extracted code into
functions so they could be called via run and run_cost. No algorithms
were harmed in the making of this PR.

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

# 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-02-07 16:29:00 -06:00
b6b36e00c6 allow ansi strip to work better on other nushell values (#11781)
# Description

This PR help `ansi strip` work on more nushell values. It does this by
converting values like filesize and dates to strings. This may not be
precisely correct but I think it does more what the user expects.

### Before

![image](https://github.com/nushell/nushell/assets/343840/768ffbb2-e3d7-424e-8e3b-1d20c9aa7d91)


### After

![image](https://github.com/nushell/nushell/assets/343840/6141aebb-481f-45a9-9cb7-084ca9ca1ea5)


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

# 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-02-07 16:28:40 -06:00
c79432f33c for ints, provide an option to convert all of them to filesizes with the into value command (#11797)
# Description

This PR allows `into value` to recognize ints and change them into file
sizes if you prefer.
### Before
```nushell
❯ free | ^column -t | lines | update 0 {$"type  ($in)"} | to text | ^column -t | detect columns | into value 
╭─#─┬─type──┬──total───┬──used───┬───free───┬shared┬buff/cache┬available─╮
│ 0 │ Mem:  │ 24614036 │ 3367680 │ 16196240 │ 3688 │  5449736 │ 21246356 │
│ 1 │ Swap: │  6291456 │       0 │  6291456 │      │          │          │
╰───┴───────┴──────────┴─────────┴──────────┴──────┴──────────┴──────────╯
```
### After
```nushell
❯ free | ^column -t | lines | update 0 {$"type  ($in)"} | to text | ^column -t | detect columns | into value --prefer-filesizes
╭─#─┬─type──┬──total──┬──used──┬──free───┬─shared─┬buff/cache┬available╮
│ 0 │ Mem:  │ 24.6 MB │ 3.4 MB │ 16.2 MB │ 3.7 KB │   5.4 MB │ 21.2 MB │
│ 1 │ Swap: │  6.3 MB │    0 B │  6.3 MB │        │          │         │
╰───┴───────┴─────────┴────────┴─────────┴────────┴──────────┴─────────╯
```
# 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 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
> ```
-->

# 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-02-07 16:28:17 -06:00
08931e976e bump to dev release of nushell 0.90.2 (#11793)
# Description

Bump nushell version to the dev version of 0.90.2

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

# 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-02-07 16:26:03 -06:00
379 changed files with 17114 additions and 7245 deletions

View File

@ -36,12 +36,10 @@ jobs:
token: ${{ secrets.WORKFLOW_TOKEN }}
- name: Setup Nushell
uses: hustcer/setup-nu@v3.8
uses: hustcer/setup-nu@v3.9
if: github.repository == 'nushell/nightly'
with:
version: 0.86.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
version: 0.90.1
# Synchronize the main branch of nightly repo with the main branch of Nushell official repo
- name: Prepare for Nightly Release
@ -81,7 +79,7 @@ jobs:
- x86_64-unknown-linux-musl
- aarch64-unknown-linux-gnu
- armv7-unknown-linux-gnueabihf
# - riscv64gc-unknown-linux-gnu
- riscv64gc-unknown-linux-gnu
extra: ['bin']
include:
- target: aarch64-apple-darwin
@ -118,9 +116,9 @@ jobs:
- target: armv7-unknown-linux-gnueabihf
os: ubuntu-20.04
target_rustflags: ''
# - target: riscv64gc-unknown-linux-gnu
# os: ubuntu-latest
# target_rustflags: ''
- target: riscv64gc-unknown-linux-gnu
os: ubuntu-latest
target_rustflags: ''
runs-on: ${{matrix.os}}
@ -141,11 +139,9 @@ jobs:
rustflags: ''
- name: Setup Nushell
uses: hustcer/setup-nu@v3.8
uses: hustcer/setup-nu@v3.9
with:
version: 0.86.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
version: 0.90.1
- name: Release Nu Binary
id: nu
@ -160,7 +156,7 @@ jobs:
- name: Create an Issue for Release Failure
if: ${{ failure() }}
uses: JasonEtco/create-an-issue@v2.9.1
uses: JasonEtco/create-an-issue@v2.9.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@ -255,11 +251,9 @@ jobs:
rustflags: ''
- name: Setup Nushell
uses: hustcer/setup-nu@v3.8
uses: hustcer/setup-nu@v3.9
with:
version: 0.86.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
version: 0.90.1
- name: Release Nu Binary
id: nu
@ -274,7 +268,7 @@ jobs:
- name: Create an Issue for Release Failure
if: ${{ failure() }}
uses: JasonEtco/create-an-issue@v2.9.1
uses: JasonEtco/create-an-issue@v2.9.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@ -321,11 +315,9 @@ jobs:
ref: main
- name: Setup Nushell
uses: hustcer/setup-nu@v3.8
uses: hustcer/setup-nu@v3.9
with:
version: 0.86.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
version: 0.90.1
# Keep the last a few releases
- name: Delete Older Releases

View File

@ -28,7 +28,7 @@ jobs:
- x86_64-unknown-linux-musl
- aarch64-unknown-linux-gnu
- armv7-unknown-linux-gnueabihf
# - riscv64gc-unknown-linux-gnu
- riscv64gc-unknown-linux-gnu
extra: ['bin']
include:
- target: aarch64-apple-darwin
@ -65,9 +65,9 @@ jobs:
- target: armv7-unknown-linux-gnueabihf
os: ubuntu-20.04
target_rustflags: ''
# - target: riscv64gc-unknown-linux-gnu
# os: ubuntu-latest
# target_rustflags: ''
- target: riscv64gc-unknown-linux-gnu
os: ubuntu-latest
target_rustflags: ''
runs-on: ${{matrix.os}}
@ -85,11 +85,9 @@ jobs:
rustflags: ''
- name: Setup Nushell
uses: hustcer/setup-nu@v3.8
uses: hustcer/setup-nu@v3.9
with:
version: 0.86.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
version: 0.90.1
- name: Release Nu Binary
id: nu
@ -176,11 +174,9 @@ jobs:
rustflags: ''
- name: Setup Nushell
uses: hustcer/setup-nu@v3.8
uses: hustcer/setup-nu@v3.9
with:
version: 0.86.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
version: 0.90.1
- name: Release Nu Binary
id: nu

View File

@ -10,6 +10,4 @@ jobs:
uses: actions/checkout@v4
- name: Check spelling
uses: crate-ci/typos@v1.18.0
with:
config: ./.github/.typos.toml
uses: crate-ci/typos@v1.19.0

673
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -10,8 +10,8 @@ homepage = "https://www.nushell.sh"
license = "MIT"
name = "nu"
repository = "https://github.com/nushell/nushell"
rust-version = "1.72.1"
version = "0.90.1"
rust-version = "1.74.1"
version = "0.91.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -43,47 +43,42 @@ members = [
"crates/nu_plugin_inc",
"crates/nu_plugin_gstat",
"crates/nu_plugin_example",
"crates/nu_plugin_stream_example",
"crates/nu_plugin_query",
"crates/nu_plugin_custom_values",
"crates/nu_plugin_formats",
"crates/nu-std",
"crates/nu-table",
"crates/nu-term-grid",
"crates/nu-test-support",
"crates/nu-utils",
]
[dependencies]
nu-cli = { path = "./crates/nu-cli", version = "0.90.1" }
nu-color-config = { path = "./crates/nu-color-config", version = "0.90.1" }
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.90.1" }
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.90.1" }
nu-cmd-dataframe = { path = "./crates/nu-cmd-dataframe", version = "0.90.1", features = [
nu-cli = { path = "./crates/nu-cli", version = "0.91.0" }
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.91.0" }
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.91.0" }
nu-cmd-dataframe = { path = "./crates/nu-cmd-dataframe", version = "0.91.0", features = [
"dataframe",
], optional = true }
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.90.1", optional = true }
nu-command = { path = "./crates/nu-command", version = "0.90.1" }
nu-engine = { path = "./crates/nu-engine", version = "0.90.1" }
nu-explore = { path = "./crates/nu-explore", version = "0.90.1" }
nu-json = { path = "./crates/nu-json", version = "0.90.1" }
nu-lsp = { path = "./crates/nu-lsp/", version = "0.90.1" }
nu-parser = { path = "./crates/nu-parser", version = "0.90.1" }
nu-path = { path = "./crates/nu-path", version = "0.90.1" }
nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.90.1" }
nu-pretty-hex = { path = "./crates/nu-pretty-hex", version = "0.90.1" }
nu-protocol = { path = "./crates/nu-protocol", version = "0.90.1" }
nu-system = { path = "./crates/nu-system", version = "0.90.1" }
nu-table = { path = "./crates/nu-table", version = "0.90.1" }
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.90.1" }
nu-std = { path = "./crates/nu-std", version = "0.90.1" }
nu-utils = { path = "./crates/nu-utils", version = "0.90.1" }
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.91.0", optional = true }
nu-command = { path = "./crates/nu-command", version = "0.91.0" }
nu-engine = { path = "./crates/nu-engine", version = "0.91.0" }
nu-explore = { path = "./crates/nu-explore", version = "0.91.0" }
nu-lsp = { path = "./crates/nu-lsp/", version = "0.91.0" }
nu-parser = { path = "./crates/nu-parser", version = "0.91.0" }
nu-path = { path = "./crates/nu-path", version = "0.91.0" }
nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.91.0" }
nu-protocol = { path = "./crates/nu-protocol", version = "0.91.0" }
nu-std = { path = "./crates/nu-std", version = "0.91.0" }
nu-utils = { path = "./crates/nu-utils", version = "0.91.0" }
nu-ansi-term = "0.50.0"
reedline = { version = "0.29.0", features = ["bashisms", "sqlite"] }
reedline = { version = "0.30.0", features = ["bashisms", "sqlite"] }
crossterm = "0.27"
ctrlc = "3.4"
log = "0.4"
miette = { version = "5.10", features = ["fancy-no-backtrace"] }
miette = { version = "7.1", features = ["fancy-no-backtrace", "fancy"] }
mimalloc = { version = "0.1.37", default-features = false, optional = true }
serde_json = "1.0"
simplelog = "0.12"
@ -105,13 +100,13 @@ nix = { version = "0.27", default-features = false, features = [
] }
[dev-dependencies]
nu-test-support = { path = "./crates/nu-test-support", version = "0.90.1" }
nu-test-support = { path = "./crates/nu-test-support", version = "0.91.0" }
assert_cmd = "2.0"
criterion = "0.5"
divan = "0.1.14"
pretty_assertions = "1.4"
rstest = { version = "0.18", default-features = false }
serial_test = "2.0"
tempfile = "3.8"
serial_test = "3.0"
tempfile = "3.10"
[features]
plugin = [
@ -183,12 +178,10 @@ bench = false
# To use a development version of a dependency please use a global override here
# changing versions in each sub-crate of the workspace is tedious
#[patch.crates-io]
#reedline = { git = "https://github.com/nushell/reedline", branch = "main" }
[patch.crates-io]
# reedline = { git = "https://github.com/nushell/reedline", branch = "main" }
# nu-ansi-term = {git = "https://github.com/nushell/nu-ansi-term.git", branch = "main"}
# uu_cp = { git = "https://github.com/uutils/coreutils.git", branch = "main" }
# Criterion benchmarking setup
# Run all benchmarks with `cargo bench`
# Run individual benchmarks like `cargo bench -- <regex>` e.g. `cargo bench -- parse`
[[bench]]

View File

@ -1,6 +1,6 @@
# Criterion benchmarks
# Divan benchmarks
These are benchmarks using [Criterion](https://github.com/bheisler/criterion.rs), a microbenchmarking tool for Rust.
These are benchmarks using [Divan](https://github.com/nvzqz/divan), a microbenchmarking tool for Rust.
Run all benchmarks with `cargo bench`

View File

@ -1,11 +1,17 @@
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
use nu_cli::eval_source;
use nu_parser::parse;
use nu_plugin::{EncodingType, PluginResponse};
use nu_protocol::{engine::EngineState, PipelineData, Span, Value};
use nu_plugin::{Encoder, EncodingType, PluginCallResponse, PluginOutput};
use nu_protocol::{
engine::EngineState, eval_const::create_nu_constant, PipelineData, Span, Value, NU_VARIABLE_ID,
};
use nu_utils::{get_default_config, get_default_env};
use std::path::{Path, PathBuf};
fn main() {
// Run registered benchmarks.
divan::main();
}
fn load_bench_commands() -> EngineState {
nu_command::add_shell_command_context(nu_cmd_lang::create_default_context())
}
@ -29,105 +35,92 @@ fn get_home_path(engine_state: &EngineState) -> PathBuf {
.unwrap_or_default()
}
fn setup_engine() -> EngineState {
let mut engine_state = load_bench_commands();
let home_path = get_home_path(&engine_state);
// parsing config.nu breaks without PWD set, so set a valid path
engine_state.add_env_var(
"PWD".into(),
Value::string(home_path.to_string_lossy(), Span::test_data()),
);
let nu_const = create_nu_constant(&engine_state, Span::unknown())
.expect("Failed to create nushell constant.");
engine_state.set_variable_const_val(NU_VARIABLE_ID, nu_const);
engine_state
}
// FIXME: All benchmarks live in this 1 file to speed up build times when benchmarking.
// When the *_benchmarks functions were in different files, `cargo bench` would build
// an executable for every single one - incredibly slowly. Would be nice to figure out
// a way to split things up again.
fn parser_benchmarks(c: &mut Criterion) {
let mut engine_state = load_bench_commands();
let home_path = get_home_path(&engine_state);
#[divan::bench_group()]
mod parser_benchmarks {
use super::*;
// parsing config.nu breaks without PWD set, so set a valid path
engine_state.add_env_var(
"PWD".into(),
Value::string(home_path.to_string_lossy(), Span::test_data()),
);
#[divan::bench()]
fn parse_default_config_file(bencher: divan::Bencher) {
let engine_state = setup_engine();
let default_env = get_default_config().as_bytes();
let default_env = get_default_env().as_bytes();
c.bench_function("parse_default_env_file", |b| {
b.iter_batched(
|| nu_protocol::engine::StateWorkingSet::new(&engine_state),
|mut working_set| parse(&mut working_set, None, default_env, false),
BatchSize::SmallInput,
)
});
bencher
.with_inputs(|| nu_protocol::engine::StateWorkingSet::new(&engine_state))
.bench_refs(|mut working_set| parse(&mut working_set, None, default_env, false))
}
let default_config = get_default_config().as_bytes();
c.bench_function("parse_default_config_file", |b| {
b.iter_batched(
|| nu_protocol::engine::StateWorkingSet::new(&engine_state),
|mut working_set| parse(&mut working_set, None, default_config, false),
BatchSize::SmallInput,
)
});
#[divan::bench()]
fn parse_default_env_file(bencher: divan::Bencher) {
let engine_state = setup_engine();
let default_env = get_default_env().as_bytes();
c.bench_function("eval default_env.nu", |b| {
b.iter(|| {
let mut stack = nu_protocol::engine::Stack::new();
eval_source(
&mut engine_state,
&mut stack,
get_default_env().as_bytes(),
"default_env.nu",
PipelineData::empty(),
false,
)
})
});
c.bench_function("eval default_config.nu", |b| {
b.iter(|| {
let mut stack = nu_protocol::engine::Stack::new();
eval_source(
&mut engine_state,
&mut stack,
get_default_config().as_bytes(),
"default_config.nu",
PipelineData::empty(),
false,
)
})
});
bencher
.with_inputs(|| nu_protocol::engine::StateWorkingSet::new(&engine_state))
.bench_refs(|mut working_set| parse(&mut working_set, None, default_env, false))
}
}
fn eval_benchmarks(c: &mut Criterion) {
let mut engine_state = load_bench_commands();
let home_path = get_home_path(&engine_state);
#[divan::bench_group()]
mod eval_benchmarks {
use super::*;
// parsing config.nu breaks without PWD set, so set a valid path
engine_state.add_env_var(
"PWD".into(),
Value::string(home_path.to_string_lossy(), Span::test_data()),
);
#[divan::bench()]
fn eval_default_env(bencher: divan::Bencher) {
let default_env = get_default_env().as_bytes();
let fname = "default_env.nu";
bencher
.with_inputs(|| (setup_engine(), nu_protocol::engine::Stack::new()))
.bench_values(|(mut engine_state, mut stack)| {
eval_source(
&mut engine_state,
&mut stack,
default_env,
fname,
PipelineData::empty(),
false,
)
})
}
c.bench_function("eval default_env.nu", |b| {
b.iter(|| {
let mut stack = nu_protocol::engine::Stack::new();
eval_source(
&mut engine_state,
&mut stack,
get_default_env().as_bytes(),
"default_env.nu",
PipelineData::empty(),
false,
)
})
});
c.bench_function("eval default_config.nu", |b| {
b.iter(|| {
let mut stack = nu_protocol::engine::Stack::new();
eval_source(
&mut engine_state,
&mut stack,
get_default_config().as_bytes(),
"default_config.nu",
PipelineData::empty(),
false,
)
})
});
#[divan::bench()]
fn eval_default_config(bencher: divan::Bencher) {
let default_env = get_default_config().as_bytes();
let fname = "default_config.nu";
bencher
.with_inputs(|| (setup_engine(), nu_protocol::engine::Stack::new()))
.bench_values(|(mut engine_state, mut stack)| {
eval_source(
&mut engine_state,
&mut stack,
default_env,
fname,
PipelineData::empty(),
false,
)
})
}
}
// generate a new table data with `row_cnt` rows, `col_cnt` columns.
@ -141,50 +134,76 @@ fn encoding_test_data(row_cnt: usize, col_cnt: usize) -> Value {
Value::list(vec![record; row_cnt], Span::test_data())
}
fn encoding_benchmarks(c: &mut Criterion) {
let mut group = c.benchmark_group("Encoding");
let test_cnt_pairs = [(100, 5), (100, 15), (10000, 5), (10000, 15)];
for (row_cnt, col_cnt) in test_cnt_pairs.into_iter() {
for fmt in ["json", "msgpack"] {
group.bench_function(&format!("{fmt} encode {row_cnt} * {col_cnt}"), |b| {
let mut res = vec![];
let test_data =
PluginResponse::Value(Box::new(encoding_test_data(row_cnt, col_cnt)));
let encoder = EncodingType::try_from_bytes(fmt.as_bytes()).unwrap();
b.iter(|| encoder.encode_response(&test_data, &mut res))
});
}
#[divan::bench_group()]
mod encoding_benchmarks {
use super::*;
#[divan::bench(args = [(100, 5), (10000, 15)])]
fn json_encode(bencher: divan::Bencher, (row_cnt, col_cnt): (usize, usize)) {
let test_data = PluginOutput::CallResponse(
0,
PluginCallResponse::value(encoding_test_data(row_cnt, col_cnt)),
);
let encoder = EncodingType::try_from_bytes(b"json").unwrap();
bencher
.with_inputs(|| (vec![]))
.bench_values(|mut res| encoder.encode(&test_data, &mut res))
}
#[divan::bench(args = [(100, 5), (10000, 15)])]
fn msgpack_encode(bencher: divan::Bencher, (row_cnt, col_cnt): (usize, usize)) {
let test_data = PluginOutput::CallResponse(
0,
PluginCallResponse::value(encoding_test_data(row_cnt, col_cnt)),
);
let encoder = EncodingType::try_from_bytes(b"msgpack").unwrap();
bencher
.with_inputs(|| (vec![]))
.bench_values(|mut res| encoder.encode(&test_data, &mut res))
}
group.finish();
}
fn decoding_benchmarks(c: &mut Criterion) {
let mut group = c.benchmark_group("Decoding");
let test_cnt_pairs = [(100, 5), (100, 15), (10000, 5), (10000, 15)];
for (row_cnt, col_cnt) in test_cnt_pairs.into_iter() {
for fmt in ["json", "msgpack"] {
group.bench_function(&format!("{fmt} decode for {row_cnt} * {col_cnt}"), |b| {
let mut res = vec![];
let test_data =
PluginResponse::Value(Box::new(encoding_test_data(row_cnt, col_cnt)));
let encoder = EncodingType::try_from_bytes(fmt.as_bytes()).unwrap();
encoder.encode_response(&test_data, &mut res).unwrap();
let mut binary_data = std::io::Cursor::new(res);
b.iter(|| {
binary_data.set_position(0);
encoder.decode_response(&mut binary_data)
})
});
}
}
group.finish();
}
#[divan::bench_group()]
mod decoding_benchmarks {
use super::*;
criterion_group!(
benches,
parser_benchmarks,
eval_benchmarks,
encoding_benchmarks,
decoding_benchmarks
);
criterion_main!(benches);
#[divan::bench(args = [(100, 5), (10000, 15)])]
fn json_decode(bencher: divan::Bencher, (row_cnt, col_cnt): (usize, usize)) {
let test_data = PluginOutput::CallResponse(
0,
PluginCallResponse::value(encoding_test_data(row_cnt, col_cnt)),
);
let encoder = EncodingType::try_from_bytes(b"json").unwrap();
let mut res = vec![];
encoder.encode(&test_data, &mut res).unwrap();
bencher
.with_inputs(|| {
let mut binary_data = std::io::Cursor::new(res.clone());
binary_data.set_position(0);
binary_data
})
.bench_values(|mut binary_data| -> Result<Option<PluginOutput>, _> {
encoder.decode(&mut binary_data)
})
}
#[divan::bench(args = [(100, 5), (10000, 15)])]
fn msgpack_decode(bencher: divan::Bencher, (row_cnt, col_cnt): (usize, usize)) {
let test_data = PluginOutput::CallResponse(
0,
PluginCallResponse::value(encoding_test_data(row_cnt, col_cnt)),
);
let encoder = EncodingType::try_from_bytes(b"msgpack").unwrap();
let mut res = vec![];
encoder.encode(&test_data, &mut res).unwrap();
bencher
.with_inputs(|| {
let mut binary_data = std::io::Cursor::new(res.clone());
binary_data.set_position(0);
binary_data
})
.bench_values(|mut binary_data| -> Result<Option<PluginOutput>, _> {
encoder.decode(&mut binary_data)
})
}
}

View File

@ -5,42 +5,43 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cli"
edition = "2021"
license = "MIT"
name = "nu-cli"
version = "0.90.1"
version = "0.91.0"
[lib]
bench = false
[dev-dependencies]
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.90.1" }
nu-command = { path = "../nu-command", version = "0.90.1" }
nu-test-support = { path = "../nu-test-support", version = "0.90.1" }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.91.0" }
nu-command = { path = "../nu-command", version = "0.91.0" }
nu-test-support = { path = "../nu-test-support", version = "0.91.0" }
rstest = { version = "0.18.1", default-features = false }
[dependencies]
nu-cmd-base = { path = "../nu-cmd-base", version = "0.90.1" }
nu-engine = { path = "../nu-engine", version = "0.90.1" }
nu-path = { path = "../nu-path", version = "0.90.1" }
nu-parser = { path = "../nu-parser", version = "0.90.1" }
nu-protocol = { path = "../nu-protocol", version = "0.90.1" }
nu-utils = { path = "../nu-utils", version = "0.90.1" }
nu-color-config = { path = "../nu-color-config", version = "0.90.1" }
nu-cmd-base = { path = "../nu-cmd-base", version = "0.91.0" }
nu-engine = { path = "../nu-engine", version = "0.91.0" }
nu-path = { path = "../nu-path", version = "0.91.0" }
nu-parser = { path = "../nu-parser", version = "0.91.0" }
nu-protocol = { path = "../nu-protocol", version = "0.91.0" }
nu-utils = { path = "../nu-utils", version = "0.91.0" }
nu-color-config = { path = "../nu-color-config", version = "0.91.0" }
nu-ansi-term = "0.50.0"
reedline = { version = "0.29.0", features = ["bashisms", "sqlite"] }
reedline = { version = "0.30.0", features = ["bashisms", "sqlite"] }
chrono = { default-features = false, features = ["std"], version = "0.4" }
crossterm = "0.27"
fancy-regex = "0.12"
fancy-regex = "0.13"
fuzzy-matcher = "0.3"
is_executable = "1.0"
log = "0.4"
miette = { version = "5.10", features = ["fancy-no-backtrace"] }
miette = { version = "7.1", features = ["fancy-no-backtrace"] }
lscolors = { version = "0.17", default-features = false, features = ["nu-ansi-term"] }
once_cell = "1.18"
percent-encoding = "2"
pathdiff = "0.2"
sysinfo = "0.30"
unicode-segmentation = "1.10"
unicode-segmentation = "1.11"
uuid = { version = "1.6.0", features = ["v4"] }
which = "5.0.0"
which = "6.0.0"
[features]
plugin = []

View File

@ -69,11 +69,23 @@ impl Command for Commandline {
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
if let Some(cmd) = call.opt::<Value>(engine_state, stack, 0)? {
let span = cmd.span();
let cmd = cmd.coerce_into_string()?;
let mut repl = engine_state.repl_state.lock().expect("repl state mutex");
if call.has_flag(engine_state, stack, "cursor")? {
let cmd_str = cmd.as_string()?;
match cmd_str.parse::<i64>() {
nu_protocol::report_error_new(
engine_state,
&ShellError::GenericError {
error: "`--cursor (-c)` is deprecated".into(),
msg: "Setting the current cursor position by `--cursor (-c)` is deprecated"
.into(),
span: Some(call.arguments_span()),
help: Some("Use `commandline set-cursor`".into()),
inner: vec![],
},
);
match cmd.parse::<i64>() {
Ok(n) => {
repl.cursor_pos = if n <= 0 {
0usize
@ -89,31 +101,79 @@ impl Command for Commandline {
return Err(ShellError::CantConvert {
to_type: "int".to_string(),
from_type: "string".to_string(),
span: cmd.span(),
help: Some(format!(
r#"string "{cmd_str}" does not represent a valid int"#
)),
span,
help: Some(format!(r#"string "{cmd}" does not represent a valid int"#)),
})
}
}
} else if call.has_flag(engine_state, stack, "append")? {
repl.buffer.push_str(&cmd.as_string()?);
nu_protocol::report_error_new(
engine_state,
&ShellError::GenericError {
error: "`--append (-a)` is deprecated".into(),
msg: "Appending the string to the end of the buffer by `--append (-a)` is deprecated".into(),
span: Some(call.arguments_span()),
help: Some("Use `commandline edit --append (-a)`".into()),
inner: vec![],
},
);
repl.buffer.push_str(&cmd);
} else if call.has_flag(engine_state, stack, "insert")? {
let cmd_str = cmd.as_string()?;
nu_protocol::report_error_new(
engine_state,
&ShellError::GenericError {
error: "`--insert (-i)` is deprecated".into(),
msg: "Inserts the string into the buffer at the cursor position by `--insert (-i)` is deprecated".into(),
span: Some(call.arguments_span()),
help: Some("Use `commandline edit --insert (-i)`".into()),
inner: vec![],
},
);
let cursor_pos = repl.cursor_pos;
repl.buffer.insert_str(cursor_pos, &cmd_str);
repl.cursor_pos += cmd_str.len();
repl.buffer.insert_str(cursor_pos, &cmd);
repl.cursor_pos += cmd.len();
} else {
repl.buffer = cmd.as_string()?;
nu_protocol::report_error_new(
engine_state,
&ShellError::GenericError {
error: "`--replace (-r)` is deprecated".into(),
msg: "Replaceing the current contents of the buffer by `--replace (-p)` or positional argument is deprecated".into(),
span: Some(call.arguments_span()),
help: Some("Use `commandline edit --replace (-r)`".into()),
inner: vec![],
},
);
repl.buffer = cmd;
repl.cursor_pos = repl.buffer.len();
}
Ok(Value::nothing(call.head).into_pipeline_data())
} else {
let mut repl = engine_state.repl_state.lock().expect("repl state mutex");
if call.has_flag(engine_state, stack, "cursor-end")? {
nu_protocol::report_error_new(
engine_state,
&ShellError::GenericError {
error: "`--cursor-end (-e)` is deprecated".into(),
msg: "Setting the current cursor position to the end of the buffer by `--cursor-end (-e)` is deprecated".into(),
span: Some(call.arguments_span()),
help: Some("Use `commandline set-cursor --end (-e)`".into()),
inner: vec![],
},
);
repl.cursor_pos = repl.buffer.len();
Ok(Value::nothing(call.head).into_pipeline_data())
} else if call.has_flag(engine_state, stack, "cursor")? {
nu_protocol::report_error_new(
engine_state,
&ShellError::GenericError {
error: "`--cursor (-c)` is deprecated".into(),
msg: "Getting the current cursor position by `--cursor (-c)` is deprecated"
.into(),
span: Some(call.arguments_span()),
help: Some("Use `commandline get-cursor`".into()),
inner: vec![],
},
);
let char_pos = repl
.buffer
.grapheme_indices(true)

View File

@ -0,0 +1,71 @@
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
};
#[derive(Clone)]
pub struct SubCommand;
impl Command for SubCommand {
fn name(&self) -> &str {
"commandline edit"
}
fn signature(&self) -> Signature {
Signature::build(self.name())
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.switch(
"append",
"appends the string to the end of the buffer",
Some('a'),
)
.switch(
"insert",
"inserts the string into the buffer at the cursor position",
Some('i'),
)
.switch(
"replace",
"replaces the current contents of the buffer (default)",
Some('r'),
)
.required(
"str",
SyntaxShape::String,
"the string to perform the operation with",
)
.category(Category::Core)
}
fn usage(&self) -> &str {
"Modify the current command line input buffer."
}
fn search_terms(&self) -> Vec<&str> {
vec!["repl", "interactive"]
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let str: String = call.req(engine_state, stack, 0)?;
let mut repl = engine_state.repl_state.lock().expect("repl state mutex");
if call.has_flag(engine_state, stack, "append")? {
repl.buffer.push_str(&str);
} else if call.has_flag(engine_state, stack, "insert")? {
let cursor_pos = repl.cursor_pos;
repl.buffer.insert_str(cursor_pos, &str);
repl.cursor_pos += str.len();
} else {
repl.buffer = str;
repl.cursor_pos = repl.buffer.len();
}
Ok(Value::nothing(call.head).into_pipeline_data())
}
}

View File

@ -0,0 +1,56 @@
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, IntoPipelineData, PipelineData, ShellError, Signature, Type, Value,
};
use unicode_segmentation::UnicodeSegmentation;
#[derive(Clone)]
pub struct SubCommand;
impl Command for SubCommand {
fn name(&self) -> &str {
"commandline get-cursor"
}
fn signature(&self) -> Signature {
Signature::build(self.name())
.input_output_types(vec![(Type::Nothing, Type::Int)])
.allow_variants_without_examples(true)
.category(Category::Core)
}
fn usage(&self) -> &str {
"Get the current cursor position."
}
fn search_terms(&self) -> Vec<&str> {
vec!["repl", "interactive"]
}
fn run(
&self,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let repl = engine_state.repl_state.lock().expect("repl state mutex");
let char_pos = repl
.buffer
.grapheme_indices(true)
.chain(std::iter::once((repl.buffer.len(), "")))
.position(|(i, _c)| i == repl.cursor_pos)
.expect("Cursor position isn't on a grapheme boundary");
match i64::try_from(char_pos) {
Ok(pos) => Ok(Value::int(pos, call.head).into_pipeline_data()),
Err(e) => Err(ShellError::GenericError {
error: "Failed to convert cursor position to int".to_string(),
msg: e.to_string(),
span: None,
help: None,
inner: vec![],
}),
}
}
}

View File

@ -0,0 +1,9 @@
mod commandline_;
mod edit;
mod get_cursor;
mod set_cursor;
pub use commandline_::Commandline;
pub use edit::SubCommand as CommandlineEdit;
pub use get_cursor::SubCommand as CommandlineGetCursor;
pub use set_cursor::SubCommand as CommandlineSetCursor;

View File

@ -0,0 +1,69 @@
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
};
use unicode_segmentation::UnicodeSegmentation;
#[derive(Clone)]
pub struct SubCommand;
impl Command for SubCommand {
fn name(&self) -> &str {
"commandline set-cursor"
}
fn signature(&self) -> Signature {
Signature::build(self.name())
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.switch(
"end",
"set the current cursor position to the end of the buffer",
Some('e'),
)
.optional("pos", SyntaxShape::Int, "Cursor position to be set")
.category(Category::Core)
}
fn usage(&self) -> &str {
"Set the current cursor position."
}
fn search_terms(&self) -> Vec<&str> {
vec!["repl", "interactive"]
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let mut repl = engine_state.repl_state.lock().expect("repl state mutex");
if let Some(pos) = call.opt::<i64>(engine_state, stack, 0)? {
repl.cursor_pos = if pos <= 0 {
0usize
} else {
repl.buffer
.grapheme_indices(true)
.map(|(i, _c)| i)
.nth(pos as usize)
.unwrap_or(repl.buffer.len())
};
Ok(Value::nothing(call.head).into_pipeline_data())
} else if call.has_flag(engine_state, stack, "end")? {
repl.cursor_pos = repl.buffer.len();
Ok(Value::nothing(call.head).into_pipeline_data())
} else {
Err(ShellError::GenericError {
error: "Required a positional argument or a flag".to_string(),
msg: "".to_string(),
span: None,
help: None,
inner: vec![],
})
}
}
}

View File

@ -14,6 +14,9 @@ pub fn add_cli_context(mut engine_state: EngineState) -> EngineState {
bind_command! {
Commandline,
CommandlineEdit,
CommandlineGetCursor,
CommandlineSetCursor,
History,
HistorySession,
Keybindings,

View File

@ -72,7 +72,7 @@ impl Command for History {
} else {
let history_reader: Option<Box<dyn ReedlineHistory>> = match history.file_format {
HistoryFileFormat::Sqlite => {
SqliteBackedHistory::with_file(history_path, None, None)
SqliteBackedHistory::with_file(history_path.clone(), None, None)
.map(|inner| {
let boxed: Box<dyn ReedlineHistory> = Box::new(inner);
boxed
@ -80,14 +80,15 @@ impl Command for History {
.ok()
}
HistoryFileFormat::PlainText => {
FileBackedHistory::with_file(history.max_size as usize, history_path)
.map(|inner| {
let boxed: Box<dyn ReedlineHistory> = Box::new(inner);
boxed
})
.ok()
}
HistoryFileFormat::PlainText => FileBackedHistory::with_file(
history.max_size as usize,
history_path.clone(),
)
.map(|inner| {
let boxed: Box<dyn ReedlineHistory> = Box::new(inner);
boxed
})
.ok(),
};
match history.file_format {
@ -107,7 +108,10 @@ impl Command for History {
)
})
})
.ok_or(ShellError::FileNotFound { span: head })?
.ok_or(ShellError::FileNotFound {
file: history_path.display().to_string(),
span: head,
})?
.into_pipeline_data(ctrlc)),
HistoryFileFormat::Sqlite => Ok(history_reader
.and_then(|h| {
@ -119,12 +123,15 @@ impl Command for History {
create_history_record(idx, entry, long, head)
})
})
.ok_or(ShellError::FileNotFound { span: head })?
.ok_or(ShellError::FileNotFound {
file: history_path.display().to_string(),
span: head,
})?
.into_pipeline_data(ctrlc)),
}
}
} else {
Err(ShellError::FileNotFound { span: head })
Err(ShellError::ConfigDirNotFound { span: Some(head) })
}
}

View File

@ -112,7 +112,7 @@ pub fn print_events(engine_state: &EngineState) -> Result<Value, ShellError> {
let o = match v {
Value::Record { val, .. } => val
.iter()
.map(|(x, y)| format!("{}: {}", x, y.into_string("", config)))
.map(|(x, y)| format!("{}: {}", x, y.to_expanded_string("", config)))
.collect::<Vec<String>>()
.join(", "),

View File

@ -6,7 +6,7 @@ mod keybindings_default;
mod keybindings_list;
mod keybindings_listen;
pub use commandline::Commandline;
pub use commandline::{Commandline, CommandlineEdit, CommandlineGetCursor, CommandlineSetCursor};
pub use history::{History, HistorySession};
pub use keybindings::Keybindings;
pub use keybindings_default::KeybindingsDefault;

View File

@ -43,9 +43,9 @@ impl CommandCompletion {
if let Some(paths) = paths {
if let Ok(paths) = paths.as_list() {
for path in paths {
let path = path.as_string().unwrap_or_default();
let path = path.coerce_str().unwrap_or_default();
if let Ok(mut contents) = std::fs::read_dir(path) {
if let Ok(mut contents) = std::fs::read_dir(path.as_ref()) {
while let Some(Ok(item)) = contents.next() {
if self.engine_state.config.max_external_completion_results
> executables.len() as i64
@ -253,7 +253,7 @@ mod command_completions_tests {
#[test]
fn test_find_non_whitespace_index() {
let commands = vec![
let commands = [
(" hello", 4),
("sudo ", 0),
(" sudo ", 2),
@ -273,7 +273,7 @@ mod command_completions_tests {
#[test]
fn test_is_last_command_passthrough() {
let commands = vec![
let commands = [
(" hello", false),
(" sudo ", true),
("sudo ", true),

View File

@ -129,6 +129,8 @@ impl NuCompleter {
for pipeline_element in pipeline.elements {
match pipeline_element {
PipelineElement::Expression(_, expr)
| PipelineElement::ErrPipedExpression(_, expr)
| PipelineElement::OutErrPipedExpression(_, expr)
| PipelineElement::Redirection(_, _, expr, _)
| PipelineElement::And(_, expr)
| PipelineElement::Or(_, expr)
@ -264,8 +266,10 @@ impl NuCompleter {
|| prev_expr_str == b"overlay use"
|| prev_expr_str == b"source-env"
{
let mut completer =
DotNuCompletion::new(self.engine_state.clone());
let mut completer = DotNuCompletion::new(
self.engine_state.clone(),
self.stack.clone(),
);
return self.process_completion(
&mut completer,
@ -276,8 +280,10 @@ impl NuCompleter {
pos,
);
} else if prev_expr_str == b"ls" {
let mut completer =
FileCompletion::new(self.engine_state.clone());
let mut completer = FileCompletion::new(
self.engine_state.clone(),
self.stack.clone(),
);
return self.process_completion(
&mut completer,
@ -311,8 +317,10 @@ impl NuCompleter {
);
}
FlatShape::Directory => {
let mut completer =
DirectoryCompletion::new(self.engine_state.clone());
let mut completer = DirectoryCompletion::new(
self.engine_state.clone(),
self.stack.clone(),
);
return self.process_completion(
&mut completer,
@ -324,8 +332,10 @@ impl NuCompleter {
);
}
FlatShape::Filepath | FlatShape::GlobPattern => {
let mut completer =
FileCompletion::new(self.engine_state.clone());
let mut completer = FileCompletion::new(
self.engine_state.clone(),
self.stack.clone(),
);
return self.process_completion(
&mut completer,
@ -372,8 +382,10 @@ impl NuCompleter {
}
// Check for file completion
let mut completer =
FileCompletion::new(self.engine_state.clone());
let mut completer = FileCompletion::new(
self.engine_state.clone(),
self.stack.clone(),
);
out = self.process_completion(
&mut completer,
&working_set,
@ -462,7 +474,7 @@ pub fn map_value_completions<'a>(
) -> Vec<Suggestion> {
list.filter_map(move |x| {
// Match for string values
if let Ok(s) = x.as_string() {
if let Ok(s) = x.coerce_string() {
return Some(Suggestion {
value: s,
description: None,
@ -495,7 +507,7 @@ pub fn map_value_completions<'a>(
// Match `value` column
if it.0 == "value" {
// Convert the value to string
if let Ok(val_str) = it.1.as_string() {
if let Ok(val_str) = it.1.coerce_string() {
// Update the suggestion value
suggestion.value = val_str;
}
@ -504,7 +516,7 @@ pub fn map_value_completions<'a>(
// Match `description` column
if it.0 == "description" {
// Convert the value to string
if let Ok(desc_str) = it.1.as_string() {
if let Ok(desc_str) = it.1.coerce_string() {
// Update the suggestion value
suggestion.description = Some(desc_str);
}
@ -552,7 +564,7 @@ mod completer_tests {
);
let mut completer = NuCompleter::new(engine_state.into(), Stack::new());
let dataset = vec![
let dataset = [
("sudo", false, "", Vec::new()),
("sudo l", true, "l", vec!["ls", "let", "lines", "loop"]),
(" sudo", false, "", Vec::new()),

View File

@ -1,6 +1,11 @@
use crate::completions::{matches, CompletionOptions};
use nu_ansi_term::Style;
use nu_engine::env_to_string;
use nu_path::home_dir;
use nu_protocol::engine::{EngineState, Stack};
use nu_protocol::{engine::StateWorkingSet, Span};
use nu_utils::get_ls_colors;
use std::ffi::OsStr;
use std::path::{is_separator, Component, Path, PathBuf, MAIN_SEPARATOR as SEP};
fn complete_rec(
@ -92,12 +97,31 @@ pub fn complete_item(
partial: &str,
cwd: &str,
options: &CompletionOptions,
) -> Vec<(nu_protocol::Span, String)> {
engine_state: &EngineState,
stack: &Stack,
) -> Vec<(nu_protocol::Span, String, Option<Style>)> {
let partial = surround_remove(partial);
let isdir = partial.ends_with(is_separator);
let cwd_pathbuf = Path::new(cwd).to_path_buf();
let ls_colors = (engine_state.config.use_ls_colors_completions
&& engine_state.config.use_ansi_coloring)
.then(|| {
let ls_colors_env_str = match stack.get_env_var(engine_state, "LS_COLORS") {
Some(v) => env_to_string("LS_COLORS", &v, engine_state, stack).ok(),
None => None,
};
get_ls_colors(ls_colors_env_str)
});
let mut original_cwd = OriginalCwd::None;
let mut components = Path::new(&partial).components().peekable();
let mut components_vec: Vec<Component> = Path::new(&partial).components().collect();
// Path components that end with a single "." get normalized away,
// so if the partial path ends in a literal "." we must add it back in manually
if partial.ends_with('.') && partial.len() > 1 {
components_vec.push(Component::Normal(OsStr::new(".")));
};
let mut components = components_vec.into_iter().peekable();
let mut cwd = match components.peek().cloned() {
Some(c @ Component::Prefix(..)) => {
// windows only by definition
@ -148,12 +172,35 @@ pub fn complete_item(
complete_rec(partial.as_slice(), &cwd, options, want_directory, isdir)
.into_iter()
.map(|p| (span, escape_path(original_cwd.apply(&p), want_directory)))
.map(|p| {
let path = original_cwd.apply(&p);
let style = ls_colors.as_ref().map(|lsc| {
lsc.style_for_path_with_metadata(
&path,
std::fs::symlink_metadata(&path).ok().as_ref(),
)
.map(lscolors::Style::to_nu_ansi_term_style)
.unwrap_or_default()
});
(span, escape_path(path, want_directory), style)
})
.collect()
}
// Fix files or folders with quotes or hashes
pub fn escape_path(path: String, dir: bool) -> String {
// make glob pattern have the highest priority.
let glob_contaminated = path.contains(['[', '*', ']', '?']);
if glob_contaminated {
return if path.contains('\'') {
// decide to use double quote, also need to escape `"` in path
// or else users can't do anything with completed path either.
format!("\"{}\"", path.replace('"', r#"\""#))
} else {
format!("'{path}'")
};
}
let filename_contaminated = !dir && path.contains(['\'', '"', ' ', '#', '(', ')']);
let dirname_contaminated = dir && path.contains(['\'', '"', ' ', '#']);
let maybe_flag = path.starts_with('-');

View File

@ -117,7 +117,7 @@ impl Completer for CustomCompletion {
},
match_algorithm: match options.get("completion_algorithm") {
Some(option) => option
.as_string()
.coerce_string()
.ok()
.and_then(|option| option.try_into().ok())
.unwrap_or(MatchAlgorithm::Prefix),

View File

@ -2,8 +2,9 @@ use crate::completions::{
completion_common::{adjust_if_intermediate, complete_item, AdjustView},
Completer, CompletionOptions, SortBy,
};
use nu_ansi_term::Style;
use nu_protocol::{
engine::{EngineState, StateWorkingSet},
engine::{EngineState, Stack, StateWorkingSet},
levenshtein_distance, Span,
};
use reedline::Suggestion;
@ -13,11 +14,15 @@ use std::sync::Arc;
#[derive(Clone)]
pub struct DirectoryCompletion {
engine_state: Arc<EngineState>,
stack: Stack,
}
impl DirectoryCompletion {
pub fn new(engine_state: Arc<EngineState>) -> Self {
Self { engine_state }
pub fn new(engine_state: Arc<EngineState>, stack: Stack) -> Self {
Self {
engine_state,
stack,
}
}
}
@ -39,12 +44,14 @@ impl Completer for DirectoryCompletion {
&prefix,
&self.engine_state.current_work_dir(),
options,
self.engine_state.as_ref(),
&self.stack,
)
.into_iter()
.map(move |x| Suggestion {
value: x.1,
description: None,
style: None,
style: x.2,
extra: None,
span: reedline::Span {
start: x.0.start - offset,
@ -113,6 +120,8 @@ pub fn directory_completion(
partial: &str,
cwd: &str,
options: &CompletionOptions,
) -> Vec<(nu_protocol::Span, String)> {
complete_item(true, span, partial, cwd, options)
engine_state: &EngineState,
stack: &Stack,
) -> Vec<(nu_protocol::Span, String, Option<Style>)> {
complete_item(true, span, partial, cwd, options, engine_state, stack)
}

View File

@ -1,6 +1,6 @@
use crate::completions::{file_path_completion, Completer, CompletionOptions, SortBy};
use nu_protocol::{
engine::{EngineState, StateWorkingSet},
engine::{EngineState, Stack, StateWorkingSet},
Span,
};
use reedline::Suggestion;
@ -12,11 +12,15 @@ use std::{
#[derive(Clone)]
pub struct DotNuCompletion {
engine_state: Arc<EngineState>,
stack: Stack,
}
impl DotNuCompletion {
pub fn new(engine_state: Arc<EngineState>) -> Self {
Self { engine_state }
pub fn new(engine_state: Arc<EngineState>, stack: Stack) -> Self {
Self {
engine_state,
stack,
}
}
}
@ -50,7 +54,7 @@ impl Completer for DotNuCompletion {
.into_iter()
.flat_map(|it| {
it.iter().map(|x| {
x.as_path()
x.to_path()
.expect("internal error: failed to convert lib path")
})
})
@ -92,7 +96,14 @@ impl Completer for DotNuCompletion {
let output: Vec<Suggestion> = search_dirs
.into_iter()
.flat_map(|search_dir| {
let completions = file_path_completion(span, &partial, &search_dir, options);
let completions = file_path_completion(
span,
&partial,
&search_dir,
options,
self.engine_state.as_ref(),
&self.stack,
);
completions
.into_iter()
.filter(move |it| {
@ -111,7 +122,7 @@ impl Completer for DotNuCompletion {
.map(move |x| Suggestion {
value: x.1,
description: None,
style: None,
style: x.2,
extra: None,
span: reedline::Span {
start: x.0.start - offset,

View File

@ -2,8 +2,9 @@ use crate::completions::{
completion_common::{adjust_if_intermediate, complete_item, AdjustView},
Completer, CompletionOptions, SortBy,
};
use nu_ansi_term::Style;
use nu_protocol::{
engine::{EngineState, StateWorkingSet},
engine::{EngineState, Stack, StateWorkingSet},
levenshtein_distance, Span,
};
use nu_utils::IgnoreCaseExt;
@ -14,11 +15,15 @@ use std::sync::Arc;
#[derive(Clone)]
pub struct FileCompletion {
engine_state: Arc<EngineState>,
stack: Stack,
}
impl FileCompletion {
pub fn new(engine_state: Arc<EngineState>) -> Self {
Self { engine_state }
pub fn new(engine_state: Arc<EngineState>, stack: Stack) -> Self {
Self {
engine_state,
stack,
}
}
}
@ -44,12 +49,14 @@ impl Completer for FileCompletion {
&prefix,
&self.engine_state.current_work_dir(),
options,
self.engine_state.as_ref(),
&self.stack,
)
.into_iter()
.map(move |x| Suggestion {
value: x.1,
description: None,
style: None,
style: x.2,
extra: None,
span: reedline::Span {
start: x.0.start - offset,
@ -118,8 +125,10 @@ pub fn file_path_completion(
partial: &str,
cwd: &str,
options: &CompletionOptions,
) -> Vec<(nu_protocol::Span, String)> {
complete_item(false, span, partial, cwd, options)
engine_state: &EngineState,
stack: &Stack,
) -> Vec<(nu_protocol::Span, String, Option<Style>)> {
complete_item(false, span, partial, cwd, options, engine_state, stack)
}
pub fn matches(partial: &str, from: &str, options: &CompletionOptions) -> bool {

View File

@ -61,17 +61,18 @@ pub fn add_plugin_file(
plugin_file: Option<Spanned<String>>,
storage_path: &str,
) {
if let Some(plugin_file) = plugin_file {
let working_set = StateWorkingSet::new(engine_state);
let cwd = working_set.get_cwd();
let working_set = StateWorkingSet::new(engine_state);
let cwd = working_set.get_cwd();
if let Some(plugin_file) = plugin_file {
if let Ok(path) = canonicalize_with(&plugin_file.item, cwd) {
engine_state.plugin_signatures = Some(path)
} else {
let e = ParseError::FileNotFound(plugin_file.item, plugin_file.span);
report_error(&working_set, &e);
}
} else if let Some(mut plugin_path) = nu_path::config_dir() {
} else if let Some(plugin_path) = nu_path::config_dir() {
let mut plugin_path = canonicalize_with(&plugin_path, cwd).unwrap_or(plugin_path);
// Path to store plugins signatures
plugin_path.push(storage_path);
plugin_path.push(PLUGIN_FILE);

View File

@ -28,7 +28,7 @@ pub fn evaluate_commands(
let (block, delta) = {
if let Some(ref t_mode) = table_mode {
let mut config = engine_state.get_config().clone();
config.table_mode = t_mode.as_string()?.parse().unwrap_or_default();
config.table_mode = t_mode.coerce_str()?.parse().unwrap_or_default();
engine_state.set_config(config);
}
@ -59,7 +59,7 @@ pub fn evaluate_commands(
Ok(pipeline_data) => {
let mut config = engine_state.get_config().clone();
if let Some(t_mode) = table_mode {
config.table_mode = t_mode.as_string()?.parse().unwrap_or_default();
config.table_mode = t_mode.coerce_str()?.parse().unwrap_or_default();
}
crate::eval_file::print_table_or_error(engine_state, stack, pipeline_data, &mut config)
}

View File

@ -256,7 +256,7 @@ fn print_or_exit(pipeline_data: PipelineData, engine_state: &mut EngineState, co
std::process::exit(1);
}
let out = item.into_string("\n", config) + "\n";
let out = item.to_expanded_string("\n", config) + "\n";
let _ = stdout_write_all_and_flush(out).map_err(|err| eprintln!("{err}"));
}
}

View File

@ -57,7 +57,7 @@ impl NuHelpCompleter {
if !sig.named.is_empty() {
long_desc.push_str(&get_flags_section(Some(&*self.0.clone()), sig, |v| {
v.into_string_parsable(", ", &self.0.config)
v.to_parsable_string(", ", &self.0.config)
}))
}
@ -73,7 +73,7 @@ impl NuHelpCompleter {
let opt_suffix = if let Some(value) = &positional.default_value {
format!(
" (optional, default: {})",
&value.into_string_parsable(", ", &self.0.config),
&value.to_parsable_string(", ", &self.0.config),
)
} else {
(" (optional)").to_string()

View File

@ -83,10 +83,12 @@ fn convert_to_suggestions(
Value::Record { val, .. } => {
let text = val
.get("value")
.and_then(|val| val.as_string().ok())
.and_then(|val| val.coerce_string().ok())
.unwrap_or_else(|| "No value key".to_string());
let description = val.get("description").and_then(|val| val.as_string().ok());
let description = val
.get("description")
.and_then(|val| val.coerce_string().ok());
let span = match val.get("span") {
Some(Value::Record { val: span, .. }) => {

View File

@ -45,10 +45,9 @@ impl Command for NuHighlight {
};
input.map(
move |x| match x.as_string() {
move |x| match x.coerce_into_string() {
Ok(line) => {
let highlights = highlighter.highlight(&line, line.len());
Value::string(highlights.render_simple(), head)
}
Err(err) => Value::error(err, head),

View File

@ -84,7 +84,7 @@ pub(crate) fn add_menus(
}
// Checking if the default menus have been added from the config file
let default_menus = vec![
let default_menus = [
("completion_menu", DEFAULT_COMPLETION_MENU),
("history_menu", DEFAULT_HISTORY_MENU),
("help_menu", DEFAULT_HELP_MENU),
@ -94,7 +94,7 @@ pub(crate) fn add_menus(
if !config
.menus
.iter()
.any(|menu| menu.name.into_string("", config) == name)
.any(|menu| menu.name.to_expanded_string("", config) == name)
{
let (block, _) = {
let mut working_set = StateWorkingSet::new(&engine_state);
@ -133,7 +133,7 @@ fn add_menu(
) -> Result<Reedline, ShellError> {
let span = menu.menu_type.span();
if let Value::Record { val, .. } = &menu.menu_type {
let layout = extract_value("layout", val, span)?.into_string("", config);
let layout = extract_value("layout", val, span)?.to_expanded_string("", config);
match layout.as_str() {
"columnar" => add_columnar_menu(line_editor, menu, engine_state, stack, config),
@ -142,14 +142,14 @@ fn add_menu(
"description" => add_description_menu(line_editor, menu, engine_state, stack, config),
_ => Err(ShellError::UnsupportedConfigValue {
expected: "columnar, list, ide or description".to_string(),
value: menu.menu_type.into_abbreviated_string(config),
value: menu.menu_type.to_abbreviated_string(config),
span: menu.menu_type.span(),
}),
}
} else {
Err(ShellError::UnsupportedConfigValue {
expected: "only record type".to_string(),
value: menu.menu_type.into_abbreviated_string(config),
value: menu.menu_type.to_abbreviated_string(config),
span: menu.menu_type.span(),
})
}
@ -181,7 +181,7 @@ pub(crate) fn add_columnar_menu(
config: &Config,
) -> Result<Reedline, ShellError> {
let span = menu.menu_type.span();
let name = menu.name.into_string("", config);
let name = menu.name.to_expanded_string("", config);
let mut columnar_menu = ColumnarMenu::default().with_name(&name);
if let Value::Record { val, .. } = &menu.menu_type {
@ -254,7 +254,7 @@ pub(crate) fn add_columnar_menu(
);
}
let marker = menu.marker.into_string("", config);
let marker = menu.marker.to_expanded_string("", config);
columnar_menu = columnar_menu.with_marker(&marker);
let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
@ -280,7 +280,7 @@ pub(crate) fn add_columnar_menu(
}
_ => Err(ShellError::UnsupportedConfigValue {
expected: "block or omitted value".to_string(),
value: menu.source.into_abbreviated_string(config),
value: menu.source.to_abbreviated_string(config),
span,
}),
}
@ -294,7 +294,7 @@ pub(crate) fn add_list_menu(
stack: &Stack,
config: &Config,
) -> Result<Reedline, ShellError> {
let name = menu.name.into_string("", config);
let name = menu.name.to_expanded_string("", config);
let mut list_menu = ListMenu::default().with_name(&name);
let span = menu.menu_type.span();
@ -336,7 +336,7 @@ pub(crate) fn add_list_menu(
);
}
let marker = menu.marker.into_string("", config);
let marker = menu.marker.to_expanded_string("", config);
list_menu = list_menu.with_marker(&marker);
let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
@ -362,7 +362,7 @@ pub(crate) fn add_list_menu(
}
_ => Err(ShellError::UnsupportedConfigValue {
expected: "block or omitted value".to_string(),
value: menu.source.into_abbreviated_string(config),
value: menu.source.to_abbreviated_string(config),
span: menu.source.span(),
}),
}
@ -377,7 +377,7 @@ pub(crate) fn add_ide_menu(
config: &Config,
) -> Result<Reedline, ShellError> {
let span = menu.menu_type.span();
let name = menu.name.into_string("", config);
let name = menu.name.to_expanded_string("", config);
let mut ide_menu = IdeMenu::default().with_name(&name);
if let Value::Record { val, .. } = &menu.menu_type {
@ -402,7 +402,7 @@ pub(crate) fn add_ide_menu(
let max_completion_height = max_completion_height.as_int()?;
ide_menu.with_max_completion_height(max_completion_height as u16)
}
Err(_) => ide_menu,
Err(_) => ide_menu.with_max_completion_height(10u16),
};
ide_menu = match extract_value("padding", val, span) {
@ -442,12 +442,12 @@ pub(crate) fn add_ide_menu(
} else {
return Err(ShellError::UnsupportedConfigValue {
expected: "bool or record".to_string(),
value: border.into_abbreviated_string(config),
value: border.to_abbreviated_string(config),
span: border.span(),
});
}
}
Err(_) => ide_menu,
Err(_) => ide_menu.with_default_border(),
};
ide_menu = match extract_value("cursor_offset", val, span) {
@ -459,21 +459,18 @@ pub(crate) fn add_ide_menu(
};
ide_menu = match extract_value("description_mode", val, span) {
Ok(description_mode) => {
let description_mode_str = description_mode.as_string()?;
match description_mode_str.as_str() {
"left" => ide_menu.with_description_mode(DescriptionMode::Left),
"right" => ide_menu.with_description_mode(DescriptionMode::Right),
"prefer_right" => ide_menu.with_description_mode(DescriptionMode::PreferRight),
_ => {
return Err(ShellError::UnsupportedConfigValue {
expected: "\"left\", \"right\" or \"prefer_right\"".to_string(),
value: description_mode.into_abbreviated_string(config),
span: description_mode.span(),
});
}
Ok(description_mode) => match description_mode.coerce_str()?.as_ref() {
"left" => ide_menu.with_description_mode(DescriptionMode::Left),
"right" => ide_menu.with_description_mode(DescriptionMode::Right),
"prefer_right" => ide_menu.with_description_mode(DescriptionMode::PreferRight),
_ => {
return Err(ShellError::UnsupportedConfigValue {
expected: "\"left\", \"right\" or \"prefer_right\"".to_string(),
value: description_mode.to_abbreviated_string(config),
span: description_mode.span(),
});
}
}
},
Err(_) => ide_menu,
};
@ -562,7 +559,7 @@ pub(crate) fn add_ide_menu(
);
}
let marker = menu.marker.into_string("", config);
let marker = menu.marker.to_expanded_string("", config);
ide_menu = ide_menu.with_marker(&marker);
let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
@ -588,7 +585,7 @@ pub(crate) fn add_ide_menu(
}
_ => Err(ShellError::UnsupportedConfigValue {
expected: "block or omitted value".to_string(),
value: menu.source.into_abbreviated_string(config),
value: menu.source.to_abbreviated_string(config),
span,
}),
}
@ -602,7 +599,7 @@ pub(crate) fn add_description_menu(
stack: &Stack,
config: &Config,
) -> Result<Reedline, ShellError> {
let name = menu.name.into_string("", config);
let name = menu.name.to_expanded_string("", config);
let mut description_menu = DescriptionMenu::default().with_name(&name);
let span = menu.menu_type.span();
@ -676,7 +673,7 @@ pub(crate) fn add_description_menu(
);
}
let marker = menu.marker.into_string("", config);
let marker = menu.marker.to_expanded_string("", config);
description_menu = description_menu.with_marker(&marker);
let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
@ -706,7 +703,7 @@ pub(crate) fn add_description_menu(
}
_ => Err(ShellError::UnsupportedConfigValue {
expected: "closure or omitted value".to_string(),
value: menu.source.into_abbreviated_string(config),
value: menu.source.to_abbreviated_string(config),
span: menu.source.span(),
}),
}
@ -845,7 +842,7 @@ fn add_keybinding(
}
v => Err(ShellError::UnsupportedConfigValue {
expected: "string or list of strings".to_string(),
value: v.into_abbreviated_string(config),
value: v.to_abbreviated_string(config),
span: v.span(),
}),
}
@ -858,7 +855,7 @@ fn add_parsed_keybinding(
) -> Result<(), ShellError> {
let modifier = match keybinding
.modifier
.into_string("", config)
.to_expanded_string("", config)
.to_ascii_lowercase()
.as_str()
{
@ -875,7 +872,7 @@ fn add_parsed_keybinding(
_ => {
return Err(ShellError::UnsupportedConfigValue {
expected: "CONTROL, SHIFT, ALT or NONE".to_string(),
value: keybinding.modifier.into_abbreviated_string(config),
value: keybinding.modifier.to_abbreviated_string(config),
span: keybinding.modifier.span(),
})
}
@ -883,7 +880,7 @@ fn add_parsed_keybinding(
let keycode = match keybinding
.keycode
.into_string("", config)
.to_expanded_string("", config)
.to_ascii_lowercase()
.as_str()
{
@ -936,7 +933,7 @@ fn add_parsed_keybinding(
_ => {
return Err(ShellError::UnsupportedConfigValue {
expected: "crossterm KeyCode".to_string(),
value: keybinding.keycode.into_abbreviated_string(config),
value: keybinding.keycode.to_abbreviated_string(config),
span: keybinding.keycode.span(),
})
}
@ -974,7 +971,10 @@ fn parse_event(value: &Value, config: &Config) -> Result<Option<ReedlineEvent>,
match value {
Value::Record { val: record, .. } => match EventType::try_from_record(record, span)? {
EventType::Send(value) => event_from_record(
value.into_string("", config).to_ascii_lowercase().as_str(),
value
.to_expanded_string("", config)
.to_ascii_lowercase()
.as_str(),
record,
config,
span,
@ -982,7 +982,10 @@ fn parse_event(value: &Value, config: &Config) -> Result<Option<ReedlineEvent>,
.map(Some),
EventType::Edit(value) => {
let edit = edit_from_record(
value.into_string("", config).to_ascii_lowercase().as_str(),
value
.to_expanded_string("", config)
.to_ascii_lowercase()
.as_str(),
record,
config,
span,
@ -1010,7 +1013,7 @@ fn parse_event(value: &Value, config: &Config) -> Result<Option<ReedlineEvent>,
}
v => Err(ShellError::UnsupportedConfigValue {
expected: "list of events".to_string(),
value: v.into_abbreviated_string(config),
value: v.to_abbreviated_string(config),
span: v.span(),
}),
},
@ -1036,7 +1039,7 @@ fn parse_event(value: &Value, config: &Config) -> Result<Option<ReedlineEvent>,
Value::Nothing { .. } => Ok(None),
v => Err(ShellError::UnsupportedConfigValue {
expected: "record or list of records, null to unbind key".to_string(),
value: v.into_abbreviated_string(config),
value: v.to_abbreviated_string(config),
span: v.span(),
}),
}
@ -1079,11 +1082,11 @@ fn event_from_record(
"openeditor" => ReedlineEvent::OpenEditor,
"menu" => {
let menu = extract_value("name", record, span)?;
ReedlineEvent::Menu(menu.into_string("", config))
ReedlineEvent::Menu(menu.to_expanded_string("", config))
}
"executehostcommand" => {
let cmd = extract_value("cmd", record, span)?;
ReedlineEvent::ExecuteHostCommand(cmd.into_string("", config))
ReedlineEvent::ExecuteHostCommand(cmd.to_expanded_string("", config))
}
v => {
return Err(ShellError::UnsupportedConfigValue {
@ -1188,7 +1191,7 @@ fn edit_from_record(
}
"insertstring" => {
let value = extract_value("value", record, span)?;
EditCommand::InsertString(value.into_string("", config))
EditCommand::InsertString(value.to_expanded_string("", config))
}
"insertnewline" => EditCommand::InsertNewline,
"backspace" => EditCommand::Backspace,
@ -1289,7 +1292,7 @@ fn edit_from_record(
fn extract_char(value: &Value, config: &Config) -> Result<char, ShellError> {
let span = value.span();
value
.into_string("", config)
.to_expanded_string("", config)
.chars()
.next()
.ok_or_else(|| ShellError::MissingConfigValue {

File diff suppressed because it is too large Load Diff

View File

@ -264,6 +264,8 @@ fn find_matching_block_end_in_block(
for e in &p.elements {
match e {
PipelineElement::Expression(_, e)
| PipelineElement::ErrPipedExpression(_, e)
| PipelineElement::OutErrPipedExpression(_, e)
| PipelineElement::Redirection(_, _, e, _)
| PipelineElement::And(_, e)
| PipelineElement::Or(_, e)

View File

@ -247,6 +247,16 @@ fn file_completions() {
// Match the results
match_suggestions(expected_paths, suggestions);
// Test completions for hidden files
let target_dir = format!("ls {}/.", folder(dir.join(".hidden_folder")));
let suggestions = completer.complete(&target_dir, target_dir.len());
let expected_paths: Vec<String> =
vec![file(dir.join(".hidden_folder").join(".hidden_subfile"))];
// Match the results
match_suggestions(expected_paths, suggestions);
}
#[test]
@ -584,6 +594,7 @@ fn file_completion_quoted() {
let suggestions = completer.complete(target_dir, target_dir.len());
let expected_paths: Vec<String> = vec![
"\'[a] bc.txt\'".to_string(),
"`--help`".to_string(),
"`-42`".to_string(),
"`-inf`".to_string(),

View File

@ -5,21 +5,17 @@ edition = "2021"
license = "MIT"
name = "nu-cmd-base"
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-base"
version = "0.90.1"
version = "0.91.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
nu-engine = { path = "../nu-engine", version = "0.90.1" }
nu-glob = { path = "../nu-glob", version = "0.90.1" }
nu-parser = { path = "../nu-parser", version = "0.90.1" }
nu-path = { path = "../nu-path", version = "0.90.1" }
nu-protocol = { path = "../nu-protocol", version = "0.90.1" }
nu-utils = { path = "../nu-utils", version = "0.90.1" }
nu-engine = { path = "../nu-engine", version = "0.91.0" }
nu-parser = { path = "../nu-parser", version = "0.91.0" }
nu-path = { path = "../nu-path", version = "0.91.0" }
nu-protocol = { path = "../nu-protocol", version = "0.91.0" }
indexmap = "2.1"
miette = "5.10.0"
indexmap = "2.2"
miette = "7.1.0"
[dev-dependencies]
nu-test-support = { path = "../nu-test-support", version = "0.90.1" }
rstest = "0.18.2"

View File

@ -150,7 +150,7 @@ pub fn eval_hook(
// If it returns true (the default if a condition block is not specified), the hook should be run.
let do_run_hook = if let Some(condition) = val.get("condition") {
let other_span = condition.span();
if let Ok(block_id) = condition.as_block() {
if let Ok(block_id) = condition.coerce_block() {
match run_hook_block(
engine_state,
stack,

View File

@ -66,7 +66,7 @@ fn get_editor_commandline(
match value {
Value::String { val, .. } if !val.is_empty() => Ok((val.to_string(), Vec::new())),
Value::List { vals, .. } if !vals.is_empty() => {
let mut editor_cmd = vals.iter().map(|l| l.as_string());
let mut editor_cmd = vals.iter().map(|l| l.coerce_string());
match editor_cmd.next().transpose()? {
Some(editor) if !editor.is_empty() => {
let params = editor_cmd.collect::<Result<_, ShellError>>()?;

View File

@ -5,7 +5,7 @@ edition = "2021"
license = "MIT"
name = "nu-cmd-dataframe"
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-dataframe"
version = "0.90.1"
version = "0.91.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -13,23 +13,23 @@ version = "0.90.1"
bench = false
[dependencies]
nu-engine = { path = "../nu-engine", version = "0.90.1" }
nu-parser = { path = "../nu-parser", version = "0.90.1" }
nu-protocol = { path = "../nu-protocol", version = "0.90.1" }
nu-engine = { path = "../nu-engine", version = "0.91.0" }
nu-parser = { path = "../nu-parser", version = "0.91.0" }
nu-protocol = { path = "../nu-protocol", version = "0.91.0" }
# Potential dependencies for extras
chrono = { version = "0.4", features = ["std", "unstable-locales"], default-features = false }
chrono-tz = "0.8"
fancy-regex = "0.12"
indexmap = { version = "2.1" }
fancy-regex = "0.13"
indexmap = { version = "2.2" }
num = { version = "0.4", optional = true }
serde = { version = "1.0", features = ["derive"] }
sqlparser = { version = "0.43", optional = true }
polars-io = { version = "0.36", features = ["avro"], optional = true }
polars-arrow = { version = "0.36", optional = true }
polars-ops = { version = "0.36", optional = true }
polars-plan = { version = "0.36", optional = true }
polars-utils = { version = "0.36", optional = true }
polars-io = { version = "0.37", features = ["avro"], optional = true }
polars-arrow = { version = "0.37", optional = true }
polars-ops = { version = "0.37", optional = true }
polars-plan = { version = "0.37", features = ["regex"], optional = true }
polars-utils = { version = "0.37", optional = true }
[dependencies.polars]
features = [
@ -63,12 +63,11 @@ features = [
"to_dummies",
]
optional = true
version = "0.36"
version = "0.37"
[features]
dataframe = ["num", "polars", "polars-io", "polars-arrow", "polars-ops", "polars-plan", "polars-utils", "sqlparser"]
default = []
[dev-dependencies]
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.90.1" }
nu-test-support = { path = "../nu-test-support", version = "0.90.1" }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.91.0" }

View File

@ -0,0 +1,201 @@
use crate::dataframe::values::{str_to_dtype, NuExpression, NuLazyFrame};
use super::super::values::NuDataFrame;
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
record, Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use polars::prelude::*;
#[derive(Clone)]
pub struct CastDF;
impl Command for CastDF {
fn name(&self) -> &str {
"dfr cast"
}
fn usage(&self) -> &str {
"Cast a column to a different dtype."
}
fn signature(&self) -> Signature {
Signature::build(self.name())
.input_output_types(vec![
(
Type::Custom("expression".into()),
Type::Custom("expression".into()),
),
(
Type::Custom("dataframe".into()),
Type::Custom("dataframe".into()),
),
])
.required(
"dtype",
SyntaxShape::String,
"The dtype to cast the column to",
)
.optional(
"column",
SyntaxShape::String,
"The column to cast. Required when used with a dataframe.",
)
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "Cast a column in a dataframe to a different dtype",
example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr cast u8 a | dfr schema",
result: Some(Value::record(
record! {
"a" => Value::string("u8", Span::test_data()),
"b" => Value::string("i64", Span::test_data()),
},
Span::test_data(),
)),
},
Example {
description: "Cast a column in a lazy dataframe to a different dtype",
example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr into-lazy | dfr cast u8 a | dfr schema",
result: Some(Value::record(
record! {
"a" => Value::string("u8", Span::test_data()),
"b" => Value::string("i64", Span::test_data()),
},
Span::test_data(),
)),
},
Example {
description: "Cast a column in a expression to a different dtype",
example: r#"[[a b]; [1 2] [1 4]] | dfr into-df | dfr group-by a | dfr agg [ (dfr col b | dfr cast u8 | dfr min | dfr as "b_min") ] | dfr schema"#,
result: None
}
]
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let value = input.into_value(call.head);
if NuLazyFrame::can_downcast(&value) {
let (dtype, column_nm) = df_args(engine_state, stack, call)?;
let df = NuLazyFrame::try_from_value(value)?;
command_lazy(call, column_nm, dtype, df)
} else if NuDataFrame::can_downcast(&value) {
let (dtype, column_nm) = df_args(engine_state, stack, call)?;
let df = NuDataFrame::try_from_value(value)?;
command_eager(call, column_nm, dtype, df)
} else {
let dtype: String = call.req(engine_state, stack, 0)?;
let dtype = str_to_dtype(&dtype, call.head)?;
let expr = NuExpression::try_from_value(value)?;
let expr: NuExpression = expr.into_polars().cast(dtype).into();
Ok(PipelineData::Value(
NuExpression::into_value(expr, call.head),
None,
))
}
}
}
fn df_args(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
) -> Result<(DataType, String), ShellError> {
let dtype = dtype_arg(engine_state, stack, call)?;
let column_nm: String =
call.opt(engine_state, stack, 1)?
.ok_or(ShellError::MissingParameter {
param_name: "column_name".into(),
span: call.head,
})?;
Ok((dtype, column_nm))
}
fn dtype_arg(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
) -> Result<DataType, ShellError> {
let dtype: String = call.req(engine_state, stack, 0)?;
str_to_dtype(&dtype, call.head)
}
fn command_lazy(
call: &Call,
column_nm: String,
dtype: DataType,
lazy: NuLazyFrame,
) -> Result<PipelineData, ShellError> {
let column = col(&column_nm).cast(dtype);
let lazy = lazy.into_polars().with_columns(&[column]);
let lazy = NuLazyFrame::new(false, lazy);
Ok(PipelineData::Value(
NuLazyFrame::into_value(lazy, call.head)?,
None,
))
}
fn command_eager(
call: &Call,
column_nm: String,
dtype: DataType,
nu_df: NuDataFrame,
) -> Result<PipelineData, ShellError> {
let mut df = nu_df.df;
let column = df
.column(&column_nm)
.map_err(|e| ShellError::GenericError {
error: format!("{e}"),
msg: "".into(),
span: Some(call.head),
help: None,
inner: vec![],
})?;
let casted = column.cast(&dtype).map_err(|e| ShellError::GenericError {
error: format!("{e}"),
msg: "".into(),
span: Some(call.head),
help: None,
inner: vec![],
})?;
let _ = df
.with_column(casted)
.map_err(|e| ShellError::GenericError {
error: format!("{e}"),
msg: "".into(),
span: Some(call.head),
help: None,
inner: vec![],
})?;
let df = NuDataFrame::new(false, df);
Ok(PipelineData::Value(df.into_value(call.head), None))
}
#[cfg(test)]
mod test {
use super::super::super::test_dataframe::test_dataframe;
use super::*;
#[test]
fn test_examples() {
test_dataframe(vec![Box::new(CastDF {})])
}
}

View File

@ -1,4 +1,5 @@
mod append;
mod cast;
mod columns;
mod drop;
mod drop_duplicates;
@ -35,6 +36,7 @@ use nu_protocol::engine::StateWorkingSet;
pub use self::open::OpenDataFrame;
pub use append::AppendDF;
pub use cast::CastDF;
pub use columns::ColumnsDF;
pub use drop::DropDF;
pub use drop_duplicates::DropDuplicates;
@ -78,6 +80,7 @@ pub fn add_eager_decls(working_set: &mut StateWorkingSet) {
// Dataframe commands
bind_command!(
AppendDF,
CastDF,
ColumnsDF,
DataTypes,
Summary,

View File

@ -154,7 +154,7 @@ fn from_parquet(
cache: true,
parallel: ParallelStrategy::Auto,
rechunk: false,
row_count: None,
row_index: None,
low_memory: false,
cloud_options: None,
use_statistics: false,
@ -252,7 +252,7 @@ fn from_ipc(
n_rows: None,
cache: true,
rechunk: false,
row_count: None,
row_index: None,
memmap: true,
};

View File

@ -3,7 +3,7 @@ use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, Record, ShellError, Signature, Span, Type, Value,
record, Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
#[derive(Clone)]
@ -33,13 +33,10 @@ impl Command for SchemaDF {
description: "Dataframe schema",
example: r#"[[a b]; [1 "foo"] [3 "bar"]] | dfr into-df | dfr schema"#,
result: Some(Value::record(
Record::from_raw_cols_vals_unchecked(
vec!["a".to_string(), "b".to_string()],
vec![
Value::string("i64", Span::test_data()),
Value::string("str", Span::test_data()),
],
),
record! {
"a" => Value::string("i64", Span::test_data()),
"b" => Value::string("str", Span::test_data()),
},
Span::test_data(),
)),
}]
@ -98,10 +95,11 @@ fn datatype_list(span: Span) -> Value {
]
.iter()
.map(|(dtype, note)| {
Value::record(Record::from_raw_cols_vals_unchecked(
vec!["dtype".to_string(), "note".to_string()],
vec![Value::string(*dtype, span), Value::string(*note, span)],
),span)
Value::record(record! {
"dtype" => Value::string(*dtype, span),
"note" => Value::string(*note, span),
},
span)
})
.collect();
Value::list(types, span)

View File

@ -148,6 +148,18 @@ impl Command for ToDataFrame {
.into_value(Span::test_data()),
),
},
Example {
description: "Convert to a dataframe and provide a schema that adds a new column",
example: r#"[[a b]; [1 "foo"] [2 "bar"]] | dfr into-df -s {a: u8, b:str, c:i64} | dfr fill-null 3"#,
result: Some(NuDataFrame::try_from_series(vec![
Series::new("a", [1u8, 2]),
Series::new("b", ["foo", "bar"]),
Series::new("c", [3i64, 3]),
], Span::test_data())
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
}
]
}
@ -163,8 +175,12 @@ impl Command for ToDataFrame {
.map(|schema| NuSchema::try_from(&schema))
.transpose()?;
NuDataFrame::try_from_iter(input.into_iter(), maybe_schema)
.map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None))
let df = NuDataFrame::try_from_iter(input.into_iter(), maybe_schema.clone())?;
Ok(PipelineData::Value(
NuDataFrame::into_value(df, call.head),
None,
))
}
}

View File

@ -86,7 +86,7 @@ impl Command for ExprConcatStr {
let value: Value = call.req(engine_state, stack, 1)?;
let expressions = NuExpression::extract_exprs(value)?;
let expr: NuExpression = concat_str(expressions, &separator).into();
let expr: NuExpression = concat_str(expressions, &separator, false).into();
Ok(PipelineData::Value(expr.into_value(call.head), None))
}

View File

@ -193,7 +193,7 @@ fn get_col_name(expr: &Expr) -> Option<String> {
| Expr::Window { .. }
| Expr::Wildcard
| Expr::RenameAlias { .. }
| Expr::Count
| Expr::Len
| Expr::Nth(_)
| Expr::SubPlan(_, _)
| Expr::Selector(_) => None,

View File

@ -20,7 +20,7 @@ use crate::dataframe::lazy::aggregate::LazyAggregate;
pub use crate::dataframe::lazy::collect::LazyCollect;
use crate::dataframe::lazy::fetch::LazyFetch;
use crate::dataframe::lazy::fill_nan::LazyFillNA;
use crate::dataframe::lazy::fill_null::LazyFillNull;
pub use crate::dataframe::lazy::fill_null::LazyFillNull;
use crate::dataframe::lazy::filter::LazyFilter;
use crate::dataframe::lazy::groupby::ToLazyGroupBy;
use crate::dataframe::lazy::join::LazyJoin;

View File

@ -6,7 +6,10 @@ use nu_protocol::{
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use polars::prelude::{IntoSeries, StringNameSpaceImpl};
use polars::{
prelude::{IntoSeries, NamedFrom, StringNameSpaceImpl},
series::Series,
};
#[derive(Clone)]
pub struct StrSlice;
@ -32,25 +35,46 @@ impl Command for StrSlice {
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Creates slices from the strings",
example: "[abcded abc321 abc123] | dfr into-df | dfr str-slice 1 --length 2",
result: Some(
NuDataFrame::try_from_columns(
vec![Column::new(
"0".to_string(),
vec![
Value::test_string("bc"),
Value::test_string("bc"),
Value::test_string("bc"),
],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
}]
vec![
Example {
description: "Creates slices from the strings",
example: "[abcded abc321 abc123] | dfr into-df | dfr str-slice 1 --length 2",
result: Some(
NuDataFrame::try_from_columns(
vec![Column::new(
"0".to_string(),
vec![
Value::test_string("bc"),
Value::test_string("bc"),
Value::test_string("bc"),
],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},
Example {
description: "Creates slices from the strings without length",
example: "[abcded abc321 abc123] | dfr into-df | dfr str-slice 1",
result: Some(
NuDataFrame::try_from_columns(
vec![Column::new(
"0".to_string(),
vec![
Value::test_string("bcded"),
Value::test_string("bc321"),
Value::test_string("bc123"),
],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},
]
}
fn run(
@ -71,9 +95,13 @@ fn command(
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let start: i64 = call.req(engine_state, stack, 0)?;
let start = Series::new("", &[start]);
let length: Option<i64> = call.get_flag(engine_state, stack, "length")?;
let length = length.map(|v| v as u64);
let length = match length {
Some(v) => Series::new("", &[v as u64]),
None => Series::new_null("", 1),
};
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let series = df.as_series(call.head)?;
@ -86,8 +114,16 @@ fn command(
inner: vec![],
})?;
let mut res = chunked.str_slice(start, length);
res.rename(series.name());
let res = chunked
.str_slice(&start, &length)
.map_err(|e| ShellError::GenericError {
error: "Dataframe Error".into(),
msg: e.to_string(),
span: Some(call.head),
help: None,
inner: vec![],
})?
.with_name(series.name());
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
.map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None))

View File

@ -5,8 +5,9 @@ use nu_protocol::{
Example, PipelineData, Span,
};
use super::eager::ToDataFrame;
use super::eager::{SchemaDF, ToDataFrame};
use super::expressions::ExprCol;
use super::lazy::LazyFillNull;
use super::lazy::{LazyCollect, ToLazyFrame};
use nu_cmd_lang::Let;
@ -36,6 +37,8 @@ pub fn build_test_engine_state(cmds: Vec<Box<dyn Command + 'static>>) -> Box<Eng
working_set.add_decl(Box::new(ToLazyFrame));
working_set.add_decl(Box::new(LazyCollect));
working_set.add_decl(Box::new(ExprCol));
working_set.add_decl(Box::new(SchemaDF));
working_set.add_decl(Box::new(LazyFillNull));
// Adding the command that is being tested to the working set
for cmd in cmds.clone() {

View File

@ -10,5 +10,5 @@ pub use nu_dataframe::{Axis, Column, NuDataFrame};
pub use nu_expression::NuExpression;
pub use nu_lazyframe::NuLazyFrame;
pub use nu_lazygroupby::NuLazyGroupBy;
pub use nu_schema::NuSchema;
pub use nu_schema::{str_to_dtype, NuSchema};
pub use nu_when::NuWhen;

View File

@ -342,7 +342,7 @@ fn typed_column_to_series(name: &str, column: TypedColumn) -> Result<Series, She
}
DataType::String => {
let series_values: Result<Vec<_>, _> =
column.values.iter().map(|v| v.as_string()).collect();
column.values.iter().map(|v| v.coerce_string()).collect();
Ok(Series::new(name, series_values?))
}
DataType::Object(_, _) => value_to_series(name, &column.values),
@ -561,7 +561,7 @@ fn input_type_list_to_series(
let value_list = v
.as_list()?
.iter()
.map(|v| v.as_string())
.map(|v| v.coerce_string())
.collect::<Result<Vec<String>, _>>()
.map_err(inconsistent_error)?;
builder.append_values_iter(value_list.iter().map(AsRef::as_ref));
@ -1033,15 +1033,14 @@ fn series_to_values(
Either::Right(it)
}
.map(|any_values| {
let vals: Result<Vec<Value>, ShellError> = any_values
let record = polar_fields
.iter()
.map(|v| any_value_to_value(v, span))
.collect();
let cols: Vec<String> = polar_fields
.iter()
.map(|field| field.name.to_string())
.collect();
let record = Record::from_raw_cols_vals_unchecked(cols, vals?);
.zip(any_values)
.map(|(field, val)| {
any_value_to_value(val, span).map(|val| (field.name.to_string(), val))
})
.collect::<Result<_, _>>()?;
Ok(Value::record(record, span))
})
.collect();
@ -1138,20 +1137,16 @@ fn any_value_to_value(any_value: &AnyValue, span: Span) -> Result<Value, ShellEr
any_value_to_value(&static_value, span)
}
AnyValue::StructOwned(struct_tuple) => {
let values: Result<Vec<Value>, ShellError> = struct_tuple
.0
.iter()
.map(|s| any_value_to_value(s, span))
.collect();
let fields = struct_tuple
let record = struct_tuple
.1
.iter()
.map(|f| f.name().to_string())
.collect();
Ok(Value::Record {
val: Record::from_raw_cols_vals_unchecked(fields, values?),
internal_span: span,
})
.zip(&struct_tuple.0)
.map(|(field, val)| {
any_value_to_value(val, span).map(|val| (field.name.to_string(), val))
})
.collect::<Result<_, _>>()?;
Ok(Value::record(record, span))
}
AnyValue::StringOwned(s) => Ok(Value::string(s.to_string(), span)),
AnyValue::Binary(bytes) => Ok(Value::binary(*bytes, span)),
@ -1426,7 +1421,7 @@ mod tests {
let test_int_arr = PrimitiveArray::from([Some(1_i32)]);
let test_bool_arr = BooleanArray::from([Some(true)]);
let test_struct_arr = StructArray::new(
DataType::Struct(fields.clone()).to_arrow(),
DataType::Struct(fields.clone()).to_arrow(true),
vec![Box::new(test_int_arr), Box::new(test_bool_arr)],
None,
);

View File

@ -9,9 +9,10 @@ pub use operations::Axis;
use indexmap::map::IndexMap;
use nu_protocol::{did_you_mean, PipelineData, Record, ShellError, Span, Value};
use polars::prelude::{DataFrame, DataType, IntoLazy, LazyFrame, PolarsObject, Series};
use polars_plan::prelude::{lit, Expr, Null};
use polars_utils::total_ord::TotalEq;
use serde::{Deserialize, Serialize};
use std::{cmp::Ordering, fmt::Display, hash::Hasher};
use std::{cmp::Ordering, collections::HashSet, fmt::Display, hash::Hasher};
use super::{nu_schema::NuSchema, utils::DEFAULT_ROWS, NuLazyFrame};
@ -154,15 +155,13 @@ impl NuDataFrame {
match value {
Value::CustomValue { .. } => return Self::try_from_value(value),
Value::List { vals, .. } => {
let cols = (0..vals.len())
.map(|i| format!("{i}"))
.collect::<Vec<String>>();
let record = vals
.into_iter()
.enumerate()
.map(|(i, val)| (format!("{i}"), val))
.collect();
conversion::insert_record(
&mut column_values,
Record::from_raw_cols_vals_unchecked(cols, vals),
&maybe_schema,
)?
conversion::insert_record(&mut column_values, record, &maybe_schema)?
}
Value::Record { val: record, .. } => {
conversion::insert_record(&mut column_values, record, &maybe_schema)?
@ -174,7 +173,8 @@ impl NuDataFrame {
}
}
conversion::from_parsed_columns(column_values)
let df = conversion::from_parsed_columns(column_values)?;
add_missing_columns(df, &maybe_schema, Span::unknown())
}
pub fn try_from_series(columns: Vec<Series>, span: Span) -> Result<Self, ShellError> {
@ -202,7 +202,8 @@ impl NuDataFrame {
}
}
conversion::from_parsed_columns(column_values)
let df = conversion::from_parsed_columns(column_values)?;
add_missing_columns(df, &maybe_schema, Span::unknown())
}
pub fn fill_list_nan(list: Vec<Value>, list_span: Span, fill: Value) -> Value {
@ -512,3 +513,44 @@ impl NuDataFrame {
NuSchema::new(self.df.schema())
}
}
fn add_missing_columns(
df: NuDataFrame,
maybe_schema: &Option<NuSchema>,
span: Span,
) -> Result<NuDataFrame, ShellError> {
// If there are fields that are in the schema, but not in the dataframe
// add them to the dataframe.
if let Some(schema) = maybe_schema {
let fields = df.df.fields();
let df_field_names: HashSet<&str> = fields.iter().map(|f| f.name().as_str()).collect();
let missing: Vec<(&str, &DataType)> = schema
.schema
.iter()
.filter_map(|(name, dtype)| {
let name = name.as_str();
if !df_field_names.contains(name) {
Some((name, dtype))
} else {
None
}
})
.collect();
let missing_exprs: Vec<Expr> = missing
.iter()
.map(|(name, dtype)| lit(Null {}).cast((*dtype).to_owned()).alias(name))
.collect();
let df = if !missing.is_empty() {
let with_columns = df.lazy().with_columns(missing_exprs);
NuLazyFrame::new(true, with_columns).collect(span)?
} else {
df
};
Ok(df)
} else {
Ok(df)
}
}

View File

@ -252,7 +252,7 @@ pub fn expr_to_value(expr: &Expr, span: Span) -> Result<Value, ShellError> {
span,
))
}
Expr::Count => Ok(Value::record(
Expr::Len => Ok(Value::record(
record! { "expr" => Value::string("count", span) },
span,
)),

View File

@ -1,6 +1,6 @@
use std::sync::Arc;
use nu_protocol::{Record, ShellError, Span, Value};
use nu_protocol::{ShellError, Span, Value};
use polars::prelude::{DataType, Field, Schema, SchemaRef, TimeUnit};
#[derive(Debug, Clone)]
@ -37,15 +37,14 @@ impl From<NuSchema> for SchemaRef {
}
fn fields_to_value(fields: impl Iterator<Item = Field>, span: Span) -> Value {
let (cols, vals) = fields
let record = fields
.map(|field| {
let val = dtype_to_value(field.data_type(), span);
let col = field.name().to_string();
let val = dtype_to_value(field.data_type(), span);
(col, val)
})
.unzip();
.collect();
let record = Record::from_raw_cols_vals_unchecked(cols, vals);
Value::record(record, Span::unknown())
}
@ -73,7 +72,7 @@ fn value_to_fields(value: &Value, span: Span) -> Result<Vec<Field>, ShellError>
Ok(Field::new(col, dtype))
}
_ => {
let dtype = dtype_str_to_schema(&val.as_string()?, span)?;
let dtype = str_to_dtype(&val.coerce_string()?, span)?;
Ok(Field::new(col, dtype))
}
})
@ -81,7 +80,7 @@ fn value_to_fields(value: &Value, span: Span) -> Result<Vec<Field>, ShellError>
Ok(fields)
}
fn dtype_str_to_schema(dtype: &str, span: Span) -> Result<DataType, ShellError> {
pub fn str_to_dtype(dtype: &str, span: Span) -> Result<DataType, ShellError> {
match dtype {
"bool" => Ok(DataType::Boolean),
"u8" => Ok(DataType::UInt8),
@ -107,7 +106,7 @@ fn dtype_str_to_schema(dtype: &str, span: Span) -> Result<DataType, ShellError>
.trim_start_matches('<')
.trim_end_matches('>')
.trim();
let dtype = dtype_str_to_schema(dtype, span)?;
let dtype = str_to_dtype(dtype, span)?;
Ok(DataType::List(Box::new(dtype)))
}
_ if dtype.starts_with("datetime") => {
@ -188,42 +187,23 @@ fn str_to_time_unit(ts_string: &str, span: Span) -> Result<TimeUnit, ShellError>
#[cfg(test)]
mod test {
use nu_protocol::record;
use super::*;
#[test]
fn test_value_to_schema() {
let value = Value::Record {
val: Record::from_raw_cols_vals_unchecked(
vec!["name".into(), "age".into(), "address".into()],
vec![
Value::String {
val: "str".into(),
internal_span: Span::test_data(),
},
Value::String {
val: "i32".into(),
internal_span: Span::test_data(),
},
Value::Record {
val: Record::from_raw_cols_vals_unchecked(
vec!["street".into(), "city".into()],
vec![
Value::String {
val: "str".into(),
internal_span: Span::test_data(),
},
Value::String {
val: "str".into(),
internal_span: Span::test_data(),
},
],
),
internal_span: Span::test_data(),
},
],
),
internal_span: Span::test_data(),
let address = record! {
"street" => Value::test_string("str"),
"city" => Value::test_string("str"),
};
let value = Value::test_record(record! {
"name" => Value::test_string("str"),
"age" => Value::test_string("i32"),
"address" => Value::test_record(address)
});
let schema = value_to_schema(&value, Span::unknown()).unwrap();
let expected = Schema::from_iter(vec![
Field::new("name", DataType::String),
@ -242,82 +222,82 @@ mod test {
#[test]
fn test_dtype_str_to_schema_simple_types() {
let dtype = "bool";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::Boolean;
assert_eq!(schema, expected);
let dtype = "u8";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::UInt8;
assert_eq!(schema, expected);
let dtype = "u16";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::UInt16;
assert_eq!(schema, expected);
let dtype = "u32";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::UInt32;
assert_eq!(schema, expected);
let dtype = "u64";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::UInt64;
assert_eq!(schema, expected);
let dtype = "i8";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::Int8;
assert_eq!(schema, expected);
let dtype = "i16";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::Int16;
assert_eq!(schema, expected);
let dtype = "i32";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::Int32;
assert_eq!(schema, expected);
let dtype = "i64";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::Int64;
assert_eq!(schema, expected);
let dtype = "str";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::String;
assert_eq!(schema, expected);
let dtype = "binary";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::Binary;
assert_eq!(schema, expected);
let dtype = "date";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::Date;
assert_eq!(schema, expected);
let dtype = "time";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::Time;
assert_eq!(schema, expected);
let dtype = "null";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::Null;
assert_eq!(schema, expected);
let dtype = "unknown";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::Unknown;
assert_eq!(schema, expected);
let dtype = "object";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::Object("unknown", None);
assert_eq!(schema, expected);
}
@ -325,54 +305,54 @@ mod test {
#[test]
fn test_dtype_str_schema_datetime() {
let dtype = "datetime<ms, *>";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::Datetime(TimeUnit::Milliseconds, None);
assert_eq!(schema, expected);
let dtype = "datetime<us, *>";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::Datetime(TimeUnit::Microseconds, None);
assert_eq!(schema, expected);
let dtype = "datetime<μs, *>";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::Datetime(TimeUnit::Microseconds, None);
assert_eq!(schema, expected);
let dtype = "datetime<ns, *>";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::Datetime(TimeUnit::Nanoseconds, None);
assert_eq!(schema, expected);
let dtype = "datetime<ms, UTC>";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::Datetime(TimeUnit::Milliseconds, Some("UTC".into()));
assert_eq!(schema, expected);
let dtype = "invalid";
let schema = dtype_str_to_schema(dtype, Span::unknown());
let schema = str_to_dtype(dtype, Span::unknown());
assert!(schema.is_err())
}
#[test]
fn test_dtype_str_schema_duration() {
let dtype = "duration<ms>";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::Duration(TimeUnit::Milliseconds);
assert_eq!(schema, expected);
let dtype = "duration<us>";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::Duration(TimeUnit::Microseconds);
assert_eq!(schema, expected);
let dtype = "duration<μs>";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::Duration(TimeUnit::Microseconds);
assert_eq!(schema, expected);
let dtype = "duration<ns>";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::Duration(TimeUnit::Nanoseconds);
assert_eq!(schema, expected);
}
@ -380,17 +360,17 @@ mod test {
#[test]
fn test_dtype_str_to_schema_list_types() {
let dtype = "list<i32>";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::List(Box::new(DataType::Int32));
assert_eq!(schema, expected);
let dtype = "list<duration<ms>>";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::List(Box::new(DataType::Duration(TimeUnit::Milliseconds)));
assert_eq!(schema, expected);
let dtype = "list<datetime<ms, *>>";
let schema = dtype_str_to_schema(dtype, Span::unknown()).unwrap();
let schema = str_to_dtype(dtype, Span::unknown()).unwrap();
let expected = DataType::List(Box::new(DataType::Datetime(TimeUnit::Milliseconds, None)));
assert_eq!(schema, expected);
}

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.90.1"
version = "0.91.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -13,30 +13,30 @@ version = "0.90.1"
bench = false
[dependencies]
nu-engine = { path = "../nu-engine", version = "0.90.1" }
nu-parser = { path = "../nu-parser", version = "0.90.1" }
nu-protocol = { path = "../nu-protocol", version = "0.90.1" }
nu-cmd-base = { path = "../nu-cmd-base", version = "0.90.1" }
nu-utils = { path = "../nu-utils", version = "0.90.1" }
nu-engine = { path = "../nu-engine", version = "0.91.0" }
nu-parser = { path = "../nu-parser", version = "0.91.0" }
nu-protocol = { path = "../nu-protocol", version = "0.91.0" }
nu-cmd-base = { path = "../nu-cmd-base", version = "0.91.0" }
nu-utils = { path = "../nu-utils", version = "0.91.0" }
# Potential dependencies for extras
heck = "0.4.1"
num-traits = "0.2"
ahash = "0.8.3"
nu-ansi-term = "0.50.0"
fancy-regex = "0.12.0"
fancy-regex = "0.13.0"
rust-embed = "8.2.0"
serde = "1.0.164"
nu-pretty-hex = { version = "0.90.1", path = "../nu-pretty-hex" }
nu-json = { version = "0.90.1", path = "../nu-json" }
nu-pretty-hex = { version = "0.91.0", path = "../nu-pretty-hex" }
nu-json = { version = "0.91.0", path = "../nu-json" }
serde_urlencoded = "0.7.1"
v_htmlescape = "0.15.0"
itertools = "0.12"
[features]
extra = ["default"]
default = []
[dev-dependencies]
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.90.1" }
nu-command = { path = "../nu-command", version = "0.90.1" }
nu-test-support = { path = "../nu-test-support", version = "0.90.1" }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.91.0" }
nu-command = { path = "../nu-command", version = "0.91.0" }
nu-test-support = { path = "../nu-test-support", version = "0.91.0" }

View File

@ -1,8 +1,9 @@
use super::binary_op;
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Type, Value,
};
#[derive(Clone)]
@ -17,17 +18,32 @@ impl Command for BitsAnd {
Signature::build("bits and")
.input_output_types(vec![
(Type::Int, Type::Int),
(Type::Binary, Type::Binary),
(
Type::List(Box::new(Type::Int)),
Type::List(Box::new(Type::Int)),
),
(
Type::List(Box::new(Type::Binary)),
Type::List(Box::new(Type::Binary)),
),
])
.required("target", SyntaxShape::Int, "target int to perform bit and")
.required(
"target",
SyntaxShape::OneOf(vec![SyntaxShape::Binary, SyntaxShape::Int]),
"right-hand side of the operation",
)
.named(
"endian",
SyntaxShape::String,
"byte encode endian, available options: native(default), little, big",
Some('e'),
)
.category(Category::Bits)
}
fn usage(&self) -> &str {
"Performs bitwise and for ints."
"Performs bitwise and for ints or binary values."
}
fn search_terms(&self) -> Vec<&str> {
@ -42,14 +58,32 @@ impl Command for BitsAnd {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let head = call.head;
let target: i64 = call.req(engine_state, stack, 0)?;
let target: Value = call.req(engine_state, stack, 0)?;
let endian = call.get_flag::<Spanned<String>>(engine_state, stack, "endian")?;
let little_endian = if let Some(endian) = endian {
match endian.item.as_str() {
"native" => cfg!(target_endian = "little"),
"little" => true,
"big" => false,
_ => {
return Err(ShellError::TypeMismatch {
err_message: "Endian must be one of native, little, big".to_string(),
span: endian.span,
})
}
}
} else {
cfg!(target_endian = "little")
};
// This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) {
return Err(ShellError::PipelineEmpty { dst_span: head });
}
input.map(
move |value| operate(value, target, head),
move |value| binary_op(&value, &target, little_endian, |(l, r)| l & r, head),
engine_state.ctrlc.clone(),
)
}
@ -57,40 +91,47 @@ impl Command for BitsAnd {
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "Apply bits and to two numbers",
description: "Apply bitwise and to two numbers",
example: "2 | bits and 2",
result: Some(Value::test_int(2)),
},
Example {
description: "Apply logical and to a list of numbers",
description: "Apply bitwise and to two binary values",
example: "0x[ab cd] | bits and 0x[99 99]",
result: Some(Value::test_binary([0x89, 0x89])),
},
Example {
description: "Apply bitwise and to a list of numbers",
example: "[4 3 2] | bits and 2",
result: Some(Value::list(
vec![Value::test_int(0), Value::test_int(2), Value::test_int(2)],
Span::test_data(),
)),
result: Some(Value::test_list(vec![
Value::test_int(0),
Value::test_int(2),
Value::test_int(2),
])),
},
Example {
description: "Apply bitwise and to a list of binary data",
example: "[0x[7f ff] 0x[ff f0]] | bits and 0x[99 99]",
result: Some(Value::test_list(vec![
Value::test_binary([0x19, 0x99]),
Value::test_binary([0x99, 0x90]),
])),
},
Example {
description:
"Apply bitwise and to binary data of varying lengths with specified endianness",
example: "0x[c0 ff ee] | bits and 0x[ff] --endian big",
result: Some(Value::test_binary(vec![0x00, 0x00, 0xee])),
},
Example {
description: "Apply bitwise and to input binary data smaller than the operand",
example: "0x[ff] | bits and 0x[12 34 56] --endian little",
result: Some(Value::test_binary(vec![0x12, 0x00, 0x00])),
},
]
}
}
fn operate(value: Value, target: i64, head: Span) -> Value {
let span = value.span();
match value {
Value::Int { val, .. } => Value::int(val & target, span),
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value,
other => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "int".into(),
wrong_type: other.get_type().to_string(),
dst_span: head,
src_span: other.span(),
},
head,
),
}
}
#[cfg(test)]
mod test {
use super::*;

View File

@ -13,6 +13,7 @@ pub use and::BitsAnd;
pub use bits_::Bits;
pub use into::BitsInto;
pub use not::BitsNot;
use nu_protocol::{ShellError, Value};
pub use or::BitsOr;
pub use rotate_left::BitsRol;
pub use rotate_right::BitsRor;
@ -20,7 +21,8 @@ pub use shift_left::BitsShl;
pub use shift_right::BitsShr;
pub use xor::BitsXor;
use nu_protocol::Spanned;
use nu_protocol::{Span, Spanned};
use std::iter;
#[derive(Clone, Copy)]
enum NumberBytes {
@ -29,7 +31,6 @@ enum NumberBytes {
Four,
Eight,
Auto,
Invalid,
}
#[derive(Clone, Copy)]
@ -44,17 +45,22 @@ enum InputNumType {
SignedEight,
}
fn get_number_bytes(number_bytes: Option<&Spanned<String>>) -> NumberBytes {
match number_bytes.as_ref() {
None => NumberBytes::Eight,
Some(size) => match size.item.as_str() {
"1" => NumberBytes::One,
"2" => NumberBytes::Two,
"4" => NumberBytes::Four,
"8" => NumberBytes::Eight,
"auto" => NumberBytes::Auto,
_ => NumberBytes::Invalid,
},
fn get_number_bytes(
number_bytes: Option<Spanned<usize>>,
head: Span,
) -> Result<NumberBytes, ShellError> {
match number_bytes {
None => Ok(NumberBytes::Auto),
Some(Spanned { item: 1, .. }) => Ok(NumberBytes::One),
Some(Spanned { item: 2, .. }) => Ok(NumberBytes::Two),
Some(Spanned { item: 4, .. }) => Ok(NumberBytes::Four),
Some(Spanned { item: 8, .. }) => Ok(NumberBytes::Eight),
Some(Spanned { span, .. }) => Err(ShellError::UnsupportedInput {
msg: "Only 1, 2, 4, or 8 bytes are supported as word sizes".to_string(),
input: "value originates from here".to_string(),
msg_span: head,
input_span: span,
}),
}
}
@ -76,7 +82,6 @@ fn get_input_num_type(val: i64, signed: bool, number_size: NumberBytes) -> Input
InputNumType::SignedEight
}
}
NumberBytes::Invalid => InputNumType::SignedFour,
}
} else {
match number_size {
@ -95,7 +100,68 @@ fn get_input_num_type(val: i64, signed: bool, number_size: NumberBytes) -> Input
InputNumType::Eight
}
}
NumberBytes::Invalid => InputNumType::Four,
}
}
}
fn binary_op<F>(lhs: &Value, rhs: &Value, little_endian: bool, f: F, head: Span) -> Value
where
F: Fn((i64, i64)) -> i64,
{
let span = lhs.span();
match (lhs, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
Value::int(f((*lhs, *rhs)), span)
}
(Value::Binary { val: lhs, .. }, Value::Binary { val: rhs, .. }) => {
let (lhs, rhs, max_len, min_len) = match (lhs.len(), rhs.len()) {
(max, min) if max > min => (lhs, rhs, max, min),
(min, max) => (rhs, lhs, max, min),
};
let pad = iter::repeat(0).take(max_len - min_len);
let mut a;
let mut b;
let padded: &mut dyn Iterator<Item = u8> = if little_endian {
a = rhs.iter().copied().chain(pad);
&mut a
} else {
b = pad.chain(rhs.iter().copied());
&mut b
};
let bytes: Vec<u8> = lhs
.iter()
.copied()
.zip(padded)
.map(|(lhs, rhs)| f((lhs as i64, rhs as i64)) as u8)
.collect();
Value::binary(bytes, span)
}
(Value::Binary { .. }, Value::Int { .. }) | (Value::Int { .. }, Value::Binary { .. }) => {
Value::error(
ShellError::PipelineMismatch {
exp_input_type: "input, and argument, to be both int or both binary"
.to_string(),
dst_span: rhs.span(),
src_span: span,
},
span,
)
}
// Propagate errors by explicitly matching them before the final case.
(e @ Value::Error { .. }, _) | (_, e @ Value::Error { .. }) => e.clone(),
(other, Value::Int { .. } | Value::Binary { .. }) | (_, other) => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "int or binary".into(),
wrong_type: other.get_type().to_string(),
dst_span: head,
src_span: other.span(),
},
span,
),
}
}

View File

@ -1,6 +1,7 @@
use super::{get_number_bytes, NumberBytes};
use nu_cmd_base::input_handler::{operate, CmdArgument};
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::ast::{Call, CellPath};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
@ -9,6 +10,18 @@ use nu_protocol::{
#[derive(Clone)]
pub struct BitsNot;
#[derive(Clone, Copy)]
struct Arguments {
signed: bool,
number_size: NumberBytes,
}
impl CmdArgument for Arguments {
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
None
}
}
impl Command for BitsNot {
fn name(&self) -> &str {
"bits not"
@ -18,10 +31,15 @@ impl Command for BitsNot {
Signature::build("bits not")
.input_output_types(vec![
(Type::Int, Type::Int),
(Type::Binary, Type::Binary),
(
Type::List(Box::new(Type::Int)),
Type::List(Box::new(Type::Int)),
),
(
Type::List(Box::new(Type::Binary)),
Type::List(Box::new(Type::Binary)),
),
])
.allow_variants_without_examples(true)
.switch(
@ -31,7 +49,7 @@ impl Command for BitsNot {
)
.named(
"number-bytes",
SyntaxShape::String,
SyntaxShape::Int,
"the size of unsigned number in bytes, it can be 1, 2, 4, 8, auto",
Some('n'),
)
@ -55,28 +73,21 @@ impl Command for BitsNot {
) -> Result<PipelineData, ShellError> {
let head = call.head;
let signed = call.has_flag(engine_state, stack, "signed")?;
let number_bytes: Option<Spanned<String>> =
let number_bytes: Option<Spanned<usize>> =
call.get_flag(engine_state, stack, "number-bytes")?;
let bytes_len = get_number_bytes(number_bytes.as_ref());
if let NumberBytes::Invalid = bytes_len {
if let Some(val) = number_bytes {
return Err(ShellError::UnsupportedInput {
msg: "Only 1, 2, 4, 8, or 'auto' bytes are supported as word sizes".to_string(),
input: "value originates from here".to_string(),
msg_span: head,
input_span: val.span,
});
}
}
let number_size = get_number_bytes(number_bytes, head)?;
// This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) {
return Err(ShellError::PipelineEmpty { dst_span: head });
}
input.map(
move |value| operate(value, head, signed, bytes_len),
engine_state.ctrlc.clone(),
)
let args = Arguments {
signed,
number_size,
};
operate(action, args, input, head, engine_state.ctrlc.clone())
}
fn examples(&self) -> Vec<Example> {
@ -86,9 +97,9 @@ impl Command for BitsNot {
example: "[4 3 2] | bits not",
result: Some(Value::list(
vec![
Value::test_int(140737488355323),
Value::test_int(140737488355324),
Value::test_int(140737488355325),
Value::test_int(251),
Value::test_int(252),
Value::test_int(253),
],
Span::test_data(),
)),
@ -96,7 +107,7 @@ impl Command for BitsNot {
Example {
description:
"Apply logical negation to a list of numbers, treat input as 2 bytes number",
example: "[4 3 2] | bits not --number-bytes '2'",
example: "[4 3 2] | bits not --number-bytes 2",
result: Some(Value::list(
vec![
Value::test_int(65531),
@ -119,14 +130,23 @@ impl Command for BitsNot {
Span::test_data(),
)),
},
Example {
description: "Apply logical negation to binary data",
example: "0x[ff 00 7f] | bits not",
result: Some(Value::binary(vec![0x00, 0xff, 0x80], Span::test_data())),
},
]
}
}
fn operate(value: Value, head: Span, signed: bool, number_size: NumberBytes) -> Value {
let span = value.span();
match value {
fn action(input: &Value, args: &Arguments, span: Span) -> Value {
let Arguments {
signed,
number_size,
} = *args;
match input {
Value::Int { val, .. } => {
let val = *val;
if signed || val < 0 {
Value::int(!val, span)
} else {
@ -147,25 +167,24 @@ fn operate(value: Value, head: Span, signed: bool, number_size: NumberBytes) ->
!val & 0x7F_FF_FF_FF_FF_FF
}
}
// This case shouldn't happen here, as it's handled before
Invalid => 0,
};
Value::int(out_val, span)
}
}
other => match other {
// Propagate errors inside the value
Value::Error { .. } => other,
_ => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "int".into(),
wrong_type: other.get_type().to_string(),
dst_span: head,
src_span: other.span(),
},
head,
),
},
Value::Binary { val, .. } => {
Value::binary(val.iter().copied().map(|b| !b).collect::<Vec<_>>(), span)
}
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => input.clone(),
other => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "int or binary".into(),
wrong_type: other.get_type().to_string(),
dst_span: other.span(),
src_span: span,
},
span,
),
}
}

View File

@ -1,8 +1,9 @@
use super::binary_op;
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Type, Value,
};
#[derive(Clone)]
@ -17,17 +18,33 @@ impl Command for BitsOr {
Signature::build("bits or")
.input_output_types(vec![
(Type::Int, Type::Int),
(Type::Binary, Type::Binary),
(
Type::List(Box::new(Type::Int)),
Type::List(Box::new(Type::Int)),
),
(
Type::List(Box::new(Type::Binary)),
Type::List(Box::new(Type::Binary)),
),
])
.required("target", SyntaxShape::Int, "target int to perform bit or")
.allow_variants_without_examples(true)
.required(
"target",
SyntaxShape::OneOf(vec![SyntaxShape::Binary, SyntaxShape::Int]),
"right-hand side of the operation",
)
.named(
"endian",
SyntaxShape::String,
"byte encode endian, available options: native(default), little, big",
Some('e'),
)
.category(Category::Bits)
}
fn usage(&self) -> &str {
"Performs bitwise or for ints."
"Performs bitwise or for ints or binary values."
}
fn search_terms(&self) -> Vec<&str> {
@ -42,14 +59,32 @@ impl Command for BitsOr {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let head = call.head;
let target: i64 = call.req(engine_state, stack, 0)?;
let target: Value = call.req(engine_state, stack, 0)?;
let endian = call.get_flag::<Spanned<String>>(engine_state, stack, "endian")?;
let little_endian = if let Some(endian) = endian {
match endian.item.as_str() {
"native" => cfg!(target_endian = "little"),
"little" => true,
"big" => false,
_ => {
return Err(ShellError::TypeMismatch {
err_message: "Endian must be one of native, little, big".to_string(),
span: endian.span,
})
}
}
} else {
cfg!(target_endian = "little")
};
// This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) {
return Err(ShellError::PipelineEmpty { dst_span: head });
}
input.map(
move |value| operate(value, target, head),
move |value| binary_op(&value, &target, little_endian, |(l, r)| l | r, head),
engine_state.ctrlc.clone(),
)
}
@ -62,35 +97,34 @@ impl Command for BitsOr {
result: Some(Value::test_int(6)),
},
Example {
description: "Apply logical or to a list of numbers",
description: "Apply bitwise or to a list of numbers",
example: "[8 3 2] | bits or 2",
result: Some(Value::list(
vec![Value::test_int(10), Value::test_int(3), Value::test_int(2)],
Span::test_data(),
)),
result: Some(Value::test_list(vec![
Value::test_int(10),
Value::test_int(3),
Value::test_int(2),
])),
},
Example {
description: "Apply bitwise or to binary data",
example: "0x[88 cc] | bits or 0x[42 32]",
result: Some(Value::test_binary(vec![0xca, 0xfe])),
},
Example {
description:
"Apply bitwise or to binary data of varying lengths with specified endianness",
example: "0x[c0 ff ee] | bits or 0x[ff] --endian big",
result: Some(Value::test_binary(vec![0xc0, 0xff, 0xff])),
},
Example {
description: "Apply bitwise or to input binary data smaller than the operor",
example: "0x[ff] | bits or 0x[12 34 56] --endian little",
result: Some(Value::test_binary(vec![0xff, 0x34, 0x56])),
},
]
}
}
fn operate(value: Value, target: i64, head: Span) -> Value {
let span = value.span();
match value {
Value::Int { val, .. } => Value::int(val | target, span),
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value,
other => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "int".into(),
wrong_type: other.get_type().to_string(),
dst_span: head,
src_span: other.span(),
},
head,
),
}
}
#[cfg(test)]
mod test {
use super::*;

View File

@ -1,12 +1,26 @@
use super::{get_input_num_type, get_number_bytes, InputNumType, NumberBytes};
use itertools::Itertools;
use nu_cmd_base::input_handler::{operate, CmdArgument};
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::ast::CellPath;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::Spanned;
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use num_traits::int::PrimInt;
use std::fmt::Display;
struct Arguments {
signed: bool,
bits: usize,
number_size: NumberBytes,
}
impl CmdArgument for Arguments {
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
None
}
}
#[derive(Clone)]
pub struct BitsRol;
@ -20,11 +34,17 @@ impl Command for BitsRol {
Signature::build("bits rol")
.input_output_types(vec![
(Type::Int, Type::Int),
(Type::Binary, Type::Binary),
(
Type::List(Box::new(Type::Int)),
Type::List(Box::new(Type::Int)),
),
(
Type::List(Box::new(Type::Binary)),
Type::List(Box::new(Type::Binary)),
),
])
.allow_variants_without_examples(true)
.required("bits", SyntaxShape::Int, "number of bits to rotate left")
.switch(
"signed",
@ -33,7 +53,7 @@ impl Command for BitsRol {
)
.named(
"number-bytes",
SyntaxShape::String,
SyntaxShape::Int,
"the word size in number of bytes, it can be 1, 2, 4, 8, auto, default value `8`",
Some('n'),
)
@ -41,7 +61,7 @@ impl Command for BitsRol {
}
fn usage(&self) -> &str {
"Bitwise rotate left for ints."
"Bitwise rotate left for ints or binary values."
}
fn search_terms(&self) -> Vec<&str> {
@ -58,27 +78,22 @@ impl Command for BitsRol {
let head = call.head;
let bits: usize = call.req(engine_state, stack, 0)?;
let signed = call.has_flag(engine_state, stack, "signed")?;
let number_bytes: Option<Spanned<String>> =
let number_bytes: Option<Spanned<usize>> =
call.get_flag(engine_state, stack, "number-bytes")?;
let bytes_len = get_number_bytes(number_bytes.as_ref());
if let NumberBytes::Invalid = bytes_len {
if let Some(val) = number_bytes {
return Err(ShellError::UnsupportedInput {
msg: "Only 1, 2, 4, 8, or 'auto' bytes are supported as word sizes".to_string(),
input: "value originates from here".to_string(),
msg_span: head,
input_span: val.span,
});
}
}
let number_size = get_number_bytes(number_bytes, head)?;
// This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) {
return Err(ShellError::PipelineEmpty { dst_span: head });
}
input.map(
move |value| operate(value, bits, head, signed, bytes_len),
engine_state.ctrlc.clone(),
)
let args = Arguments {
signed,
number_size,
bits,
};
operate(action, args, input, head, engine_state.ctrlc.clone())
}
fn examples(&self) -> Vec<Example> {
@ -96,61 +111,82 @@ impl Command for BitsRol {
Span::test_data(),
)),
},
Example {
description: "rotate left binary data",
example: "0x[c0 ff ee] | bits rol 10",
result: Some(Value::binary(vec![0xff, 0xbb, 0x03], Span::test_data())),
},
]
}
}
fn get_rotate_left<T: Display + PrimInt>(val: T, bits: u32, span: Span) -> Value
where
i64: std::convert::TryFrom<T>,
{
let rotate_result = i64::try_from(val.rotate_left(bits));
match rotate_result {
Ok(val) => Value::int(val, span),
Err(_) => Value::error(
ShellError::GenericError {
error: "Rotate left result beyond the range of 64 bit signed number".into(),
msg: format!(
"{val} of the specified number of bytes rotate left {bits} bits exceed limit"
),
span: Some(span),
help: None,
inner: vec![],
},
span,
),
}
}
fn action(input: &Value, args: &Arguments, span: Span) -> Value {
let Arguments {
signed,
number_size,
bits,
} = *args;
fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: NumberBytes) -> Value {
let span = value.span();
match value {
match input {
Value::Int { val, .. } => {
use InputNumType::*;
// let bits = (((bits % 64) + 64) % 64) as u32;
let val = *val;
let bits = bits as u32;
let input_type = get_input_num_type(val, signed, number_size);
match input_type {
One => get_rotate_left(val as u8, bits, span),
Two => get_rotate_left(val as u16, bits, span),
Four => get_rotate_left(val as u32, bits, span),
Eight => get_rotate_left(val as u64, bits, span),
SignedOne => get_rotate_left(val as i8, bits, span),
SignedTwo => get_rotate_left(val as i16, bits, span),
SignedFour => get_rotate_left(val as i32, bits, span),
SignedEight => get_rotate_left(val, bits, span),
}
let input_num_type = get_input_num_type(val, signed, number_size);
let int = match input_num_type {
One => (val as u8).rotate_left(bits) as i64,
Two => (val as u16).rotate_left(bits) as i64,
Four => (val as u32).rotate_left(bits) as i64,
Eight => {
let Ok(i) = i64::try_from((val as u64).rotate_left(bits)) else {
return Value::error(
ShellError::GenericError {
error: "result out of range for specified number".into(),
msg: format!(
"rotating left by {bits} is out of range for the value {val}"
),
span: Some(span),
help: None,
inner: vec![],
},
span,
);
};
i
}
SignedOne => (val as i8).rotate_left(bits) as i64,
SignedTwo => (val as i16).rotate_left(bits) as i64,
SignedFour => (val as i32).rotate_left(bits) as i64,
SignedEight => val.rotate_left(bits),
};
Value::int(int, span)
}
Value::Binary { val, .. } => {
let byte_shift = bits / 8;
let bit_rotate = bits % 8;
let mut bytes = val
.iter()
.copied()
.circular_tuple_windows::<(u8, u8)>()
.map(|(lhs, rhs)| (lhs << bit_rotate) | (rhs >> (8 - bit_rotate)))
.collect::<Vec<u8>>();
bytes.rotate_left(byte_shift);
Value::binary(bytes, span)
}
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value,
Value::Error { .. } => input.clone(),
other => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "int".into(),
exp_input_type: "int or binary".into(),
wrong_type: other.get_type().to_string(),
dst_span: head,
dst_span: span,
src_span: other.span(),
},
head,
span,
),
}
}

View File

@ -1,12 +1,26 @@
use super::{get_input_num_type, get_number_bytes, InputNumType, NumberBytes};
use itertools::Itertools;
use nu_cmd_base::input_handler::{operate, CmdArgument};
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::ast::CellPath;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::Spanned;
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use num_traits::int::PrimInt;
use std::fmt::Display;
struct Arguments {
signed: bool,
bits: usize,
number_size: NumberBytes,
}
impl CmdArgument for Arguments {
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
None
}
}
#[derive(Clone)]
pub struct BitsRor;
@ -20,11 +34,17 @@ impl Command for BitsRor {
Signature::build("bits ror")
.input_output_types(vec![
(Type::Int, Type::Int),
(Type::Binary, Type::Binary),
(
Type::List(Box::new(Type::Int)),
Type::List(Box::new(Type::Int)),
),
(
Type::List(Box::new(Type::Binary)),
Type::List(Box::new(Type::Binary)),
),
])
.allow_variants_without_examples(true)
.required("bits", SyntaxShape::Int, "number of bits to rotate right")
.switch(
"signed",
@ -33,7 +53,7 @@ impl Command for BitsRor {
)
.named(
"number-bytes",
SyntaxShape::String,
SyntaxShape::Int,
"the word size in number of bytes, it can be 1, 2, 4, 8, auto, default value `8`",
Some('n'),
)
@ -41,7 +61,7 @@ impl Command for BitsRor {
}
fn usage(&self) -> &str {
"Bitwise rotate right for ints."
"Bitwise rotate right for ints or binary values."
}
fn search_terms(&self) -> Vec<&str> {
@ -58,103 +78,119 @@ impl Command for BitsRor {
let head = call.head;
let bits: usize = call.req(engine_state, stack, 0)?;
let signed = call.has_flag(engine_state, stack, "signed")?;
let number_bytes: Option<Spanned<String>> =
let number_bytes: Option<Spanned<usize>> =
call.get_flag(engine_state, stack, "number-bytes")?;
let bytes_len = get_number_bytes(number_bytes.as_ref());
if let NumberBytes::Invalid = bytes_len {
if let Some(val) = number_bytes {
return Err(ShellError::UnsupportedInput {
msg: "Only 1, 2, 4, 8, or 'auto' bytes are supported as word sizes".to_string(),
input: "value originates from here".to_string(),
msg_span: head,
input_span: val.span,
});
}
}
let number_size = get_number_bytes(number_bytes, head)?;
// This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) {
return Err(ShellError::PipelineEmpty { dst_span: head });
}
input.map(
move |value| operate(value, bits, head, signed, bytes_len),
engine_state.ctrlc.clone(),
)
let args = Arguments {
signed,
number_size,
bits,
};
operate(action, args, input, head, engine_state.ctrlc.clone())
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "Rotate right a number with 60 bits",
example: "17 | bits ror 60",
result: Some(Value::test_int(272)),
description: "rotate right a number with 2 bits",
example: "17 | bits ror 2",
result: Some(Value::test_int(68)),
},
Example {
description: "Rotate right a list of numbers of one byte",
example: "[15 33 92] | bits ror 2 --number-bytes '1'",
description: "rotate right a list of numbers of two bytes",
example: "[15 33 92] | bits ror 2 --number-bytes 2",
result: Some(Value::list(
vec![
Value::test_int(195),
Value::test_int(72),
Value::test_int(49155),
Value::test_int(16392),
Value::test_int(23),
],
Span::test_data(),
)),
},
Example {
description: "rotate right binary data",
example: "0x[ff bb 03] | bits ror 10",
result: Some(Value::binary(vec![0xc0, 0xff, 0xee], Span::test_data())),
},
]
}
}
fn get_rotate_right<T: Display + PrimInt>(val: T, bits: u32, span: Span) -> Value
where
i64: std::convert::TryFrom<T>,
{
let rotate_result = i64::try_from(val.rotate_right(bits));
match rotate_result {
Ok(val) => Value::int(val, span),
Err(_) => Value::error(
ShellError::GenericError {
error: "Rotate right result beyond the range of 64 bit signed number".into(),
msg: format!(
"{val} of the specified number of bytes rotate right {bits} bits exceed limit"
),
span: Some(span),
help: None,
inner: vec![],
},
span,
),
}
}
fn action(input: &Value, args: &Arguments, span: Span) -> Value {
let Arguments {
signed,
number_size,
bits,
} = *args;
fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: NumberBytes) -> Value {
let span = value.span();
match value {
match input {
Value::Int { val, .. } => {
use InputNumType::*;
// let bits = (((bits % 64) + 64) % 64) as u32;
let val = *val;
let bits = bits as u32;
let input_type = get_input_num_type(val, signed, number_size);
match input_type {
One => get_rotate_right(val as u8, bits, span),
Two => get_rotate_right(val as u16, bits, span),
Four => get_rotate_right(val as u32, bits, span),
Eight => get_rotate_right(val as u64, bits, span),
SignedOne => get_rotate_right(val as i8, bits, span),
SignedTwo => get_rotate_right(val as i16, bits, span),
SignedFour => get_rotate_right(val as i32, bits, span),
SignedEight => get_rotate_right(val, bits, span),
}
let input_num_type = get_input_num_type(val, signed, number_size);
let int = match input_num_type {
One => (val as u8).rotate_right(bits) as i64,
Two => (val as u16).rotate_right(bits) as i64,
Four => (val as u32).rotate_right(bits) as i64,
Eight => {
let Ok(i) = i64::try_from((val as u64).rotate_right(bits)) else {
return Value::error(
ShellError::GenericError {
error: "result out of range for specified number".into(),
msg: format!(
"rotating right by {bits} is out of range for the value {val}"
),
span: Some(span),
help: None,
inner: vec![],
},
span,
);
};
i
}
SignedOne => (val as i8).rotate_right(bits) as i64,
SignedTwo => (val as i16).rotate_right(bits) as i64,
SignedFour => (val as i32).rotate_right(bits) as i64,
SignedEight => val.rotate_right(bits),
};
Value::int(int, span)
}
Value::Binary { val, .. } => {
let byte_shift = bits / 8;
let bit_rotate = bits % 8;
let mut bytes = val
.iter()
.copied()
.circular_tuple_windows::<(u8, u8)>()
.map(|(lhs, rhs)| (lhs >> bit_rotate) | (rhs << (8 - bit_rotate)))
.collect::<Vec<u8>>();
bytes.rotate_right(byte_shift);
Value::binary(bytes, span)
}
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value,
Value::Error { .. } => input.clone(),
other => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "int".into(),
exp_input_type: "int or binary".into(),
wrong_type: other.get_type().to_string(),
dst_span: head,
dst_span: span,
src_span: other.span(),
},
head,
span,
),
}
}

View File

@ -1,12 +1,27 @@
use super::{get_input_num_type, get_number_bytes, InputNumType, NumberBytes};
use itertools::Itertools;
use nu_cmd_base::input_handler::{operate, CmdArgument};
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::ast::CellPath;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::Spanned;
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use num_traits::CheckedShl;
use std::fmt::Display;
use std::iter;
struct Arguments {
signed: bool,
bits: usize,
number_size: NumberBytes,
}
impl CmdArgument for Arguments {
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
None
}
}
#[derive(Clone)]
pub struct BitsShl;
@ -20,11 +35,17 @@ impl Command for BitsShl {
Signature::build("bits shl")
.input_output_types(vec![
(Type::Int, Type::Int),
(Type::Binary, Type::Binary),
(
Type::List(Box::new(Type::Int)),
Type::List(Box::new(Type::Int)),
),
(
Type::List(Box::new(Type::Binary)),
Type::List(Box::new(Type::Binary)),
),
])
.allow_variants_without_examples(true)
.required("bits", SyntaxShape::Int, "number of bits to shift left")
.switch(
"signed",
@ -33,7 +54,7 @@ impl Command for BitsShl {
)
.named(
"number-bytes",
SyntaxShape::String,
SyntaxShape::Int,
"the word size in number of bytes, it can be 1, 2, 4, 8, auto, default value `8`",
Some('n'),
)
@ -41,7 +62,7 @@ impl Command for BitsShl {
}
fn usage(&self) -> &str {
"Bitwise shift left for ints."
"Bitwise shift left for ints or binary values."
}
fn search_terms(&self) -> Vec<&str> {
@ -58,27 +79,22 @@ impl Command for BitsShl {
let head = call.head;
let bits: usize = call.req(engine_state, stack, 0)?;
let signed = call.has_flag(engine_state, stack, "signed")?;
let number_bytes: Option<Spanned<String>> =
let number_bytes: Option<Spanned<usize>> =
call.get_flag(engine_state, stack, "number-bytes")?;
let bytes_len = get_number_bytes(number_bytes.as_ref());
if let NumberBytes::Invalid = bytes_len {
if let Some(val) = number_bytes {
return Err(ShellError::UnsupportedInput {
msg: "Only 1, 2, 4, 8, or 'auto' bytes are supported as word sizes".to_string(),
input: "value originates from here".to_string(),
msg_span: head,
input_span: val.span,
});
}
}
let number_size = get_number_bytes(number_bytes, head)?;
// This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) {
return Err(ShellError::PipelineEmpty { dst_span: head });
}
input.map(
move |value| operate(value, bits, head, signed, bytes_len),
engine_state.ctrlc.clone(),
)
let args = Arguments {
signed,
number_size,
bits,
};
operate(action, args, input, head, engine_state.ctrlc.clone())
}
fn examples(&self) -> Vec<Example> {
@ -86,17 +102,17 @@ impl Command for BitsShl {
Example {
description: "Shift left a number by 7 bits",
example: "2 | bits shl 7",
result: Some(Value::test_int(256)),
result: Some(Value::test_int(0)),
},
Example {
description: "Shift left a number with 1 byte by 7 bits",
example: "2 | bits shl 7 --number-bytes '1'",
result: Some(Value::test_int(0)),
description: "Shift left a number with 2 byte by 7 bits",
example: "2 | bits shl 7 --number-bytes 2",
result: Some(Value::test_int(256)),
},
Example {
description: "Shift left a signed number by 1 bit",
example: "0x7F | bits shl 1 --signed",
result: Some(Value::test_int(254)),
result: Some(Value::test_int(-2)),
},
Example {
description: "Shift left a list of numbers",
@ -106,75 +122,88 @@ impl Command for BitsShl {
Span::test_data(),
)),
},
Example {
description: "Shift left a binary value",
example: "0x[4f f4] | bits shl 4",
result: Some(Value::binary(vec![0xff, 0x40], Span::test_data())),
},
]
}
}
fn get_shift_left<T: CheckedShl + Display + Copy>(val: T, bits: u32, span: Span) -> Value
where
i64: std::convert::TryFrom<T>,
{
match val.checked_shl(bits) {
Some(val) => {
let shift_result = i64::try_from(val);
match shift_result {
Ok(val) => Value::int( val, span ),
Err(_) => Value::error(
ShellError::GenericError {
error:"Shift left result beyond the range of 64 bit signed number".into(),
msg: format!(
"{val} of the specified number of bytes shift left {bits} bits exceed limit"
),
span: Some(span),
help: None,
inner: vec![],
},
span,
),
}
}
None => Value::error(
ShellError::GenericError {
error: "Shift left failed".into(),
msg: format!("{val} shift left {bits} bits failed, you may shift too many bits"),
span: Some(span),
help: None,
inner: vec![],
},
span,
),
}
}
fn action(input: &Value, args: &Arguments, span: Span) -> Value {
let Arguments {
signed,
number_size,
bits,
} = *args;
fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: NumberBytes) -> Value {
let span = value.span();
match value {
match input {
Value::Int { val, .. } => {
use InputNumType::*;
// let bits = (((bits % 64) + 64) % 64) as u32;
let bits = bits as u32;
let input_type = get_input_num_type(val, signed, number_size);
match input_type {
One => get_shift_left(val as u8, bits, span),
Two => get_shift_left(val as u16, bits, span),
Four => get_shift_left(val as u32, bits, span),
Eight => get_shift_left(val as u64, bits, span),
SignedOne => get_shift_left(val as i8, bits, span),
SignedTwo => get_shift_left(val as i16, bits, span),
SignedFour => get_shift_left(val as i32, bits, span),
SignedEight => get_shift_left(val, bits, span),
}
let val = *val;
let bits = bits as u64;
let input_num_type = get_input_num_type(val, signed, number_size);
let int = match input_num_type {
One => ((val as u8) << bits) as i64,
Two => ((val as u16) << bits) as i64,
Four => ((val as u32) << bits) as i64,
Eight => {
let Ok(i) = i64::try_from((val as u64) << bits) else {
return Value::error(
ShellError::GenericError {
error: "result out of range for specified number".into(),
msg: format!(
"shifting left by {bits} is out of range for the value {val}"
),
span: Some(span),
help: None,
inner: vec![],
},
span,
);
};
i
}
SignedOne => ((val as i8) << bits) as i64,
SignedTwo => ((val as i16) << bits) as i64,
SignedFour => ((val as i32) << bits) as i64,
SignedEight => val << bits,
};
Value::int(int, span)
}
Value::Binary { val, .. } => {
let byte_shift = bits / 8;
let bit_shift = bits % 8;
use itertools::Position::*;
let bytes = val
.iter()
.copied()
.skip(byte_shift)
.circular_tuple_windows::<(u8, u8)>()
.with_position()
.map(|(pos, (lhs, rhs))| match pos {
Last | Only => lhs << bit_shift,
_ => (lhs << bit_shift) | (rhs >> bit_shift),
})
.chain(iter::repeat(0).take(byte_shift))
.collect::<Vec<u8>>();
Value::binary(bytes, span)
}
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value,
Value::Error { .. } => input.clone(),
other => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "int".into(),
exp_input_type: "int or binary".into(),
wrong_type: other.get_type().to_string(),
dst_span: head,
dst_span: span,
src_span: other.span(),
},
head,
span,
),
}
}

View File

@ -1,12 +1,27 @@
use super::{get_input_num_type, get_number_bytes, InputNumType, NumberBytes};
use itertools::Itertools;
use nu_cmd_base::input_handler::{operate, CmdArgument};
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::ast::CellPath;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::Spanned;
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use num_traits::CheckedShr;
use std::fmt::Display;
use std::iter;
struct Arguments {
signed: bool,
bits: usize,
number_size: NumberBytes,
}
impl CmdArgument for Arguments {
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
None
}
}
#[derive(Clone)]
pub struct BitsShr;
@ -20,11 +35,17 @@ impl Command for BitsShr {
Signature::build("bits shr")
.input_output_types(vec![
(Type::Int, Type::Int),
(Type::Binary, Type::Binary),
(
Type::List(Box::new(Type::Int)),
Type::List(Box::new(Type::Int)),
),
(
Type::List(Box::new(Type::Binary)),
Type::List(Box::new(Type::Binary)),
),
])
.allow_variants_without_examples(true)
.required("bits", SyntaxShape::Int, "number of bits to shift right")
.switch(
"signed",
@ -33,7 +54,7 @@ impl Command for BitsShr {
)
.named(
"number-bytes",
SyntaxShape::String,
SyntaxShape::Int,
"the word size in number of bytes, it can be 1, 2, 4, 8, auto, default value `8`",
Some('n'),
)
@ -41,7 +62,7 @@ impl Command for BitsShr {
}
fn usage(&self) -> &str {
"Bitwise shift right for ints."
"Bitwise shift right for ints or binary values."
}
fn search_terms(&self) -> Vec<&str> {
@ -58,27 +79,22 @@ impl Command for BitsShr {
let head = call.head;
let bits: usize = call.req(engine_state, stack, 0)?;
let signed = call.has_flag(engine_state, stack, "signed")?;
let number_bytes: Option<Spanned<String>> =
let number_bytes: Option<Spanned<usize>> =
call.get_flag(engine_state, stack, "number-bytes")?;
let bytes_len = get_number_bytes(number_bytes.as_ref());
if let NumberBytes::Invalid = bytes_len {
if let Some(val) = number_bytes {
return Err(ShellError::UnsupportedInput {
msg: "Only 1, 2, 4, 8, or 'auto' bytes are supported as word sizes".to_string(),
input: "value originates from here".to_string(),
msg_span: head,
input_span: val.span,
});
}
}
let number_size = get_number_bytes(number_bytes, head)?;
// This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) {
return Err(ShellError::PipelineEmpty { dst_span: head });
}
input.map(
move |value| operate(value, bits, head, signed, bytes_len),
engine_state.ctrlc.clone(),
)
let args = Arguments {
signed,
number_size,
bits,
};
operate(action, args, input, head, engine_state.ctrlc.clone())
}
fn examples(&self) -> Vec<Example> {
@ -96,75 +112,75 @@ impl Command for BitsShr {
Span::test_data(),
)),
},
Example {
description: "Shift right a binary value",
example: "0x[4f f4] | bits shr 4",
result: Some(Value::binary(vec![0x04, 0xff], Span::test_data())),
},
]
}
}
fn get_shift_right<T: CheckedShr + Display + Copy>(val: T, bits: u32, span: Span) -> Value
where
i64: std::convert::TryFrom<T>,
{
match val.checked_shr(bits) {
Some(val) => {
let shift_result = i64::try_from(val);
match shift_result {
Ok(val) => Value::int( val, span ),
Err(_) => Value::error(
ShellError::GenericError {
error: "Shift right result beyond the range of 64 bit signed number".into(),
msg: format!(
"{val} of the specified number of bytes shift right {bits} bits exceed limit"
),
span: Some(span),
help: None,
inner: vec![],
},
span,
),
}
}
None => Value::error(
ShellError::GenericError {
error: "Shift right failed".into(),
msg: format!("{val} shift right {bits} bits failed, you may shift too many bits"),
span: Some(span),
help: None,
inner: vec![],
},
span,
),
}
}
fn action(input: &Value, args: &Arguments, span: Span) -> Value {
let Arguments {
signed,
number_size,
bits,
} = *args;
fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: NumberBytes) -> Value {
let span = value.span();
match value {
match input {
Value::Int { val, .. } => {
use InputNumType::*;
// let bits = (((bits % 64) + 64) % 64) as u32;
let val = *val;
let bits = bits as u32;
let input_type = get_input_num_type(val, signed, number_size);
match input_type {
One => get_shift_right(val as u8, bits, span),
Two => get_shift_right(val as u16, bits, span),
Four => get_shift_right(val as u32, bits, span),
Eight => get_shift_right(val as u64, bits, span),
SignedOne => get_shift_right(val as i8, bits, span),
SignedTwo => get_shift_right(val as i16, bits, span),
SignedFour => get_shift_right(val as i32, bits, span),
SignedEight => get_shift_right(val, bits, span),
}
let input_num_type = get_input_num_type(val, signed, number_size);
let int = match input_num_type {
One => ((val as u8) >> bits) as i64,
Two => ((val as u16) >> bits) as i64,
Four => ((val as u32) >> bits) as i64,
Eight => ((val as u64) >> bits) as i64,
SignedOne => ((val as i8) >> bits) as i64,
SignedTwo => ((val as i16) >> bits) as i64,
SignedFour => ((val as i32) >> bits) as i64,
SignedEight => val >> bits,
};
Value::int(int, span)
}
Value::Binary { val, .. } => {
let byte_shift = bits / 8;
let bit_shift = bits % 8;
let len = val.len();
use itertools::Position::*;
let bytes = iter::repeat(0)
.take(byte_shift)
.chain(
val.iter()
.copied()
.circular_tuple_windows::<(u8, u8)>()
.with_position()
.map(|(pos, (lhs, rhs))| match pos {
First | Only => lhs >> bit_shift,
_ => (lhs >> bit_shift) | (rhs << bit_shift),
})
.take(len - byte_shift),
)
.collect::<Vec<u8>>();
Value::binary(bytes, span)
}
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value,
Value::Error { .. } => input.clone(),
other => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "int".into(),
exp_input_type: "int or binary".into(),
wrong_type: other.get_type().to_string(),
dst_span: head,
dst_span: span,
src_span: other.span(),
},
head,
span,
),
}
}

View File

@ -1,8 +1,9 @@
use super::binary_op;
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Type, Value,
};
#[derive(Clone)]
@ -17,17 +18,33 @@ impl Command for BitsXor {
Signature::build("bits xor")
.input_output_types(vec![
(Type::Int, Type::Int),
(Type::Binary, Type::Binary),
(
Type::List(Box::new(Type::Int)),
Type::List(Box::new(Type::Int)),
),
(
Type::List(Box::new(Type::Binary)),
Type::List(Box::new(Type::Binary)),
),
])
.required("target", SyntaxShape::Int, "target int to perform bit xor")
.allow_variants_without_examples(true)
.required(
"target",
SyntaxShape::OneOf(vec![SyntaxShape::Binary, SyntaxShape::Int]),
"right-hand side of the operation",
)
.named(
"endian",
SyntaxShape::String,
"byte encode endian, available options: native(default), little, big",
Some('e'),
)
.category(Category::Bits)
}
fn usage(&self) -> &str {
"Performs bitwise xor for ints."
"Performs bitwise xor for ints or binary values."
}
fn search_terms(&self) -> Vec<&str> {
@ -42,13 +59,32 @@ impl Command for BitsXor {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let head = call.head;
let target: i64 = call.req(engine_state, stack, 0)?;
let target: Value = call.req(engine_state, stack, 0)?;
let endian = call.get_flag::<Spanned<String>>(engine_state, stack, "endian")?;
let little_endian = if let Some(endian) = endian {
match endian.item.as_str() {
"native" => cfg!(target_endian = "little"),
"little" => true,
"big" => false,
_ => {
return Err(ShellError::TypeMismatch {
err_message: "Endian must be one of native, little, big".to_string(),
span: endian.span,
})
}
}
} else {
cfg!(target_endian = "little")
};
// This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) {
return Err(ShellError::PipelineEmpty { dst_span: head });
}
input.map(
move |value| operate(value, target, head),
move |value| binary_op(&value, &target, little_endian, |(l, r)| l ^ r, head),
engine_state.ctrlc.clone(),
)
}
@ -61,35 +97,34 @@ impl Command for BitsXor {
result: Some(Value::test_int(0)),
},
Example {
description: "Apply logical xor to a list of numbers",
description: "Apply bitwise xor to a list of numbers",
example: "[8 3 2] | bits xor 2",
result: Some(Value::list(
vec![Value::test_int(10), Value::test_int(1), Value::test_int(0)],
Span::test_data(),
)),
result: Some(Value::test_list(vec![
Value::test_int(10),
Value::test_int(1),
Value::test_int(0),
])),
},
Example {
description: "Apply bitwise xor to binary data",
example: "0x[ca fe] | bits xor 0x[ba be]",
result: Some(Value::test_binary(vec![0x70, 0x40])),
},
Example {
description:
"Apply bitwise xor to binary data of varying lengths with specified endianness",
example: "0x[ca fe] | bits xor 0x[aa] --endian big",
result: Some(Value::test_binary(vec![0xca, 0x54])),
},
Example {
description: "Apply bitwise xor to input binary data smaller than the operand",
example: "0x[ff] | bits xor 0x[12 34 56] --endian little",
result: Some(Value::test_binary(vec![0xed, 0x34, 0x56])),
},
]
}
}
fn operate(value: Value, target: i64, head: Span) -> Value {
let span = value.span();
match value {
Value::Int { val, .. } => Value::int(val ^ target, span),
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value,
other => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "int".into(),
wrong_type: other.get_type().to_string(),
dst_span: head,
src_span: other.span(),
},
head,
),
}
}
#[cfg(test)]
mod test {
use super::*;

View File

@ -4,7 +4,7 @@ mod roll_left;
mod roll_right;
mod roll_up;
use nu_protocol::{Record, ShellError, Value};
use nu_protocol::{ShellError, Value};
pub use roll_::Roll;
pub use roll_down::RollDown;
pub use roll_left::RollLeft;
@ -70,10 +70,8 @@ fn horizontal_rotate_value(
HorizontalDirection::Left => vals.rotate_left(rotations),
}
Ok(Value::record(
Record::from_raw_cols_vals_unchecked(cols, vals),
span,
))
let record = cols.into_iter().zip(vals).collect();
Ok(Value::record(record, span))
}
Value::List { vals, .. } => {
let values = vals

View File

@ -6,7 +6,6 @@ use nu_protocol::{
PipelineIterator, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use std::collections::HashSet;
use std::iter::FromIterator;
#[derive(Clone)]
pub struct UpdateCells;
@ -114,14 +113,12 @@ impl Command for UpdateCells {
// the columns to update
let columns: Option<Value> = call.get_flag(&engine_state, &mut stack, "columns")?;
let columns: Option<HashSet<String>> = match columns {
Some(val) => {
let cols = val
.as_list()?
.iter()
.map(|val| val.as_string())
.collect::<Result<Vec<String>, ShellError>>()?;
Some(HashSet::from_iter(cols))
}
Some(val) => Some(
val.into_list()?
.into_iter()
.map(Value::coerce_into_string)
.collect::<Result<HashSet<String>, ShellError>>()?,
),
None => None,
};

View File

@ -432,7 +432,7 @@ fn html_value(value: Value, config: &Config) -> String {
output_string.push_str("</pre>");
}
other => output_string.push_str(
&v_htmlescape::escape(&other.into_abbreviated_string(config))
&v_htmlescape::escape(&other.to_abbreviated_string(config))
.to_string()
.replace('\n', "<br>"),
),

View File

@ -104,7 +104,7 @@ impl Command for SubCommand {
fn value_to_color(v: Option<Value>) -> Result<Option<Rgb>, ShellError> {
let s = match v {
None => return Ok(None),
Some(x) => x.as_string()?,
Some(x) => x.coerce_into_string()?,
};
Ok(Some(Rgb::from_hex_string(s)))
}

View File

@ -54,8 +54,8 @@ impl Command for FormatPattern {
match specified_pattern {
Err(e) => Err(e),
Ok(pattern) => {
let string_pattern = pattern.as_string()?;
let string_span = pattern.span();
let string_pattern = pattern.coerce_into_string()?;
// the string span is start as `"`, we don't need the character
// to generate proper span for sub expression.
let ops = extract_formatting_operations(
@ -287,7 +287,7 @@ fn format_record(
.collect();
match data_as_value.clone().follow_cell_path(&path_members, false) {
Ok(value_at_column) => {
output.push_str(value_at_column.into_string(", ", config).as_str())
output.push_str(value_at_column.to_expanded_string(", ", config).as_str())
}
Err(se) => return Err(se),
}
@ -298,7 +298,7 @@ fn format_record(
None => {
let parsed_result = eval_expression(engine_state, stack, &exp);
if let Ok(val) = parsed_result {
output.push_str(&val.into_abbreviated_string(config))
output.push_str(&val.to_abbreviated_string(config))
}
}
Some(err) => {

View File

@ -6,19 +6,17 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-lang"
edition = "2021"
license = "MIT"
name = "nu-cmd-lang"
version = "0.90.1"
version = "0.91.0"
[lib]
bench = false
[dependencies]
nu-engine = { path = "../nu-engine", version = "0.90.1" }
nu-parser = { path = "../nu-parser", version = "0.90.1" }
nu-protocol = { path = "../nu-protocol", version = "0.90.1" }
nu-utils = { path = "../nu-utils", version = "0.90.1" }
nu-ansi-term = "0.50.0"
nu-engine = { path = "../nu-engine", version = "0.91.0" }
nu-parser = { path = "../nu-parser", version = "0.91.0" }
nu-protocol = { path = "../nu-protocol", version = "0.91.0" }
nu-utils = { path = "../nu-utils", version = "0.91.0" }
fancy-regex = "0.12"
itertools = "0.12"
shadow-rs = { version = "0.26", default-features = false }

View File

@ -305,7 +305,7 @@ fn describe_value(
| Value::Date { .. }
| Value::Range { .. }
| Value::String { .. }
| Value::QuotedString { .. }
| Value::Glob { .. }
| Value::Nothing { .. } => Value::record(
record!(
"type" => Value::string(value.get_type().to_string(), head),

View File

@ -4,8 +4,8 @@ use nu_engine::{eval_block_with_early_return, redirect_env, CallExt};
use nu_protocol::ast::Call;
use nu_protocol::engine::{Closure, Command, EngineState, Stack};
use nu_protocol::{
Category, Example, ListStream, PipelineData, RawStream, ShellError, Signature, SyntaxShape,
Type, Value,
Category, Example, IntoSpanned, ListStream, PipelineData, RawStream, ShellError, Signature,
SyntaxShape, Type, Value,
};
#[derive(Clone)]
@ -147,23 +147,25 @@ impl Command for Do {
// consumes the first 65535 bytes
// So we need a thread to receive stdout message, then the current thread can continue to consume
// stderr messages.
let stdout_handler = stdout.map(|stdout_stream| {
thread::Builder::new()
.name("stderr redirector".to_string())
.spawn(move || {
let ctrlc = stdout_stream.ctrlc.clone();
let span = stdout_stream.span;
RawStream::new(
Box::new(
vec![stdout_stream.into_bytes().map(|s| s.item)].into_iter(),
),
ctrlc,
span,
None,
)
})
.expect("Failed to create thread")
});
let stdout_handler = stdout
.map(|stdout_stream| {
thread::Builder::new()
.name("stderr redirector".to_string())
.spawn(move || {
let ctrlc = stdout_stream.ctrlc.clone();
let span = stdout_stream.span;
RawStream::new(
Box::new(std::iter::once(
stdout_stream.into_bytes().map(|s| s.item),
)),
ctrlc,
span,
None,
)
})
.map_err(|e| e.into_spanned(call.head))
})
.transpose()?;
// Intercept stderr so we can return it in the error if the exit code is non-zero.
// The threading issues mentioned above dictate why we also need to intercept stdout.
@ -213,7 +215,7 @@ impl Command for Do {
Ok(PipelineData::ExternalStream {
stdout,
stderr: Some(RawStream::new(
Box::new(vec![Ok(stderr_msg.into_bytes())].into_iter()),
Box::new(std::iter::once(Ok(stderr_msg.into_bytes()))),
stderr_ctrlc,
span,
None,

View File

@ -1,3 +1,5 @@
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use nu_engine::{eval_block, CallExt};
@ -5,7 +7,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{Closure, Command, EngineState, Stack};
use nu_protocol::{
Category, Example, IntoPipelineData, LazyRecord, PipelineData, ShellError, Signature, Span,
SyntaxShape, Type, Value,
Spanned, SyntaxShape, Type, Value,
};
#[derive(Clone)]
@ -58,18 +60,36 @@ impl Command for LazyMake {
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let span = call.head;
let columns: Vec<String> = call
let columns: Vec<Spanned<String>> = call
.get_flag(engine_state, stack, "columns")?
.expect("required flag");
let get_value: Closure = call
.get_flag(engine_state, stack, "get-value")?
.expect("required flag");
let mut unique = HashMap::with_capacity(columns.len());
for col in &columns {
match unique.entry(&col.item) {
Entry::Occupied(entry) => {
return Err(ShellError::ColumnDefinedTwice {
col_name: col.item.clone(),
second_use: col.span,
first_use: *entry.get(),
});
}
Entry::Vacant(entry) => {
entry.insert(col.span);
}
}
}
Ok(Value::lazy_record(
Box::new(NuLazyRecord {
engine_state: engine_state.clone(),
stack: Arc::new(Mutex::new(stack.clone())),
columns,
columns: columns.into_iter().map(|s| s.item).collect(),
get_value,
span,
}),

View File

@ -1,7 +1,9 @@
use nu_engine::eval_block;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
};
#[derive(Clone)]
pub struct Let;
@ -61,8 +63,24 @@ impl Command for Let {
.expect("internal error: missing right hand side");
let block = engine_state.get_block(block_id);
let pipeline_data = eval_block(engine_state, stack, block, input, true, false)?;
stack.add_var(var_id, pipeline_data.into_value(call.head));
let mut value = pipeline_data.into_value(call.head);
// if given variable type is Glob, and our result is string
// then nushell need to convert from Value::String to Value::Glob
// it's assigned by demand, then it's not quoted, and it's required to expand
// if we pass it to other commands.
let var_type = &engine_state.get_var(var_id).ty;
let val_span = value.span();
match value {
Value::String { val, .. } if var_type == &Type::Glob => {
value = Value::glob(val, false, val_span);
}
_ => {}
}
stack.add_var(var_id, value);
Ok(PipelineData::empty())
}

View File

@ -1,7 +1,9 @@
use nu_engine::eval_block;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
};
#[derive(Clone)]
pub struct Mut;
@ -69,10 +71,22 @@ impl Command for Mut {
call.redirect_stdout,
call.redirect_stderr,
)?;
let mut value = pipeline_data.into_value(call.head);
//println!("Adding: {:?} to {}", rhs, var_id);
// if given variable type is Glob, and our result is string
// then nushell need to convert from Value::String to Value::Glob
// it's assigned by demand, then it's not quoted, and it's required to expand
// if we pass it to other commands.
let var_type = &engine_state.get_var(var_id).ty;
let val_span = value.span();
match value {
Value::String { val, .. } if var_type == &Type::Glob => {
value = Value::glob(val, false, val_span);
}
_ => {}
}
stack.add_var(var_id, pipeline_data.into_value(call.head));
stack.add_var(var_id, value);
Ok(PipelineData::empty())
}

View File

@ -228,7 +228,7 @@ impl<'a> std::fmt::Debug for DebuggableValue<'a> {
val.from, val.to, val.incr
),
},
Value::String { val, .. } | Value::QuotedString { val, .. } => {
Value::String { val, .. } | Value::Glob { val, .. } => {
write!(f, "{:?}", val)
}
Value::Record { val, .. } => {

View File

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

View File

@ -6,7 +6,7 @@ pub fn get_matching_brackets_style(default_style: Style, conf: &Config) -> Style
const MATCHING_BRACKETS_CONFIG_KEY: &str = "shape_matching_brackets";
match conf.color_config.get(MATCHING_BRACKETS_CONFIG_KEY) {
Some(int_color) => match int_color.as_string() {
Some(int_color) => match int_color.coerce_str() {
Ok(int_color) => merge_styles(default_style, lookup_ansi_color_style(&int_color)),
Err(_) => default_style,
},

View File

@ -104,7 +104,7 @@ pub fn color_record_to_nustyle(value: &Value) -> Style {
for (k, v) in record {
// Because config already type-checked the color_config records, this doesn't bother giving errors
// if there are unrecognised keys or bad values.
if let Ok(v) = v.as_string() {
if let Ok(v) = v.coerce_string() {
match k.as_str() {
"fg" => fg = Some(v),

View File

@ -122,7 +122,7 @@ impl<'a> StyleComputer<'a> {
Value::Range { .. } => TextStyle::with_style(Left, s),
Value::Float { .. } => TextStyle::with_style(Right, s),
Value::String { .. } => TextStyle::with_style(Left, s),
Value::QuotedString { .. } => TextStyle::with_style(Left, s),
Value::Glob { .. } => TextStyle::with_style(Left, s),
Value::Nothing { .. } => TextStyle::with_style(Left, s),
Value::Binary { .. } => TextStyle::with_style(Left, s),
Value::CellPath { .. } => TextStyle::with_style(Left, s),

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.90.1"
version = "0.91.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -14,26 +14,26 @@ bench = false
[dependencies]
nu-ansi-term = "0.50.0"
nu-cmd-base = { path = "../nu-cmd-base", version = "0.90.1" }
nu-color-config = { path = "../nu-color-config", version = "0.90.1" }
nu-engine = { path = "../nu-engine", version = "0.90.1" }
nu-glob = { path = "../nu-glob", version = "0.90.1" }
nu-json = { path = "../nu-json", version = "0.90.1" }
nu-parser = { path = "../nu-parser", version = "0.90.1" }
nu-path = { path = "../nu-path", version = "0.90.1" }
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.90.1" }
nu-protocol = { path = "../nu-protocol", version = "0.90.1" }
nu-system = { path = "../nu-system", version = "0.90.1" }
nu-table = { path = "../nu-table", version = "0.90.1" }
nu-term-grid = { path = "../nu-term-grid", version = "0.90.1" }
nu-utils = { path = "../nu-utils", version = "0.90.1" }
nu-cmd-base = { path = "../nu-cmd-base", version = "0.91.0" }
nu-color-config = { path = "../nu-color-config", version = "0.91.0" }
nu-engine = { path = "../nu-engine", version = "0.91.0" }
nu-glob = { path = "../nu-glob", version = "0.91.0" }
nu-json = { path = "../nu-json", version = "0.91.0" }
nu-parser = { path = "../nu-parser", version = "0.91.0" }
nu-path = { path = "../nu-path", version = "0.91.0" }
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.91.0" }
nu-protocol = { path = "../nu-protocol", version = "0.91.0" }
nu-system = { path = "../nu-system", version = "0.91.0" }
nu-table = { path = "../nu-table", version = "0.91.0" }
nu-term-grid = { path = "../nu-term-grid", version = "0.91.0" }
nu-utils = { path = "../nu-utils", version = "0.91.0" }
alphanumeric-sort = "1.5"
base64 = "0.21"
byteorder = "1.5"
bytesize = "1.3"
calamine = "0.23.1"
chrono = { version = "0.4", features = ["std", "unstable-locales"], default-features = false }
calamine = { version = "0.24.0", features = ["dates"] }
chrono = { version = "0.4.34", features = ["std", "unstable-locales", "clock"], default-features = false }
chrono-humanize = "0.2.3"
chrono-tz = "0.8"
crossterm = "0.27"
@ -42,23 +42,21 @@ dialoguer = { default-features = false, features = ["fuzzy-select"], version = "
digest = { default-features = false, version = "0.10" }
dtparse = "2.0"
encoding_rs = "0.8"
fancy-regex = "0.12"
fancy-regex = "0.13"
filesize = "0.2"
filetime = "0.2"
fs_extra = "1.3"
human-date-parser = "0.1.1"
indexmap = "2.1"
indexmap = "2.2"
indicatif = "0.17"
itertools = "0.12"
log = "0.4"
lscolors = { version = "0.17", default-features = false, features = ["nu-ansi-term"] }
md5 = { package = "md-5", version = "0.10" }
miette = { version = "5.10", features = ["fancy-no-backtrace"] }
mime = "0.3"
mime_guess = "2.0"
native-tls = "0.2"
notify-debouncer-full = { version = "0.3", default-features = false }
num = { version = "0.4", optional = true }
num-format = { version = "0.4" }
num-traits = "0.2"
once_cell = "1.18"
@ -71,8 +69,8 @@ quick-xml = "0.31.0"
rand = "0.8"
rayon = "1.8"
regex = "1.9.5"
roxmltree = "0.18"
rusqlite = { version = "0.29", features = ["bundled", "backup", "chrono"], optional = true }
roxmltree = "0.19"
rusqlite = { version = "0.31", features = ["bundled", "backup", "chrono"], optional = true }
same-file = "1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", features = ["preserve_order"] }
@ -84,7 +82,7 @@ tabled = { version = "0.14.0", features = ["color"], default-features = false }
terminal_size = "0.3"
titlecase = "2.0"
toml = "0.8"
unicode-segmentation = "1.10"
unicode-segmentation = "1.11"
ureq = { version = "2.9", default-features = false, features = ["charset", "gzip", "json", "native-tls"] }
url = "2.2"
uu_mv = "0.0.23"
@ -95,7 +93,7 @@ uu_mktemp = "0.0.23"
uuid = { version = "1.6", features = ["v4"] }
v_htmlescape = "0.15.0"
wax = { version = "0.6" }
which = { version = "5.0", optional = true }
which = { version = "6.0", optional = true }
bracoxide = "0.1.2"
chardetng = "0.1.17"
@ -112,7 +110,7 @@ procfs = "0.16.0"
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies.trash]
optional = true
version = "3.1"
version = "3.3"
[target.'cfg(windows)'.dependencies.windows]
features = [
@ -132,11 +130,11 @@ trash-support = ["trash"]
which-support = ["which"]
[dev-dependencies]
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.90.1" }
nu-test-support = { path = "../nu-test-support", version = "0.90.1" }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.91.0" }
nu-test-support = { path = "../nu-test-support", version = "0.91.0" }
dirs-next = "2.0"
mockito = { version = "1.2", default-features = false }
mockito = { version = "1.3", default-features = false }
quickcheck = "1.0"
quickcheck_macros = "1.0"
rstest = { version = "0.18", default-features = false }

View File

@ -4,7 +4,7 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
record, Category, Example, IntoPipelineData, PipelineData, Record, ShellError, Signature, Span,
record, Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span,
Spanned, SyntaxShape, Type, Value,
};
use std::collections::HashMap;
@ -127,15 +127,16 @@ impl Command for Histogram {
let span = call.head;
let data_as_value = input.into_value(span);
let value_span = data_as_value.span();
// `input` is not a list, here we can return an error.
run_histogram(
data_as_value.as_list()?.to_vec(),
data_as_value.into_list()?,
column_name,
frequency_column_name,
calc_method,
span,
// Note that as_list() filters out Value::Error here.
data_as_value.span(),
value_span,
)
}
}
@ -238,13 +239,6 @@ fn histogram_impl(
}
let mut result = vec![];
let result_cols = vec![
value_column_name.to_string(),
"count".to_string(),
"quantile".to_string(),
"percentage".to_string(),
freq_column.to_string(),
];
const MAX_FREQ_COUNT: f64 = 100.0;
for (val, count) in counter.into_iter().sorted() {
let quantile = match calc_method {
@ -258,16 +252,13 @@ fn histogram_impl(
result.push((
count, // attach count first for easily sorting.
Value::record(
Record::from_raw_cols_vals_unchecked(
result_cols.clone(),
vec![
val.into_value(),
Value::int(count, span),
Value::float(quantile, span),
Value::string(percentage, span),
Value::string(freq, span),
],
),
record! {
value_column_name => val.into_value(),
"count" => Value::int(count, span),
"quantile" => Value::float(quantile, span),
"percentage" => Value::string(percentage, span),
freq_column => Value::string(freq, span),
},
span,
),
));

View File

@ -261,11 +261,12 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
// Let's try dtparse first
if matches!(input, Value::String { .. }) && dateformat.is_none() {
if let Ok(input_val) = input.as_spanned_string() {
match parse_date_from_string(&input_val.item, input_val.span) {
Ok(date) => return Value::date(date, input_val.span),
let span = input.span();
if let Ok(input_val) = input.coerce_str() {
match parse_date_from_string(&input_val, span) {
Ok(date) => return Value::date(date, span),
Err(_) => {
if let Ok(date) = from_human_time(&input_val.item) {
if let Ok(date) = from_human_time(&input_val) {
match date {
ParseResult::Date(date) => {
let time = NaiveTime::from_hms_opt(0, 0, 0).expect("valid time");
@ -274,10 +275,10 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
combined,
*Local::now().offset(),
);
return Value::date(dt_fixed, input_val.span);
return Value::date(dt_fixed, span);
}
ParseResult::DateTime(date) => {
return Value::date(date.fixed_offset(), input_val.span)
return Value::date(date.fixed_offset(), span)
}
ParseResult::Time(time) => {
let date = Local::now().date_naive();
@ -286,7 +287,7 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
combined,
*Local::now().offset(),
);
return Value::date(dt_fixed, input_val.span);
return Value::date(dt_fixed, span);
}
}
}
@ -338,7 +339,7 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
}
None => Value::error(
ShellError::DatetimeParseError {
msg: input.debug_value(),
msg: input.to_debug_string(),
span: *span,
},
*span,
@ -351,7 +352,7 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
}
None => Value::error(
ShellError::DatetimeParseError {
msg: input.debug_value(),
msg: input.to_debug_string(),
span: *span,
},
*span,

View File

@ -0,0 +1,133 @@
use nu_cmd_base::input_handler::{operate, CmdArgument};
use nu_engine::CallExt;
use nu_protocol::{
ast::{Call, CellPath},
engine::{Command, EngineState, Stack},
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
Type, Value,
};
struct Arguments {
cell_paths: Option<Vec<CellPath>>,
}
impl CmdArgument for Arguments {
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
self.cell_paths.take()
}
}
#[derive(Clone)]
pub struct SubCommand;
impl Command for SubCommand {
fn name(&self) -> &str {
"into glob"
}
fn signature(&self) -> Signature {
Signature::build("into glob")
.input_output_types(vec![
(Type::String, Type::Glob),
(
Type::List(Box::new(Type::String)),
Type::List(Box::new(Type::Glob)),
),
(Type::Table(vec![]), Type::Table(vec![])),
(Type::Record(vec![]), Type::Record(vec![])),
])
.allow_variants_without_examples(true) // https://github.com/nushell/nushell/issues/7032
.rest(
"rest",
SyntaxShape::CellPath,
"For a data structure input, convert data at the given cell paths.",
)
.category(Category::Conversions)
}
fn usage(&self) -> &str {
"Convert value to glob."
}
fn search_terms(&self) -> Vec<&str> {
vec!["convert", "text"]
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
glob_helper(engine_state, stack, call, input)
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "convert string to glob",
example: "'1234' | into glob",
result: Some(Value::test_glob("1234")),
},
Example {
description: "convert filepath to glob",
example: "ls Cargo.toml | get name | into glob",
result: None,
},
]
}
}
fn glob_helper(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let head = call.head;
let cell_paths = call.rest(engine_state, stack, 0)?;
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
let args = Arguments { cell_paths };
match input {
PipelineData::ExternalStream { stdout: None, .. } => {
Ok(Value::glob(String::new(), false, head).into_pipeline_data())
}
PipelineData::ExternalStream {
stdout: Some(stream),
..
} => {
// TODO: in the future, we may want this to stream out, converting each to bytes
let output = stream.into_string()?;
Ok(Value::glob(output.item, false, head).into_pipeline_data())
}
_ => operate(action, args, input, head, engine_state.ctrlc.clone()),
}
}
fn action(input: &Value, _args: &Arguments, span: Span) -> Value {
match input {
Value::String { val, .. } => Value::glob(val.to_string(), false, span),
x => Value::error(
ShellError::CantConvert {
to_type: String::from("glob"),
from_type: x.get_type().to_string(),
span,
help: None,
},
span,
),
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_examples() {
use crate::test_examples;
test_examples(SubCommand {})
}
}

View File

@ -11,6 +11,7 @@ use nu_utils::get_system_locale;
struct Arguments {
radix: u32,
cell_paths: Option<Vec<CellPath>>,
signed: bool,
little_endian: bool,
}
@ -79,6 +80,11 @@ impl Command for SubCommand {
"byte encode endian, available options: native(default), little, big",
Some('e'),
)
.switch(
"signed",
"always treat input number as a signed number",
Some('s'),
)
.rest(
"rest",
SyntaxShape::CellPath,
@ -148,9 +154,12 @@ impl Command for SubCommand {
None => cfg!(target_endian = "little"),
};
let signed = call.has_flag(engine_state, stack, "signed")?;
let args = Arguments {
radix,
little_endian,
signed,
cell_paths,
};
operate(action, args, input, call.head, engine_state.ctrlc.clone())
@ -221,12 +230,23 @@ impl Command for SubCommand {
example: "'0010132' | into int --radix 8",
result: Some(Value::test_int(4186)),
},
Example {
description: "Convert binary value to int",
example: "0x[10] | into int",
result: Some(Value::test_int(16)),
},
Example {
description: "Convert binary value to signed int",
example: "0x[a0] | into int --signed",
result: Some(Value::test_int(-96)),
},
]
}
}
fn action(input: &Value, args: &Arguments, span: Span) -> Value {
let radix = args.radix;
let signed = args.signed;
let little_endian = args.little_endian;
let val_span = input.span();
match input {
@ -307,21 +327,42 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {
use byteorder::{BigEndian, ByteOrder, LittleEndian};
let mut val = val.to_vec();
let size = val.len();
if little_endian {
while val.len() < 8 {
val.push(0);
if size == 0 {
return Value::int(0, span);
}
if size > 8 {
return Value::error(
ShellError::IncorrectValue {
msg: format!("binary input is too large to convert to int ({size} bytes)"),
val_span,
call_span: span,
},
span,
);
}
match (little_endian, signed) {
(true, true) => Value::int(LittleEndian::read_int(&val, size), span),
(false, true) => Value::int(BigEndian::read_int(&val, size), span),
(true, false) => {
while val.len() < 8 {
val.push(0);
}
val.resize(8, 0);
Value::int(LittleEndian::read_i64(&val), span)
}
val.resize(8, 0);
(false, false) => {
while val.len() < 8 {
val.insert(0, 0);
}
val.resize(8, 0);
Value::int(LittleEndian::read_i64(&val), val_span)
} else {
while val.len() < 8 {
val.insert(0, 0);
Value::int(BigEndian::read_i64(&val), span)
}
val.resize(8, 0);
Value::int(BigEndian::read_i64(&val), val_span)
}
}
// Propagate errors by explicitly matching them before the final case.
@ -497,6 +538,7 @@ mod test {
&Arguments {
radix: 10,
cell_paths: None,
signed: false,
little_endian: false,
},
Span::test_data(),
@ -512,6 +554,7 @@ mod test {
&Arguments {
radix: 10,
cell_paths: None,
signed: false,
little_endian: false,
},
Span::test_data(),
@ -527,6 +570,7 @@ mod test {
&Arguments {
radix: 16,
cell_paths: None,
signed: false,
little_endian: false,
},
Span::test_data(),
@ -543,6 +587,7 @@ mod test {
&Arguments {
radix: 10,
cell_paths: None,
signed: false,
little_endian: false,
},
Span::test_data(),
@ -565,6 +610,7 @@ mod test {
&Arguments {
radix: 10,
cell_paths: None,
signed: false,
little_endian: false,
},
Span::test_data(),
@ -587,6 +633,7 @@ mod test {
&Arguments {
radix: 10,
cell_paths: None,
signed: false,
little_endian: false,
},
Span::test_data(),

View File

@ -6,6 +6,7 @@ mod datetime;
mod duration;
mod filesize;
mod float;
mod glob;
mod int;
mod record;
mod string;
@ -19,6 +20,7 @@ pub use command::Into;
pub use datetime::SubCommand as IntoDatetime;
pub use duration::SubCommand as IntoDuration;
pub use float::SubCommand as IntoFloat;
pub use glob::SubCommand as IntoGlob;
pub use int::SubCommand as IntoInt;
pub use record::SubCommand as IntoRecord;
pub use string::SubCommand as IntoString;

View File

@ -36,6 +36,7 @@ impl Command for SubCommand {
(Type::Int, Type::String),
(Type::Number, Type::String),
(Type::String, Type::String),
(Type::Glob, Type::String),
(Type::Bool, Type::String),
(Type::Filesize, Type::String),
(Type::Date, Type::String),
@ -202,9 +203,12 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {
Value::Bool { val, .. } => Value::string(val.to_string(), span),
Value::Date { val, .. } => Value::string(val.format("%c").to_string(), span),
Value::String { val, .. } => Value::string(val.to_string(), span),
Value::Glob { val, .. } => Value::string(val.to_string(), span),
Value::Filesize { val: _, .. } => Value::string(input.into_string(", ", config), span),
Value::Duration { val: _, .. } => Value::string(input.into_string("", config), span),
Value::Filesize { val: _, .. } => {
Value::string(input.to_expanded_string(", ", config), span)
}
Value::Duration { val: _, .. } => Value::string(input.to_expanded_string("", config), span),
Value::Error { error, .. } => Value::string(into_code(error).unwrap_or_default(), span),
Value::Nothing { .. } => Value::string("".to_string(), span),

View File

@ -8,7 +8,7 @@ use nu_protocol::{
};
use once_cell::sync::Lazy;
use regex::{Regex, RegexBuilder};
use std::{collections::HashSet, iter::FromIterator};
use std::collections::HashSet;
#[derive(Clone)]
pub struct IntoValue;
@ -27,6 +27,11 @@ impl Command for IntoValue {
"list of columns to update",
Some('c'),
)
.switch(
"prefer-filesizes",
"For ints display them as human-readable file sizes",
Some('f'),
)
.allow_variants_without_examples(true)
.category(Category::Filters)
}
@ -61,24 +66,24 @@ impl Command for IntoValue {
let metadata = input.metadata();
let ctrlc = engine_state.ctrlc.clone();
let span = call.head;
let display_as_filesizes = call.has_flag(&engine_state, stack, "prefer-filesizes")?;
// the columns to update
let columns: Option<Value> = call.get_flag(&engine_state, stack, "columns")?;
let columns: Option<HashSet<String>> = match columns {
Some(val) => {
let cols = val
.as_list()?
.iter()
.map(|val| val.as_string())
.collect::<Result<Vec<String>, ShellError>>()?;
Some(HashSet::from_iter(cols))
}
Some(val) => Some(
val.into_list()?
.into_iter()
.map(Value::coerce_into_string)
.collect::<Result<HashSet<String>, ShellError>>()?,
),
None => None,
};
Ok(UpdateCellIterator {
input: input.into_iter(),
columns,
display_as_filesizes,
span,
}
.into_pipeline_data(ctrlc)
@ -89,6 +94,7 @@ impl Command for IntoValue {
struct UpdateCellIterator {
input: PipelineIterator,
columns: Option<HashSet<String>>,
display_as_filesizes: bool,
span: Span,
}
@ -112,7 +118,7 @@ impl Iterator for UpdateCellIterator {
Some(cols) if !cols.contains(&col) => (col, val),
_ => (
col,
match process_cell(val, span) {
match process_cell(val, self.display_as_filesizes, span) {
Ok(val) => val,
Err(err) => Value::error(err, span),
},
@ -121,7 +127,7 @@ impl Iterator for UpdateCellIterator {
.collect(),
span,
)),
val => match process_cell(val, self.span) {
val => match process_cell(val, self.display_as_filesizes, self.span) {
Ok(val) => Some(val),
Err(err) => Some(Value::error(err, self.span)),
},
@ -134,9 +140,9 @@ impl Iterator for UpdateCellIterator {
// This function will check each cell to see if it matches a regular expression
// for a particular datatype. If it does, it will convert the cell to that datatype.
fn process_cell(val: Value, span: Span) -> Result<Value, ShellError> {
fn process_cell(val: Value, display_as_filesizes: bool, span: Span) -> Result<Value, ShellError> {
// step 1: convert value to string
let val_str = val.as_string().unwrap_or_default();
let val_str = val.coerce_str().unwrap_or_default();
// step 2: bounce string up against regexes
if BOOLEAN_RE.is_match(&val_str) {
@ -177,9 +183,13 @@ fn process_cell(val: Value, span: Span) -> Result<Value, ShellError> {
)),
})?;
Ok(Value::int(ival, span))
if display_as_filesizes {
Ok(Value::filesize(ival, span))
} else {
Ok(Value::int(ival, span))
}
} else if INTEGER_WITH_DELIMS_RE.is_match(&val_str) {
let mut val_str = val_str;
let mut val_str = val_str.into_owned();
val_str.retain(|x| !['_', ','].contains(&x));
let ival = val_str
@ -193,7 +203,11 @@ fn process_cell(val: Value, span: Span) -> Result<Value, ShellError> {
)),
})?;
Ok(Value::int(ival, span))
if display_as_filesizes {
Ok(Value::filesize(ival, span))
} else {
Ok(Value::int(ival, span))
}
} else if DATETIME_DMY_RE.is_match(&val_str) {
let dt = parse_date_from_string(&val_str, span).map_err(|_| ShellError::CantConvert {
to_type: "date".to_string(),

View File

@ -162,7 +162,7 @@ fn operate(
) -> Result<PipelineData, ShellError> {
let span = call.head;
let file_name: Spanned<String> = call.req(engine_state, stack, 0)?;
let table_name: Option<Spanned<String>> = call.get_flag(engine_state, stack, "table_name")?;
let table_name: Option<Spanned<String>> = call.get_flag(engine_state, stack, "table-name")?;
let table = Table::new(&file_name, table_name)?;
match action(input, table, span) {
@ -354,6 +354,7 @@ fn nu_value_to_sqlite_type(val: &Value) -> Result<&'static str, ShellError> {
| Type::Range
| Type::Record(_)
| Type::Signature
| Type::Glob
| Type::Table(_) => Err(ShellError::OnlySupportsThisInputType {
exp_input_type: "sql".into(),
wrong_type: val.get_type().to_string(),

View File

@ -441,15 +441,15 @@ fn prepared_statement_to_nu_list(
) -> Result<Value, SqliteError> {
let column_names = stmt
.column_names()
.iter()
.map(|c| c.to_string())
.into_iter()
.map(String::from)
.collect::<Vec<String>>();
let row_results = stmt.query_map([], |row| {
Ok(convert_sqlite_row_to_nu_value(
row,
call_span,
column_names.clone(),
&column_names,
))
})?;
@ -491,18 +491,19 @@ fn read_entire_sqlite_db(
Ok(Value::record(tables, call_span))
}
pub fn convert_sqlite_row_to_nu_value(row: &Row, span: Span, column_names: Vec<String>) -> Value {
let mut vals = Vec::with_capacity(column_names.len());
pub fn convert_sqlite_row_to_nu_value(row: &Row, span: Span, column_names: &[String]) -> Value {
let record = column_names
.iter()
.enumerate()
.map(|(i, col)| {
(
col.clone(),
convert_sqlite_value_to_nu_value(row.get_ref_unwrap(i), span),
)
})
.collect();
for i in 0..column_names.len() {
let val = convert_sqlite_value_to_nu_value(row.get_ref_unwrap(i), span);
vals.push(val);
}
Value::record(
Record::from_raw_cols_vals_unchecked(column_names, vals),
span,
)
Value::record(record, span)
}
pub fn convert_sqlite_value_to_nu_value(value: ValueRef, span: Span) -> Value {
@ -521,6 +522,27 @@ pub fn convert_sqlite_value_to_nu_value(value: ValueRef, span: Span) -> Value {
}
}
pub fn open_connection_in_memory_custom() -> Result<Connection, ShellError> {
let flags = OpenFlags::default();
Connection::open_with_flags(MEMORY_DB, flags).map_err(|e| ShellError::GenericError {
error: "Failed to open SQLite custom connection in memory".into(),
msg: e.to_string(),
span: Some(Span::test_data()),
help: None,
inner: vec![],
})
}
pub fn open_connection_in_memory() -> Result<Connection, ShellError> {
Connection::open_in_memory().map_err(|e| ShellError::GenericError {
error: "Failed to open SQLite standard connection in memory".into(),
msg: e.to_string(),
span: Some(Span::test_data()),
help: None,
inner: vec![],
})
}
#[cfg(test)]
mod test {
use super::*;
@ -598,24 +620,3 @@ mod test {
assert_eq!(converted_db, expected);
}
}
pub fn open_connection_in_memory_custom() -> Result<Connection, ShellError> {
let flags = OpenFlags::default();
Connection::open_with_flags(MEMORY_DB, flags).map_err(|e| ShellError::GenericError {
error: "Failed to open SQLite custom connection in memory".into(),
msg: e.to_string(),
span: Some(Span::test_data()),
help: None,
inner: vec![],
})
}
pub fn open_connection_in_memory() -> Result<Connection, ShellError> {
Connection::open_in_memory().map_err(|e| ShellError::GenericError {
error: "Failed to open SQLite standard connection in memory".into(),
msg: e.to_string(),
span: Some(Span::test_data()),
help: None,
inner: vec![],
})
}

View File

@ -80,7 +80,7 @@ fn helper(value: Value, head: Span) -> Value {
Value::Date { val, .. } => Value::string(humanize_date(val), head),
_ => Value::error(
ShellError::DatetimeParseError {
msg: value.debug_value(),
msg: value.to_debug_string(),
span: head,
},
head,

View File

@ -51,7 +51,7 @@ impl Command for SubCommand {
fn examples(&self) -> Vec<Example> {
vec![Example {
example: "date list-timezone | where timezone =~ Shanghai",
description: "Show timezone(s) that contains 'Shanghai'",
description: "Show time zone(s) that contains 'Shanghai'",
result: Some(Value::test_list(vec![Value::test_record(record! {
"timezone" => Value::test_string("Asia/Shanghai"),
})])),

View File

@ -46,17 +46,17 @@ impl Command for SubCommand {
result: None,
},
Example {
description: "Get the time duration from 2019-04-30 to now",
description: "Get the time duration since 2019-04-30.",
example: r#"(date now) - 2019-05-01"#,
result: None,
},
Example {
description: "Get the time duration since a more accurate time",
description: "Get the time duration since a more specific time.",
example: r#"(date now) - 2019-05-01T04:12:05.20+08:00"#,
result: None,
},
Example {
description: "Get current time in full RFC3339 format with timezone",
description: "Get current time in full RFC 3339 format with time zone.",
example: r#"date now | debug"#,
result: None,
},

View File

@ -50,11 +50,6 @@ impl Command for SubCommand {
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "Convert the current date into a record.",
example: "date to-record",
result: None,
},
Example {
description: "Convert the current date into a record.",
example: "date now | date to-record",
@ -123,7 +118,7 @@ fn helper(val: Value, head: Span) -> Value {
Value::Date { val, .. } => parse_date_into_table(val, head),
_ => Value::error(
DatetimeParseError {
msg: val.debug_value(),
msg: val.to_debug_string(),
span: head,
},
head,

View File

@ -52,11 +52,6 @@ impl Command for SubCommand {
vec![
Example {
description: "Convert the current date into a table.",
example: "date to-table",
result: None,
},
Example {
description: "Convert the date into a table.",
example: "date now | date to-table",
result: None,
},
@ -122,7 +117,7 @@ fn helper(val: Value, head: Span) -> Value {
Value::Date { val, .. } => parse_date_into_table(val, head),
_ => Value::error(
DatetimeParseError {
msg: val.debug_value(),
msg: val.to_debug_string(),
span: head,
},
head,

View File

@ -77,27 +77,27 @@ impl Command for SubCommand {
vec![
Example {
description: "Get the current date in UTC+05:00",
description: "Get the current date in UTC+05:00.",
example: "date now | date to-timezone '+0500'",
result: None,
},
Example {
description: "Get the current local date",
description: "Get the current date in the local time zone.",
example: "date now | date to-timezone local",
result: None,
},
Example {
description: "Get the current date in Hawaii",
description: "Get the current date in Hawaii.",
example: "date now | date to-timezone US/Hawaii",
result: None,
},
Example {
description: "Get the current date in Hawaii",
description: "Get a date in a different time zone, from a string.",
example: r#""2020-10-10 10:00:00 +02:00" | date to-timezone "+0500""#,
result: example_result_1(),
},
Example {
description: "Get the current date in Hawaii, from a datetime object",
description: "Get a date in a different time zone, from a datetime.",
example: r#""2020-10-10 10:00:00 +02:00" | into datetime | date to-timezone "+0500""#,
result: example_result_1(),
},
@ -123,7 +123,7 @@ fn helper(value: Value, head: Span, timezone: &Spanned<String>) -> Value {
}
_ => Value::error(
ShellError::DatetimeParseError {
msg: value.debug_value(),
msg: value.to_debug_string(),
span: head,
},
head,

View File

@ -46,7 +46,7 @@ pub(crate) fn generate_strftime_list(head: Span, show_parse_only_formats: bool)
description: &'a str,
}
let specifications = vec![
let specifications = [
FormatSpecification {
spec: "%Y",
description: "The full proleptic Gregorian year, zero-padded to 4 digits.",

View File

@ -44,9 +44,9 @@ impl Command for Debug {
input.map(
move |x| {
if raw {
Value::string(x.debug_value(), head)
Value::string(x.to_debug_string(), head)
} else {
Value::string(x.debug_string(", ", &config), head)
Value::string(x.to_expanded_string(", ", &config), head)
}
},
engine_state.ctrlc.clone(),

View File

@ -251,7 +251,7 @@ pub fn debug_string_without_formatting(value: &Value) -> String {
)
}
Value::String { val, .. } => val.clone(),
Value::QuotedString { val, .. } => val.clone(),
Value::Glob { val, .. } => val.clone(),
Value::List { vals: val, .. } => format!(
"[{}]",
val.iter()

View File

@ -79,12 +79,7 @@ impl LazySystemInfoRecord {
"ppid" => {
// only get information requested
let system_opt = SystemOpt::from((system_option, || {
RefreshKind::new().with_processes(
ProcessRefreshKind::new()
.without_cpu()
.without_disk_usage()
.without_user(),
)
RefreshKind::new().with_processes(ProcessRefreshKind::everything())
}));
let system = system_opt.get_system();
@ -117,16 +112,10 @@ impl LazySystemInfoRecord {
"process" => {
// only get information requested
let system_opt = SystemOpt::from((system_option, || {
RefreshKind::new().with_processes(
ProcessRefreshKind::new()
.without_cpu()
.without_disk_usage()
.without_user(),
)
RefreshKind::new().with_processes(ProcessRefreshKind::everything())
}));
let system = system_opt.get_system();
// get the process information for the nushell pid
let pinfo = system.process(pid);
if let Some(p) = pinfo {
@ -236,12 +225,7 @@ impl<'a> LazyRecord<'a> for LazySystemInfoRecord {
fn collect(&'a self) -> Result<Value, ShellError> {
let rk = RefreshKind::new()
.with_processes(
ProcessRefreshKind::new()
.without_cpu()
.without_disk_usage()
.without_user(),
)
.with_processes(ProcessRefreshKind::everything())
.with_memory(MemoryRefreshKind::everything());
// only get information requested
let system = System::new_with_specifics(rk);

View File

@ -46,8 +46,19 @@ impl Command for ViewSource {
let vec_of_optional = &sig.optional_positional;
let rest = &sig.rest_positional;
let vec_of_flags = &sig.named;
if decl.is_alias() {
if let Some(alias) = &decl.as_alias() {
let contents = String::from_utf8_lossy(
engine_state.get_span_contents(alias.wrapped_call.span),
);
Ok(Value::string(contents, call.head).into_pipeline_data())
} else {
Ok(Value::string("no alias found", call.head).into_pipeline_data())
}
}
// gets vector of positionals.
if let Some(block_id) = decl.get_block_id() {
else if let Some(block_id) = decl.get_block_id() {
let block = engine_state.get_block(block_id);
if let Some(block_span) = block.span {
let contents = engine_state.get_span_contents(block_span);
@ -87,7 +98,7 @@ impl Command for ViewSource {
} else {
Err(ShellError::GenericError {
error: "Cannot view value".to_string(),
msg: "the command does not have a viewable block".to_string(),
msg: "the command does not have a viewable block span".to_string(),
span: Some(arg_span),
help: None,
inner: vec![],
@ -129,7 +140,7 @@ impl Command for ViewSource {
}
}
value => {
if let Ok(block_id) = value.as_block() {
if let Ok(block_id) = value.coerce_block() {
let block = engine_state.get_block(block_id);
if let Some(span) = block.span {

Some files were not shown because too many files have changed in this diff Show More