Compare commits

...

140 Commits

Author SHA1 Message Date
a6f62e05ae Bump version for the 0.85 release (#10425) 2023-09-19 21:42:47 +03:00
f8939de14f Remove str replace --string after deprecation (#10064)
related to
- https://github.com/nushell/nushell/pull/10038

# Description
`str replace --string` has been deprecated in
https://github.com/nushell/nushell/pull/10038 and should be removed
before 0.85.

this PR removes the `--string` option from `str replace` completely.

# User-Facing Changes
`str replace --string` will no longer work and will give an error
instead of a warning.
2023-09-19 15:54:20 +02:00
01ade02ac1 Pin reedline to 0.24 for release (#10426)
See release notes:
https://github.com/nushell/reedline/releases/tag/v0.24.0
2023-09-19 15:21:09 +02:00
39d93b536a Bump toml from 0.7.6 to 0.8.0 (#10408)
Bumps [toml](https://github.com/toml-rs/toml) from 0.7.6 to 0.8.0.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="310f6ee9c5"><code>310f6ee</code></a>
chore: Release</li>
<li><a
href="90da8bc425"><code>90da8bc</code></a>
docs: Update changelog</li>
<li><a
href="f3e120f1a0"><code>f3e120f</code></a>
Merge pull request <a
href="https://redirect.github.com/toml-rs/toml/issues/608">#608</a> from
epage/enum</li>
<li><a
href="58a7101f68"><code>58a7101</code></a>
fix(serde): Support struct variants as table of a table</li>
<li><a
href="88a4dba312"><code>88a4dba</code></a>
fix(serde): Support tuple variants as table of an array</li>
<li><a
href="cf06b83424"><code>cf06b83</code></a>
test(serde): Verify both Table and Value serializers</li>
<li><a
href="4ffa44ec16"><code>4ffa44e</code></a>
test(serde): Make parameter order more consistent</li>
<li><a
href="2b7c34c900"><code>2b7c34c</code></a>
test(serde): Focus on string serialization first</li>
<li><a
href="e2a6a1cece"><code>e2a6a1c</code></a>
test(serde): Verify existing variant behavior</li>
<li><a
href="3f3e8329bb"><code>3f3e832</code></a>
chore: Release</li>
<li>Additional commits viewable in <a
href="https://github.com/toml-rs/toml/compare/toml-v0.7.6...toml-v0.8.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=toml&package-manager=cargo&previous-version=0.7.6&new-version=0.8.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>
2023-09-18 13:50:30 +08:00
32f67557af Bump terminal_size from 0.2.6 to 0.3.0 (#10409)
Bumps [terminal_size](https://github.com/eminence/terminal-size) from
0.2.6 to 0.3.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/eminence/terminal-size/releases">terminal_size's
releases</a>.</em></p>
<blockquote>
<h2>v0.3.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Check all streams (out/err/in) to find one that has a tty and size
by <a href="https://github.com/eminence"><code>@​eminence</code></a> in
<a
href="https://redirect.github.com/eminence/terminal-size/pull/58">eminence/terminal-size#58</a>
<ul>
<li>Note that this is a subtle change in behavior, since the
<code>terminal_size()</code> function will now return success in cases
more cases than before</li>
</ul>
</li>
<li>Update to rustix 0.38 by <a
href="https://github.com/chenx97"><code>@​chenx97</code></a> in <a
href="https://redirect.github.com/eminence/terminal-size/pull/57">eminence/terminal-size#57</a>
<ul>
<li>This change bumps the MSRV from 1.48.0 to 1.63.0</li>
</ul>
</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/eminence/terminal-size/compare/v0.2.6...v0.3.0">https://github.com/eminence/terminal-size/compare/v0.2.6...v0.3.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="2983b7bf18"><code>2983b7b</code></a>
Release v0.3.0</li>
<li><a
href="27a4459b22"><code>27a4459</code></a>
Merge pull request <a
href="https://redirect.github.com/eminence/terminal-size/issues/57">#57</a>
from chenx97/rustix-0.38</li>
<li><a
href="c24c1c34e5"><code>c24c1c3</code></a>
Bump MSRV to 1.63.0</li>
<li><a
href="78e13c77d7"><code>78e13c7</code></a>
Update to rustix 0.38</li>
<li><a
href="18c58b1ed5"><code>18c58b1</code></a>
Merge pull request <a
href="https://redirect.github.com/eminence/terminal-size/issues/58">#58</a>
from eminence/check_all_streams</li>
<li><a
href="08f0e73926"><code>08f0e73</code></a>
Check all streams (out/err/in) to find one that has a tty and size</li>
<li>See full diff in <a
href="https://github.com/eminence/terminal-size/compare/v0.2.6...v0.3.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=terminal_size&package-manager=cargo&previous-version=0.2.6&new-version=0.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>
2023-09-18 13:50:17 +08:00
f05eed8e8d Bump mockito from 1.1.0 to 1.2.0 (#10407)
Bumps [mockito](https://github.com/lipanski/mockito) from 1.1.0 to
1.2.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.2.0</h2>
<ul>
<li><strong>[Breaking]</strong> The minimum supported Rust version was
bumped to 1.68.0</li>
<li>The server pool was limited to 20 servers for <code>mac_os</code>
targets to prevent hitting the file descriptor limit</li>
</ul>
<p>Thanks to <a
href="https://github.com/kornelski"><code>@​kornelski</code></a></p>
<h2>1.1.1</h2>
<ul>
<li><a
href="https://redirect.github.com/lipanski/mockito/pull/176">Ensure</a>
<code>with_chunked_body</code> supports streaming responses (as opposed
to writing the entire buffer in one go)</li>
</ul>
<p>Thanks to <a
href="https://github.com/kornelski"><code>@​kornelski</code></a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="7514e38524"><code>7514e38</code></a>
Bump to 1.2.0</li>
<li><a
href="be00de417e"><code>be00de4</code></a>
Merge pull request <a
href="https://redirect.github.com/lipanski/mockito/issues/177">#177</a>
from kornelski/pool</li>
<li><a
href="6b4073e911"><code>6b4073e</code></a>
MSRV</li>
<li><a
href="9faa825110"><code>9faa825</code></a>
Test exhausting server pool</li>
<li><a
href="3099e94471"><code>3099e94</code></a>
Simplify server pool</li>
<li><a
href="99735e7c41"><code>99735e7</code></a>
Bump to 1.1.1</li>
<li><a
href="3b63970619"><code>3b63970</code></a>
Merge pull request <a
href="https://redirect.github.com/lipanski/mockito/issues/176">#176</a>
from kornelski/stream</li>
<li><a
href="339bffc983"><code>339bffc</code></a>
Support streaming body</li>
<li><a
href="8b7575cd38"><code>8b7575c</code></a>
Simplify server pool test</li>
<li>See full diff in <a
href="https://github.com/lipanski/mockito/compare/1.1.0...1.2.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.1.0&new-version=1.2.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>
2023-09-18 13:50:08 +08:00
f0a265dbee Adapt for improved history isolation in reedline (#10402)
Depends on https://github.com/nushell/reedline/pull/634

---------

Co-authored-by: WindSoilder <WindSoilder@outlook.com>
2023-09-18 13:49:26 +08:00
bc7736bc99 Add 2 fuzzers for nu-path, nu-parser (#10376)
# Description

This PR adds a fuzzer for the nu-path and the nu-parser crate.
Now you can go to `crates/nu-path/fuzz`/`crates/nu-parser/fuzz` and run `cargo fuzz` to
find crashes.
https://github.com/nushell/nushell/issues/10365 and #9417 was found by
this


---------

Co-authored-by: sholderbach <sholderbach@users.noreply.github.com>
2023-09-16 22:32:53 +02:00
19d732f313 Clippy in tests (#10394)
Running `cargo clippy --workspace --tests`

We should move that to CI as well
2023-09-16 21:49:10 +02:00
a9a82de5c4 fix some new chrono warnings (#10384)
# Description

This PR cleans up some warnings on the latest chrono dependency.

# 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.
-->
2023-09-15 15:46:25 -05:00
9074015d1c Adds mimalloc as default feature. (#10378)
<!--
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 `mimalloc` the default allocator, it has been the default
on the nightly builds of nushell now for a couple of months and the
performance improvements are quite nice, measuring upwards of 30% faster
startup time on Windows, and a bit smaller on Linux,
https://github.com/nushell/nushell/pull/9415

# 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.
-->
2023-09-15 14:17:33 -05:00
2b77544e58 nu-table: Fix expand table unnessary color in trail head config when wrap is used (#10367)
So it must address it,
But please check.

PS: I don't like the patch... but it is what it is

fix: #10359
cc: @amtoine
2023-09-15 11:44:53 -05:00
5ee74b6ab5 fix input --until-bytes: now stops at any of given bytes (#10235)
- this PR should close #10197

# Description
`input --bytes-until` takes a string but used to only terminate on the
first byte of that string. Now it checks for each byte in the string.

# User-Facing Changes
all of the above. No change in documentation needed. New behavior
arguably fits better.

# Tests + Formatting
don't know how to test input
2023-09-15 06:55:37 -05:00
3a04bd9154 fix the pretty printing of failing tests in std (#10373)
related to
-
https://github.com/nushell/nushell/pull/10293/files#diff-371ea1a6b13ef0f2f10ddd0b23b86c54eb8221892e45c2e4c1913a233c585ae7R137

# Description
looks to me like https://github.com/nushell/nushell/pull/10293
introduced the use of `map` command in `std testing`, but it's not a
valid Nushell command, right?

this PR uses `each` as a replacement, that's what the error even says
2023-09-14 20:11:08 +02:00
2c176a7f14 Ps: add cwd column on linux and macos (#10347)
# Description
Close:  #7484

Just found that I want `cwd` column on linux/macos as well..
2023-09-14 08:10:15 -05:00
JT
026e18399e fix 'let' to properly redirect (#10360)
# Description

Fixes a bug in `let` where the pipeline wasn't being properly
redirected.

fixes #9767

# User-Facing Changes

Shouldn't have any breaking changes, as this should be better for
expected use cases.

# 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.
-->
2023-09-14 10:18:29 +12:00
bbf0b45c59 Update internal use of decimal to float (#10333)
# Description
We made the decision that our floating point type should be referred to
as `float` over `decimal`.
Commands were updated by #9979 and #10320

Now make the internal codebase consistent in referring to this data type
as `float`.

Work for #10332

# User-Facing Changes

`decimal` has been removed as a type name/symbol. 

Instead of 
```nushell
def foo [bar: decimal] decimal -> decimal {}
```
use 
```nushell
def foo [bar: float] float -> float {}
```

Potential effect of `SyntaxShape`'s `Display` implementation now also
referring to `float` instead of `decimal`

# Details
- Rename `SyntaxShape::Decimal` to `Float`
- Update `Display for SyntaxShape` to `float`
- Update error message + fn name in dataframe code
- Fix docs in command examples
- Rename tests that are float specific
- Update doccomment on `SyntaxShape`
- Update comment in script

# Tests + Formatting
Updates the names of some tests
2023-09-13 23:53:55 +02:00
5bd7300cd5 add helper switch to move cursor to end of buffer (#10354)
# Description

This PR adds a helper flag named `--cursor-end`/`-e` that allows you to
set the cursor to the end of the buffer. Before this, you'd have to do
something like `--cursor 100` where you're guessing that 100 would be
longer than the buffer and just put it at the 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.
-->
2023-09-13 12:44:09 -05:00
ffb5051f6c nu-table: Strip custom color in the header when used on border (#10357)
ref: #10351
cc: @fdncred
2023-09-13 12:11:00 -05:00
ce4ea16c08 fix #10319: allow json request of value type list (#10356)
# Description

this commit adds the handling of Value::List when BodyType is Json
it also adds the corresponding test (trying to send a list)

Fixes #10319

# User-Facing Changes

Added the ability to send a json list in the POST message

# Tests + Formatting
- [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

Also ran `nc -l -p 8080` in other terminal and `http post -fe -t
application/json http://localhost:8080 [{ field: true }]` I see the
following appear in the output of nc:
```
POST / HTTP/1.1
Host: localhost:8080
User-Agent: nushell
Accept: */*
Content-Type: application/json
accept-encoding: gzip
Content-Length: 16

[{"field":true}]%
```
2023-09-13 16:54:03 +02:00
48c94c75fc Optimize use of range in std repeat (#10353)
# Description
By using a `from: 1` the additional subexpression for `to` becomes
unnecessary.

Saves additional evaluation steps if `std repeat` is frequently used
with low `n`

# User-Facing Changes
None

# Tests + Formatting
(-)
2023-09-13 07:50:09 -05:00
73d3708006 Patch restore lead trail space bg color (#10351)
```nu
 $env.config.color_config.leading_trailing_space_bg = { bg: 'white' }; [[a b, 'c   ']; ['  1  ' '    2' '3    '] ['  4  ' "hello   \n  world  " ['  1  ' 2 [1 '  2  ' 3]]]] | table --expand
```


![image](https://github.com/nushell/nushell/assets/20165848/01a35042-0e36-4c51-99a9-3011fabb551b)

ref: #2794
close: #10317

note: test are not actually make scenes cause `nu!` strips colors.
(Ideally it would need a flag to not do so)
note: It does does does ... slower down quite a bit rendering... (

PS: Maybe it's better being a flag to `table` rather then a
configuration option?
PS: I am not sure why the logic was removed in a first place
2023-09-13 07:47:53 -05:00
bbea7da669 Remove select error if same row/column is provided (#10350)
This PR is in reference to #10215.

This PR changes `select` to work even if multiple equal items were
provided.
This would previously error, but now works
```nushell
let arg = [ 1 a ]
[[a b c]; [1 2 3] [4 5 6] [7 8 9]] 
| select $arg

```
# User-Facing Changes

Nothing too radical, just experience improvements. Users won't need to
pass the values through `unique` beforehand.
2023-09-13 13:49:55 +02:00
7f39609d9a Remove python-like string multiplication (#10293)
# Description
Currently we support "multiplication" of strings, resulting in a terse
way to repeat a particular string.
This can have unintended side effects when dealing with mixed data (e.g.
after parsing data that is not all numbers).
Furthermore as we frequently fall-back to strings while parsing source
code, this introduced a runaway edge case in const evaluation (#10212)

Work for #10233

## Details
- Remove python-like string multiplication.
- Workaround for indentation
  - This should probably be addressed with a purpose built command
- Remove special const-eval error test

# User-Facing Changes
**Major breaking change!**
`"string" * 42` will stop working. (This was used for example in the
stdlib)

We should bless a good alternative before landing this

---------

Co-authored-by: JT <547158+jntrnr@users.noreply.github.com>
2023-09-13 19:52:04 +12:00
a14e9e0a2e Invert &Options to Option<&T> (#10315)
Elide the reference for `Copy` type (`usize`)
Use the canonical deref where possible.
* `&Box` -> `&`
* `&String` -> `&str`
* `&PathBuf` -> `&Path`

Skips the ctrl-C handler for now.
2023-09-13 07:00:58 +08:00
3e14dc3eb8 Remove pythonic int * list behavior (#10292)
# Description
The pythonism that multiplying a scalar integer with a list results in a
repeated concatenation of the list, is ambiguous with other possible
interpretations and thus actively harmful to clear semantics in nushell.

Another possible reading of this scalar/vector product would be trying
to perform elementwise multiplication with the scalar.

Before we bless this alternative as a more reasonable design the best
course of action is to remove this pythonism.

Work related to #10233


# User-Facing Changes
Breaking change as this turns `int * list` or `list * int` into hard
errors.

# Tests + Formatting
Remove the associated test
2023-09-13 10:43:49 +12:00
ba6d8ad261 add std repeat command to replace "foo" * 3 (#10339)
related to
- https://github.com/nushell/nushell/issues/10233
- https://github.com/nushell/nushell/pull/10293
- https://github.com/nushell/nushell/pull/10292

inspired by @kubouch 

# Description
this PR adds a `repeat` command to the standard library

# User-Facing Changes
a new `repeat` command in `std`
```nushell
repeat anything a bunch of times, yielding a list of *n* times the input

# Examples
    repeat a string
    > "foo" | std repeat 3 | str join
    "foofoofoo"

Usage:
  > repeat <n>

Flags:
  -h, --help - Display the help message for this command

Parameters:
  n <int>: the number of repetitions, must be positive

Input/output types:
  ╭───┬───────┬───────────╮
  │ # │ input │  output   │
  ├───┼───────┼───────────┤
  │ 0 │ any   │ list<any> │
  ╰───┴───────┴───────────╯
```

# Tests + Formatting
a new test called `repeat_things` in `test_std.nu`

# After Submitting
2023-09-12 21:59:31 +02:00
2a08865851 add a few more columns to linux ps -l output (#10344)
# Description

This PR tried to add a few more columns to the Linux `ps -l` command.
Those columns are:
* start_time
* user_id
* priority
* process_threads

There are a few that I left commented out that could be added but the
screen was beginning to look crowded. So, I left out:
* group_id
* session_id
* tgp_id (which could be helpful for eventual job control)

And there's like 100 more things that could be added that didn't seem
especially useful right now.


![image](https://github.com/nushell/nushell/assets/343840/065c0538-8f7d-4c9f-871f-a1bc98aff9d1)


# 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.
-->
2023-09-12 14:50:05 -05:00
0a3bfe7f73 Allow parse-time evaluation of if (#10326) 2023-09-12 21:35:47 +03:00
JT
451a9c64d3 Change echo to print when not redirected (#10338)
# Description

This changes `echo` to work more closely to what users of other shells
would expect:

* when redirected, `echo` works as before and sends values through the
pipeline
* when not redirected, `echo` will print values to the screen/terminal

# User-Facing Changes

A standalone `echo` now will print to the terminal, if not redirected.

The `echo` command is no longer const eval-able, as it will now print to
the terminal in some cases.

# 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.
-->
2023-09-13 06:35:01 +12:00
88d79c84cd Update Nu to v0.84 for release and nightly-build (#10334)
<!--
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
Update Nu to v0.84 for release and nightly-build
2023-09-12 22:00:58 +08:00
abcb0877e2 Upgrade softprops/action-gh-release to v0.1.15 for release and nightly build workflow (#10331) 2023-09-12 21:05:55 +08:00
9e1e2a4320 provide env to commands and try to start provided path (#10302)
fixes #8551

# Description
Use `open::commands` function to get list of command available for
starting given path. run commands directly, providing environment, until
one of them is successful.

example of output if start was not successful:
```
~\code\nushell> start ..\nustart\a.myext                                                                    09/12/2023 01:37:55 PM
Error: nu:🐚:external_command

  × External command failed
   ╭─[entry #1:1:1]
 1 │ start ..\nustart\a.myext
   ·       ─────────┬────────
   ·                ╰── No command found to start with this path
   ╰────
  help: Try different path or install appropriate command

        Command `cmd /c start "" "..\nustart\a.myext"` failed with exit code: 1
```

# User-Facing Changes
`start` command now provides environment to the external command. This
is how it worked in `nu 0.72`, see linked issue.

# Tests + Formatting
`start` command didn't have any tests and this PR does not add any.
Integration-level tests will require setup specific to OS and
potentially change global environment on testing machine. For unit-level
test it is possible to test `try_commands` function. But is still runs
external commands, and robust test will require apriori knowledge which
commands are necessary successful to run and which are not.
2023-09-12 14:03:41 +02:00
d53b0a99d0 Rename random decimal to random float (#10320)
# Description
Similar to #9979

# User-Facing Changes
`random decimal` will now raise a warning and can be removed in an
upcoming release.

New command is named `random float`

# Tests + Formatting
Tests updated and improved.
2023-09-12 13:03:05 +02:00
1fb4f9e455 Rename into decimal to into float (#9979)
# Description
We keep "into decimal" for a release and warn through a message that it
will be removed in 0.86.

All tests are updated to use `into float`

# User-Facing Changes
`into decimal` raises a deprecation warning, will be removed soon.
Use `into float` as the new functionally identical command instead.

```
~/nushell> 2 | into decimal
Error:   × Deprecated command
   ╭─[entry #1:1:1]
 1 │ 2 | into decimal
   ·     ──────┬─────
   ·           ╰── `into decimal` is deprecated and will be removed in 0.86.
   ╰────
  help: Use `into float` instead


2
```

# Tests + Formatting
Updated

---------

Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2023-09-12 13:02:47 +02:00
6e9b6f22c9 Deref &String arguments to &str where appropriate (#10321)
# Description
This generally makes for nicer APIs, as you are not forced to use an
existing allocation covering the full `String`.

Some exceptions remain where the underlying type requirements favor it.

# User-Facing Changes
None
2023-09-12 14:06:56 +08:00
e90b099622 Use slices directly instead of &Vec (#10328)
Simplifies the signature, makes it more flexible.
Detected a few unnecessary allocations in the process.
2023-09-12 11:38:20 +08:00
JT
84c10de864 remove profiling from nushell's hot loop (#10325)
# Description

This removes pipeline element profiling. This could be a useful feature,
but pipeline elements are going to be the most sensitive to in terms of
performance, as `eval_block` and how pipelines are built is one of the
hot loops inside of the eval engine.

# User-Facing Changes

Removes pipeline element profiling.

# 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.
-->
2023-09-12 06:50:03 +12:00
d618b60d9e Remove leftover const eval file (#10324) 2023-09-11 21:30:38 +03:00
c761f7f844 add 'from ndjson' into standard library (#10283)
close #8574
related #10276 
# Description

added below into standard library
```
def "from ndjson" []: string -> any {
    from json --objects
}
```

# User-Facing Changes


Users can use functions like "from ndjson" in standard library, and can
open ndjson files with `open` command.
```
use std formats *
# `from ndjson` is available now
open sample.ndjson
```

# Tests + Formatting

`toolkit check pr`

- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`


# After Submitting

---------

Co-authored-by: Stefan Holderbach <sholderbach@users.noreply.github.com>
2023-09-11 14:59:07 +02:00
7b89fab327 Keep order for par-each (#10249)
# Description
This PR adds new flag `--keep-order/-k` for the `par_each` filter. This
flag keeps sequence of output same as the order of input.

Output without the flag:
```nu
> 1..6 | par-each {|n| $n * 2 }
╭────╮
│  4 │
│ 10 │
│  2 │
│  8 │
│ 12 │
│  6 │
╰────╯
```

Output with the `--keep-order` flag:
```nu
> 1..6 | par-each --keep-order {|n| $n * 2 }
╭────╮
│  2 │
│  4 │
│  6 │
│  8 │
│ 10 │
│ 12 │
╰────╯
```

I think the presence of this flag is justified, since:
- Much easier to use than `.. | enumerate | par-each {|p| update item
..} | sort-by index | get item`
- Faster, as it uses internally parallel sorting in the same thread pool

A note about naming: it may conflict with `--keep-empty/-k` flag of the
`each` filter if the same feature will be used in `par-each`, so maybe
it needs some other name.
2023-09-11 06:42:09 -05:00
eddff46155 Bump calamine and fix clippy (#10314)
Upgrade calamine to 0.22
Reduces one potential dependency duplication

Supersedes #10305

Includes fixes for clippy lints as API changed to return owned data.
2023-09-11 12:39:52 +02:00
baa50ec9b2 Update crates-ci/typos and fix new typos (#10313)
Supersedes #10309
2023-09-11 12:37:06 +02:00
513186c390 Bump bytesize from 1.2.0 to 1.3.0 (#10306) 2023-09-11 09:55:21 +00:00
0c37463bfa Bump tempfile from 3.7.0 to 3.8.0 (#10307) 2023-09-11 09:54:49 +00:00
94fc33bbee Bump actions/checkout from 3 to 4 (#10308) 2023-09-11 09:54:22 +00:00
ce378a68a6 Fix variables not allowed in ucp (#10304)
<!--
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
Fixes #10300 , where using variables didnt work with `ucp` as it was
only expecting a `Expr::FilePath`.

Before: (from the issue)
```
❯ ucp -r $var $folder
Error:   × Missing file operand
   ╭─[entry #40:1:1]
 1 │ ucp -r $var $folder
   · ─┬─
   ·  ╰── Missing file operand
   ╰────
  help: Please provide source and destination paths
```
Now:
```
`ucp -r $var $folder`
# success
```

Also added the test to ensure its working:) . Oh, and I tweaked again
slightly the messages on two tests because now the whole `path` is
printed rather than `a`. Say:
```
#before
`cp a a` --> 'a' and 'a' are the same file 
# now
`cp a a` --> /home/current/location/a and /home/current/location/a are the same file
```
<!--
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.
-->
2023-09-10 17:54:33 -05:00
fa40740e77 add case-insensitive example to where (#10299)
related to
-
https://discord.com/channels/601130461678272522/614593951969574961/1150395064292495400

# Description
two cool things about the `where` command
- it's versatile enough to allow creating a case-insensitive version of
itself
- it does not require the explicit use of a closure

this PR adds an example showing how to filter with `where` but
case-insensitively and without an explicite closure.

# User-Facing Changes
new example to `where`:
```nushell
  Find case-insensitively files called "readme", without an explicit closure
  > ls | where ($it.name | str downcase) =~ readme
```

# Tests + Formatting
the new example test above.

# After Submitting
2023-09-10 15:24:38 -05:00
762fdb98ac silence some ucp warnings (#10294)
# Description

This PR fixes some ucp warnings.

# 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.
-->
2023-09-09 19:41:53 -05:00
5f795b1aec Mention that perl is required for feature static-link-openssl… (#10291)
this PR should close https://github.com/nushell/nushell/issues/10290

it is a simple comment in Cargo.toml, which explains that perl is
required for feature static-link-openssl to work.
2023-09-09 22:34:07 +02:00
6811700b90 update reject to be able to recive arg list (#10216)
This PR is in relation to #10215 

# Description

This PR introduces `reject` to receive list of columns or rows as
argument.
This change is similar to change of `select` and the code used is
similar.

# User-Facing Changes
The user will be able to pass a list as rejection arguments.
```nushell
let arg = [ type size ]
[[name type size]; [ cargo.toml file 20mb ] [ Cargo.lock file 20mb] [src dir 100mb]] | reject $arg
```
2023-09-09 15:01:25 -05:00
248aca7a44 reject multiple row args support (#10163)
# Description
This PR fixes `reject` failing when providing row items in ascending
order.


# User-Facing Changes
users can now `reject` multiple rows independently of each other.
```nushell
let foo = [[a b]; [ 1 2] [3 4] [ 5 6]]
# this will work independant of the order
print ($foo | reject 2 1)
print ($foo | reject 1 2)
```

---------

Co-authored-by: Antoine Stevan <44101798+amtoine@users.noreply.github.com>
2023-09-09 13:59:31 -05:00
17abbdf6e0 allow into duration to take an integer amount of ns (#10286)
related to
-
https://discord.com/channels/601130461678272522/615329862395101194/1149717458786197524

# Description
because `1_234 | into datetime` takes an integer number of `ns` and
`1_234 | into filesize` takes an integer amount of bytes, i think `1_234
| into duration` should also be valid and see `1_234` as an integer
amount of `ns` 😋

# User-Facing Changes
## before
either
```nushell
1234 | into string | $in ++ "ns" | into duration
```
```nushell
1234 | $"($in)ns" | into duration
```
or
```nushell
1234 * 1ns
```
and
```nushell
> 1_234 | into duration
Error: nu::parser::input_type_mismatch

  × Command does not support int input.
   ╭─[entry #2:1:1]
 1 │ 1_234 | into duration
   ·         ──────┬──────
   ·               ╰── command doesn't support int input
   ╰────
```

## after
```nushell
> 1_234 | into duration
1µs 234ns
```

# Tests + Formatting
new example test
```rust
Example {
    description: "Convert a number of ns to duration",
    example: "1_234_567 | into duration",
    result: Some(Value::duration(1_234_567, span)),
}
```

# After Submitting
2023-09-09 13:49:08 -05:00
40eca52ed5 allow update to use metadata (#10264)
# Description

This PR is an attempt to fix the `update` command so that it passes
along metadata. I'm not really sure I did this right, so please feel
free to point out where it's wrong.

The point is to be able to do something like this and have it respect
your LS_COLORS.
```
ls | update modified { format date }
```
### Before

![image](https://github.com/nushell/nushell/assets/343840/fc3eb207-4f6f-42b1-b5a4-87a1fe194399)

### After

![image](https://github.com/nushell/nushell/assets/343840/19d58443-7c88-4dd6-9532-1f45f615ac7b)


# 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.
-->
2023-09-09 13:47:42 -05:00
7907dda8f7 Make cursor_shape optional (#10289)
# Description
There are several cursor shape related issues #7151 #9243 #7271 #8452
#10169, you can't disable the cursor shape feature even if you comment
out the entire `cursor_shape` block in the config.nu, and even worse,
when nushell exits with an error, the cursor shape can't be restored,
that is annoying.

This PR provides an opportunity to disable setting the cursor shape.

# User-Facing Changes
If you use the default config.nu, nothing changes, but if you comment
out `cursor_shape` block or set them to `inherit`, related cursor shape
will not be set.

# 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.
-->
2023-09-09 13:42:36 -05:00
8501024546 signpost 'input list --types [key]' from 'keybindings list' (#10287)
Supercedes https://github.com/nushell/nushell/pull/10196

# Description

After reading
https://github.com/nushell/nushell/pull/10196#issuecomment-1703986359 I
added a signpost from `keybindings listen` to `input listen`

When I initially tried `input listen` it always immediately returned
with:
```
╭───────┬────────╮
│ type  │ focus  │
│ event │ gained │
╰───────┴────────╯
```

I added an example to `input listen --help` to suggest only listening to
key events

Initially I also included a `result` but it prints as:

```
  ╭───────────┬───────────────╮
  │ type      │ key           │
  │ key_type  │ char          │
  │ code      │ c             │
  │ modifiers │ [list 1 item] │
  ╰───────────┴───────────────╯
```

rather than:

```
╭───────────┬───────────────────────────────╮
│ type      │ key                           │
│ key_type  │ char                          │
│ code      │ c                             │
│           │ ╭───┬───────────────────────╮ │
│ modifiers │ │ 0 │ keymodifiers(control) │ │
│           │ ╰───┴───────────────────────╯ │
╰───────────┴───────────────────────────────╯
```
so I removed it.

# User-Facing Changes

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

* Example describing how to use `input list --types [key]` to listen for
keybindings.
* Signpost pointing at `use std input; input list --types [key]` from
`keybindings list`.

## After merging

It is probably worth:

a) signposting to the keybindings section of the book from both of these
subcommands (like I did in
https://github.com/nushell/nushell/pull/10193),
b) giving an example in the book of how to take the output from `input
listen --types [key]` and format it for including in `config nu`
c) there are not currently any examples in
crates/nu-utils/src/sample_config/default_config.nu for keybindings with
multiple modifiers. Should I add alt+backspace-in-macos-vscode as an
example (gets translated to `{ modifier: control_alt keycode: char_h }`
for historical reasons)?

---------

Co-authored-by: Antoine Stevan <44101798+amtoine@users.noreply.github.com>
2023-09-09 09:42:37 -05:00
21d30d1e4d Fix rm on macOS (#10282)
# Description

Removes the signal ignore for `SIGCHLD` added by #10021, since it
interferes with `rm` on macOS.
2023-09-08 19:03:30 -05:00
eeaa65c8af Bump itertools from 0.10.5 to 0.11.0 (#9524) 2023-09-08 23:12:45 +00:00
6754b8534e Remove Cargo.lock in subcrates (#10280)
This should not be there in a workspace crate.

[See cargo
docs](https://doc.rust-lang.org/cargo/reference/workspaces.html)

Causes a spurious dependabot alert and is not easily updated.
2023-09-09 00:45:43 +02:00
2ffff959fc add 6 more table themes (#10279)
# Description

After looking at a users terminal that didn't support UTF-8, I wanted to
add some themes that may help them. Here's what they look like.

## psql

![image](https://github.com/nushell/nushell/assets/343840/67ac003a-72f1-4e2b-8bb0-244b70385d59)

## markdown

![image](https://github.com/nushell/nushell/assets/343840/a8f4a439-013b-48ee-b9e0-284ec47d1eef)

## dots
please excuse the different theme

![image](https://github.com/nushell/nushell/assets/343840/fb931650-cc64-4f0a-bf3d-ec736e0374ad)

## restructured

![image](https://github.com/nushell/nushell/assets/343840/80595a8e-f2b3-49dc-ad02-81e94bde5253)

## ascii_rounded

![image](https://github.com/nushell/nushell/assets/343840/42f0b8b2-1fd2-4ae5-b28c-477e83ded354)

## basic_compact

![image](https://github.com/nushell/nushell/assets/343840/5888b6b2-b9b8-48bc-963e-5a76ef246adc)


# 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.
-->
2023-09-08 16:34:36 -05:00
fed4233db4 use uutils/coreutils cp command in place of nushell's cp command (#10097)
<!--
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. Basically, this is a continuation of the work that @fdncred started.
Given some nice discussions on #9463 , and [merged uutils
PR](https://github.com/uutils/coreutils/pull/5152) from @tertsdiepraam
we have decided to give the `cp` command the `crawl` stage as it was
named.

> [!NOTE] 
Given that the `uutils` crate has not made the release for the merged
PR, just make sure you checkout latest and put it in the required place
to make this PR work.

The aim of this PR is for is to see how to move forward using `uutils`
crate. In order to getting this started, I have made the current
`nushell cp tests` pass along with some extra ones I copied over from
the `uutils` repo.

With all of that being said, things that would be nice to decide, and
keep working on:

Crawl:
- Handling of certain `named` flags, with their long and short
forms(e.g. --update, --reflink, --preserve, etc), and using default
values. Maybe `-u` can already have a `default_missing_value`.
- Should we maybe just support one single option `switch` flags (see
`--backup` in code) as a contrast to the other named args.
- Complete test coverage from `uutils`. They had > 100 tests, and I
could only port like 12 as they are a bit time consuming given they
cannot be straight up copy pasted. Maybe we do not need all >100, but
maybe the more relevant to what we want.
- Refactor this code

Walk:
- Non fatal errors on `copy` from `utils`. Currently it just sends it to
stdout but errors have no span
- Better integration 

An added possibility is the addition of `SyntaxShape::OneOf()` for
`Named` arguments which was briefly mentioned in the discord server, but
that is still to be decided. This could greatly improve some of the
integration. This would enable something like `cp --preserve [all
timestamp]` or `cp --preserve all` to both work.

I did not want to keep holding on this, and wait till I was happy with
the code because I think its nice if everyone can start up and suggest
refactors, but the main important part now was getting it out the door,
as if I take my sweet time this will take way longer 😛

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

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

---------

Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2023-09-08 13:57:38 -05:00
2f47263380 respect a users locale with the right prompt (#10273)
# Description

This PR tries to respect a person's locale setting with date/time in the
default right prompt. This also restores the right prompt so that it
does not load from the US default from reedline.

closes https://github.com/nushell/nushell/issues/9924


Here's the fromat reference if anyone thinks there's a better time
format. I could be talked into `%c` maybe.
https://docs.rs/chrono/latest/chrono/format/strftime/index.html

# 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.
-->
2023-09-08 12:24:42 -05:00
4d5386635e add more ps columns in Windows (#10275)
# Description

This PR adds a few more columns to `ps -l` on Windows. It would be good
to add these changes cross-platform in separate PRs. This PR also fixes
a bug where start time was calculated wrong.

I've added:
start_time
user
user_sid
priority


![image](https://github.com/nushell/nushell/assets/343840/cba16a17-ee70-46b5-9e6d-ef06641b264e)

# 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.
-->
2023-09-08 12:24:29 -05:00
872eb2c3df Restore initial foreground process group on exit (#10021)
# Description
When launching nushell interactively from another shell, the parent
shell usually gives us own our process group and handles restoring
control to itself. However, other programs that do not support job
control expect us to give control of the terminal back to them. This PR
makes it so that we record the initial foreground process group and
restore it when nushell exits. An "exit" can be from the `exit` command,
a panic, or a `SIGTERM` signal.

The changes in `terminal.rs` mostly follow [fish's
example](0874dd6a96/fish-rust/src/common.rs (L1634)).

# User-Facing Changes
Fixes interactions between nushell and other interactive CLI commands
(e.g., VIFM #10015).
2023-09-08 18:19:01 +02:00
e62a77a885 Start removing colour config from explore (#10270)
This PR removes the `explore.try.border_color` config item, and instead
always uses the `separator` colour (the one used for regular table
borders) from the current theme.

The PR also removes some unused `explore.config` bits from the default
config (I missed this in https://github.com/nushell/nushell/pull/10259).

### Future Work

This PR is intentionally small, I want to confirm that I'm on the right
track before I rip out more colour config from `explore`. If all goes
well, expect more PRs like this soon.

### Testing

I confirmed that this works by changing my `separator` colour in
`config.nu`, and also confirmed that nothing breaks if a user still has
`explore.try.border_color` in their config.
2023-09-08 07:34:47 -07:00
9bca63ebef update format date when using %x %X %r (#10272)
# Description

Apparently some strftime formats are already localized and when you
"double localize" them, they don't work. This PR fixes that so that %x
%X %r %c don't go through the localization step.

Example: %x %X
### Before
```nushell
❯ date now | format date "%x %X %p"
09/08/2023 08 AM
```
### After
```nushell
❯ date now | format date "%x %X %p"
09/08/23 08:09:14 AM
```

I started to make one format_datetime to rule them all but one returns a
string and one returns a value. If we convert to the string, we lose the
nice error messages. If we change to value, more code has to be changed
elsewhere. So, I decided to just leave two functions.

# 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.
-->
2023-09-08 08:59:05 -05:00
ae54dc862c Move spellcheck config into .github folder (#10267)
Keep the `.typos.toml` out of the repo root for better readability

Also specify a version for the workflow to protect against breakage
2023-09-07 22:46:00 +02:00
5e951b2be9 Remove codecov.io setup (#10266)
As we currently don't run the coverage in CI and don't upload to
codecov.io remove the config to clean up the repo root.
2023-09-07 22:12:23 +02:00
f78d57a703 feat: Search terms for use, while, and range (#5093) (#10265)
# Description

Add search terms to the commands: `use` ("environment", "import"),
`while` ("loop"), and `range` ("filter", "head", "tail").

# Tests + Formatting
All completed successfully.

---------

Co-authored-by: Stefan Holderbach <sholderbach@users.noreply.github.com>
2023-09-07 22:11:42 +02:00
f021be623e Exit explore on ctrl+c/d/q (#10257)
Currently, `ctrl+z` is the command to exit `explore` no matter where you
are in the UI. IMO this is a bit unintuitive since that's usually used
to suspend a process.

After this change, `ctrl+c`, `ctrl+d`, and `ctrl+q` all work to exit
`explore`.

I think these are all shortcuts that users might try when attempting to
exit `explore`, and I think we might as well handle them all.
2023-09-07 19:47:17 +02:00
b6189879e3 explore: remove :config, :show-config, :tweak commands (#10259)
More trimming of underused `explore` functionality.

The `explore` command has subcommands that can be run like `:config` or
`:try` or whatnot. This PR removes the `:config`, `:show-config`, and
`:tweak` commands which are all for viewing+modifying config.

These are interesting commands and they were cool experiments, but
ultimately I don't think they fit with our plans for a simplified
`explore`. They'd need a lot more polish if we want to keep them and I
don't think we do. Happy to discuss if I've missed a good reason to keep
these.

cc @fdncred
2023-09-07 10:34:08 -05:00
c7c6445b03 Remove exit_esc and show_banner config from explore (#10258)
Removing 2 underused config options from `explore`.

`show_banner` controls whether `For help type :help"` is shown in the
message area when `explore is first launched. I don't think there's any
good reason not to show it, it's not a modal dialog or anything.

`exit_esc` controls whether to exit `explore` when `esc` is pressed and
we can't "go up" any further (or at least that's what it's supposed to
do, looking at the code I'm not so sure). IMO we don't need to make this
kind of basic interaction configurable unless there's a really good
reason.

## Context

`explore` is complicated and we want to overhaul its design. It will be
easier to make meaningful changes if `explore` is a little slimmer
first, so I'm trying to pare back unused/underused code and config as a
starting point.

I'm gonna be making more PRs like this, I'll try to keep them
small+self-contained.
2023-09-07 14:39:04 +02:00
535aec0648 readme: add dorothy to supported by (#10262)
Add Dorothy — https://github.com/bevry/dorothy — to the supported by
section. Dorothy is a dotfile ecosystem that enables a cross-shell and
cross-operating system dotfile experience. Allowing you to easily switch
to Nu, while keeping your existing env configuration, and allowing you
to write Nu commands that are accessible to other shells.

Dorothy  now has CI testing for its Nu integration.
2023-09-07 13:58:31 +02:00
664dd291eb Restore NU_LIB_DIRS and NU_PLUGIN_DIRS defaults (#10252)
# Description

This PR reverts some changes to NU_LIB_DIRS and NU_PLUGIN_DIRS in the
default_env.config file. Our practice is to have default configs that
match if you were to run `nu -n`. I agree with this goal, but until
someone adds NU_LIB_DIRS and NU_PLUGIN_DIRS, we should revert this
change and not penalize users, breaking their scripts that run with `nu
-c blah` when `blah` is located in the default_env's NU_LIB_DIRS.


# 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.
-->
2023-09-06 22:00:55 +02:00
a9216deaa4 allow --login to be used with nu's --commands parameter (#10253)
# Description

This PR allows the `--login`/`-l` parameter to be used with nushell's
`--commands`/`-c` parameter. When you do this, since you're invoking it
with the `-l` flag, nushell will load your env.nu, config.nu, and
login.nu, in that order. Then it will proceed to run your commands. I
think this provides a better quality of life when you want to run
scripts with your personal config files as a login shell.


### Before (these entries are from the default_env.nu)

![image](https://github.com/nushell/nushell/assets/343840/ce7adcd0-419e-485c-b7d1-f11f162e8e9e)


### After (these entries are from my personal env.nu)

![image](https://github.com/nushell/nushell/assets/343840/33bbc06b-983c-4461-8274-290e4c712506)


closes https://github.com/nushell/nushell/issues/9833

# 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.
-->
2023-09-06 13:27:16 -05:00
99caad7d60 nu-explore: Refactorings (#10247)
1. Added mode to the status bar right most corner
2. Added a command name with a status when run

ref #8582 
cc: @fdncred
2023-09-06 13:24:24 -05:00
7486850357 rename the types with spaces in them to use - (#9929)
# Description
before this PR,
```nushell
> $.a.b | describe
cell path
```
which feels inconsistent with the `cell-path` type annotation, like in
```nushell
> def foo [x: cell-path] { $x | describe }; foo $.a.b
cell path
```

this PR changes the name of the "cell path" type from `cell path` to
`cell-path`

# User-Facing Changes
`cell path` is now `cell-path` in the output of `describe`.
this might be a breaking change in some scripts.

same goes with
- `list stream` -> `list-stream`
- `match pattern` -> `match-pattern`

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

this PR adds a new `cell_path_type` test to make sure it stays equal to
`cell-path` in the future.

# After Submitting

---------

Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2023-09-06 13:22:12 -05:00
bb06661d24 Document that open looks up from subcommands (#10255)
# Description
Related to https://github.com/nushell/nushell.github.io/pull/1048

Include this information in the command help.


# User-Facing Changes
As soon as this information is documented people are much more likely to
depend on it so we need to be careful in the future if this design
sparks joy or not.
2023-09-06 19:26:53 +02:00
6a374182a7 change LOG_FORMAT to NU_LOG_FORMAT in nu-std library (#10254)
this closes #10248 

@fdncred pointed out the problem and he was correct 😄 

I went ahead and made the simple change and the
https://github.com/influxdata/influxdb_iox binary
works like a charm...

@amtoine hopefully there are no issues with this change

I believe its a good one as other rust binaries might take advantage of
this common
environment variable as well...
2023-09-06 10:17:14 -07:00
f433b3102f fix default after an empty where (#10240)
should close https://github.com/nushell/nushell/issues/10237

# Description
this is @fdncred's findings 😋 
i just made the PR 😌 

# User-Facing Changes
```nushell
[a b] | where $it == 'c' | last | default 'd'
```
now works and gives `d`


# Tests + Formatting
adds a new `default_after_empty_filter` test.

# After Submitting
2023-09-06 16:39:35 +08:00
456e2a8ee3 move math constants to standard library (#9678)
# Description
we talked about this before in some meetings so i thought, why not?

the hope is that these constants do not require Rust code to be
implemented and that this move will make the Rust source base a bit
smaller 🤞

# User-Facing Changes
mathematical constants (e, pi, tau, phi and gamma) are now in `std math`
rather than `math`

## what can be done
```nushell
> use std; $std.math
> use std math; $math
> use std *; $math
```
will all give
```
╭───────┬────────────────────╮
│ GAMMA │ 0.5772156649015329 │
│ E     │ 2.718281828459045  │
│ PI    │ 3.141592653589793  │
│ TAU   │ 6.283185307179586  │
│ PHI   │ 1.618033988749895  │
╰───────┴────────────────────╯
```
and the following will work too
```nushell
> use std math E; $E
2.718281828459045
```
```nushell
> use std math *; $GAMMA
0.5772156649015329
```

## what can NOT be done
looks like every export works fine now 😌 

# Tests + Formatting
# After Submitting
2023-09-05 19:32:31 +02:00
1ee3bf784c Tweak contributor image to include more users (#10238)
We previously had a limit of 500 users but we are well past that
2023-09-05 16:52:21 +02:00
54394fe9af Allow operator in constants (#10212)
This pr fixes https://github.com/nushell/nushell/issues/10200

# Description

Allow unary and binary operators in constants, e.g.

```bash
const a = 1 + 2
const b = [0, 1, 2, 3] ++ [4]
```

# User-Facing Changes

Now constants can contain operators.

# Tests + Formatting

- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`

# After Submitting

None

---------

Co-authored-by: Horasal <horsal@horsal.dev>
2023-09-05 16:35:58 +02:00
7a728340de return error when user break sleep by ctrl-c (#10234)
# Description

Closes: #10218
I think this is `sleep`'s specific issue, it's because it always return
a `Value::nothing` where it's interrupted by `ctrl-c`.

To fix the issue, I'd propose to make it returns Err(ShellError)

This is how it behaves:
```nushell
❯ sleep 5sec; echo "hello!"
^CError: nu:🐚:sleep_breaked

  × Sleep is breaked.

❯ sleep 5sec; ^echo "hello!"
^CError: nu:🐚:sleep_breaked

  × Sleep is breaked.
```
# User-Facing Changes
None

# Tests + Formatting


# After Submitting
2023-09-05 09:21:30 -05:00
5f1e8a6af8 Clean up trash support on Android (#10225)
# Description

Currently on Android, there are warnings about unused variables. This PR
fixes that with more conditional guards for the unused variables.

Additionally, in #10013, @kubouch gave feedback in [the last
PR](https://github.com/nushell/nushell/pull/10013#pullrequestreview-1596828128)
that it was unwieldy to repeat

```rust
#[cfg(all(
    feature = "trash-support",
    not(target_os = "android"),
    not(target_os = "ios")
))]
```
2023-09-05 14:38:23 +02:00
e566a073dc Exit early when encountering parsing errors (#10213)
# Description
This PR tries to fix #10184 and #10182.
2023-09-05 14:36:37 +02:00
9a4dad6ca1 Fix unit tests on Android (#10224)
# Description

* The path to the binaries for tests is slightly incorrect. It is
missing the build target when it is set with the `CARGO_BUILD_TARGET`
environment variable. For example, when `CARGO_BUILD_TARGET` is set to
`aarch64-linux-android`, the path to the `nu` binary is:

  `./target/aarch64-linux-android/debug/nu`

  rather than

  `./target/debug/nu`

This is common on Termux since the default target that rustc detects can
cause problems on some projects, such as [python's `cryptography`
package](https://github.com/pyca/cryptography/issues/7248).
  
This technically isn't a problem specific to Android, but is more likely
to happen on Android due to the latter.
* Additionally, the existing variable named `NUSHELL_CARGO_TARGET` is in
fact the profile, not the build target, so this was renamed to
`NUSHELL_CARGO_PROFILE`. This change is included because without the
rename, the build system would be using `CARGO_BUILD_TARGET` for the
build target and `NUSHELL_CARGO_TARGET` for the build profile, which is
confusing.
* `std path add` tests were missing `android` test

# User-Facing Changes

For those who would like to build nushell on Termux, the unit tests will
pass now.
2023-09-05 20:17:34 +12:00
eca9f461da Make append/prepend consistent for ranges (#10231)
# Description
This PR makes `append`/`prepend` more consistent, in particular, it allows you to
work with ranges. Previously, you couldn't append a list by range:
```nu
> 0..1 | append 2..4
╭──────╮
│    0 │
│    1 │
│ 2..4 │
╰──────╯
```

Now it works:
```nu
> 0..1 | append 2..4
╭───╮
│ 0 │
│ 1 │
│ 2 │
│ 3 │
│ 4 │
╰───╯
```

# User-Facing Changes
If someone needs the old behavior, then it can be obtained like this:
```nu
> 0..1 | append [2..4]
╭──────╮
│    0 │
│    1 │
│ 2..4 │
╰──────╯
```
2023-09-05 01:47:51 +02:00
08aaa9494c Bump rust-embed from 6.8.1 to 8.0.0 (#10208) 2023-09-04 21:16:44 +00:00
352f913c39 Bump git2 from 0.17.2 to 0.18.0 (#10207) 2023-09-04 21:10:25 +00:00
aeeb5dd405 Bump winreg from 0.50.0 to 0.51.0 (#10209) 2023-09-04 21:05:00 +00:00
278bf7ffa9 upgrade nix to 0.27 (#10223)
This fixes a segfault on Android when fetching the user group.

See: https://github.com/nix-rust/nix/issues/2084
2023-09-04 22:41:28 +02:00
b15c824932 Fix example history command pipeline (#10220)
the example for `history` was out of date, this PR updates it.

## the failing command
```
❯ history | wrap cmd | where cmd =~ cargo
Error: nu:🐚:type_mismatch

  × Type mismatch during operation.
   ╭─[entry #23:1:1]
 1 │ history | wrap cmd | where cmd =~ cargo
   · ───┬───                        ─┬ ──┬──
   ·    │                            │   ╰── string
   ·    │                            ╰── type mismatch for operator
   ·    ╰── record<start_timestamp: string, command: string, cwd: string, duration: duration, exit_status: int>
   ╰────
```
2023-09-04 19:17:56 +02:00
5ad3bfa31b Auto format let-else block (#10214)
<!--
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.
-->
rustfmt 1.6.0 has added support for formatting [let-else
statements](https://doc.rust-lang.org/rust-by-example/flow_control/let_else.html)

See https://github.com/rust-lang/rustfmt/blob/master/CHANGELOG.md#added

# 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.
-->
2023-09-04 19:42:31 +12:00
e5145358eb treat path contains '?' as pattern (#10142)
Fix https://github.com/nushell/nushell/issues/10136

# Description
Current nushell only handle path containing '*' as match pattern and
treat '?' as just normal path.
This pr makes path containing '?' is also processed as pattern.

🔴 **Concerns: Need to design/comfirm a consistent rule to handle
dirs/files with '?' in their names.**

Currently:

- if no dir has exactly same name with pattern, it will print the list
of matched directories
- if pattern exactly matches an empty dir's name, it will just print the
empty dir's content ( i.e. `[]`)
- if pattern exactly matches an dir's name, it will perform pattern
match and print all the dir contains

e.g.
```bash
mkdir src
ls s?c 
```

| name | type | size   | modified                                      |
| ---- | ---- | ------ | --------------------------------------------- |
| src  | dir  | 1.1 KB | Tue, 29 Aug 2023 07:39:41 +0900 (9 hours ago) |

-----------

```bash
mkdir src
mkdir scc
mkdir scs
ls s?c
```

| name | type | size | modified |
| ---- | ---- | ------ |
------------------------------------------------ |
| scc | dir | 64 B | Tue, 29 Aug 2023 16:55:31 +0900 (14 seconds ago) |
| src | dir | 1.1 KB | Tue, 29 Aug 2023 07:39:41 +0900 (9 hours ago) |

-----------

```bash
mkdir  s?c
ls s?c
```

print empty (i.e. ls of dir `s?c`)

-----------

```bash
mkdir -p  s?c/test
ls s?c
```
|name|type|size|modified|
|-|-|-|-|
|s?c/test|dir|64 B|Tue, 29 Aug 2023 16:47:53 +0900 (2 minutes ago)|
|src/bytes|dir|480 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
|src/charting|dir|160 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
|src/conversions|dir|160 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|

-----------

# User-Facing Changes

User will be able to use '?' to match directory/file.

# Tests + Formatting

- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`

# After Submitting

None

---------

Co-authored-by: Horasal <horsal@horsal.dev>
2023-09-03 19:25:00 -05:00
3a20fbfe94 Update crossterm/ratatui/dev-reedline (#10137)
# Description
This updates most crates to 0.27 `crossterm`.
To do so we need the most recent `ratatui`

`reedline` can now update as well.
See https://github.com/nushell/reedline/pull/625

Sadly this introduces some crate duplication again as there are some
other dependency updates.
Furthermore we have another crate depending on 0.26.1 crossterm
(`comfy-table` that some how gets pulled in by polars)

# User-Facing Changes
2 additional mouse events detected by `input listen`

# Tests + Formatting
None
2023-09-03 19:22:25 -05:00
dac32557cd prevent crash when use redirection with let/mut (#10139)
Fix #9992 

I mistakenly messed up https://github.com/nushell/nushell/pull/10118 and
this is a cleaned version.

# Description

* This pr changes the panic to errors while parsing `let`, now user will
get the following errors:
<img width="395" alt="scr"
src="https://github.com/nushell/nushell/assets/1991933/4b39ac14-cd1f-47b3-9490-81009ca42717">
<img width="394" alt="scr"
src="https://github.com/nushell/nushell/assets/1991933/71ce33ad-f4d0-4132-828f-9674b9603556">
<img width="440" alt="scr"
src="https://github.com/nushell/nushell/assets/1991933/257eab4d-1a72-42db-b09e-f42bef33d2ec">

* `out+err>` is cached by `parse_expression` but not this, which may be
a potential problem.
* `Commond(None, ..)` remains panic for future bug report because I
don't actually know when/how does it happen

# User-Facing Changes

Nushell won't crash when user typing `let a = 1 err> ...`

# Tests + Formatting

- `cargo fmt --all -- --check` : OK
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` : OK
- `cargo test --workspace` : OK
- `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` : OK

# After Submitting

None

Co-authored-by: Horasal <horsal@horsal.dev>
2023-09-03 19:21:45 -05:00
fedd879b2e support tab completion cycling (#10199)
should close https://github.com/nushell/nushell/issues/7202

# Description
i have been annoyed enough by this missing feature, so let's add that to
Nushell without requiring any user configuration 😏

# User-Facing Changes
this PR should allow tab completion cycling everytime, without requiring
the user to use the default config files or add the following
keybindings to their config
```nushell
    {
        name: completion_menu
        modifier: none
        keycode: tab
        mode: [emacs vi_normal vi_insert]
        event: {
            until: [
                { send: menu name: completion_menu }
                { send: menunext }
                { edit: complete }
            ]
        }
    }
```

### 🧪 try it out
from the root of the repo, one can try `<tab>` in each of the following
cases:
- `cargo run -- -n` to load Nushell without any config
- `cargo run -- --config
crates/nu-utils/src/sample_config/default_config.nu --env-config
crates/nu-utils/src/sample_config/default_env.nu` to load the default
configuration
- `cargo run` to load the user configuration

## before
- `<tab>`, `ls <tab>` and `str <tab>` only work with the second `cargo
run`, i.e. when loading the default config files

## after
- `<tab>` should cycle through the available commands
- `ls <tab>` should cycle through the available files and directories
- `str <tab>` should cycle the subcommands of `str`

in all three cases

# Tests + Formatting

# After submitting
2023-09-03 19:19:39 -05:00
a46c21cffb add plugin path when there are no signatures (#10201)
# Description

This PR adds the ability to have a `$nu.plugin-path` even when you
plugins are registered and it also should work with `nu -n --no-stdlib`.

### Before
It would give an error
```
│ plugin-path        │ IOError("Could not get plugin signature location")             │
```

### After
It returns the proper path, like this for me
```
│ plugin-path        │ /Users/fdncred/Library/Application Support/nushell/plugin.nu   │
```

Closed #10198 
# 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.
-->
2023-09-03 19:19:04 -05:00
JT
6cdfee3573 Move Value to helpers, separate span call (#10121)
# Description

As part of the refactor to split spans off of Value, this moves to using
helper functions to create values, and using `.span()` instead of
matching span out of Value directly.

Hoping to get a few more helping hands to finish this, as there are a
lot of commands to update :)

# 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>
Co-authored-by: WindSoilder <windsoilder@outlook.com>
2023-09-03 07:27:29 -07:00
af79eb2943 Point from keybindings help to the book's reedline chapter (#10193)
Documentation of keybindings command now points to the appropriate
section of the book.
2023-09-02 21:12:14 +02:00
e9d4730099 refactor input command (#10150)
close #8074 

I attempted to refactor the "input" command. The reason for this is that
the current implementation of the "input" command lacks consistency for
different options. For instance, some parts use `std::io::stdin` while
others use `crossterm::event::read`.

In this pull request, I have made changes to use crossterm consistently:
- Detection of the -u option is now done using `crossterm`'s
`KeyCode::Char`.
- The current input is displayed when using `crossterm` for input (it
won't be displayed when -s is present).
- Ctrl-C triggers SIGINT. 


# User-Facing Changes

Users can interrupt "input" with ctrl-c.
2023-09-02 21:09:26 +02:00
844f541719 changed default env file to use $nu.home_path to find home (#10192)
# Description
Changed the default env file so that home is found using `$nu.home-path`
instead to using an if-else statement to find the os then find the
specific environment variable
2023-09-02 09:00:10 -05:00
d28f728787 Add NU_VERSION environment variable on startup (#10177) 2023-09-01 09:48:13 +03:00
f35808cb89 Make $nu constant (#10160) 2023-09-01 09:18:55 +03:00
7d6b23ee2f Simplify rawstrings in tests (#10180)
Inspired by
https://rust-lang.github.io/rust-clippy/master/index.html#/needless_raw_string_hashes

Ran `cargo +stable clippy --workspace --all-targets`

Fixed manually as I ran into a false positive along the lines of:
https://github.com/rust-lang/rust-clippy/issues/11068

Also collapse one set of single line tests.

Work for #8670
2023-09-01 00:08:27 +02:00
e68ae4c8d1 Bump notify-debouncer-full from 0.2.0 to 0.3.1 (#10129) 2023-08-31 22:07:41 +00:00
faad6ca355 Remove dead tests depending on inc (#10179)
They relied on the `nu_plugin_inc` but where behind a feature flag that
isn't actually defined anywhere. These tests of `update` or `upsert`
shouldn't really depend on `inc` so I decided to remove them outright as
they haven't been used to exercise the commands under test.
2023-08-31 23:11:04 +02:00
c77c1bd297 Tests: clean up unnecessary use of pipeline() (#10170)
As described in Issue #8670, removed `pipeline()` wherever its argument
contained no line breaks.

---------

Co-authored-by: sholderbach <sholderbach@users.noreply.github.com>
2023-08-31 23:10:29 +02:00
5b4b4446b7 Keep arrow2 out of basic --workspace build (#10178)
Same logic as in #9971

Prevents building the heavy polars and arrow dependencies when just
running `cargo test --workspace` or `rust-analyzer`

`polars-io` dependency was introduced in #10019
2023-08-31 23:10:11 +02:00
93f20b406e feat: allow from csv to accept 4 byte unicode separator chars (#10138)
- this PR should close #10132

# Description
* added a flag to `from csv --ascii` that replaces the given `separator
with the unicode separator x1f https://www.codetable.net/hex/1f (aka
Information Separator One)

# User-Facing Changes
New flags are available for `from csv` ( `--ascii` or short `-a`)

# Tests + Formatting
There are no tests at the moment. Code has been formatted.
- `cargo test --workspace` (breaks with a non related test on my
machine)
2023-08-31 18:55:39 +02:00
02318cf3a7 update query web example because wikipedia changed their page (#10173)
# Description

This PR updates one of the query web examples because the wikipedia page
changed. This works again.

![image](https://github.com/nushell/nushell/assets/343840/72658c98-a339-4e76-96da-56d725e7a0e1)


# 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.
-->
2023-08-31 11:00:30 -05:00
35fc387505 Fix #10154 (#10162)
close #10154
2023-08-31 08:43:27 -05:00
fd4ba0443d fixed usages of deprecated chrono DateTime::from_utc (#10161)
This addresses the warnings generated from using DateTime::from_utc.
DateTime::from_utc was deprecated as of chrono 0.4.27

Co-authored-by: Jack Wright <jack.wright@disqo.com>
2023-08-30 17:04:19 -05:00
b943cbedff skip comments and eols while parsing pipeline (#10149)
This pr 
- fixes https://github.com/nushell/nushell/issues/10143
- fixes https://github.com/nushell/nushell/issues/5559

# Description

Current `lite_parse` does not handle multiple line comments and eols in
pipeline.
When parsing the following tokens:


| `"abcdefg"` | ` \|` | `# foobar` | ` \n` | `split chars` |
| ------------- | ------------- |------------- |-------------
|------------- |
| [Command] | [Pipe] | [Comment] | [Eol] | [Command] |
| | | Last Token |Current Token | |

`TokenContent::Eol` handler only checks if `last_token` is `Pipe` but it
will be broken if there exist any other thing, e.g. extra `[Comment]` in
this example.

This pr make the following change:

- While parsing `[Eol]`, try to find the last non-comment token as
`last_token`
- Comment is supposed as `[Comment]+` or `([Comment] [Eol])+`
- `[Eol]+` is still parsed just like current nu (i.e. generates
`nothing`).

Notice that this pr is just a quick patch if more comment/eol related
issue occures, `lite_parser` may need a rewrite.

# User-Facing Changes

Now the following pipeline works: 

```bash
1 | # comment
each { |it| $it + 2 } | # comment
math sum
```

Comment will not end the pipeline in interactive mode:

```bash
❯ 1 | # comment   (now enter multiple line mode instead of end)
▶▶ # foo
▶▶ 2
```

# Tests + Formatting

- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`

# After Submitting

None

---------

Co-authored-by: Horasal <horsal@horsal.dev>
2023-08-30 13:24:13 -05:00
3fd1a26ec0 Updating polars and sqlparser versions (#10114)
Polars and SQLParser upgrade.

I have exposed features that have been added to polars as command args
where appropriate.

---------

Co-authored-by: Jack Wright <jack.wright@disqo.com>
Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
Co-authored-by: sholderbach <sholderbach@users.noreply.github.com>
2023-08-30 00:13:34 +02:00
3f2c76df28 Move eval_hook to nu-cmd-base (#10146)
I moved hook to *nu_cmd_base* instead of *nu_cli* because it will enable
other developers to continue to use hook even if they decide to write
their on cli or NOT depend on nu-cli

Then they will still have the hook functionality because they can
include nu-cmd-base
2023-08-29 23:46:50 +02:00
7d3312e96e remove warnings in nu_command tests (#10145)
several warnings were appearing in nu_command tests when running just
the tests
in nu_command so I went ahead and removed the warnings...
2023-08-29 13:18:52 -07:00
c59d9dc306 update rust-toolchain doc to 4 weeks from 3 (#10140)
When we updated our release schedule from 3 weeks to 4 weeks the doc on
the toolchain
file was never updated so I went ahead and did that...
2023-08-28 20:57:03 -07:00
1f06f8405c handle empty pipeline while parsing let (fix Issue10083) (#10116)
- fixes #10083 

# Description

nushell crashes in the following 2 condition:

- `let a = {}` , then delete `{`
- `let a = | {}`, then delete `{`

When delete `{` the pipeline becomes empty but current `nu-parser`
assume they are non-empty. This pr adds extra empty check to avoid
crash.


Co-authored-by: Horasal <horsal@horsal.dev>
2023-08-28 13:38:11 +02:00
38f454d5ab Support Termux (#10013) 2023-08-28 09:53:25 +03:00
487f1a97ea Update removed "MDI" icons to current MD icons (#10126)
# Description
This PR updates now-removed (since NF 3.0.0) file icons shown in e.g.
`grid` to their updated codepoints.

# User-Facing Changes
File icons changed were for:
`cs`, `csproj`, `csx`, `license`, `node`, `rtf`, `vue`, `xml`, and `xul`

# Tests + Formatting

# After Submitting
2023-08-27 15:48:37 +02:00
0f05475e2e name hooks internally (#10127)
# Description

This PR names the hooks as they're executing so that you can see them
with debug statements. So, at the beginning of `eval_hook()` you could
put a dbg! or eprintln! to see what hook was executing. It also shows up
in View files.

### Before - notice item 14 and 25

![image](https://github.com/nushell/nushell/assets/343840/22c19bbe-6bac-4132-9579-863922d91f22)

### After - The hooks are now named (14 & 25)

![image](https://github.com/nushell/nushell/assets/343840/a08abd11-4f03-4f09-bbac-e4b5180df078)


Curiosity, on my mac, the display_output hook fires 3 times before
anything else. Also, curious is that the value if the display_output, is
not what I have in my config but what is in the default_config. So,
there may be a bug or some shenanigans going on somewhere with hooks.

# 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.
-->
2023-08-27 06:55:20 -05:00
cc805f3f01 Screen reader-friendly errors (#10122)
- Hopefully closes #10120  

# Description

This PR adds a new config item, `error_style`. It will render errors in
a screen reader friendly mode when set to `"simple"`. This is done using
`miette`'s own `NarratableReportHandler`, which seamlessly replaces the
default one when needed.

Before:
```
Error: nu:🐚:external_command

  × External command failed
   ╭─[entry #2:1:1]
 1 │ doesnt exist
   · ───┬──
   ·    ╰── executable was not found
   ╰────
  help: No such file or directory (os error 2)
```

After:
```
Error: External command failed
    Diagnostic severity: error
Begin snippet for entry #4 starting at line 1, column 1

snippet line 1: doesnt exist
    label at line 1, columns 1 to 6: executable was not found
diagnostic help: No such file or directory (os error 2)
diagnostic code: nu:🐚:external_command

```

## Things to be determined

- ~Review naming. `errors.style` is not _that_ consistent with the rest
of the code. Menus use a `style` record, but table rendering mode is set
via `mode`.~ As it's a single config, we're using `error_style` for now.
- Should this kind of setting be toggable with one single parameter?
`accessibility.no_decorations` or similar, which would adjust the style
of both errors and tables accordingly.

# User-Facing Changes

No changes by default, errors will be rendered differently if
`error_style` is set to `simple`.

# 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

There's a PR updating the docs over here
https://github.com/nushell/nushell.github.io/pull/1026
2023-08-27 06:54:15 -05:00
5ac5b90aed Allow parse-time evaluation of calls, pipelines and subexpressions (#9499)
Co-authored-by: Antoine Stevan <44101798+amtoine@users.noreply.github.com>
2023-08-26 16:41:29 +03:00
3d73287ea4 add support for Vim motions in explore (#9966)
related to
- https://github.com/nushell/nushell/issues/7819

# Description
this PR does not quite address
https://github.com/nushell/nushell/issues/7819 because it does not
implement configurable keybindings for `explore` but rather only adds
support for Vim-like motions *out of the box*.

# User-Facing Changes
in *view* and *cursor* modes,
- `h`, `j`, `k` and `l` give standard Qwerty-based Vim motions
- `g` and `G` go to the top and the end respectively
- `u` and `d` scroll up and down

> **Note**
> the bindings do not support the use of modifiers for now, so it's not
`c-u` and `c-d` which scroll pages but rather `u` and `d`

# Tests + Formatting

# After Submitting
2023-08-26 07:48:37 -05:00
7ebdced256 toolkit: Renames pretty-print-command (#10110)
It doesn't print, but returns a string.
So it should be called format.
2023-08-25 19:23:30 +02:00
ad12018199 Use built-in is_terminal instead of is_terminal::is_terminal (#9550)
# Description
This PR tries to remove ~atty~ is-terminal from the entire code base,
since ~[atty is
unmaintained](https://rustsec.org/advisories/RUSTSEC-2021-0145) and~
[`is_terminal` has been
stabilized](https://blog.rust-lang.org/2023/06/01/Rust-1.70.0.html#isterminal)
in rust 1.70.0.

cc @fdncred 

# 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 -A
clippy::needless_collect -A clippy::result_large_err` to check that
you're using the standard code style
- `cargo test --workspace` to check that all tests pass
- `cargo run -- crates/nu-std/tests/run.nu` 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.
-->
2023-08-25 10:54:44 +02:00
27dcc3ecc3 Don't use oldtime feature of chrono (#9577)
<!--
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
`chrono` crate enables `oldtime` feature by default, which has a
vulnerability (https://rustsec.org/advisories/RUSTSEC-2020-0071). This
PR tries to remove `time` v0.1.45 completely from nu and add an audit CI
to check for security vulnerabilities.

 Wait for the following PRs:
- [x] https://github.com/nushell/reedline/pull/599
- [x] https://github.com/bspeice/dtparse/pull/44
- [x] https://github.com/Byron/trash-rs/pull/75
- [x] https://gitlab.com/imp/chrono-humanize-rs/-/merge_requests/15

# 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 -A
clippy::needless_collect -A clippy::result_large_err` to check that
you're using the standard code style
- `cargo test --workspace` to check that all tests pass
- `cargo run -- crates/nu-std/tests/run.nu` 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: sholderbach <sholderbach@users.noreply.github.com>
2023-08-25 10:54:01 +02:00
e25a795cf6 Add encoding auto-detection for decode (#10030)
# Description
Allow `decode` command to guess the encoding of input if no encoding
name is given.

# User-Facing Changes

* `decode` now has an optional parameter instead of required one. User
can just run `decode` to let the command automatically detect encoding
and convert it to utf-8.
<img width="575" alt="Example"
src="https://github.com/nushell/nushell/assets/1991933/03a0ba11-910e-4db9-89aa-79cfec06893f">



* Based on the detect result, user may have to give a encoding name
<img width="572" alt="Error Sample1"
src="https://github.com/nushell/nushell/assets/1991933/f21fda85-1f04-4cb3-9feb-cb9fb7dcee07">
     or get informed that the input is not supported by `decode`
<img width="568" alt="Error Sample2"
src="https://github.com/nushell/nushell/assets/1991933/dd3cc4c0-f119-493e-8609-d07594fc055a">

# Tests + Formatting

* `cargo fmt --all -- --check` : OK
* `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect -A clippy::result_large_err`: OK
* `cargo test --workspace` : OK
* `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"`: OK


# After Submitting

[Command document](https://www.nushell.sh/commands/docs/decode.html) is
auto-generated and requires no action.

---------

Co-authored-by: Horasal <horsal@horsal.dev>
2023-08-24 19:21:17 -05:00
16c15e83a3 bump rust-toolchain to 1.70.0 (#10113)
# Description

This PR bumps the rust-toolchain to 1.70.0 since 1.72.0 was released
today.

# 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.
-->
2023-08-24 19:13:57 -05:00
cea67cb30b Allow for .parq file ending as alternative to .parquet (#10112)
# Description

Many systems like Hadoops HDFS store parquet files with the short
variant `.parq`. It is quite annoying to rename these file before
opening them with nushell. This PR lets nushell accept .parq alongside
.parquet file endings.


# User-Facing Changes
Not sure if this is applicable here.

# Tests + Formatting

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 -  (fails on
none related test)
- `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library -
✔️
2023-08-24 15:57:33 -05:00
JT
1e3e034021 Spanned Value step 1: span all value cases (#10042)
# Description

This doesn't really do much that the user could see, but it helps get us
ready to do the steps of the refactor to split the span off of Value, so
that values can be spanless. This allows us to have top-level values
that can hold both a Value and a Span, without requiring that all values
have them.

We expect to see significant memory reduction by removing so many
unnecessary spans from values. For example, a table of 100,000 rows and
5 columns would have a savings of ~8megs in just spans that are almost
always duplicated.

# User-Facing Changes

Nothing yet

# 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 -A
clippy::needless_collect -A clippy::result_large_err` to check that
you're using the standard code style
- `cargo test --workspace` to check that all tests pass
- `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.
-->
2023-08-25 08:48:05 +12:00
8da27a1a09 Create Record type (#10103)
# Description
This PR creates a new `Record` type to reduce duplicate code and
possibly bugs as well. (This is an edited version of #9648.)
- `Record` implements `FromIterator` and `IntoIterator` and so can be
iterated over or collected into. For example, this helps with
conversions to and from (hash)maps. (Also, no more
`cols.iter().zip(vals)`!)
- `Record` has a `push(col, val)` function to help insure that the
number of columns is equal to the number of values. I caught a few
potential bugs thanks to this (e.g. in the `ls` command).
- Finally, this PR also adds a `record!` macro that helps simplify
record creation. It is used like so:
   ```rust
   record! {
       "key1" => some_value,
       "key2" => Value::string("text", span),
       "key3" => Value::int(optional_int.unwrap_or(0), span),
       "key4" => Value::bool(config.setting, span),
   }
   ```
Since macros hinder formatting, etc., the right hand side values should
be relatively short and sweet like the examples above.

Where possible, prefer `record!` or `.collect()` on an iterator instead
of multiple `Record::push`s, since the first two automatically set the
record capacity and do less work overall.

# User-Facing Changes
Besides the changes in `nu-protocol` the only other breaking changes are
to `nu-table::{ExpandedTable::build_map, JustTable::kv_table}`.
2023-08-25 07:50:29 +12:00
030e749fe7 Add notice to enable develop mode on Windows (#10111)
Developer mode needs to be enabled to create symlinks on Windows. Since
creating symlinks is part of the testbench, this needs to be enabled.

(I always wondered why two tests fail on my Windows machine, but not on
the CI)
2023-08-24 11:02:54 -07:00
a785e64bc9 Fix 9156 endian consistency (#9873)
- fixed #9156

# Description
I'm trying to fix the problems mentioned in the issue. It's my first
attempt in Rust. Please let me know if there are any problems.

# User-Facing Changes
- The `--little-endian` option dropped, replaced with `--endian`.
- Add the `--compact` option to the `into binary` command.
- `into int` accepts binary input
2023-08-24 07:08:58 -05:00
d4eeef4bd1 Fix tab completion order of directories to consistent with order of files (#10102)
# Description

fixed #10020

Tab completion order of directories is inconsistent with order of files.
This problem is caused by sorting folder names containing a trailing
slash.
This PR fixes the problem.

# User-Facing Changes

Users get the same order of suggestions in the tab completion for both
file and directory.


![image](https://github.com/nushell/nushell/assets/37319612/208e5a01-01a2-489c-b41a-36ece999f971)


# Tests + Formatting

```
$ toolkit check pr

- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`
```

# After Submitting

nothing
2023-08-24 06:19:13 -05:00
c8a07d477f Fix watch not detecting modifications on Windows (#10109)
Closes #9910 FOR REAL this time.

I had fixed the issue on Linux but not Windows. Context:
https://github.com/nushell/nushell/issues/9910#issuecomment-1689308886

I've tested this PR successfully on Windows, Linux, and macOS by running
`watch . {|a,b| print $a; print $b}` and confirming that it prints once
when I change a file in the current directory.
2023-08-23 19:07:39 -07:00
af82eeca72 remove --column from length command and remove record processing (#10091)
# Description

This PR removes `record` processing from the `length` command. It just
doesn't make sense to try and get the length of a record. This PR also
removes the `--column` parameter. If you want to list or count columns,
you could use `$table | columns` or `$table | columns | length`.

close #10074 

### Before

![image](https://github.com/nushell/nushell/assets/343840/83488316-3ec4-4c32-9583-00341a71f46f)

### After
Catches records two different ways now.
with the `input_output_types` checker

![image](https://github.com/nushell/nushell/assets/343840/ca67f8b6-359e-4933-ab4d-1b702f8d79cf)

and with additional logic in the command for cases like `echo`

![image](https://github.com/nushell/nushell/assets/343840/99064351-b208-4bd3-bab9-535f97cd7ad4)


# 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
- `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.
-->
2023-08-23 16:03:26 -05:00
3d698b74d8 bump nushell to dev version 0.84.1 (#10101)
# Description

This PR bumps nushell from release version 0.84.0 to dev version 0.84.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
- `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.
-->
2023-08-23 15:23:27 -05:00
681 changed files with 17093 additions and 18135 deletions

View File

View File

@ -25,7 +25,7 @@ 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
- `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**

25
.github/workflows/audit.yml vendored Normal file
View File

@ -0,0 +1,25 @@
name: Security audit
on:
pull_request:
paths:
- '**/Cargo.toml'
- '**/Cargo.lock'
push:
branches:
- main
env:
RUST_BACKTRACE: 1
CARGO_TERM_COLOR: always
CLICOLOR: 1
jobs:
security_audit:
runs-on: ubuntu-latest
# Prevent sudden announcement of a new advisory from failing ci:
continue-on-error: true
steps:
- uses: actions/checkout@v4
- uses: rustsec/audit-check@v1.4.1
with:
token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -7,7 +7,7 @@ on:
name: continuous-integration
env:
NUSHELL_CARGO_TARGET: ci
NUSHELL_CARGO_PROFILE: ci
NU_LOG_LEVEL: DEBUG
CLIPPY_OPTIONS: "-D warnings -D clippy::unwrap_used"
@ -37,7 +37,7 @@ jobs:
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup Rust toolchain and cache
uses: actions-rust-lang/setup-rust-toolchain@v1.5.0
@ -49,6 +49,10 @@ jobs:
- name: Clippy
run: cargo clippy --workspace ${{ matrix.flags }} --exclude nu_plugin_* -- $CLIPPY_OPTIONS
# In tests we don't have to deny unwrap
- name: Clippy of tests
run: cargo clippy --tests --workspace ${{ matrix.flags }} --exclude nu_plugin_* -- -D warnings
tests:
strategy:
@ -76,7 +80,7 @@ jobs:
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup Rust toolchain and cache
uses: actions-rust-lang/setup-rust-toolchain@v1.5.0
@ -97,7 +101,7 @@ jobs:
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup Rust toolchain and cache
uses: actions-rust-lang/setup-rust-toolchain@v1.5.0
@ -132,7 +136,7 @@ jobs:
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup Rust toolchain and cache
uses: actions-rust-lang/setup-rust-toolchain@v1.5.0

View File

@ -13,7 +13,7 @@ on:
- nightly # Just for test purpose only with the nightly repo
# This schedule will run only from the default branch
schedule:
- cron: '15 1 * * *' # run at 01:15 AM UTC
- cron: '15 0 * * *' # run at 00:15 AM UTC
defaults:
run:
@ -27,7 +27,7 @@ jobs:
# if: github.repository == 'nushell/nightly'
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
if: github.repository == 'nushell/nightly'
with:
ref: main
@ -36,10 +36,10 @@ jobs:
token: ${{ secrets.WORKFLOW_TOKEN }}
- name: Setup Nushell
uses: hustcer/setup-nu@v3
uses: hustcer/setup-nu@v3.6
if: github.repository == 'nushell/nightly'
with:
version: 0.81.0
version: 0.84.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -53,14 +53,13 @@ jobs:
# We can't push if no user name and email are configured
git config user.name 'hustcer'
git config user.email 'hustcer@outlook.com'
git fetch origin main
git pull origin main
git remote add src https://github.com/nushell/nushell.git
git fetch src main
# git pull --rebase src main
# All the changes will be overwritten by the upstream main branch
git reset --hard src/main
git push origin main -f
let sha_short = (git rev-parse --short src/main | str trim | str substring 0..7)
let sha_short = (git rev-parse --short origin/main | str trim | str substring 0..7)
let tag_name = $'nightly-($sha_short)'
if (git ls-remote --tags origin $tag_name | is-empty) {
git tag -a $tag_name -m $'Nightly build from ($sha_short)'
@ -126,7 +125,7 @@ jobs:
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
ref: main
@ -140,9 +139,9 @@ jobs:
rustflags: ''
- name: Setup Nushell
uses: hustcer/setup-nu@v3
uses: hustcer/setup-nu@v3.6
with:
version: 0.81.0
version: 0.84.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -176,7 +175,7 @@ jobs:
# REF: https://github.com/marketplace/actions/gh-release
# Create a release only in nushell/nightly repo
- name: Publish Archive
uses: softprops/action-gh-release@v0.1.13
uses: softprops/action-gh-release@v0.1.15
if: ${{ startsWith(github.repository, 'nushell/nightly') }}
with:
draft: false
@ -200,14 +199,14 @@ jobs:
- name: Waiting for Release
run: sleep 1800
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
ref: main
- name: Setup Nushell
uses: hustcer/setup-nu@v3
uses: hustcer/setup-nu@v3.6
with:
version: 0.81.0
version: 0.84.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -172,18 +172,22 @@ if $os in [$USE_UBUNTU, 'macos-latest'] {
cp -r $'($dist)/*' target/release/
cargo install cargo-wix --version 0.3.4
cargo wix --no-build --nocapture --package nu --output $wixRelease
print $'archive: ---> ($wixRelease)';
echo $"archive=($wixRelease)" | save --append $env.GITHUB_OUTPUT
# Workaround for https://github.com/softprops/action-gh-release/issues/280
let archive = ($wixRelease | str replace -a '\' '/')
print $'archive: ---> ($archive)';
echo $"archive=($archive)" | save --append $env.GITHUB_OUTPUT
} else {
print $'(char nl)(ansi g)Archive contents:(ansi reset)'; hr-line; ls
let archive = $'($dist)/($releaseStem).zip'
7z a $archive *
print $'archive: ---> ($archive)';
let pkg = (ls -f $archive | get name)
if not ($pkg | is-empty) {
echo $"archive=($pkg | get 0)" | save --append $env.GITHUB_OUTPUT
# Workaround for https://github.com/softprops/action-gh-release/issues/280
let archive = ($pkg | get 0 | str replace -a '\' '/')
print $'archive: ---> ($archive)'
echo $"archive=($archive)" | save --append $env.GITHUB_OUTPUT
}
}
}

View File

@ -72,7 +72,7 @@ jobs:
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Update Rust Toolchain Target
run: |
@ -84,9 +84,9 @@ jobs:
rustflags: ''
- name: Setup Nushell
uses: hustcer/setup-nu@v3
uses: hustcer/setup-nu@v3.6
with:
version: 0.81.0
version: 0.84.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -102,7 +102,7 @@ jobs:
# REF: https://github.com/marketplace/actions/gh-release
- name: Publish Archive
uses: softprops/action-gh-release@v0.1.13
uses: softprops/action-gh-release@v0.1.15
if: ${{ startsWith(github.ref, 'refs/tags/') }}
with:
draft: true

View File

@ -7,7 +7,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Actions Repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Check spelling
uses: crate-ci/typos@master
uses: crate-ci/typos@v1.16.11
with:
config: ./.github/.typos.toml

705
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@ license = "MIT"
name = "nu"
repository = "https://github.com/nushell/nushell"
rust-version = "1.60"
version = "0.84.0"
version = "0.85.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -46,34 +46,34 @@ members = [
]
[dependencies]
nu-cli = { path = "./crates/nu-cli", version = "0.84.0" }
nu-color-config = { path = "./crates/nu-color-config", version = "0.84.0" }
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.84.0" }
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.84.0" }
nu-cmd-dataframe = { path = "./crates/nu-cmd-dataframe", version = "0.84.0", features = ["dataframe"], optional = true }
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.84.0", optional = true }
nu-command = { path = "./crates/nu-command", version = "0.84.0" }
nu-engine = { path = "./crates/nu-engine", version = "0.84.0" }
nu-explore = { path = "./crates/nu-explore", version = "0.84.0" }
nu-json = { path = "./crates/nu-json", version = "0.84.0" }
nu-parser = { path = "./crates/nu-parser", version = "0.84.0" }
nu-path = { path = "./crates/nu-path", version = "0.84.0" }
nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.84.0" }
nu-pretty-hex = { path = "./crates/nu-pretty-hex", version = "0.84.0" }
nu-protocol = { path = "./crates/nu-protocol", version = "0.84.0" }
nu-system = { path = "./crates/nu-system", version = "0.84.0" }
nu-table = { path = "./crates/nu-table", version = "0.84.0" }
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.84.0" }
nu-std = { path = "./crates/nu-std", version = "0.84.0" }
nu-utils = { path = "./crates/nu-utils", version = "0.84.0" }
nu-cli = { path = "./crates/nu-cli", version = "0.85.0" }
nu-color-config = { path = "./crates/nu-color-config", version = "0.85.0" }
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.85.0" }
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.85.0" }
nu-cmd-dataframe = { path = "./crates/nu-cmd-dataframe", version = "0.85.0", features = ["dataframe"], optional = true }
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.85.0", optional = true }
nu-command = { path = "./crates/nu-command", version = "0.85.0" }
nu-engine = { path = "./crates/nu-engine", version = "0.85.0" }
nu-explore = { path = "./crates/nu-explore", version = "0.85.0" }
nu-json = { path = "./crates/nu-json", version = "0.85.0" }
nu-parser = { path = "./crates/nu-parser", version = "0.85.0" }
nu-path = { path = "./crates/nu-path", version = "0.85.0" }
nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.85.0" }
nu-pretty-hex = { path = "./crates/nu-pretty-hex", version = "0.85.0" }
nu-protocol = { path = "./crates/nu-protocol", version = "0.85.0" }
nu-system = { path = "./crates/nu-system", version = "0.85.0" }
nu-table = { path = "./crates/nu-table", version = "0.85.0" }
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.85.0" }
nu-std = { path = "./crates/nu-std", version = "0.85.0" }
nu-utils = { path = "./crates/nu-utils", version = "0.85.0" }
nu-ansi-term = "0.49.0"
reedline = { version = "0.23.0", features = ["bashisms", "sqlite"]}
reedline = { version = "0.24.0", features = ["bashisms", "sqlite"] }
crossterm = "0.26"
crossterm = "0.27"
ctrlc = "3.4"
log = "0.4"
miette = { version = "5.10", features = ["fancy-no-backtrace"] }
mimalloc = { version = "0.1.37", default-features = false, optional = true}
mimalloc = { version = "0.1.37", default-features = false, optional = true }
serde_json = "1.0"
simplelog = "0.12"
time = "0.3"
@ -87,22 +87,21 @@ signal-hook = { version = "0.3", default-features = false }
winresource = "0.1"
[target.'cfg(target_family = "unix")'.dependencies]
nix = { version = "0.26", default-features = false, features = [
nix = { version = "0.27", default-features = false, features = [
"signal",
"process",
"fs",
"term",
] }
is-terminal = "0.4.8"
[dev-dependencies]
nu-test-support = { path = "./crates/nu-test-support", version = "0.84.0" }
nu-test-support = { path = "./crates/nu-test-support", version = "0.85.0" }
assert_cmd = "2.0"
criterion = "0.5"
pretty_assertions = "1.4"
rstest = { version = "0.18", default-features = false }
serial_test = "2.0"
tempfile = "3.7"
tempfile = "3.8"
[features]
plugin = [
@ -113,12 +112,13 @@ plugin = [
"nu-protocol/plugin",
"nu-engine/plugin",
]
default = ["plugin", "which-support", "trash-support", "sqlite"]
default = ["plugin", "which-support", "trash-support", "sqlite", "mimalloc"]
stable = ["default"]
wasi = ["nu-cmd-lang/wasi"]
# NOTE: individual features are also passed to `nu-cmd-lang` that uses them to generate the feature matrix in the `version` command
# Enable to statically link OpenSSL; otherwise the system version will be used. Not enabled by default because it takes a while to build
# Enable to statically link OpenSSL (perl is required, to build OpenSSL https://docs.rs/openssl/latest/openssl/);
# otherwise the system version will be used. Not enabled by default because it takes a while to build
static-link-openssl = ["dep:openssl", "nu-cmd-lang/static-link-openssl"]
mimalloc = ["nu-cmd-lang/mimalloc", "dep:mimalloc"]

View File

@ -7,7 +7,6 @@
[![@nu_shell](https://img.shields.io/badge/twitter-@nu_shell-1DA1F3?style=flat-square)](https://twitter.com/nu_shell)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/m/nushell/nushell)](https://github.com/nushell/nushell/graphs/commit-activity)
[![GitHub contributors](https://img.shields.io/github/contributors/nushell/nushell)](https://github.com/nushell/nushell/graphs/contributors)
[![codecov](https://codecov.io/gh/nushell/nushell/branch/main/graph/badge.svg?token=JheS8qu2II)](https://codecov.io/gh/nushell/nushell)
A new type of shell.
@ -220,13 +219,14 @@ Please submit an issue or PR to be added to this list.
- [virtualenv](https://github.com/pypa/virtualenv)
- [atuin](https://github.com/ellie/atuin)
- [clap](https://github.com/clap-rs/clap/tree/master/clap_complete_nushell)
- [Dorothy](http://github.com/bevry/dorothy)
## Contributing
See [Contributing](CONTRIBUTING.md) for details. Thanks to all the people who already contributed!
<a href="https://github.com/nushell/nushell/graphs/contributors">
<img src="https://contributors-img.web.app/image?repo=nushell/nushell&max=500" />
<img src="https://contributors-img.web.app/image?repo=nushell/nushell&max=600" />
</a>
## License

View File

@ -114,15 +114,13 @@ fn eval_benchmarks(c: &mut Criterion) {
// generate a new table data with `row_cnt` rows, `col_cnt` columns.
fn encoding_test_data(row_cnt: usize, col_cnt: usize) -> Value {
let columns: Vec<String> = (0..col_cnt).map(|x| format!("col_{x}")).collect();
let vals: Vec<Value> = (0..col_cnt as i64).map(Value::test_int).collect();
Value::List {
vals: (0..row_cnt)
.map(|_| Value::test_record(columns.clone(), vals.clone()))
let record = Value::test_record(
(0..col_cnt)
.map(|x| (format!("col_{x}"), Value::test_int(x as i64)))
.collect(),
span: Span::test_data(),
}
);
Value::list(vec![record; row_cnt], Span::test_data())
}
fn encoding_benchmarks(c: &mut Criterion) {

View File

@ -1,17 +0,0 @@
coverage:
status:
project:
default:
target: 55%
threshold: 2%
patch:
default:
informational: true
comment:
layout: reach, diff, files
behavior: default
require_base: yes
require_head: yes
after_n_builds: 1 # Disabled windows else: 2

View File

@ -5,34 +5,33 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cli"
edition = "2021"
license = "MIT"
name = "nu-cli"
version = "0.84.0"
version = "0.85.0"
[lib]
bench = false
[dev-dependencies]
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.84.0" }
nu-test-support = { path = "../nu-test-support", version = "0.84.0" }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.85.0" }
nu-command = { path = "../nu-command", version = "0.85.0" }
nu-test-support = { path = "../nu-test-support", version = "0.85.0" }
rstest = { version = "0.18.1", default-features = false }
[dependencies]
nu-cmd-base = { path = "../nu-cmd-base", version = "0.84.0" }
nu-command = { path = "../nu-command", version = "0.84.0" }
nu-engine = { path = "../nu-engine", version = "0.84.0" }
nu-path = { path = "../nu-path", version = "0.84.0" }
nu-parser = { path = "../nu-parser", version = "0.84.0" }
nu-protocol = { path = "../nu-protocol", version = "0.84.0" }
nu-utils = { path = "../nu-utils", version = "0.84.0" }
nu-color-config = { path = "../nu-color-config", version = "0.84.0" }
nu-cmd-base = { path = "../nu-cmd-base", version = "0.85.0" }
nu-engine = { path = "../nu-engine", version = "0.85.0" }
nu-path = { path = "../nu-path", version = "0.85.0" }
nu-parser = { path = "../nu-parser", version = "0.85.0" }
nu-protocol = { path = "../nu-protocol", version = "0.85.0" }
nu-utils = { path = "../nu-utils", version = "0.85.0" }
nu-color-config = { path = "../nu-color-config", version = "0.85.0" }
nu-ansi-term = "0.49.0"
reedline = { version = "0.23.0", features = ["bashisms", "sqlite"]}
reedline = { version = "0.24.0", features = ["bashisms", "sqlite"] }
chrono = { default-features = false, features = ["std"], version = "0.4" }
crossterm = "0.26"
crossterm = "0.27"
fancy-regex = "0.11"
fuzzy-matcher = "0.3"
is_executable = "1.0"
is-terminal = "0.4.8"
log = "0.4"
miette = { version = "5.10", features = ["fancy-no-backtrace"] }
once_cell = "1.18"

View File

@ -1,9 +1,9 @@
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::Category;
use nu_protocol::IntoPipelineData;
use nu_protocol::{PipelineData, ShellError, Signature, SyntaxShape, Type, Value};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
};
use unicode_segmentation::UnicodeSegmentation;
#[derive(Clone)]
@ -25,6 +25,11 @@ impl Command for Commandline {
"Set or get the current cursor position",
Some('c'),
)
.switch(
"cursor-end",
"Set the current cursor position to the end of the buffer",
Some('e'),
)
.switch(
"append",
"appends the string to the end of the buffer",
@ -84,7 +89,7 @@ impl Command for Commandline {
return Err(ShellError::CantConvert {
to_type: "int".to_string(),
from_type: "string".to_string(),
span: cmd.span()?,
span: cmd.span(),
help: Some(format!(
r#"string "{cmd_str}" does not represent a valid integer"#
)),
@ -102,27 +107,22 @@ impl Command for Commandline {
repl.buffer = cmd.as_string()?;
repl.cursor_pos = repl.buffer.len();
}
Ok(Value::Nothing { span: call.head }.into_pipeline_data())
Ok(Value::nothing(call.head).into_pipeline_data())
} else {
let repl = engine_state.repl_state.lock().expect("repl state mutex");
if call.has_flag("cursor") {
let mut repl = engine_state.repl_state.lock().expect("repl state mutex");
if call.has_flag("cursor-end") {
repl.cursor_pos = repl.buffer.graphemes(true).count();
Ok(Value::nothing(call.head).into_pipeline_data())
} else if call.has_flag("cursor") {
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");
Ok(Value::String {
val: char_pos.to_string(),
span: call.head,
}
.into_pipeline_data())
Ok(Value::string(char_pos.to_string(), call.head).into_pipeline_data())
} else {
Ok(Value::String {
val: repl.buffer.to_string(),
span: call.head,
}
.into_pipeline_data())
Ok(Value::string(repl.buffer.to_string(), call.head).into_pipeline_data())
}
}
}

View File

@ -1,8 +1,8 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, HistoryFileFormat, IntoInterruptiblePipelineData, PipelineData, ShellError,
Signature, Span, Type, Value,
record, Category, Example, HistoryFileFormat, IntoInterruptiblePipelineData, PipelineData,
ShellError, Signature, Span, Type, Value,
};
use reedline::{
FileBackedHistory, History as ReedlineHistory, HistoryItem, SearchDirection, SearchQuery,
@ -70,12 +70,14 @@ impl Command for History {
} else {
let history_reader: Option<Box<dyn ReedlineHistory>> =
match engine_state.config.history_file_format {
HistoryFileFormat::Sqlite => SqliteBackedHistory::with_file(history_path)
.map(|inner| {
let boxed: Box<dyn ReedlineHistory> = Box::new(inner);
boxed
})
.ok(),
HistoryFileFormat::Sqlite => {
SqliteBackedHistory::with_file(history_path, None, None)
.map(|inner| {
let boxed: Box<dyn ReedlineHistory> = Box::new(inner);
boxed
})
.ok()
}
HistoryFileFormat::PlainText => FileBackedHistory::with_file(
engine_state.config.max_history_size as usize,
@ -95,20 +97,15 @@ impl Command for History {
.ok()
})
.map(move |entries| {
entries
.into_iter()
.enumerate()
.map(move |(idx, entry)| Value::Record {
cols: vec!["command".to_string(), "index".to_string()],
vals: vec![
Value::String {
val: entry.command_line,
span: head,
},
Value::int(idx as i64, head),
],
span: head,
})
entries.into_iter().enumerate().map(move |(idx, entry)| {
Value::record(
record! {
"command" => Value::string(entry.command_line, head),
"index" => Value::int(idx as i64, head),
},
head,
)
})
})
.ok_or(ShellError::FileNotFound(head))?
.into_pipeline_data(ctrlc)),
@ -144,7 +141,7 @@ impl Command for History {
result: None,
},
Example {
example: "history | wrap cmd | where cmd =~ cargo",
example: "history | where command =~ cargo | get command",
description: "Search all the commands from history that contains 'cargo'",
result: None,
},
@ -156,8 +153,8 @@ fn create_history_record(idx: usize, entry: HistoryItem, long: bool, head: Span)
//1. Format all the values
//2. Create a record of either short or long columns and values
let item_id_value = Value::Int {
val: match entry.id {
let item_id_value = Value::int(
match entry.id {
Some(id) => {
let ids = id.to_string();
match ids.parse::<i64>() {
@ -167,21 +164,18 @@ fn create_history_record(idx: usize, entry: HistoryItem, long: bool, head: Span)
}
None => 0i64,
},
span: head,
};
let start_timestamp_value = Value::String {
val: match entry.start_timestamp {
head,
);
let start_timestamp_value = Value::string(
match entry.start_timestamp {
Some(time) => time.to_string(),
None => "".into(),
},
span: head,
};
let command_value = Value::String {
val: entry.command_line,
span: head,
};
let session_id_value = Value::Int {
val: match entry.session_id {
head,
);
let command_value = Value::string(entry.command_line, head);
let session_id_value = Value::int(
match entry.session_id {
Some(sid) => {
let sids = sid.to_string();
match sids.parse::<i64>() {
@ -191,74 +185,56 @@ fn create_history_record(idx: usize, entry: HistoryItem, long: bool, head: Span)
}
None => 0i64,
},
span: head,
};
let hostname_value = Value::String {
val: match entry.hostname {
head,
);
let hostname_value = Value::string(
match entry.hostname {
Some(host) => host,
None => "".into(),
},
span: head,
};
let cwd_value = Value::String {
val: match entry.cwd {
head,
);
let cwd_value = Value::string(
match entry.cwd {
Some(cwd) => cwd,
None => "".into(),
},
span: head,
};
let duration_value = Value::Duration {
val: match entry.duration {
head,
);
let duration_value = Value::duration(
match entry.duration {
Some(d) => d.as_nanos().try_into().unwrap_or(0),
None => 0,
},
span: head,
};
head,
);
let exit_status_value = Value::int(entry.exit_status.unwrap_or(0), head);
let index_value = Value::int(idx as i64, head);
if long {
Value::Record {
cols: vec![
"item_id".into(),
"start_timestamp".into(),
"command".to_string(),
"session_id".into(),
"hostname".into(),
"cwd".into(),
"duration".into(),
"exit_status".into(),
"idx".to_string(),
],
vals: vec![
item_id_value,
start_timestamp_value,
command_value,
session_id_value,
hostname_value,
cwd_value,
duration_value,
exit_status_value,
index_value,
],
span: head,
}
Value::record(
record! {
"item_id" => item_id_value,
"start_timestamp" => start_timestamp_value,
"command" => command_value,
"session_id" => session_id_value,
"hostname" => hostname_value,
"cwd" => cwd_value,
"duration" => duration_value,
"exit_status" => exit_status_value,
"idx" => index_value,
},
head,
)
} else {
Value::Record {
cols: vec![
"start_timestamp".into(),
"command".to_string(),
"cwd".into(),
"duration".into(),
"exit_status".into(),
],
vals: vec![
start_timestamp_value,
command_value,
cwd_value,
duration_value,
exit_status_value,
],
span: head,
}
Value::record(
record! {
"start_timestamp" => start_timestamp_value,
"command" => command_value,
"cwd" => cwd_value,
"duration" => duration_value,
"exit_status" => exit_status_value,
},
head,
)
}
}

View File

@ -24,7 +24,10 @@ impl Command for Keybindings {
}
fn extra_usage(&self) -> &str {
"You must use one of the following subcommands. Using this command as-is will only produce this help message."
r#"You must use one of the following subcommands. Using this command as-is will only produce this help message.
For more information on input and keybindings, check:
https://www.nushell.sh/book/line_editor.html"#
}
fn search_terms(&self) -> Vec<&str> {
@ -38,16 +41,16 @@ impl Command for Keybindings {
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
Ok(Value::String {
val: get_full_help(
Ok(Value::string(
get_full_help(
&Keybindings.signature(),
&Keybindings.examples(),
engine_state,
stack,
self.is_parser_keyword(),
),
span: call.head,
}
call.head,
)
.into_pipeline_data())
}
}

View File

@ -1,7 +1,7 @@
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Type, Value,
record, Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Type, Value,
};
use reedline::get_reedline_default_keybindings;
@ -41,43 +41,18 @@ impl Command for KeybindingsDefault {
let records = get_reedline_default_keybindings()
.into_iter()
.map(|(mode, modifier, code, event)| {
let mode = Value::String {
val: mode,
span: call.head,
};
let modifier = Value::String {
val: modifier,
span: call.head,
};
let code = Value::String {
val: code,
span: call.head,
};
let event = Value::String {
val: event,
span: call.head,
};
Value::Record {
cols: vec![
"mode".to_string(),
"modifier".to_string(),
"code".to_string(),
"event".to_string(),
],
vals: vec![mode, modifier, code, event],
span: call.head,
}
Value::record(
record! {
"mode" => Value::string(mode, call.head),
"modifier" => Value::string(modifier, call.head),
"code" => Value::string(code, call.head),
"event" => Value::string(event, call.head),
},
call.head,
)
})
.collect();
Ok(Value::List {
vals: records,
span: call.head,
}
.into_pipeline_data())
Ok(Value::list(records, call.head).into_pipeline_data())
}
}

View File

@ -1,7 +1,8 @@
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Type, Value,
record, Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Type,
Value,
};
use reedline::{
get_reedline_edit_commands, get_reedline_keybinding_modifiers, get_reedline_keycodes,
@ -70,11 +71,7 @@ impl Command for KeybindingsList {
.collect()
};
Ok(Value::List {
vals: records,
span: call.head,
}
.into_pipeline_data())
Ok(Value::list(records, call.head).into_pipeline_data())
}
}
@ -96,15 +93,13 @@ fn get_records(entry_type: &str, span: Span) -> Vec<Value> {
}
fn convert_to_record(edit: &str, entry_type: &str, span: Span) -> Value {
let entry_type = Value::string(entry_type, span);
let name = Value::string(edit, span);
Value::Record {
cols: vec!["type".to_string(), "name".to_string()],
vals: vec![entry_type, name],
Value::record(
record! {
"type" => Value::string(entry_type, span),
"name" => Value::string(edit, span),
},
span,
}
)
}
// Helper to sort a vec and return a vec

View File

@ -3,7 +3,8 @@ use crossterm::{event::Event, event::KeyCode, event::KeyEvent, terminal};
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Type, Value,
record, Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Type,
Value,
};
use std::io::{stdout, Write};
@ -19,6 +20,10 @@ impl Command for KeybindingsListen {
"Get input from the user."
}
fn extra_usage(&self) -> &str {
"This is an internal debugging tool. For better output, try `input listen --types [key]`"
}
fn signature(&self) -> Signature {
Signature::build(self.name())
.category(Category::Platform)
@ -78,9 +83,8 @@ pub fn print_events(engine_state: &EngineState) -> Result<Value, ShellError> {
let v = print_events_helper(event)?;
// Print out the record
let o = match v {
Value::Record { cols, vals, .. } => cols
Value::Record { val, .. } => val
.iter()
.zip(vals.iter())
.map(|(x, y)| format!("{}: {}", x, y.into_string("", config)))
.collect::<Vec<String>>()
.join(", "),
@ -111,54 +115,29 @@ fn print_events_helper(event: Event) -> Result<Value, ShellError> {
{
match code {
KeyCode::Char(c) => {
let record = Value::Record {
cols: vec![
"char".into(),
"code".into(),
"modifier".into(),
"flags".into(),
"kind".into(),
"state".into(),
],
vals: vec![
Value::string(format!("{c}"), Span::unknown()),
Value::string(format!("{:#08x}", u32::from(c)), Span::unknown()),
Value::string(format!("{modifiers:?}"), Span::unknown()),
Value::string(format!("{modifiers:#08b}"), Span::unknown()),
Value::string(format!("{kind:?}"), Span::unknown()),
Value::string(format!("{state:?}"), Span::unknown()),
],
span: Span::unknown(),
let record = record! {
"char" => Value::string(format!("{c}"), Span::unknown()),
"code" => Value::string(format!("{:#08x}", u32::from(c)), Span::unknown()),
"modifier" => Value::string(format!("{modifiers:?}"), Span::unknown()),
"flags" => Value::string(format!("{modifiers:#08b}"), Span::unknown()),
"kind" => Value::string(format!("{kind:?}"), Span::unknown()),
"state" => Value::string(format!("{state:?}"), Span::unknown()),
};
Ok(record)
Ok(Value::record(record, Span::unknown()))
}
_ => {
let record = Value::Record {
cols: vec![
"code".into(),
"modifier".into(),
"flags".into(),
"kind".into(),
"state".into(),
],
vals: vec![
Value::string(format!("{code:?}"), Span::unknown()),
Value::string(format!("{modifiers:?}"), Span::unknown()),
Value::string(format!("{modifiers:#08b}"), Span::unknown()),
Value::string(format!("{kind:?}"), Span::unknown()),
Value::string(format!("{state:?}"), Span::unknown()),
],
span: Span::unknown(),
let record = record! {
"code" => Value::string(format!("{code:?}"), Span::unknown()),
"modifier" => Value::string(format!("{modifiers:?}"), Span::unknown()),
"flags" => Value::string(format!("{modifiers:#08b}"), Span::unknown()),
"kind" => Value::string(format!("{kind:?}"), Span::unknown()),
"state" => Value::string(format!("{state:?}"), Span::unknown()),
};
Ok(record)
Ok(Value::record(record, Span::unknown()))
}
}
} else {
let record = Value::Record {
cols: vec!["event".into()],
vals: vec![Value::string(format!("{event:?}"), Span::unknown())],
span: Span::unknown(),
};
Ok(record)
let record = record! { "event" => Value::string(format!("{event:?}"), Span::unknown()) };
Ok(Value::record(record, Span::unknown()))
}
}

View File

@ -263,7 +263,7 @@ mod command_completions_tests {
(" hello sud", 1),
];
for (idx, ele) in commands.iter().enumerate() {
let index = find_non_whitespace_index(&Vec::from(ele.0.as_bytes()), 0);
let index = find_non_whitespace_index(ele.0.as_bytes(), 0);
assert_eq!(index, ele.1, "Failed on index {}", idx);
}
}

View File

@ -74,13 +74,13 @@ impl NuCompleter {
if let Some(var_id) = pos_arg.var_id {
callee_stack.add_var(
var_id,
Value::List {
vals: spans
Value::list(
spans
.iter()
.map(|it| Value::string(it, Span::unknown()))
.collect(),
span: Span::unknown(),
},
Span::unknown(),
),
);
}
}
@ -97,7 +97,7 @@ impl NuCompleter {
match result {
Ok(pd) => {
let value = pd.into_value(span);
if let Value::List { vals, span: _ } = value {
if let Value::List { vals, .. } = value {
let result =
map_value_completions(vals.iter(), Span::new(span.start, span.end), offset);
@ -136,7 +136,7 @@ impl NuCompleter {
for (flat_idx, flat) in flattened.iter().enumerate() {
let is_passthrough_command = spans
.first()
.filter(|content| *content == &String::from("sudo"))
.filter(|content| content.as_str() == "sudo")
.is_some();
// Read the current spam to string
let current_span = working_set.get_span_contents(flat.0).to_vec();
@ -454,7 +454,7 @@ pub fn map_value_completions<'a>(
}
// Match for record values
if let Ok((cols, vals)) = x.as_record() {
if let Ok(record) = x.as_record() {
let mut suggestion = Suggestion {
value: String::from(""), // Initialize with empty string
description: None,
@ -467,7 +467,7 @@ pub fn map_value_completions<'a>(
};
// Iterate the cols looking for `value` and `description`
cols.iter().zip(vals).for_each(|it| {
record.iter().for_each(|it| {
// Match `value` column
if it.0 == "value" {
// Convert the value to string

View File

@ -63,7 +63,12 @@ impl Completer for DirectoryCompletion {
match self.get_sort_by() {
SortBy::Ascending => {
sorted_items.sort_by(|a, b| a.value.cmp(&b.value));
sorted_items.sort_by(|a, b| {
// Ignore trailing slashes in folder names when sorting
a.value
.trim_end_matches(SEP)
.cmp(b.value.trim_end_matches(SEP))
});
}
SortBy::LevenshteinDistance => {
sorted_items.sort_by(|a, b| {

View File

@ -60,7 +60,12 @@ impl Completer for FileCompletion {
match self.get_sort_by() {
SortBy::Ascending => {
sorted_items.sort_by(|a, b| a.value.cmp(&b.value));
sorted_items.sort_by(|a, b| {
// Ignore trailing slashes in folder names when sorting
a.value
.trim_end_matches(SEP)
.cmp(b.value.trim_end_matches(SEP))
});
}
SortBy::LevenshteinDistance => {
sorted_items.sort_by(|a, b| {

View File

@ -235,13 +235,9 @@ fn nested_suggestions(
let value = recursive_value(val, sublevels);
match value {
Value::Record {
cols,
vals: _,
span: _,
} => {
Value::Record { val, .. } => {
// Add all the columns as completion
for item in cols {
for item in val.cols {
output.push(Suggestion {
value: item,
description: None,
@ -267,7 +263,7 @@ fn nested_suggestions(
output
}
Value::List { vals, span: _ } => {
Value::List { vals, .. } => {
for column_name in get_columns(vals.as_slice()) {
output.push(Suggestion {
value: column_name,
@ -288,13 +284,10 @@ fn nested_suggestions(
fn recursive_value(val: Value, sublevels: Vec<Vec<u8>>) -> Value {
// Go to next sublevel
if let Some(next_sublevel) = sublevels.clone().into_iter().next() {
let span = val.span();
match val {
Value::Record {
cols,
vals,
span: _,
} => {
for item in cols.into_iter().zip(vals) {
Value::Record { val, .. } => {
for item in val {
// Check if index matches with sublevel
if item.0.as_bytes().to_vec() == next_sublevel {
// If matches try to fetch recursively the next
@ -303,11 +296,9 @@ fn recursive_value(val: Value, sublevels: Vec<Vec<u8>>) -> Value {
}
// Current sublevel value not found
return Value::Nothing {
span: Span::unknown(),
};
return Value::nothing(span);
}
Value::LazyRecord { val, span: _ } => {
Value::LazyRecord { val, .. } => {
for col in val.column_names() {
if col.as_bytes().to_vec() == next_sublevel {
return recursive_value(
@ -318,15 +309,13 @@ fn recursive_value(val: Value, sublevels: Vec<Vec<u8>>) -> Value {
}
// Current sublevel value not found
return Value::Nothing {
span: Span::unknown(),
};
return Value::nothing(span);
}
Value::List { vals, span } => {
Value::List { vals, .. } => {
for col in get_columns(vals.as_slice()) {
if col.as_bytes().to_vec() == next_sublevel {
return recursive_value(
Value::List { vals, span }
Value::list(vals, span)
.get_data_by_key(&col)
.unwrap_or_default(),
sublevels.into_iter().skip(1).collect(),
@ -335,9 +324,7 @@ fn recursive_value(val: Value, sublevels: Vec<Vec<u8>>) -> Value {
}
// Current sublevel value not found
return Value::Nothing {
span: Span::unknown(),
};
return Value::nothing(span);
}
_ => return val,
}

View File

@ -107,13 +107,17 @@ pub fn evaluate_file(
trace!("parsing file: {}", file_path_str);
let block = parse(&mut working_set, Some(file_path_str), &file, false);
if let Some(err) = working_set.parse_errors.first() {
report_error(&working_set, err);
std::process::exit(1);
}
for block in &mut working_set.delta.blocks {
if block.signature.name == "main" {
block.signature.name = source_filename.to_string_lossy().to_string();
} else if block.signature.name.starts_with("main ") {
block.signature.name = source_filename.to_string_lossy().to_string()
+ " "
+ &String::from_utf8_lossy(&block.signature.name.as_bytes()[5..]);
block.signature.name =
source_filename.to_string_lossy().to_string() + " " + &block.signature.name[5..];
}
}
@ -185,7 +189,7 @@ pub(crate) fn print_table_or_error(
// Change the engine_state config to use the passed in configuration
engine_state.set_config(config);
if let PipelineData::Value(Value::Error { error }, ..) = &pipeline_data {
if let PipelineData::Value(Value::Error { error, .. }, ..) = &pipeline_data {
let working_set = StateWorkingSet::new(engine_state);
report_error(&working_set, &**error);
std::process::exit(1);
@ -232,7 +236,7 @@ pub(crate) fn print_table_or_error(
fn print_or_exit(pipeline_data: PipelineData, engine_state: &mut EngineState, config: &Config) {
for item in pipeline_data {
if let Value::Error { error } = item {
if let Value::Error { error, .. } = item {
let working_set = StateWorkingSet::new(engine_state);
report_error(&working_set, &*error);

View File

@ -48,14 +48,9 @@ impl Command for NuHighlight {
Ok(line) => {
let highlights = highlighter.highlight(&line, line.len());
Value::String {
val: highlights.render_simple(),
span: head,
}
Value::string(highlights.render_simple(), head)
}
Err(err) => Value::Error {
error: Box::new(err),
},
Err(err) => Value::error(err, head),
},
ctrlc,
)

View File

@ -7,7 +7,8 @@ use nu_parser::parse;
use nu_protocol::{
create_menus,
engine::{EngineState, Stack, StateWorkingSet},
extract_value, Config, ParsedKeybinding, ParsedMenu, PipelineData, ShellError, Span, Value,
extract_value, Config, ParsedKeybinding, ParsedMenu, PipelineData, Record, ShellError, Span,
Value,
};
use reedline::{
default_emacs_keybindings, default_vi_insert_keybindings, default_vi_normal_keybindings,
@ -130,8 +131,9 @@ fn add_menu(
stack: &Stack,
config: &Config,
) -> Result<Reedline, ShellError> {
if let Value::Record { cols, vals, span } = &menu.menu_type {
let layout = extract_value("layout", cols, vals, *span)?.into_string("", config);
let span = menu.menu_type.span();
if let Value::Record { val, .. } = &menu.menu_type {
let layout = extract_value("layout", val, span)?.into_string("", config);
match layout.as_str() {
"columnar" => add_columnar_menu(line_editor, menu, engine_state, stack, config),
@ -140,22 +142,22 @@ fn add_menu(
_ => Err(ShellError::UnsupportedConfigValue(
"columnar, list or description".to_string(),
menu.menu_type.into_abbreviated_string(config),
menu.menu_type.span()?,
menu.menu_type.span(),
)),
}
} else {
Err(ShellError::UnsupportedConfigValue(
"only record type".to_string(),
menu.menu_type.into_abbreviated_string(config),
menu.menu_type.span()?,
menu.menu_type.span(),
))
}
}
macro_rules! add_style {
// first arm match add!(1,2), add!(2,3) etc
($name:expr, $cols: expr, $vals:expr, $span:expr, $config: expr, $menu:expr, $f:expr) => {
$menu = match extract_value($name, $cols, $vals, *$span) {
($name:expr, $record: expr, $span:expr, $config: expr, $menu:expr, $f:expr) => {
$menu = match extract_value($name, $record, $span) {
Ok(text) => {
let style = match text {
Value::String { val, .. } => lookup_ansi_color_style(&val),
@ -177,11 +179,12 @@ pub(crate) fn add_columnar_menu(
stack: &Stack,
config: &Config,
) -> Result<Reedline, ShellError> {
let span = menu.menu_type.span();
let name = menu.name.into_string("", config);
let mut columnar_menu = ColumnarMenu::default().with_name(&name);
if let Value::Record { cols, vals, span } = &menu.menu_type {
columnar_menu = match extract_value("columns", cols, vals, *span) {
if let Value::Record { val, .. } = &menu.menu_type {
columnar_menu = match extract_value("columns", val, span) {
Ok(columns) => {
let columns = columns.as_int()?;
columnar_menu.with_columns(columns as u16)
@ -189,7 +192,7 @@ pub(crate) fn add_columnar_menu(
Err(_) => columnar_menu,
};
columnar_menu = match extract_value("col_width", cols, vals, *span) {
columnar_menu = match extract_value("col_width", val, span) {
Ok(col_width) => {
let col_width = col_width.as_int()?;
columnar_menu.with_column_width(Some(col_width as usize))
@ -197,7 +200,7 @@ pub(crate) fn add_columnar_menu(
Err(_) => columnar_menu.with_column_width(None),
};
columnar_menu = match extract_value("col_padding", cols, vals, *span) {
columnar_menu = match extract_value("col_padding", val, span) {
Ok(col_padding) => {
let col_padding = col_padding.as_int()?;
columnar_menu.with_column_padding(col_padding as usize)
@ -206,11 +209,11 @@ pub(crate) fn add_columnar_menu(
};
}
if let Value::Record { cols, vals, span } = &menu.style {
let span = menu.style.span();
if let Value::Record { val, .. } = &menu.style {
add_style!(
"text",
cols,
vals,
val,
span,
config,
columnar_menu,
@ -218,8 +221,7 @@ pub(crate) fn add_columnar_menu(
);
add_style!(
"selected_text",
cols,
vals,
val,
span,
config,
columnar_menu,
@ -227,8 +229,7 @@ pub(crate) fn add_columnar_menu(
);
add_style!(
"description_text",
cols,
vals,
val,
span,
config,
columnar_menu,
@ -242,18 +243,15 @@ pub(crate) fn add_columnar_menu(
let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
columnar_menu = columnar_menu.with_only_buffer_difference(only_buffer_difference);
let span = menu.source.span();
match &menu.source {
Value::Nothing { .. } => {
Ok(line_editor.with_menu(ReedlineMenu::EngineCompleter(Box::new(columnar_menu))))
}
Value::Closure {
val,
captures,
span,
} => {
Value::Closure { val, captures, .. } => {
let menu_completer = NuMenuCompleter::new(
*val,
*span,
span,
stack.captures_to_stack(captures),
engine_state,
only_buffer_difference,
@ -266,7 +264,7 @@ pub(crate) fn add_columnar_menu(
_ => Err(ShellError::UnsupportedConfigValue(
"block or omitted value".to_string(),
menu.source.into_abbreviated_string(config),
menu.source.span()?,
span,
)),
}
}
@ -282,8 +280,9 @@ pub(crate) fn add_list_menu(
let name = menu.name.into_string("", config);
let mut list_menu = ListMenu::default().with_name(&name);
if let Value::Record { cols, vals, span } = &menu.menu_type {
list_menu = match extract_value("page_size", cols, vals, *span) {
let span = menu.menu_type.span();
if let Value::Record { val, .. } = &menu.menu_type {
list_menu = match extract_value("page_size", val, span) {
Ok(page_size) => {
let page_size = page_size.as_int()?;
list_menu.with_page_size(page_size as usize)
@ -292,11 +291,11 @@ pub(crate) fn add_list_menu(
};
}
if let Value::Record { cols, vals, span } = &menu.style {
let span = menu.style.span();
if let Value::Record { val, .. } = &menu.style {
add_style!(
"text",
cols,
vals,
val,
span,
config,
list_menu,
@ -304,8 +303,7 @@ pub(crate) fn add_list_menu(
);
add_style!(
"selected_text",
cols,
vals,
val,
span,
config,
list_menu,
@ -313,8 +311,7 @@ pub(crate) fn add_list_menu(
);
add_style!(
"description_text",
cols,
vals,
val,
span,
config,
list_menu,
@ -328,18 +325,15 @@ pub(crate) fn add_list_menu(
let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
list_menu = list_menu.with_only_buffer_difference(only_buffer_difference);
let span = menu.source.span();
match &menu.source {
Value::Nothing { .. } => {
Ok(line_editor.with_menu(ReedlineMenu::HistoryMenu(Box::new(list_menu))))
}
Value::Closure {
val,
captures,
span,
} => {
Value::Closure { val, captures, .. } => {
let menu_completer = NuMenuCompleter::new(
*val,
*span,
span,
stack.captures_to_stack(captures),
engine_state,
only_buffer_difference,
@ -352,7 +346,7 @@ pub(crate) fn add_list_menu(
_ => Err(ShellError::UnsupportedConfigValue(
"block or omitted value".to_string(),
menu.source.into_abbreviated_string(config),
menu.source.span()?,
menu.source.span(),
)),
}
}
@ -368,8 +362,9 @@ pub(crate) fn add_description_menu(
let name = menu.name.into_string("", config);
let mut description_menu = DescriptionMenu::default().with_name(&name);
if let Value::Record { cols, vals, span } = &menu.menu_type {
description_menu = match extract_value("columns", cols, vals, *span) {
let span = menu.menu_type.span();
if let Value::Record { val, .. } = &menu.menu_type {
description_menu = match extract_value("columns", val, span) {
Ok(columns) => {
let columns = columns.as_int()?;
description_menu.with_columns(columns as u16)
@ -377,7 +372,7 @@ pub(crate) fn add_description_menu(
Err(_) => description_menu,
};
description_menu = match extract_value("col_width", cols, vals, *span) {
description_menu = match extract_value("col_width", val, span) {
Ok(col_width) => {
let col_width = col_width.as_int()?;
description_menu.with_column_width(Some(col_width as usize))
@ -385,7 +380,7 @@ pub(crate) fn add_description_menu(
Err(_) => description_menu.with_column_width(None),
};
description_menu = match extract_value("col_padding", cols, vals, *span) {
description_menu = match extract_value("col_padding", val, span) {
Ok(col_padding) => {
let col_padding = col_padding.as_int()?;
description_menu.with_column_padding(col_padding as usize)
@ -393,7 +388,7 @@ pub(crate) fn add_description_menu(
Err(_) => description_menu,
};
description_menu = match extract_value("selection_rows", cols, vals, *span) {
description_menu = match extract_value("selection_rows", val, span) {
Ok(selection_rows) => {
let selection_rows = selection_rows.as_int()?;
description_menu.with_selection_rows(selection_rows as u16)
@ -401,7 +396,7 @@ pub(crate) fn add_description_menu(
Err(_) => description_menu,
};
description_menu = match extract_value("description_rows", cols, vals, *span) {
description_menu = match extract_value("description_rows", val, span) {
Ok(description_rows) => {
let description_rows = description_rows.as_int()?;
description_menu.with_description_rows(description_rows as usize)
@ -410,11 +405,11 @@ pub(crate) fn add_description_menu(
};
}
if let Value::Record { cols, vals, span } = &menu.style {
let span = menu.style.span();
if let Value::Record { val, .. } = &menu.style {
add_style!(
"text",
cols,
vals,
val,
span,
config,
description_menu,
@ -422,8 +417,7 @@ pub(crate) fn add_description_menu(
);
add_style!(
"selected_text",
cols,
vals,
val,
span,
config,
description_menu,
@ -431,8 +425,7 @@ pub(crate) fn add_description_menu(
);
add_style!(
"description_text",
cols,
vals,
val,
span,
config,
description_menu,
@ -446,6 +439,7 @@ pub(crate) fn add_description_menu(
let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
description_menu = description_menu.with_only_buffer_difference(only_buffer_difference);
let span = menu.source.span();
match &menu.source {
Value::Nothing { .. } => {
let completer = Box::new(NuHelpCompleter::new(engine_state));
@ -454,14 +448,10 @@ pub(crate) fn add_description_menu(
completer,
}))
}
Value::Closure {
val,
captures,
span,
} => {
Value::Closure { val, captures, .. } => {
let menu_completer = NuMenuCompleter::new(
*val,
*span,
span,
stack.captures_to_stack(captures),
engine_state,
only_buffer_difference,
@ -474,7 +464,7 @@ pub(crate) fn add_description_menu(
_ => Err(ShellError::UnsupportedConfigValue(
"closure or omitted value".to_string(),
menu.source.into_abbreviated_string(config),
menu.source.span()?,
menu.source.span(),
)),
}
}
@ -486,6 +476,7 @@ fn add_menu_keybindings(keybindings: &mut Keybindings) {
KeyCode::Tab,
ReedlineEvent::UntilFound(vec![
ReedlineEvent::Menu("completion_menu".to_string()),
ReedlineEvent::MenuNext,
ReedlineEvent::Edit(vec![EditCommand::Complete]),
]),
);
@ -583,15 +574,16 @@ fn add_keybinding(
insert_keybindings: &mut Keybindings,
normal_keybindings: &mut Keybindings,
) -> Result<(), ShellError> {
let span = mode.span();
match &mode {
Value::String { val, span } => match val.as_str() {
Value::String { val, .. } => match val.as_str() {
"emacs" => add_parsed_keybinding(emacs_keybindings, keybinding, config),
"vi_insert" => add_parsed_keybinding(insert_keybindings, keybinding, config),
"vi_normal" => add_parsed_keybinding(normal_keybindings, keybinding, config),
m => Err(ShellError::UnsupportedConfigValue(
"emacs, vi_insert or vi_normal".to_string(),
m.to_string(),
*span,
span,
)),
},
Value::List { vals, .. } => {
@ -611,7 +603,7 @@ fn add_keybinding(
v => Err(ShellError::UnsupportedConfigValue(
"string or list of strings".to_string(),
v.into_abbreviated_string(config),
v.span()?,
v.span(),
)),
}
}
@ -641,7 +633,7 @@ fn add_parsed_keybinding(
return Err(ShellError::UnsupportedConfigValue(
"CONTROL, SHIFT, ALT or NONE".to_string(),
keybinding.modifier.into_abbreviated_string(config),
keybinding.modifier.span()?,
keybinding.modifier.span(),
))
}
};
@ -665,7 +657,7 @@ fn add_parsed_keybinding(
return Err(ShellError::UnsupportedConfigValue(
"char_<CHAR: unicode codepoint>".to_string(),
c.to_string(),
keybinding.keycode.span()?,
keybinding.keycode.span(),
));
};
@ -692,7 +684,7 @@ fn add_parsed_keybinding(
.ok_or(ShellError::UnsupportedConfigValue(
"(f1|f2|...|f20)".to_string(),
format!("unknown function key: {c}"),
keybinding.keycode.span()?,
keybinding.keycode.span(),
))?;
KeyCode::F(fn_num)
}
@ -702,7 +694,7 @@ fn add_parsed_keybinding(
return Err(ShellError::UnsupportedConfigValue(
"crossterm KeyCode".to_string(),
keybinding.keycode.into_abbreviated_string(config),
keybinding.keycode.span()?,
keybinding.keycode.span(),
))
}
};
@ -722,68 +714,61 @@ enum EventType<'config> {
}
impl<'config> EventType<'config> {
fn try_from_columns(
cols: &'config [String],
vals: &'config [Value],
span: Span,
) -> Result<Self, ShellError> {
extract_value("send", cols, vals, span)
fn try_from_record(record: &'config Record, span: Span) -> Result<Self, ShellError> {
extract_value("send", record, span)
.map(Self::Send)
.or_else(|_| extract_value("edit", cols, vals, span).map(Self::Edit))
.or_else(|_| extract_value("until", cols, vals, span).map(Self::Until))
.or_else(|_| extract_value("edit", record, span).map(Self::Edit))
.or_else(|_| extract_value("until", record, span).map(Self::Until))
.map_err(|_| ShellError::MissingConfigValue("send, edit or until".to_string(), span))
}
}
fn parse_event(value: &Value, config: &Config) -> Result<Option<ReedlineEvent>, ShellError> {
let span = value.span();
match value {
Value::Record { cols, vals, span } => {
match EventType::try_from_columns(cols, vals, *span)? {
EventType::Send(value) => event_from_record(
Value::Record { val: record, .. } => match EventType::try_from_record(record, span)? {
EventType::Send(value) => event_from_record(
value.into_string("", config).to_lowercase().as_str(),
record,
config,
span,
)
.map(Some),
EventType::Edit(value) => {
let edit = edit_from_record(
value.into_string("", config).to_lowercase().as_str(),
cols,
vals,
record,
config,
*span,
)
.map(Some),
EventType::Edit(value) => {
let edit = edit_from_record(
value.into_string("", config).to_lowercase().as_str(),
cols,
vals,
config,
*span,
)?;
Ok(Some(ReedlineEvent::Edit(vec![edit])))
}
EventType::Until(value) => match value {
Value::List { vals, .. } => {
let events = vals
.iter()
.map(|value| match parse_event(value, config) {
Ok(inner) => match inner {
None => Err(ShellError::UnsupportedConfigValue(
"List containing valid events".to_string(),
"Nothing value (null)".to_string(),
value.span()?,
)),
Some(event) => Ok(event),
},
Err(e) => Err(e),
})
.collect::<Result<Vec<ReedlineEvent>, ShellError>>()?;
Ok(Some(ReedlineEvent::UntilFound(events)))
}
v => Err(ShellError::UnsupportedConfigValue(
"list of events".to_string(),
v.into_abbreviated_string(config),
v.span()?,
)),
},
span,
)?;
Ok(Some(ReedlineEvent::Edit(vec![edit])))
}
}
EventType::Until(value) => match value {
Value::List { vals, .. } => {
let events = vals
.iter()
.map(|value| match parse_event(value, config) {
Ok(inner) => match inner {
None => Err(ShellError::UnsupportedConfigValue(
"List containing valid events".to_string(),
"Nothing value (null)".to_string(),
value.span(),
)),
Some(event) => Ok(event),
},
Err(e) => Err(e),
})
.collect::<Result<Vec<ReedlineEvent>, ShellError>>()?;
Ok(Some(ReedlineEvent::UntilFound(events)))
}
v => Err(ShellError::UnsupportedConfigValue(
"list of events".to_string(),
v.into_abbreviated_string(config),
v.span(),
)),
},
},
Value::List { vals, .. } => {
let events = vals
.iter()
@ -792,7 +777,7 @@ fn parse_event(value: &Value, config: &Config) -> Result<Option<ReedlineEvent>,
None => Err(ShellError::UnsupportedConfigValue(
"List containing valid events".to_string(),
"Nothing value (null)".to_string(),
value.span()?,
value.span(),
)),
Some(event) => Ok(event),
},
@ -806,15 +791,14 @@ fn parse_event(value: &Value, config: &Config) -> Result<Option<ReedlineEvent>,
v => Err(ShellError::UnsupportedConfigValue(
"record or list of records, null to unbind key".to_string(),
v.into_abbreviated_string(config),
v.span()?,
v.span(),
)),
}
}
fn event_from_record(
name: &str,
cols: &[String],
vals: &[Value],
record: &Record,
config: &Config,
span: Span,
) -> Result<ReedlineEvent, ShellError> {
@ -848,11 +832,11 @@ fn event_from_record(
"menupageprevious" => ReedlineEvent::MenuPagePrevious,
"openeditor" => ReedlineEvent::OpenEditor,
"menu" => {
let menu = extract_value("name", cols, vals, span)?;
let menu = extract_value("name", record, span)?;
ReedlineEvent::Menu(menu.into_string("", config))
}
"executehostcommand" => {
let cmd = extract_value("cmd", cols, vals, span)?;
let cmd = extract_value("cmd", record, span)?;
ReedlineEvent::ExecuteHostCommand(cmd.into_string("", config))
}
v => {
@ -869,8 +853,7 @@ fn event_from_record(
fn edit_from_record(
name: &str,
cols: &[String],
vals: &[Value],
record: &Record,
config: &Config,
span: Span,
) -> Result<EditCommand, ShellError> {
@ -889,16 +872,16 @@ fn edit_from_record(
"movewordrightstart" => EditCommand::MoveWordRightStart,
"movebigwordrightstart" => EditCommand::MoveBigWordRightStart,
"movetoposition" => {
let value = extract_value("value", cols, vals, span)?;
let value = extract_value("value", record, span)?;
EditCommand::MoveToPosition(value.as_int()? as usize)
}
"insertchar" => {
let value = extract_value("value", cols, vals, span)?;
let value = extract_value("value", record, span)?;
let char = extract_char(value, config)?;
EditCommand::InsertChar(char)
}
"insertstring" => {
let value = extract_value("value", cols, vals, span)?;
let value = extract_value("value", record, span)?;
EditCommand::InsertString(value.into_string("", config))
}
"insertnewline" => EditCommand::InsertNewline,
@ -930,42 +913,42 @@ fn edit_from_record(
"undo" => EditCommand::Undo,
"redo" => EditCommand::Redo,
"cutrightuntil" => {
let value = extract_value("value", cols, vals, span)?;
let value = extract_value("value", record, span)?;
let char = extract_char(value, config)?;
EditCommand::CutRightUntil(char)
}
"cutrightbefore" => {
let value = extract_value("value", cols, vals, span)?;
let value = extract_value("value", record, span)?;
let char = extract_char(value, config)?;
EditCommand::CutRightBefore(char)
}
"moverightuntil" => {
let value = extract_value("value", cols, vals, span)?;
let value = extract_value("value", record, span)?;
let char = extract_char(value, config)?;
EditCommand::MoveRightUntil(char)
}
"moverightbefore" => {
let value = extract_value("value", cols, vals, span)?;
let value = extract_value("value", record, span)?;
let char = extract_char(value, config)?;
EditCommand::MoveRightBefore(char)
}
"cutleftuntil" => {
let value = extract_value("value", cols, vals, span)?;
let value = extract_value("value", record, span)?;
let char = extract_char(value, config)?;
EditCommand::CutLeftUntil(char)
}
"cutleftbefore" => {
let value = extract_value("value", cols, vals, span)?;
let value = extract_value("value", record, span)?;
let char = extract_char(value, config)?;
EditCommand::CutLeftBefore(char)
}
"moveleftuntil" => {
let value = extract_value("value", cols, vals, span)?;
let value = extract_value("value", record, span)?;
let char = extract_char(value, config)?;
EditCommand::MoveLeftUntil(char)
}
"moveleftbefore" => {
let value = extract_value("value", cols, vals, span)?;
let value = extract_value("value", record, span)?;
let char = extract_char(value, config)?;
EditCommand::MoveLeftBefore(char)
}
@ -983,7 +966,7 @@ fn edit_from_record(
}
fn extract_char(value: &Value, config: &Config) -> Result<char, ShellError> {
let span = value.span()?;
let span = value.span();
value
.into_string("", config)
.chars()
@ -999,16 +982,13 @@ mod test {
fn test_send_event() {
let cols = vec!["send".to_string()];
let vals = vec![Value::test_string("Enter")];
let event = Record { vals, cols };
let span = Span::test_data();
let b = EventType::try_from_columns(&cols, &vals, span).unwrap();
let b = EventType::try_from_record(&event, span).unwrap();
assert!(matches!(b, EventType::Send(_)));
let event = Value::Record {
vals,
cols,
span: Span::test_data(),
};
let event = Value::test_record(event);
let config = Config::default();
let parsed_event = parse_event(&event, &config).unwrap();
@ -1019,16 +999,13 @@ mod test {
fn test_edit_event() {
let cols = vec!["edit".to_string()];
let vals = vec![Value::test_string("Clear")];
let event = Record { vals, cols };
let span = Span::test_data();
let b = EventType::try_from_columns(&cols, &vals, span).unwrap();
let b = EventType::try_from_record(&event, span).unwrap();
assert!(matches!(b, EventType::Edit(_)));
let event = Value::Record {
vals,
cols,
span: Span::test_data(),
};
let event = Value::test_record(event);
let config = Config::default();
let parsed_event = parse_event(&event, &config).unwrap();
@ -1045,16 +1022,13 @@ mod test {
Value::test_string("Menu"),
Value::test_string("history_menu"),
];
let event = Record { vals, cols };
let span = Span::test_data();
let b = EventType::try_from_columns(&cols, &vals, span).unwrap();
let b = EventType::try_from_record(&event, span).unwrap();
assert!(matches!(b, EventType::Send(_)));
let event = Value::Record {
vals,
cols,
span: Span::test_data(),
};
let event = Value::test_record(event);
let config = Config::default();
let parsed_event = parse_event(&event, &config).unwrap();
@ -1073,38 +1047,27 @@ mod test {
Value::test_string("history_menu"),
];
let menu_event = Value::Record {
cols,
vals,
span: Span::test_data(),
};
let menu_event = Value::test_record(Record { cols, vals });
// Enter event
let cols = vec!["send".to_string()];
let vals = vec![Value::test_string("Enter")];
let enter_event = Value::Record {
cols,
vals,
span: Span::test_data(),
};
let enter_event = Value::test_record(Record { cols, vals });
// Until event
let cols = vec!["until".to_string()];
let vals = vec![Value::List {
vals: vec![menu_event, enter_event],
span: Span::test_data(),
}];
let vals = vec![Value::list(
vec![menu_event, enter_event],
Span::test_data(),
)];
let event = Record { cols, vals };
let span = Span::test_data();
let b = EventType::try_from_columns(&cols, &vals, span).unwrap();
let b = EventType::try_from_record(&event, span).unwrap();
assert!(matches!(b, EventType::Until(_)));
let event = Value::Record {
cols,
vals,
span: Span::test_data(),
};
let event = Value::test_record(event);
let config = Config::default();
let parsed_event = parse_event(&event, &config).unwrap();
@ -1126,27 +1089,16 @@ mod test {
Value::test_string("history_menu"),
];
let menu_event = Value::Record {
cols,
vals,
span: Span::test_data(),
};
let menu_event = Value::test_record(Record { cols, vals });
// Enter event
let cols = vec!["send".to_string()];
let vals = vec![Value::test_string("Enter")];
let enter_event = Value::Record {
cols,
vals,
span: Span::test_data(),
};
let enter_event = Value::test_record(Record { cols, vals });
// Multiple event
let event = Value::List {
vals: vec![menu_event, enter_event],
span: Span::test_data(),
};
let event = Value::list(vec![menu_event, enter_event], Span::test_data());
let config = Config::default();
let parsed_event = parse_event(&event, &config).unwrap();
@ -1163,9 +1115,10 @@ mod test {
fn test_error() {
let cols = vec!["not_exist".to_string()];
let vals = vec![Value::test_string("Enter")];
let event = Record { cols, vals };
let span = Span::test_data();
let b = EventType::try_from_columns(&cols, &vals, span);
let b = EventType::try_from_record(&event, span);
assert!(matches!(b, Err(ShellError::MissingConfigValue(_, _))));
}
}

View File

@ -6,19 +6,19 @@ use crate::{
NuHighlighter, NuValidator, NushellPrompt,
};
use crossterm::cursor::SetCursorStyle;
use is_terminal::IsTerminal;
use log::{trace, warn};
use miette::{ErrReport, IntoDiagnostic, Result};
use nu_cmd_base::hook::eval_hook;
use nu_cmd_base::util::get_guaranteed_cwd;
use nu_color_config::StyleComputer;
use nu_command::hook::eval_hook;
use nu_engine::convert_env_values;
use nu_parser::{lex, parse, trim_quotes_str};
use nu_protocol::{
config::NuCursorShape,
engine::{EngineState, Stack, StateWorkingSet},
eval_const::create_nu_constant,
report_error, report_error_new, HistoryFileFormat, PipelineData, ShellError, Span, Spanned,
Value,
Value, NU_VARIABLE_ID,
};
use nu_utils::utils::perf;
use reedline::{
@ -26,7 +26,7 @@ use reedline::{
SqliteBackedHistory, Vi,
};
use std::{
io::{self, Write},
io::{self, IsTerminal, Write},
path::Path,
sync::atomic::Ordering,
time::Instant,
@ -51,7 +51,7 @@ pub fn evaluate_repl(
load_std_lib: Option<Spanned<String>>,
entire_start_time: Instant,
) -> Result<()> {
use nu_command::hook;
use nu_cmd_base::hook;
use reedline::Signal;
let use_color = engine_state.get_config().use_ansi_coloring;
@ -165,6 +165,10 @@ pub fn evaluate_repl(
engine_state.set_startup_time(entire_start_time.elapsed().as_nanos() as i64);
// Regenerate the $nu constant to contain the startup time and any other potential updates
let nu_const = create_nu_constant(engine_state, Span::unknown())?;
engine_state.set_variable_const_val(NU_VARIABLE_ID, nu_const);
if load_std_lib.is_none() && engine_state.get_config().show_banner {
eval_source(
engine_state,
@ -231,13 +235,15 @@ pub fn evaluate_repl(
// Find the configured cursor shapes for each mode
let cursor_config = CursorConfig {
vi_insert: Some(map_nucursorshape_to_cursorshape(
config.cursor_shape_vi_insert,
)),
vi_normal: Some(map_nucursorshape_to_cursorshape(
config.cursor_shape_vi_normal,
)),
emacs: Some(map_nucursorshape_to_cursorshape(config.cursor_shape_emacs)),
vi_insert: config
.cursor_shape_vi_insert
.map(map_nucursorshape_to_cursorshape),
vi_normal: config
.cursor_shape_vi_normal
.map(map_nucursorshape_to_cursorshape),
emacs: config
.cursor_shape_emacs
.map(map_nucursorshape_to_cursorshape),
};
perf(
"get config/cursor config",
@ -391,7 +397,7 @@ pub fn evaluate_repl(
// Right before we start our prompt and take input from the user,
// fire the "pre_prompt" hook
if let Some(hook) = config.hooks.pre_prompt.clone() {
if let Err(err) = eval_hook(engine_state, stack, None, vec![], &hook) {
if let Err(err) = eval_hook(engine_state, stack, None, vec![], &hook, "pre_prompt") {
report_error_new(engine_state, &err);
}
}
@ -466,7 +472,9 @@ pub fn evaluate_repl(
repl.buffer = s.to_string();
drop(repl);
if let Err(err) = eval_hook(engine_state, stack, None, vec![], &hook) {
if let Err(err) =
eval_hook(engine_state, stack, None, vec![], &hook, "pre_execution")
{
report_error_new(engine_state, &err);
}
}
@ -508,24 +516,12 @@ pub fn evaluate_repl(
(path.to_string_lossy().to_string(), tokens.0[0].span)
};
stack.add_env_var(
"OLDPWD".into(),
Value::String {
val: cwd.clone(),
span: Span::unknown(),
},
);
stack.add_env_var("OLDPWD".into(), Value::string(cwd.clone(), Span::unknown()));
//FIXME: this only changes the current scope, but instead this environment variable
//should probably be a block that loads the information from the state in the overlay
stack.add_env_var(
"PWD".into(),
Value::String {
val: path.clone(),
span: Span::unknown(),
},
);
let cwd = Value::String { val: cwd, span };
stack.add_env_var("PWD".into(), Value::string(path.clone(), Span::unknown()));
let cwd = Value::string(cwd, span);
let shells = stack.get_env_var(engine_state, "NUSHELL_SHELLS");
let mut shells = if let Some(v) = shells {
@ -550,15 +546,12 @@ pub fn evaluate_repl(
0
};
shells[current_shell] = Value::String { val: path, span };
shells[current_shell] = Value::string(path, span);
stack.add_env_var("NUSHELL_SHELLS".into(), Value::List { vals: shells, span });
stack.add_env_var("NUSHELL_SHELLS".into(), Value::list(shells, span));
stack.add_env_var(
"NUSHELL_LAST_SHELL".into(),
Value::Int {
val: last_shell as i64,
span,
},
Value::int(last_shell as i64, span),
);
} else if !s.trim().is_empty() {
trace!("eval source: {}", s);
@ -601,10 +594,7 @@ pub fn evaluate_repl(
stack.add_env_var(
"CMD_DURATION_MS".into(),
Value::String {
val: format!("{}", cmd_duration.as_millis()),
span: Span::unknown(),
},
Value::string(format!("{}", cmd_duration.as_millis()), Span::unknown()),
);
if history_supports_meta && !s.is_empty() && line_editor.has_last_command_context()
@ -740,9 +730,14 @@ fn update_line_editor_history(
)
.into_diagnostic()?,
),
HistoryFileFormat::Sqlite => {
Box::new(SqliteBackedHistory::with_file(history_path.to_path_buf()).into_diagnostic()?)
}
HistoryFileFormat::Sqlite => Box::new(
SqliteBackedHistory::with_file(
history_path.to_path_buf(),
history_session_id,
Some(chrono::Utc::now()),
)
.into_diagnostic()?,
),
};
let line_editor = line_editor
.with_history_session_id(history_session_id)

View File

@ -144,7 +144,7 @@ impl Highlighter for NuHighlighter {
fn split_span_by_highlight_positions(
line: &str,
span: Span,
highlight_positions: &Vec<usize>,
highlight_positions: &[usize],
global_span_offset: usize,
) -> Vec<(Span, bool)> {
let mut start = span.start;

View File

@ -1,4 +1,4 @@
use nu_command::hook::eval_hook;
use nu_cmd_base::hook::eval_hook;
use nu_engine::{eval_block, eval_block_with_early_return};
use nu_parser::{escape_quote_string, lex, parse, unescape_unquote_string, Token, TokenContents};
use nu_protocol::engine::StateWorkingSet;
@ -185,10 +185,7 @@ fn gather_env_vars(
continue;
}
Value::String {
val: bytes,
span: *span,
}
Value::string(bytes, *span)
} else {
report_capture_error(
engine_state,
@ -257,7 +254,14 @@ pub fn eval_source(
{
result = print_if_stream(stream, stderr_stream, false, exit_code);
} else if let Some(hook) = config.hooks.display_output.clone() {
match eval_hook(engine_state, stack, Some(pipeline_data), vec![], &hook) {
match eval_hook(
engine_state,
stack,
Some(pipeline_data),
vec![],
&hook,
"display_output",
) {
Err(err) => {
result = Err(err);
}

View File

@ -4,7 +4,8 @@ use nu_engine::eval_block;
use nu_parser::parse;
use nu_protocol::{
engine::{EngineState, Stack, StateWorkingSet},
PipelineData, ShellError, Span, Value,
eval_const::create_nu_constant,
PipelineData, ShellError, Span, Value, NU_VARIABLE_ID,
};
use nu_test_support::fs;
use reedline::Suggestion;
@ -28,39 +29,41 @@ pub fn new_engine() -> (PathBuf, String, EngineState, Stack) {
// Create a new engine with default context
let mut engine_state = create_default_context();
// Add $nu
let nu_const =
create_nu_constant(&engine_state, Span::test_data()).expect("Failed creating $nu");
engine_state.set_variable_const_val(NU_VARIABLE_ID, nu_const);
// New stack
let mut stack = Stack::new();
// Add pwd as env var
stack.add_env_var(
"PWD".to_string(),
Value::String {
val: dir_str.clone(),
span: nu_protocol::Span::new(0, dir_str.len()),
},
Value::string(dir_str.clone(), nu_protocol::Span::new(0, dir_str.len())),
);
stack.add_env_var(
"TEST".to_string(),
Value::String {
val: "NUSHELL".to_string(),
span: nu_protocol::Span::new(0, dir_str.len()),
},
Value::string(
"NUSHELL".to_string(),
nu_protocol::Span::new(0, dir_str.len()),
),
);
#[cfg(windows)]
stack.add_env_var(
"Path".to_string(),
Value::String {
val: "c:\\some\\path;c:\\some\\other\\path".to_string(),
span: nu_protocol::Span::new(0, dir_str.len()),
},
Value::string(
"c:\\some\\path;c:\\some\\other\\path".to_string(),
nu_protocol::Span::new(0, dir_str.len()),
),
);
#[cfg(not(windows))]
stack.add_env_var(
"PATH".to_string(),
Value::String {
val: "/some/path:/some/other/path".to_string(),
span: nu_protocol::Span::new(0, dir_str.len()),
},
Value::string(
"/some/path:/some/other/path".to_string(),
nu_protocol::Span::new(0, dir_str.len()),
),
);
// Merge environment into the permanent state
@ -89,17 +92,14 @@ pub fn new_quote_engine() -> (PathBuf, String, EngineState, Stack) {
// Add pwd as env var
stack.add_env_var(
"PWD".to_string(),
Value::String {
val: dir_str.clone(),
span: nu_protocol::Span::new(0, dir_str.len()),
},
Value::string(dir_str.clone(), nu_protocol::Span::new(0, dir_str.len())),
);
stack.add_env_var(
"TEST".to_string(),
Value::String {
val: "NUSHELL".to_string(),
span: nu_protocol::Span::new(0, dir_str.len()),
},
Value::string(
"NUSHELL".to_string(),
nu_protocol::Span::new(0, dir_str.len()),
),
);
// Merge environment into the permanent state
@ -162,12 +162,7 @@ pub fn merge_input(
engine_state,
stack,
&block,
PipelineData::Value(
Value::Nothing {
span: Span::unknown(),
},
None
),
PipelineData::Value(Value::nothing(Span::unknown(),), None),
false,
false
)

View File

@ -5,12 +5,14 @@ edition = "2021"
license = "MIT"
name = "nu-cmd-base"
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-base"
version = "0.84.0"
version = "0.85.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.84.0" }
nu-path = { path = "../nu-path", version = "0.84.0" }
nu-protocol = { version = "0.84.0", path = "../nu-protocol" }
nu-engine = { path = "../nu-engine", version = "0.85.0" }
nu-parser = { path = "../nu-parser", version = "0.85.0" }
nu-path = { path = "../nu-path", version = "0.85.0" }
nu-protocol = { version = "0.85.0", path = "../nu-protocol" }
indexmap = { version = "2.0" }
miette = { version = "5.10", features = ["fancy-no-backtrace"] }

View File

@ -6,7 +6,7 @@ pub fn merge_descriptors(values: &[Value]) -> Vec<String> {
let mut seen: IndexSet<String> = indexset! {};
for value in values {
let data_descriptors = match value {
Value::Record { cols, .. } => cols.to_owned(),
Value::Record { val, .. } => val.cols.clone(),
_ => vec!["".to_string()],
};
for desc in data_descriptors {

View File

@ -1,5 +1,5 @@
use crate::util::get_guaranteed_cwd;
use miette::Result;
use nu_cmd_base::util::get_guaranteed_cwd;
use nu_engine::{eval_block, eval_block_with_early_return};
use nu_parser::parse;
use nu_protocol::ast::PathMember;
@ -14,12 +14,8 @@ pub fn eval_env_change_hook(
) -> Result<(), ShellError> {
if let Some(hook) = env_change_hook {
match hook {
Value::Record {
cols: env_names,
vals: hook_values,
..
} => {
for (env_name, hook_value) in env_names.iter().zip(hook_values.iter()) {
Value::Record { val, .. } => {
for (env_name, hook_value) in &val {
let before = engine_state
.previous_env_vars
.get(env_name)
@ -37,6 +33,7 @@ pub fn eval_env_change_hook(
None,
vec![("$before".into(), before), ("$after".into(), after.clone())],
hook_value,
"env_change",
)?;
engine_state
@ -48,7 +45,7 @@ pub fn eval_env_change_hook(
x => {
return Err(ShellError::TypeMismatch {
err_message: "record for the 'env_change' hook".to_string(),
span: x.span()?,
span: x.span(),
});
}
}
@ -63,8 +60,9 @@ pub fn eval_hook(
input: Option<PipelineData>,
arguments: Vec<(String, Value)>,
value: &Value,
hook_name: &str,
) -> Result<PipelineData, ShellError> {
let value_span = value.span()?;
let value_span = value.span();
// Hooks can optionally be a record in this form:
// {
@ -86,8 +84,9 @@ pub fn eval_hook(
optional: false,
};
let span = value.span();
match value {
Value::String { val, span } => {
Value::String { val, .. } => {
let (block, delta, vars) = {
let mut working_set = StateWorkingSet::new(engine_state);
@ -96,22 +95,26 @@ pub fn eval_hook(
for (name, val) in arguments {
let var_id = working_set.add_variable(
name.as_bytes().to_vec(),
val.span()?,
val.span(),
Type::Any,
false,
);
vars.push((var_id, val));
}
let output = parse(&mut working_set, Some("hook"), val.as_bytes(), false);
let output = parse(
&mut working_set,
Some(&format!("{hook_name} hook")),
val.as_bytes(),
false,
);
if let Some(err) = working_set.parse_errors.first() {
report_error(&working_set, err);
return Err(ShellError::UnsupportedConfigValue(
"valid source code".into(),
"source code with syntax errors".into(),
*span,
span,
));
}
@ -148,68 +151,67 @@ pub fn eval_hook(
}
Value::List { vals, .. } => {
for val in vals {
eval_hook(engine_state, stack, None, arguments.clone(), val)?;
eval_hook(
engine_state,
stack,
None,
arguments.clone(),
val,
&format!("{hook_name} list, recursive"),
)?;
}
}
Value::Record { .. } => {
let do_run_hook =
if let Ok(condition) = value.clone().follow_cell_path(&[condition_path], false) {
match condition {
Value::Block {
val: block_id,
span: block_span,
..
}
| Value::Closure {
val: block_id,
span: block_span,
..
} => {
match run_hook_block(
engine_state,
stack,
block_id,
None,
arguments.clone(),
block_span,
) {
Ok(pipeline_data) => {
if let PipelineData::Value(Value::Bool { val, .. }, ..) =
pipeline_data
{
val
} else {
return Err(ShellError::UnsupportedConfigValue(
"boolean output".to_string(),
"other PipelineData variant".to_string(),
block_span,
));
}
}
Err(err) => {
return Err(err);
let do_run_hook = if let Ok(condition) =
value.clone().follow_cell_path(&[condition_path], false)
{
let other_span = condition.span();
match condition {
Value::Block { val: block_id, .. } | Value::Closure { val: block_id, .. } => {
match run_hook_block(
engine_state,
stack,
block_id,
None,
arguments.clone(),
other_span,
) {
Ok(pipeline_data) => {
if let PipelineData::Value(Value::Bool { val, .. }, ..) =
pipeline_data
{
val
} else {
return Err(ShellError::UnsupportedConfigValue(
"boolean output".to_string(),
"other PipelineData variant".to_string(),
other_span,
));
}
}
}
other => {
return Err(ShellError::UnsupportedConfigValue(
"block".to_string(),
format!("{}", other.get_type()),
other.span()?,
));
Err(err) => {
return Err(err);
}
}
}
} else {
// always run the hook
true
};
other => {
return Err(ShellError::UnsupportedConfigValue(
"block".to_string(),
format!("{}", other.get_type()),
other_span,
));
}
}
} else {
// always run the hook
true
};
if do_run_hook {
match value.clone().follow_cell_path(&[code_path], false)? {
Value::String {
val,
span: source_span,
} => {
let follow = value.clone().follow_cell_path(&[code_path], false)?;
let source_span = follow.span();
match follow {
Value::String { val, .. } => {
let (block, delta, vars) = {
let mut working_set = StateWorkingSet::new(engine_state);
@ -218,16 +220,19 @@ pub fn eval_hook(
for (name, val) in arguments {
let var_id = working_set.add_variable(
name.as_bytes().to_vec(),
val.span()?,
val.span(),
Type::Any,
false,
);
vars.push((var_id, val));
}
let output =
parse(&mut working_set, Some("hook"), val.as_bytes(), false);
let output = parse(
&mut working_set,
Some(&format!("{hook_name} hook")),
val.as_bytes(),
false,
);
if let Some(err) = working_set.parse_errors.first() {
report_error(&working_set, err);
@ -265,77 +270,47 @@ pub fn eval_hook(
stack.remove_var(*var_id);
}
}
Value::Block {
val: block_id,
span: block_span,
..
} => {
Value::Block { val: block_id, .. } => {
run_hook_block(
engine_state,
stack,
block_id,
input,
arguments,
block_span,
source_span,
)?;
}
Value::Closure {
val: block_id,
span: block_span,
..
} => {
Value::Closure { val: block_id, .. } => {
run_hook_block(
engine_state,
stack,
block_id,
input,
arguments,
block_span,
source_span,
)?;
}
other => {
return Err(ShellError::UnsupportedConfigValue(
"block or string".to_string(),
format!("{}", other.get_type()),
other.span()?,
source_span,
));
}
}
}
}
Value::Block {
val: block_id,
span: block_span,
..
} => {
output = run_hook_block(
engine_state,
stack,
*block_id,
input,
arguments,
*block_span,
)?;
Value::Block { val: block_id, .. } => {
output = run_hook_block(engine_state, stack, *block_id, input, arguments, span)?;
}
Value::Closure {
val: block_id,
span: block_span,
..
} => {
output = run_hook_block(
engine_state,
stack,
*block_id,
input,
arguments,
*block_span,
)?;
Value::Closure { val: block_id, .. } => {
output = run_hook_block(engine_state, stack, *block_id, input, arguments, span)?;
}
other => {
return Err(ShellError::UnsupportedConfigValue(
"string, block, record, or list of commands".into(),
format!("{}", other.get_type()),
other.span()?,
other.span(),
));
}
}
@ -378,7 +353,7 @@ fn run_hook_block(
let pipeline_data =
eval_block_with_early_return(engine_state, &mut callee_stack, block, input, false, false)?;
if let PipelineData::Value(Value::Error { error }, _) = pipeline_data {
if let PipelineData::Value(Value::Error { error, .. }, _) = pipeline_data {
return Err(*error);
}

View File

@ -76,9 +76,7 @@ where
}),
);
if let Err(error) = r {
return Value::Error {
error: Box::new(error),
};
return Value::error(error, span);
}
}
v

View File

@ -1,3 +1,4 @@
pub mod formats;
pub mod hook;
pub mod input_handler;
pub mod util;

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.84.0"
version = "0.85.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -13,9 +13,9 @@ version = "0.84.0"
bench = false
[dependencies]
nu-engine = { path = "../nu-engine", version = "0.84.0" }
nu-parser = { path = "../nu-parser", version = "0.84.0" }
nu-protocol = { path = "../nu-protocol", version = "0.84.0" }
nu-engine = { path = "../nu-engine", version = "0.85.0" }
nu-parser = { path = "../nu-parser", version = "0.85.0" }
nu-protocol = { path = "../nu-protocol", version = "0.85.0" }
# Potential dependencies for extras
chrono = { version = "0.4", features = ["std", "unstable-locales"], default-features = false }
@ -23,8 +23,8 @@ fancy-regex = "0.11"
indexmap = { version = "2.0" }
num = { version = "0.4", optional = true }
serde = { version = "1.0", features = ["derive"] }
sqlparser = { version = "0.34", features = ["serde"], optional = true }
polars-io = { version = "0.30.0", features = ["avro"] }
sqlparser = { version = "0.36.1", optional = true }
polars-io = { version = "0.32", features = ["avro"], optional = true }
[dependencies.polars]
features = [
@ -51,15 +51,15 @@ features = [
"serde",
"serde-lazy",
"strings",
"to_dummies"
"to_dummies",
]
optional = true
version = "0.30.0"
version = "0.32"
[features]
dataframe = ["num", "polars", "sqlparser"]
dataframe = ["num", "polars", "polars-io", "sqlparser"]
default = []
[dev-dependencies]
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.84.0" }
nu-test-support = { path = "../nu-test-support", version = "0.84.0" }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.85.0" }
nu-test-support = { path = "../nu-test-support", version = "0.85.0" }

View File

@ -27,10 +27,10 @@ impl Command for ColumnsDF {
vec![Example {
description: "Dataframe columns",
example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr columns",
result: Some(Value::List {
vals: vec![Value::test_string("a"), Value::test_string("b")],
span: Span::test_data(),
}),
result: Some(Value::list(
vec![Value::test_string("a"), Value::test_string("b")],
Span::test_data(),
)),
}]
}
@ -60,10 +60,7 @@ fn command(
.map(|v| Value::string(*v, call.head))
.collect();
let names = Value::List {
vals: names,
span: call.head,
};
let names = Value::list(names, call.head);
Ok(PipelineData::Value(names, None))
}

View File

@ -79,10 +79,7 @@ fn command(
.dtype();
let dtype_str = dtype.to_string();
dtypes.push(Value::String {
val: dtype_str,
span: call.head,
});
dtypes.push(Value::string(dtype_str, call.head));
Value::string(*v, call.head)
})

View File

@ -20,6 +20,7 @@ impl Command for Dummies {
fn signature(&self) -> Signature {
Signature::build(self.name())
.switch("drop-first", "Drop first row", Some('d'))
.input_output_type(
Type::Custom("dataframe".into()),
Type::Custom("dataframe".into()),
@ -115,10 +116,11 @@ fn command(
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let drop_first: bool = call.has_flag("drop-first");
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
df.as_ref()
.to_dummies(None)
.to_dummies(None, drop_first)
.map_err(|e| {
ShellError::GenericError(
"Error calculating dummies".into(),

View File

@ -92,7 +92,7 @@ fn command_eager(
df: NuDataFrame,
) -> Result<PipelineData, ShellError> {
let mask_value: Value = call.req(engine_state, stack, 0)?;
let mask_span = mask_value.span()?;
let mask_span = mask_value.span();
if NuExpression::can_downcast(&mask_value) {
let expression = NuExpression::try_from_value(mask_value)?;

View File

@ -1,7 +1,7 @@
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Value,
record, Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Value,
};
use crate::dataframe::values::NuDataFrame;
@ -55,34 +55,18 @@ impl Command for ListDF {
NuDataFrame::try_from_value(value).ok().map(|df| (name, df))
})
.map(|(name, df)| {
let name = Value::String {
val: name,
span: call.head,
};
let columns = Value::int(df.as_ref().width() as i64, call.head);
let rows = Value::int(df.as_ref().height() as i64, call.head);
let cols = vec![
"name".to_string(),
"columns".to_string(),
"rows".to_string(),
];
let vals = vec![name, columns, rows];
Value::Record {
cols,
vals,
span: call.head,
}
Value::record(
record! {
"name" => Value::string(name, call.head),
"columns" => Value::int(df.as_ref().width() as i64, call.head),
"rows" => Value::int(df.as_ref().height() as i64, call.head),
},
call.head,
)
})
.collect::<Vec<Value>>();
let list = Value::List {
vals,
span: call.head,
};
let list = Value::list(vals, call.head);
Ok(list.into_pipeline_data())
}

View File

@ -116,7 +116,7 @@ fn command(
match type_id {
Some((e, msg, blamed)) => match e.as_str() {
"csv" | "tsv" => from_csv(engine_state, stack, call),
"parquet" => from_parquet(engine_state, stack, call),
"parquet" | "parq" => from_parquet(engine_state, stack, call),
"ipc" | "arrow" => from_ipc(engine_state, stack, call),
"json" => from_json(engine_state, stack, call),
"jsonl" => from_jsonl(engine_state, stack, call),

View File

@ -88,10 +88,7 @@ fn command(
let lazy = NuLazyFrame::new(false, df_sql);
let eager = lazy.collect(call.head)?;
let value = Value::CustomValue {
val: Box::new(eager),
span: call.head,
};
let value = Value::custom_value(Box::new(eager), call.head);
Ok(PipelineData::Value(value, None))
}

View File

@ -160,7 +160,7 @@ fn command_lazy(
let value: Value = call.req(engine_state, stack, 1)?;
return Err(ShellError::IncompatibleParametersSingle {
msg: "New name list has different size to column list".into(),
span: value.span()?,
span: value.span(),
});
}

View File

@ -125,7 +125,7 @@ pub fn parse_sql_expr(expr: &SqlExpr) -> Result<Expr> {
})
}
fn apply_window_spec(expr: Expr, window_type: &Option<WindowType>) -> Result<Expr> {
fn apply_window_spec(expr: Expr, window_type: Option<&WindowType>) -> Result<Expr> {
Ok(match &window_type {
Some(wtype) => match wtype {
WindowType::WindowSpec(window_spec) => {
@ -168,13 +168,13 @@ fn parse_sql_function(sql_function: &SQLFunction) -> Result<Expr> {
sql_function.distinct,
) {
("sum", [FunctionArgExpr::Expr(expr)], false) => {
apply_window_spec(parse_sql_expr(expr)?, &sql_function.over)?.sum()
apply_window_spec(parse_sql_expr(expr)?, sql_function.over.as_ref())?.sum()
}
("count", [FunctionArgExpr::Expr(expr)], false) => {
apply_window_spec(parse_sql_expr(expr)?, &sql_function.over)?.count()
apply_window_spec(parse_sql_expr(expr)?, sql_function.over.as_ref())?.count()
}
("count", [FunctionArgExpr::Expr(expr)], true) => {
apply_window_spec(parse_sql_expr(expr)?, &sql_function.over)?.n_unique()
apply_window_spec(parse_sql_expr(expr)?, sql_function.over.as_ref())?.n_unique()
}
// Special case for wildcard args to count function.
("count", [FunctionArgExpr::Wildcard], false) => lit(1i32).count(),

View File

@ -120,30 +120,31 @@ fn command(
let quantiles = quantiles.map(|values| {
values
.iter()
.map(|value| match value {
Value::Float { val, span } => {
if (&0.0..=&1.0).contains(&val) {
Ok(*val)
} else {
Err(ShellError::GenericError(
"Incorrect value for quantile".to_string(),
"value should be between 0 and 1".to_string(),
Some(*span),
None,
Vec::new(),
))
.map(|value| {
let span = value.span();
match value {
Value::Float { val, .. } => {
if (&0.0..=&1.0).contains(&val) {
Ok(*val)
} else {
Err(ShellError::GenericError(
"Incorrect value for quantile".to_string(),
"value should be between 0 and 1".to_string(),
Some(span),
None,
Vec::new(),
))
}
}
}
_ => match value.span() {
Ok(span) => Err(ShellError::GenericError(
Value::Error { error, .. } => Err(*error.clone()),
_ => Err(ShellError::GenericError(
"Incorrect value for quantile".to_string(),
"value should be a float".to_string(),
Some(span),
None,
Vec::new(),
)),
Err(e) => Err(e),
},
}
})
.collect::<Result<Vec<f64>, ShellError>>()
});

View File

@ -93,7 +93,7 @@ fn command(
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let index_value: Value = call.req(engine_state, stack, 0)?;
let index_span = index_value.span()?;
let index_span = index_value.span();
let index = NuDataFrame::try_from_value(index_value)?.as_series(index_span)?;
let casted = match index.dtype() {

View File

@ -78,16 +78,10 @@ fn command(
)
})?;
let file_value = Value::String {
val: format!("saved {:?}", &file_name.item),
span: file_name.span,
};
let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span);
Ok(PipelineData::Value(
Value::List {
vals: vec![file_value],
span: call.head,
},
Value::list(vec![file_value], call.head),
None,
))
}

View File

@ -108,16 +108,10 @@ fn command(
)
})?;
let file_value = Value::String {
val: format!("saved {:?}", &file_name.item),
span: file_name.span,
};
let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span);
Ok(PipelineData::Value(
Value::List {
vals: vec![file_value],
span: call.head,
},
Value::list(vec![file_value], call.head),
None,
))
}

View File

@ -124,16 +124,10 @@ fn command(
)
})?;
let file_value = Value::String {
val: format!("saved {:?}", &file_name.item),
span: file_name.span,
};
let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span);
Ok(PipelineData::Value(
Value::List {
vals: vec![file_value],
span: call.head,
},
Value::list(vec![file_value], call.head),
None,
))
}

View File

@ -81,16 +81,10 @@ fn command(
)
})?;
let file_value = Value::String {
val: format!("saved {:?}", &file_name.item),
span: file_name.span,
};
let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span);
Ok(PipelineData::Value(
Value::List {
vals: vec![file_value],
span: call.head,
},
Value::list(vec![file_value], call.head),
None,
))
}

View File

@ -2,7 +2,7 @@ use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
Category, Example, PipelineData, Record, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use crate::dataframe::values::NuExpression;
@ -40,47 +40,37 @@ impl Command for ToNu {
fn examples(&self) -> Vec<Example> {
let cols = vec!["index".into(), "a".into(), "b".into()];
let rec_1 = Value::Record {
let rec_1 = Value::test_record(Record {
cols: cols.clone(),
vals: vec![Value::test_int(0), Value::test_int(1), Value::test_int(2)],
span: Span::test_data(),
};
let rec_2 = Value::Record {
});
let rec_2 = Value::test_record(Record {
cols: cols.clone(),
vals: vec![Value::test_int(1), Value::test_int(3), Value::test_int(4)],
span: Span::test_data(),
};
let rec_3 = Value::Record {
});
let rec_3 = Value::test_record(Record {
cols,
vals: vec![Value::test_int(2), Value::test_int(3), Value::test_int(4)],
span: Span::test_data(),
};
});
vec![
Example {
description: "Shows head rows from dataframe",
example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr into-nu",
result: Some(Value::List {
vals: vec![rec_1, rec_2],
span: Span::test_data(),
}),
result: Some(Value::list(vec![rec_1, rec_2], Span::test_data())),
},
Example {
description: "Shows tail rows from dataframe",
example: "[[a b]; [1 2] [5 6] [3 4]] | dfr into-df | dfr into-nu -t -n 1",
result: Some(Value::List {
vals: vec![rec_3],
span: Span::test_data(),
}),
result: Some(Value::list(vec![rec_3], Span::test_data())),
},
Example {
description: "Convert a col expression into a nushell value",
example: "dfr col a | dfr into-nu",
result: Some(Value::Record {
result: Some(Value::test_record(Record {
cols: vec!["expr".into(), "value".into()],
vals: vec![Value::test_string("column"), Value::test_string("a")],
span: Span::test_data(),
}),
})),
},
]
}
@ -123,16 +113,13 @@ fn dataframe_command(
}
};
let value = Value::List {
vals: values,
span: call.head,
};
let value = Value::list(values, call.head);
Ok(PipelineData::Value(value, None))
}
fn expression_command(call: &Call, input: Value) -> Result<PipelineData, ShellError> {
let expr = NuExpression::try_from_value(input)?;
let value = expr.to_value(call.head);
let value = expr.to_value(call.head)?;
Ok(PipelineData::Value(value, None))
}

View File

@ -78,16 +78,10 @@ fn command(
)
})?;
let file_value = Value::String {
val: format!("saved {:?}", &file_name.item),
span: file_name.span,
};
let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span);
Ok(PipelineData::Value(
Value::List {
vals: vec![file_value],
span: call.head,
},
Value::list(vec![file_value], call.head),
None,
))
}

View File

@ -114,7 +114,7 @@ impl Command for WithColumn {
Err(ShellError::CantConvert {
to_type: "lazy or eager dataframe".into(),
from_type: value.get_type().to_string(),
span: value.span()?,
span: value.span(),
help: None,
})
}
@ -128,14 +128,11 @@ fn command_eager(
mut df: NuDataFrame,
) -> Result<PipelineData, ShellError> {
let new_column: Value = call.req(engine_state, stack, 0)?;
let column_span = new_column.span()?;
let column_span = new_column.span();
if NuExpression::can_downcast(&new_column) {
let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
let value = Value::List {
vals,
span: call.head,
};
let value = Value::list(vals, call.head);
let expressions = NuExpression::extract_exprs(value)?;
let lazy = NuLazyFrame::new(true, df.lazy().with_columns(&expressions));
@ -179,10 +176,7 @@ fn command_lazy(
lazy: NuLazyFrame,
) -> Result<PipelineData, ShellError> {
let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
let value = Value::List {
vals,
span: call.head,
};
let value = Value::list(vals, call.head);
let expressions = NuExpression::extract_exprs(value)?;
let lazy: NuLazyFrame = lazy.into_polars().with_columns(&expressions).into();

View File

@ -4,7 +4,7 @@ use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
Category, Example, PipelineData, Record, ShellError, Signature, SyntaxShape, Type, Value,
};
#[derive(Clone)]
@ -41,20 +41,18 @@ impl Command for ExprAlias {
let cols = vec!["expr".into(), "value".into()];
let expr = Value::test_string("column");
let value = Value::test_string("a");
let expr = Value::Record {
let expr = Value::test_record(Record {
cols,
vals: vec![expr, value],
span: Span::test_data(),
};
});
let cols = vec!["expr".into(), "alias".into()];
let value = Value::test_string("new_a");
let record = Value::Record {
let record = Value::test_record(Record {
cols,
vals: vec![expr, value],
span: Span::test_data(),
};
});
Some(record)
},

View File

@ -3,7 +3,7 @@ use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
Category, Example, PipelineData, Record, ShellError, Signature, SyntaxShape, Type, Value,
};
use polars::prelude::col;
@ -34,11 +34,10 @@ impl Command for ExprCol {
vec![Example {
description: "Creates a named column expression and converts it to a nu object",
example: "dfr col a | dfr into-nu",
result: Some(Value::Record {
result: Some(Value::test_record(Record {
cols: vec!["expr".into(), "value".into()],
vals: vec![Value::test_string("column"), Value::test_string("a")],
span: Span::test_data(),
}),
})),
}]
}

View File

@ -3,7 +3,7 @@ use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
Category, Example, PipelineData, Record, ShellError, Signature, SyntaxShape, Type, Value,
};
#[derive(Clone)]
@ -33,11 +33,10 @@ impl Command for ExprLit {
vec![Example {
description: "Created a literal expression and converts it to a nu object",
example: "dfr lit 2 | dfr into-nu",
result: Some(Value::Record {
result: Some(Value::test_record(Record {
cols: vec!["expr".into(), "value".into()],
vals: vec![Value::test_string("literal"), Value::test_string("2")],
span: Span::test_data(),
}),
})),
}]
}

View File

@ -95,10 +95,8 @@ impl Command for ExprOtherwise {
let value = input.into_value(call.head);
let complete: NuExpression = match NuWhen::try_from_value(value)? {
NuWhen::WhenThen(when_then) => when_then
.otherwise(otherwise_predicate.into_polars())
.into(),
NuWhen::WhenThenThen(when_then_then) => when_then_then
NuWhen::Then(then) => then.otherwise(otherwise_predicate.into_polars()).into(),
NuWhen::ChainedThen(chained_when) => chained_when
.otherwise(otherwise_predicate.into_polars())
.into(),
};

View File

@ -110,11 +110,11 @@ impl Command for ExprWhen {
.then(then_predicate.into_polars())
.into(),
v => match NuWhen::try_from_value(v)? {
NuWhen::WhenThen(when_then) => when_then
NuWhen::Then(when_then) => when_then
.when(when_predicate.into_polars())
.then(then_predicate.into_polars())
.into(),
NuWhen::WhenThenThen(when_then_then) => when_then_then
NuWhen::ChainedThen(when_then_then) => when_then_then
.when(when_predicate.into_polars())
.then(then_predicate.into_polars())
.into(),

View File

@ -114,10 +114,7 @@ impl Command for LazyAggregate {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
let value = Value::List {
vals,
span: call.head,
};
let value = Value::list(vals, call.head);
let expressions = NuExpression::extract_exprs(value)?;
let group_by = NuLazyGroupBy::try_from_pipeline(input, call.head)?;
@ -172,7 +169,6 @@ fn get_col_name(expr: &Expr) -> Option<String> {
},
Expr::Filter { input: expr, .. }
| Expr::Slice { input: expr, .. }
| Expr::Cache { input: expr, .. }
| Expr::Cast { expr, .. }
| Expr::Sort { expr, .. }
| Expr::Take { expr, .. }
@ -192,7 +188,8 @@ fn get_col_name(expr: &Expr) -> Option<String> {
| Expr::Wildcard
| Expr::RenameAlias { .. }
| Expr::Count
| Expr::Nth(_) => None,
| Expr::Nth(_)
| Expr::Selector(_) => None,
}
}

View File

@ -58,10 +58,7 @@ impl Command for LazyCollect {
) -> Result<PipelineData, ShellError> {
let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?;
let eager = lazy.collect(call.head)?;
let value = Value::CustomValue {
val: Box::new(eager),
span: call.head,
};
let value = Value::custom_value(Box::new(eager), call.head);
Ok(PipelineData::Value(value, None))
}

View File

@ -93,7 +93,7 @@ impl Command for LazyFillNA {
None,
))
} else {
let val_span = value.span()?;
let val_span = value.span();
let frame = NuDataFrame::try_from_value(value)?;
let columns = frame.columns(val_span)?;
let dataframe = columns
@ -102,18 +102,21 @@ impl Command for LazyFillNA {
let column_name = column.name().to_string();
let values = column
.into_iter()
.map(|value| match value {
Value::Float { val, .. } => {
if val.is_nan() {
fill.clone()
} else {
value
.map(|value| {
let span = value.span();
match value {
Value::Float { val, .. } => {
if val.is_nan() {
fill.clone()
} else {
value
}
}
Value::List { vals, .. } => {
NuDataFrame::fill_list_nan(vals, span, fill.clone())
}
_ => value,
}
Value::List { vals, span } => {
NuDataFrame::fill_list_nan(vals, span, fill.clone())
}
_ => value,
})
.collect::<Vec<Value>>();
Column::new(column_name, values)

View File

@ -113,10 +113,7 @@ impl Command for ToLazyGroupBy {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
let value = Value::List {
vals,
span: call.head,
};
let value = Value::list(vals, call.head);
let expressions = NuExpression::extract_exprs(value)?;
if expressions
@ -126,7 +123,7 @@ impl Command for ToLazyGroupBy {
let value: Value = call.req(engine_state, stack, 0)?;
return Err(ShellError::IncompatibleParametersSingle {
msg: "Expected only Col expressions".into(),
span: value.span()?,
span: value.span(),
});
}

View File

@ -199,7 +199,7 @@ impl Command for LazyJoin {
let right_on: Value = call.req(engine_state, stack, 2)?;
return Err(ShellError::IncompatibleParametersSingle {
msg: "The right column list has a different size to the left column list".into(),
span: right_on.span()?,
span: right_on.span(),
});
}
@ -209,7 +209,7 @@ impl Command for LazyJoin {
let value: Value = call.req(engine_state, stack, *index)?;
return Err(ShellError::IncompatibleParametersSingle {
msg: "Expected only a string, col expressions or list of strings".into(),
span: value.span()?,
span: value.span(),
});
}
}

View File

@ -55,10 +55,7 @@ impl Command for LazySelect {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
let value = Value::List {
vals,
span: call.head,
};
let value = Value::list(vals, call.head);
let expressions = NuExpression::extract_exprs(value)?;
let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?;

View File

@ -37,6 +37,7 @@ impl Command for LazySortBy {
"nulls are shown last in the dataframe",
Some('n'),
)
.switch("maintain-order", "Maintains order during sort", Some('m'))
.input_output_type(
Type::Custom("dataframe".into()),
Type::Custom("dataframe".into()),
@ -104,12 +105,10 @@ impl Command for LazySortBy {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
let value = Value::List {
vals,
span: call.head,
};
let value = Value::list(vals, call.head);
let expressions = NuExpression::extract_exprs(value)?;
let nulls_last = call.has_flag("nulls-last");
let maintain_order = call.has_flag("maintain-order");
let reverse: Option<Vec<bool>> = call.get_flag(engine_state, stack, "reverse")?;
let reverse = match reverse {
@ -118,7 +117,7 @@ impl Command for LazySortBy {
let span = call
.get_flag::<Value>(engine_state, stack, "reverse")?
.expect("already checked and it exists")
.span()?;
.span();
return Err(ShellError::GenericError(
"Incorrect list size".into(),
"Size doesn't match expression list".into(),
@ -137,7 +136,7 @@ impl Command for LazySortBy {
let lazy = NuLazyFrame::new(
lazy.from_eager,
lazy.into_polars()
.sort_by_exprs(&expressions, reverse, nulls_last),
.sort_by_exprs(&expressions, reverse, nulls_last, maintain_order),
);
Ok(PipelineData::Value(

View File

@ -41,10 +41,7 @@ impl Command for ToLazyFrame {
) -> Result<PipelineData, ShellError> {
let df = NuDataFrame::try_from_iter(input.into_iter())?;
let lazy = NuLazyFrame::from_dataframe(df);
let value = Value::CustomValue {
val: Box::new(lazy),
span: call.head,
};
let value = Value::custom_value(Box::new(lazy), call.head);
Ok(PipelineData::Value(value, None))
}

View File

@ -56,22 +56,22 @@ impl Command for AsDateTime {
NuDataFrame::try_from_columns(vec![Column::new(
"datetime".to_string(),
vec![
Value::Date {
val: DateTime::parse_from_str(
Value::date(
DateTime::parse_from_str(
"2021-12-30 00:00:00 +0000",
"%Y-%m-%d %H:%M:%S %z",
)
.expect("date calculation should not fail in test"),
span: Span::test_data(),
},
Value::Date {
val: DateTime::parse_from_str(
Span::test_data(),
),
Value::date(
DateTime::parse_from_str(
"2021-12-31 00:00:00 +0000",
"%Y-%m-%d %H:%M:%S %z",
)
.expect("date calculation should not fail in test"),
span: Span::test_data(),
},
Span::test_data(),
),
],
)])
.expect("simple df for test should not fail")
@ -85,22 +85,22 @@ impl Command for AsDateTime {
NuDataFrame::try_from_columns(vec![Column::new(
"datetime".to_string(),
vec![
Value::Date {
val: DateTime::parse_from_str(
Value::date(
DateTime::parse_from_str(
"2021-12-30 00:00:00.123456789 +0000",
"%Y-%m-%d %H:%M:%S.%9f %z",
)
.expect("date calculation should not fail in test"),
span: Span::test_data(),
},
Value::Date {
val: DateTime::parse_from_str(
Span::test_data(),
),
Value::date(
DateTime::parse_from_str(
"2021-12-31 00:00:00.123456789 +0000",
"%Y-%m-%d %H:%M:%S.%9f %z",
)
.expect("date calculation should not fail in test"),
span: Span::test_data(),
},
Span::test_data(),
),
],
)])
.expect("simple df for test should not fail")
@ -143,7 +143,13 @@ fn command(
})?;
let res = if not_exact {
casted.as_datetime_not_exact(Some(format.as_str()), TimeUnit::Nanoseconds, None)
casted.as_datetime_not_exact(
Some(format.as_str()),
TimeUnit::Nanoseconds,
false,
None,
None,
)
} else {
casted.as_datetime(
Some(format.as_str()),
@ -151,6 +157,7 @@ fn command(
false,
false,
None,
None,
)
};

View File

@ -27,6 +27,11 @@ impl Command for ArgSort {
Signature::build(self.name())
.switch("reverse", "reverse order", Some('r'))
.switch("nulls-last", "nulls ordered last", Some('n'))
.switch(
"maintain-order",
"maintain order on sorted items",
Some('m'),
)
.input_output_type(
Type::Custom("dataframe".into()),
Type::Custom("dataframe".into()),
@ -98,6 +103,7 @@ fn command(
descending: call.has_flag("reverse"),
nulls_last: call.has_flag("nulls-last"),
multithreaded: true,
maintain_order: call.has_flag("maintain-order"),
};
let mut res = df

View File

@ -98,7 +98,12 @@ fn command(
let value = NuDataFrame::dataframe_into_value(res, call.head);
Ok(PipelineData::Value(value, None))
}
_ => todo!(),
_ => Err(ShellError::UnsupportedInput(
"Expected the dataframe to have a column".to_string(),
"".to_string(),
call.head,
call.head,
)),
}
}

View File

@ -82,7 +82,7 @@ fn command(
let indices_value: Value = call
.get_flag(engine_state, stack, "indices")?
.expect("required named value");
let indices_span = indices_value.span()?;
let indices_span = indices_value.span();
let indices = NuDataFrame::try_from_value(indices_value)?.as_series(indices_span)?;
let casted = match indices.dtype() {
@ -123,8 +123,9 @@ fn command(
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let series = df.as_series(call.head)?;
let span = value.span();
let res = match value {
Value::Int { val, span } => {
Value::Int { val, .. } => {
let chunked = series.i64().map_err(|e| {
ShellError::GenericError(
"Error casting to i64".into(),
@ -147,7 +148,7 @@ fn command(
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
}
Value::Float { val, span } => {
Value::Float { val, .. } => {
let chunked = series.f64().map_err(|e| {
ShellError::GenericError(
"Error casting to f64".into(),
@ -170,7 +171,7 @@ fn command(
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
}
Value::String { val, span } => {
Value::String { val, .. } => {
let chunked = series.utf8().map_err(|e| {
ShellError::GenericError(
"Error casting to string".into(),
@ -204,7 +205,7 @@ fn command(
"this value cannot be set in a series of type '{}'",
series.dtype()
),
Some(value.span()?),
Some(span),
None,
Vec::new(),
)),

View File

@ -74,7 +74,7 @@ fn command(
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let other_value: Value = call.req(engine_state, stack, 0)?;
let other_span = other_value.span()?;
let other_span = other_value.span();
let other_df = NuDataFrame::try_from_value(other_value)?;
let other = other_df.as_series(other_span)?;

View File

@ -81,7 +81,7 @@ fn command(
let mask_value: Value = call
.get_flag(engine_state, stack, "mask")?
.expect("required named value");
let mask_span = mask_value.span()?;
let mask_span = mask_value.span();
let mask = NuDataFrame::try_from_value(mask_value)?.as_series(mask_span)?;
let bool_mask = match mask.dtype() {
@ -105,9 +105,9 @@ fn command(
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let series = df.as_series(call.head)?;
let span = value.span();
let res = match value {
Value::Int { val, span } => {
Value::Int { val, .. } => {
let chunked = series.i64().map_err(|e| {
ShellError::GenericError(
"Error casting to i64".into(),
@ -130,7 +130,7 @@ fn command(
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
}
Value::Float { val, span } => {
Value::Float { val, .. } => {
let chunked = series.f64().map_err(|e| {
ShellError::GenericError(
"Error casting to f64".into(),
@ -153,7 +153,7 @@ fn command(
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
}
Value::String { val, span } => {
Value::String { val, .. } => {
let chunked = series.utf8().map_err(|e| {
ShellError::GenericError(
"Error casting to string".into(),
@ -185,7 +185,7 @@ fn command(
"this value cannot be set in a series of type '{}'",
series.dtype()
),
Some(value.span()?),
Some(span),
None,
Vec::new(),
)),

View File

@ -149,6 +149,7 @@ fn command(
closed_window: None,
tu: None,
tz: None,
fn_params: None,
};
let res = match roll_type {
RollType::Max => series.rolling_max(rolling_opts),

View File

@ -74,7 +74,7 @@ fn command(
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let other: Value = call.req(engine_state, stack, 0)?;
let other_span = other.span()?;
let other_span = other.span();
let other_df = NuDataFrame::try_from_value(other)?;
let other_series = other_df.as_series(other_span)?;

View File

@ -9,7 +9,7 @@ pub fn extract_strings(value: Value) -> Result<Vec<String>, ShellError> {
(Err(_), Ok(cols)) => Ok(cols),
_ => Err(ShellError::IncompatibleParametersSingle {
msg: "Expected a string or list of strings".into(),
span: value.span()?,
span: value.span(),
}),
}
}

View File

@ -17,7 +17,7 @@ pub(super) fn between_dataframes(
right: &Value,
rhs: &NuDataFrame,
) -> Result<Value, ShellError> {
let operation_span = span(&[left.span()?, right.span()?]);
let operation_span = span(&[left.span(), right.span()]);
match operator.item {
Operator::Math(Math::Plus) => match lhs.append_df(rhs, Axis::Row, operation_span) {
Ok(df) => Ok(df.into_value(operation_span)),
@ -26,9 +26,9 @@ pub(super) fn between_dataframes(
_ => Err(ShellError::OperatorMismatch {
op_span: operator.span,
lhs_ty: left.get_type().to_string(),
lhs_span: left.span()?,
lhs_span: left.span(),
rhs_ty: right.get_type().to_string(),
rhs_span: right.span()?,
rhs_span: right.span(),
}),
}
}
@ -40,7 +40,7 @@ pub(super) fn compute_between_series(
right: &Value,
rhs: &Series,
) -> Result<Value, ShellError> {
let operation_span = span(&[left.span()?, right.span()?]);
let operation_span = span(&[left.span(), right.span()]);
match operator.item {
Operator::Math(Math::Plus) => {
let mut res = lhs + rhs;
@ -71,7 +71,7 @@ pub(super) fn compute_between_series(
Err(e) => Err(ShellError::GenericError(
"Division error".into(),
e.to_string(),
Some(right.span()?),
Some(right.span()),
None,
Vec::new(),
)),
@ -79,32 +79,32 @@ pub(super) fn compute_between_series(
}
Operator::Comparison(Comparison::Equal) => {
let name = format!("eq_{}_{}", lhs.name(), rhs.name());
let res = compare_series(lhs, rhs, name.as_str(), right.span().ok(), Series::equal)?;
let res = compare_series(lhs, rhs, name.as_str(), right.span(), Series::equal)?;
NuDataFrame::series_to_value(res, operation_span)
}
Operator::Comparison(Comparison::NotEqual) => {
let name = format!("neq_{}_{}", lhs.name(), rhs.name());
let res = compare_series(lhs, rhs, name.as_str(), right.span().ok(), Series::equal)?;
let res = compare_series(lhs, rhs, name.as_str(), right.span(), Series::equal)?;
NuDataFrame::series_to_value(res, operation_span)
}
Operator::Comparison(Comparison::LessThan) => {
let name = format!("lt_{}_{}", lhs.name(), rhs.name());
let res = compare_series(lhs, rhs, name.as_str(), right.span().ok(), Series::equal)?;
let res = compare_series(lhs, rhs, name.as_str(), right.span(), Series::equal)?;
NuDataFrame::series_to_value(res, operation_span)
}
Operator::Comparison(Comparison::LessThanOrEqual) => {
let name = format!("lte_{}_{}", lhs.name(), rhs.name());
let res = compare_series(lhs, rhs, name.as_str(), right.span().ok(), Series::equal)?;
let res = compare_series(lhs, rhs, name.as_str(), right.span(), Series::equal)?;
NuDataFrame::series_to_value(res, operation_span)
}
Operator::Comparison(Comparison::GreaterThan) => {
let name = format!("gt_{}_{}", lhs.name(), rhs.name());
let res = compare_series(lhs, rhs, name.as_str(), right.span().ok(), Series::equal)?;
let res = compare_series(lhs, rhs, name.as_str(), right.span(), Series::equal)?;
NuDataFrame::series_to_value(res, operation_span)
}
Operator::Comparison(Comparison::GreaterThanOrEqual) => {
let name = format!("gte_{}_{}", lhs.name(), rhs.name());
let res = compare_series(lhs, rhs, name.as_str(), right.span().ok(), Series::equal)?;
let res = compare_series(lhs, rhs, name.as_str(), right.span(), Series::equal)?;
NuDataFrame::series_to_value(res, operation_span)
}
Operator::Boolean(Boolean::And) => match lhs.dtype() {
@ -122,7 +122,7 @@ pub(super) fn compute_between_series(
_ => Err(ShellError::GenericError(
"Incompatible types".into(),
"unable to cast to boolean".into(),
Some(right.span()?),
Some(right.span()),
None,
Vec::new(),
)),
@ -151,7 +151,7 @@ pub(super) fn compute_between_series(
_ => Err(ShellError::GenericError(
"Incompatible types".into(),
"unable to cast to boolean".into(),
Some(right.span()?),
Some(right.span()),
None,
Vec::new(),
)),
@ -168,9 +168,9 @@ pub(super) fn compute_between_series(
_ => Err(ShellError::OperatorMismatch {
op_span: operator.span,
lhs_ty: left.get_type().to_string(),
lhs_span: left.span()?,
lhs_span: left.span(),
rhs_ty: right.get_type().to_string(),
rhs_span: right.span()?,
rhs_span: right.span(),
}),
}
}
@ -179,7 +179,7 @@ fn compare_series<'s, F>(
lhs: &'s Series,
rhs: &'s Series,
name: &'s str,
span: Option<Span>,
span: Span,
f: F,
) -> Result<Series, ShellError>
where
@ -190,7 +190,7 @@ where
ShellError::GenericError(
"Equality error".into(),
e.to_string(),
span,
Some(span),
None,
Vec::new(),
)
@ -211,13 +211,13 @@ pub(super) fn compute_series_single_value(
return Err(ShellError::OperatorMismatch {
op_span: operator.span,
lhs_ty: left.get_type().to_string(),
lhs_span: left.span()?,
lhs_span: left.span(),
rhs_ty: right.get_type().to_string(),
rhs_span: right.span()?,
rhs_span: right.span(),
});
}
let lhs_span = left.span()?;
let lhs_span = left.span();
let lhs = lhs.as_series(lhs_span)?;
match operator.item {
@ -226,15 +226,15 @@ pub(super) fn compute_series_single_value(
compute_series_i64(&lhs, *val, <ChunkedArray<Int64Type>>::add, lhs_span)
}
Value::Float { val, .. } => {
compute_series_decimal(&lhs, *val, <ChunkedArray<Float64Type>>::add, lhs_span)
compute_series_float(&lhs, *val, <ChunkedArray<Float64Type>>::add, lhs_span)
}
Value::String { val, .. } => add_string_to_series(&lhs, val, lhs_span),
_ => Err(ShellError::OperatorMismatch {
op_span: operator.span,
lhs_ty: left.get_type().to_string(),
lhs_span: left.span()?,
lhs_span: left.span(),
rhs_ty: right.get_type().to_string(),
rhs_span: right.span()?,
rhs_span: right.span(),
}),
},
Operator::Math(Math::Minus) => match &right {
@ -242,14 +242,14 @@ pub(super) fn compute_series_single_value(
compute_series_i64(&lhs, *val, <ChunkedArray<Int64Type>>::sub, lhs_span)
}
Value::Float { val, .. } => {
compute_series_decimal(&lhs, *val, <ChunkedArray<Float64Type>>::sub, lhs_span)
compute_series_float(&lhs, *val, <ChunkedArray<Float64Type>>::sub, lhs_span)
}
_ => Err(ShellError::OperatorMismatch {
op_span: operator.span,
lhs_ty: left.get_type().to_string(),
lhs_span: left.span()?,
lhs_span: left.span(),
rhs_ty: right.get_type().to_string(),
rhs_span: right.span()?,
rhs_span: right.span(),
}),
},
Operator::Math(Math::Multiply) => match &right {
@ -257,43 +257,46 @@ pub(super) fn compute_series_single_value(
compute_series_i64(&lhs, *val, <ChunkedArray<Int64Type>>::mul, lhs_span)
}
Value::Float { val, .. } => {
compute_series_decimal(&lhs, *val, <ChunkedArray<Float64Type>>::mul, lhs_span)
compute_series_float(&lhs, *val, <ChunkedArray<Float64Type>>::mul, lhs_span)
}
_ => Err(ShellError::OperatorMismatch {
op_span: operator.span,
lhs_ty: left.get_type().to_string(),
lhs_span: left.span()?,
lhs_span: left.span(),
rhs_ty: right.get_type().to_string(),
rhs_span: right.span()?,
rhs_span: right.span(),
}),
},
Operator::Math(Math::Divide) => match &right {
Value::Int { val, span } => {
if *val == 0 {
Err(ShellError::DivisionByZero { span: *span })
} else {
compute_series_i64(&lhs, *val, <ChunkedArray<Int64Type>>::div, lhs_span)
Operator::Math(Math::Divide) => {
let span = right.span();
match &right {
Value::Int { val, .. } => {
if *val == 0 {
Err(ShellError::DivisionByZero { span })
} else {
compute_series_i64(&lhs, *val, <ChunkedArray<Int64Type>>::div, lhs_span)
}
}
}
Value::Float { val, span } => {
if val.is_zero() {
Err(ShellError::DivisionByZero { span: *span })
} else {
compute_series_decimal(&lhs, *val, <ChunkedArray<Float64Type>>::div, lhs_span)
Value::Float { val, .. } => {
if val.is_zero() {
Err(ShellError::DivisionByZero { span })
} else {
compute_series_float(&lhs, *val, <ChunkedArray<Float64Type>>::div, lhs_span)
}
}
_ => Err(ShellError::OperatorMismatch {
op_span: operator.span,
lhs_ty: left.get_type().to_string(),
lhs_span: left.span(),
rhs_ty: right.get_type().to_string(),
rhs_span: right.span(),
}),
}
_ => Err(ShellError::OperatorMismatch {
op_span: operator.span,
lhs_ty: left.get_type().to_string(),
lhs_span: left.span()?,
rhs_ty: right.get_type().to_string(),
rhs_span: right.span()?,
}),
},
}
Operator::Comparison(Comparison::Equal) => match &right {
Value::Int { val, .. } => compare_series_i64(&lhs, *val, ChunkedArray::equal, lhs_span),
Value::Float { val, .. } => {
compare_series_decimal(&lhs, *val, ChunkedArray::equal, lhs_span)
compare_series_float(&lhs, *val, ChunkedArray::equal, lhs_span)
}
Value::String { val, .. } => {
let equal_pattern = format!("^{}$", fancy_regex::escape(val));
@ -305,9 +308,9 @@ pub(super) fn compute_series_single_value(
_ => Err(ShellError::OperatorMismatch {
op_span: operator.span,
lhs_ty: left.get_type().to_string(),
lhs_span: left.span()?,
lhs_span: left.span(),
rhs_ty: right.get_type().to_string(),
rhs_span: right.span()?,
rhs_span: right.span(),
}),
},
Operator::Comparison(Comparison::NotEqual) => match &right {
@ -315,7 +318,7 @@ pub(super) fn compute_series_single_value(
compare_series_i64(&lhs, *val, ChunkedArray::not_equal, lhs_span)
}
Value::Float { val, .. } => {
compare_series_decimal(&lhs, *val, ChunkedArray::not_equal, lhs_span)
compare_series_float(&lhs, *val, ChunkedArray::not_equal, lhs_span)
}
Value::Date { val, .. } => compare_series_i64(
&lhs,
@ -326,15 +329,15 @@ pub(super) fn compute_series_single_value(
_ => Err(ShellError::OperatorMismatch {
op_span: operator.span,
lhs_ty: left.get_type().to_string(),
lhs_span: left.span()?,
lhs_span: left.span(),
rhs_ty: right.get_type().to_string(),
rhs_span: right.span()?,
rhs_span: right.span(),
}),
},
Operator::Comparison(Comparison::LessThan) => match &right {
Value::Int { val, .. } => compare_series_i64(&lhs, *val, ChunkedArray::lt, lhs_span),
Value::Float { val, .. } => {
compare_series_decimal(&lhs, *val, ChunkedArray::lt, lhs_span)
compare_series_float(&lhs, *val, ChunkedArray::lt, lhs_span)
}
Value::Date { val, .. } => {
compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::lt, lhs_span)
@ -342,15 +345,15 @@ pub(super) fn compute_series_single_value(
_ => Err(ShellError::OperatorMismatch {
op_span: operator.span,
lhs_ty: left.get_type().to_string(),
lhs_span: left.span()?,
lhs_span: left.span(),
rhs_ty: right.get_type().to_string(),
rhs_span: right.span()?,
rhs_span: right.span(),
}),
},
Operator::Comparison(Comparison::LessThanOrEqual) => match &right {
Value::Int { val, .. } => compare_series_i64(&lhs, *val, ChunkedArray::lt_eq, lhs_span),
Value::Float { val, .. } => {
compare_series_decimal(&lhs, *val, ChunkedArray::lt_eq, lhs_span)
compare_series_float(&lhs, *val, ChunkedArray::lt_eq, lhs_span)
}
Value::Date { val, .. } => {
compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::lt_eq, lhs_span)
@ -358,15 +361,15 @@ pub(super) fn compute_series_single_value(
_ => Err(ShellError::OperatorMismatch {
op_span: operator.span,
lhs_ty: left.get_type().to_string(),
lhs_span: left.span()?,
lhs_span: left.span(),
rhs_ty: right.get_type().to_string(),
rhs_span: right.span()?,
rhs_span: right.span(),
}),
},
Operator::Comparison(Comparison::GreaterThan) => match &right {
Value::Int { val, .. } => compare_series_i64(&lhs, *val, ChunkedArray::gt, lhs_span),
Value::Float { val, .. } => {
compare_series_decimal(&lhs, *val, ChunkedArray::gt, lhs_span)
compare_series_float(&lhs, *val, ChunkedArray::gt, lhs_span)
}
Value::Date { val, .. } => {
compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::gt, lhs_span)
@ -374,15 +377,15 @@ pub(super) fn compute_series_single_value(
_ => Err(ShellError::OperatorMismatch {
op_span: operator.span,
lhs_ty: left.get_type().to_string(),
lhs_span: left.span()?,
lhs_span: left.span(),
rhs_ty: right.get_type().to_string(),
rhs_span: right.span()?,
rhs_span: right.span(),
}),
},
Operator::Comparison(Comparison::GreaterThanOrEqual) => match &right {
Value::Int { val, .. } => compare_series_i64(&lhs, *val, ChunkedArray::gt_eq, lhs_span),
Value::Float { val, .. } => {
compare_series_decimal(&lhs, *val, ChunkedArray::gt_eq, lhs_span)
compare_series_float(&lhs, *val, ChunkedArray::gt_eq, lhs_span)
}
Value::Date { val, .. } => {
compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::gt_eq, lhs_span)
@ -390,9 +393,9 @@ pub(super) fn compute_series_single_value(
_ => Err(ShellError::OperatorMismatch {
op_span: operator.span,
lhs_ty: left.get_type().to_string(),
lhs_span: left.span()?,
lhs_span: left.span(),
rhs_ty: right.get_type().to_string(),
rhs_span: right.span()?,
rhs_span: right.span(),
}),
},
// TODO: update this to do a regex match instead of a simple contains?
@ -401,9 +404,9 @@ pub(super) fn compute_series_single_value(
_ => Err(ShellError::OperatorMismatch {
op_span: operator.span,
lhs_ty: left.get_type().to_string(),
lhs_span: left.span()?,
lhs_span: left.span(),
rhs_ty: right.get_type().to_string(),
rhs_span: right.span()?,
rhs_span: right.span(),
}),
},
Operator::Comparison(Comparison::StartsWith) => match &right {
@ -414,9 +417,9 @@ pub(super) fn compute_series_single_value(
_ => Err(ShellError::OperatorMismatch {
op_span: operator.span,
lhs_ty: left.get_type().to_string(),
lhs_span: left.span()?,
lhs_span: left.span(),
rhs_ty: right.get_type().to_string(),
rhs_span: right.span()?,
rhs_span: right.span(),
}),
},
Operator::Comparison(Comparison::EndsWith) => match &right {
@ -427,17 +430,17 @@ pub(super) fn compute_series_single_value(
_ => Err(ShellError::OperatorMismatch {
op_span: operator.span,
lhs_ty: left.get_type().to_string(),
lhs_span: left.span()?,
lhs_span: left.span(),
rhs_ty: right.get_type().to_string(),
rhs_span: right.span()?,
rhs_span: right.span(),
}),
},
_ => Err(ShellError::OperatorMismatch {
op_span: operator.span,
lhs_ty: left.get_type().to_string(),
lhs_span: left.span()?,
lhs_span: left.span(),
rhs_ty: right.get_type().to_string(),
rhs_span: right.span()?,
rhs_span: right.span(),
}),
}
}
@ -506,12 +509,7 @@ where
}
}
fn compute_series_decimal<F>(
series: &Series,
val: f64,
f: F,
span: Span,
) -> Result<Value, ShellError>
fn compute_series_float<F>(series: &Series, val: f64, f: F, span: Span) -> Result<Value, ShellError>
where
F: Fn(ChunkedArray<Float64Type>, f64) -> ChunkedArray<Float64Type>,
{
@ -540,7 +538,7 @@ where
_ => Err(ShellError::GenericError(
"Incorrect type".into(),
format!(
"Series of type {} can not be used for operations with a decimal value",
"Series of type {} can not be used for operations with a float value",
series.dtype()
),
Some(span),
@ -660,12 +658,7 @@ where
}
}
fn compare_series_decimal<F>(
series: &Series,
val: f64,
f: F,
span: Span,
) -> Result<Value, ShellError>
fn compare_series_float<F>(series: &Series, val: f64, f: F, span: Span) -> Result<Value, ShellError>
where
F: Fn(&ChunkedArray<Float64Type>, f64) -> ChunkedArray<BooleanType>,
{
@ -694,7 +687,7 @@ where
_ => Err(ShellError::GenericError(
"Incorrect type".into(),
format!(
"Series of type {} can not be used for operations with a decimal value",
"Series of type {} can not be used for operations with a float value",
series.dtype()
),
Some(span),

View File

@ -2,7 +2,7 @@ use super::{DataFrameValue, NuDataFrame};
use chrono::{DateTime, FixedOffset, NaiveDateTime};
use indexmap::map::{Entry, IndexMap};
use nu_protocol::{ShellError, Span, Value};
use nu_protocol::{Record, ShellError, Span, Value};
use polars::chunked_array::builder::AnonymousOwnedListBuilder;
use polars::chunked_array::object::builder::ObjectChunkedBuilder;
use polars::chunked_array::ChunkedArray;
@ -128,36 +128,21 @@ pub fn create_column(
// Adds a separator to the vector of values using the column names from the
// dataframe to create the Values Row
pub fn add_separator(values: &mut Vec<Value>, df: &DataFrame, span: Span) {
let mut cols = vec![];
let mut vals = vec![];
let mut record = Record::new();
cols.push("index".to_string());
vals.push(Value::String {
val: "...".into(),
span,
});
record.push("index", Value::string("...", span));
for name in df.get_column_names() {
cols.push(name.to_string());
vals.push(Value::String {
val: "...".into(),
span,
})
record.push(name, Value::string("...", span))
}
let extra_record = Value::Record { cols, vals, span };
values.push(extra_record);
values.push(Value::record(record, span));
}
// Inserting the values found in a Value::List
pub fn insert_record(
column_values: &mut ColumnMap,
cols: &[String],
values: &[Value],
) -> Result<(), ShellError> {
for (col, value) in cols.iter().zip(values.iter()) {
insert_value(value.clone(), col.clone(), column_values)?;
// Inserting the values found in a Value::List or Value::Record
pub fn insert_record(column_values: &mut ColumnMap, record: Record) -> Result<(), ShellError> {
for (col, value) in record {
insert_value(value, col, column_values)?;
}
Ok(())
@ -284,7 +269,7 @@ pub fn from_parsed_columns(column_values: ColumnMap) -> Result<NuDataFrame, Shel
InputType::Date => {
let it = column.values.iter().map(|v| {
if let Value::Date { val, .. } = &v {
Some(val.timestamp_nanos())
Some(val.timestamp_nanos_opt().unwrap_or_default())
} else {
None
}
@ -428,7 +413,7 @@ fn input_type_list_to_series(
let it = v.as_list()?.iter().map(|v| {
if let Value::Date { val, .. } = &v {
Some(val.timestamp_nanos())
Some(val.timestamp_nanos_opt().unwrap_or_default())
} else {
None
}
@ -436,7 +421,17 @@ fn input_type_list_to_series(
let dt_chunked = ChunkedArray::<Int64Type>::from_iter_options(&list_name, it)
.into_datetime(TimeUnit::Nanoseconds, None);
builder.append_series(&dt_chunked.into_series());
builder
.append_series(&dt_chunked.into_series())
.map_err(|e| {
ShellError::GenericError(
"Error appending to series".into(),
"".to_string(),
None,
Some(e.to_string()),
Vec::new(),
)
})?
}
let res = builder.finish();
Ok(res.into_series())
@ -457,7 +452,7 @@ fn series_to_values(
) -> Result<Vec<Value>, ShellError> {
match series.dtype() {
DataType::Null => {
let it = std::iter::repeat(Value::Nothing { span });
let it = std::iter::repeat(Value::nothing(span));
let values = if let Some(size) = maybe_size {
Either::Left(it.take(size))
} else {
@ -485,11 +480,8 @@ fn series_to_values(
Either::Right(it)
}
.map(|v| match v {
Some(a) => Value::Int {
val: a as i64,
span,
},
None => Value::Nothing { span },
Some(a) => Value::int(a as i64, span),
None => Value::nothing(span),
})
.collect::<Vec<Value>>();
@ -513,11 +505,8 @@ fn series_to_values(
Either::Right(it)
}
.map(|v| match v {
Some(a) => Value::Int {
val: a as i64,
span,
},
None => Value::Nothing { span },
Some(a) => Value::int(a as i64, span),
None => Value::nothing(span),
})
.collect::<Vec<Value>>();
@ -541,11 +530,8 @@ fn series_to_values(
Either::Right(it)
}
.map(|v| match v {
Some(a) => Value::Int {
val: a as i64,
span,
},
None => Value::Nothing { span },
Some(a) => Value::int(a as i64, span),
None => Value::nothing(span),
})
.collect::<Vec<Value>>();
@ -569,11 +555,8 @@ fn series_to_values(
Either::Right(it)
}
.map(|v| match v {
Some(a) => Value::Int {
val: a as i64,
span,
},
None => Value::Nothing { span },
Some(a) => Value::int(a as i64, span),
None => Value::nothing(span),
})
.collect::<Vec<Value>>();
@ -597,11 +580,8 @@ fn series_to_values(
Either::Right(it)
}
.map(|v| match v {
Some(a) => Value::Int {
val: a as i64,
span,
},
None => Value::Nothing { span },
Some(a) => Value::int(a as i64, span),
None => Value::nothing(span),
})
.collect::<Vec<Value>>();
@ -625,11 +605,8 @@ fn series_to_values(
Either::Right(it)
}
.map(|v| match v {
Some(a) => Value::Int {
val: a as i64,
span,
},
None => Value::Nothing { span },
Some(a) => Value::int(a as i64, span),
None => Value::nothing(span),
})
.collect::<Vec<Value>>();
@ -653,11 +630,8 @@ fn series_to_values(
Either::Right(it)
}
.map(|v| match v {
Some(a) => Value::Int {
val: a as i64,
span,
},
None => Value::Nothing { span },
Some(a) => Value::int(a as i64, span),
None => Value::nothing(span),
})
.collect::<Vec<Value>>();
@ -681,8 +655,8 @@ fn series_to_values(
Either::Right(it)
}
.map(|v| match v {
Some(a) => Value::Int { val: a, span },
None => Value::Nothing { span },
Some(a) => Value::int(a, span),
None => Value::nothing(span),
})
.collect::<Vec<Value>>();
@ -706,11 +680,8 @@ fn series_to_values(
Either::Right(it)
}
.map(|v| match v {
Some(a) => Value::Float {
val: a as f64,
span,
},
None => Value::Nothing { span },
Some(a) => Value::float(a as f64, span),
None => Value::nothing(span),
})
.collect::<Vec<Value>>();
@ -734,8 +705,8 @@ fn series_to_values(
Either::Right(it)
}
.map(|v| match v {
Some(a) => Value::Float { val: a, span },
None => Value::Nothing { span },
Some(a) => Value::float(a, span),
None => Value::nothing(span),
})
.collect::<Vec<Value>>();
@ -759,8 +730,8 @@ fn series_to_values(
Either::Right(it)
}
.map(|v| match v {
Some(a) => Value::Bool { val: a, span },
None => Value::Nothing { span },
Some(a) => Value::bool(a, span),
None => Value::nothing(span),
})
.collect::<Vec<Value>>();
@ -784,11 +755,8 @@ fn series_to_values(
Either::Right(it)
}
.map(|v| match v {
Some(a) => Value::String {
val: a.into(),
span,
},
None => Value::Nothing { span },
Some(a) => Value::string(a.to_string(), span),
None => Value::nothing(span),
})
.collect::<Vec<Value>>();
@ -817,7 +785,7 @@ fn series_to_values(
}
.map(|v| match v {
Some(a) => a.get_value(),
None => Value::Nothing { span },
None => Value::nothing(span),
})
.collect::<Vec<Value>>();
@ -855,10 +823,7 @@ fn series_to_values(
}
})
.unwrap_or(vec![]);
Value::List {
vals: sublist,
span,
}
Value::list(sublist, span)
})
.collect::<Vec<Value>>();
Ok(values)
@ -889,40 +854,40 @@ fn series_to_values(
let naive_datetime = match NaiveDateTime::from_timestamp_opt(seconds, 0) {
Some(val) => val,
None => {
return Value::Error {
error: Box::new(ShellError::UnsupportedInput(
return Value::error(
ShellError::UnsupportedInput(
"The given local datetime representation is invalid."
.to_string(),
format!("timestamp is {a:?}"),
span,
Span::unknown(),
)),
}
),
span,
)
}
};
// Zero length offset
let offset = match FixedOffset::east_opt(0) {
Some(val) => val,
None => {
return Value::Error {
error: Box::new(ShellError::UnsupportedInput(
return Value::error(
ShellError::UnsupportedInput(
"The given local datetime representation is invalid."
.to_string(),
format!("timestamp is {a:?}"),
span,
Span::unknown(),
)),
}
),
span,
)
}
};
let datetime = DateTime::<FixedOffset>::from_utc(naive_datetime, offset);
let datetime =
DateTime::<FixedOffset>::from_naive_utc_and_offset(naive_datetime, offset);
Value::Date {
val: datetime,
span,
}
Value::date(datetime, span)
}
None => Value::Nothing { span },
None => Value::nothing(span),
})
.collect::<Vec<Value>>();
@ -957,40 +922,40 @@ fn series_to_values(
let naive_datetime = match NaiveDateTime::from_timestamp_opt(seconds, 0) {
Some(val) => val,
None => {
return Value::Error {
error: Box::new(ShellError::UnsupportedInput(
return Value::error(
ShellError::UnsupportedInput(
"The given local datetime representation is invalid."
.to_string(),
format!("timestamp is {a:?}"),
span,
Span::unknown(),
)),
}
),
span,
)
}
};
// Zero length offset
let offset = match FixedOffset::east_opt(0) {
Some(val) => val,
None => {
return Value::Error {
error: Box::new(ShellError::UnsupportedInput(
return Value::error(
ShellError::UnsupportedInput(
"The given local datetime representation is invalid."
.to_string(),
format!("timestamp is {a:?}"),
span,
Span::unknown(),
)),
}
),
span,
)
}
};
let datetime = DateTime::<FixedOffset>::from_utc(naive_datetime, offset);
let datetime =
DateTime::<FixedOffset>::from_naive_utc_and_offset(naive_datetime, offset);
Value::Date {
val: datetime,
span,
}
Value::date(datetime, span)
}
None => Value::Nothing { span },
None => Value::nothing(span),
})
.collect::<Vec<Value>>();
@ -1014,11 +979,8 @@ fn series_to_values(
Either::Right(it)
}
.map(|v| match v {
Some(nanoseconds) => Value::Duration {
val: nanoseconds,
span,
},
None => Value::Nothing { span },
Some(nanoseconds) => Value::duration(nanoseconds, span),
None => Value::nothing(span),
})
.collect::<Vec<Value>>();
@ -1042,20 +1004,14 @@ mod tests {
#[test]
fn test_parsed_column_string_list() -> Result<(), Box<dyn std::error::Error>> {
let values = vec![
Value::List {
vals: vec![Value::String {
val: "bar".to_string(),
span: Span::test_data(),
}],
span: Span::test_data(),
},
Value::List {
vals: vec![Value::String {
val: "baz".to_string(),
span: Span::test_data(),
}],
span: Span::test_data(),
},
Value::list(
vec![Value::string("bar".to_string(), Span::test_data())],
Span::test_data(),
),
Value::list(
vec![Value::string("baz".to_string(), Span::test_data())],
Span::test_data(),
),
];
let column = Column {
name: "foo".to_string(),

View File

@ -17,10 +17,7 @@ impl CustomValue for NuDataFrame {
from_lazy: false,
};
Value::CustomValue {
val: Box::new(cloned),
span,
}
Value::custom_value(Box::new(cloned), span)
}
fn value_string(&self) -> String {
@ -30,7 +27,7 @@ impl CustomValue for NuDataFrame {
fn to_base_value(&self, span: Span) -> Result<Value, ShellError> {
let vals = self.print(span)?;
Ok(Value::List { vals, span })
Ok(Value::list(vals, span))
}
fn as_any(&self) -> &dyn std::any::Any {

View File

@ -7,7 +7,7 @@ pub use conversion::{Column, ColumnMap};
pub use operations::Axis;
use indexmap::map::IndexMap;
use nu_protocol::{did_you_mean, PipelineData, ShellError, Span, Value};
use nu_protocol::{did_you_mean, PipelineData, Record, ShellError, Span, Value};
use polars::prelude::{DataFrame, DataType, IntoLazy, LazyFrame, PolarsObject, Series};
use serde::{Deserialize, Serialize};
use std::{cmp::Ordering, fmt::Display, hash::Hasher};
@ -38,9 +38,7 @@ impl Display for DataFrameValue {
impl Default for DataFrameValue {
fn default() -> Self {
Self(Value::Nothing {
span: Span::unknown(),
})
Self(Value::nothing(Span::unknown()))
}
}
@ -111,24 +109,15 @@ impl NuDataFrame {
}
pub fn dataframe_into_value(dataframe: DataFrame, span: Span) -> Value {
Value::CustomValue {
val: Box::new(Self::new(false, dataframe)),
span,
}
Value::custom_value(Box::new(Self::new(false, dataframe)), span)
}
pub fn into_value(self, span: Span) -> Value {
if self.from_lazy {
let lazy = NuLazyFrame::from_dataframe(self);
Value::CustomValue {
val: Box::new(lazy),
span,
}
Value::custom_value(Box::new(lazy), span)
} else {
Value::CustomValue {
val: Box::new(self),
span,
}
Value::custom_value(Box::new(self), span)
}
}
@ -162,10 +151,10 @@ impl NuDataFrame {
.map(|i| format!("{i}"))
.collect::<Vec<String>>();
conversion::insert_record(&mut column_values, &cols, &vals)?
conversion::insert_record(&mut column_values, Record { cols, vals })?
}
Value::Record { cols, vals, .. } => {
conversion::insert_record(&mut column_values, &cols, &vals)?
Value::Record { val: record, .. } => {
conversion::insert_record(&mut column_values, record)?
}
_ => {
let key = "0".to_string();
@ -207,16 +196,19 @@ impl NuDataFrame {
pub fn fill_list_nan(list: Vec<Value>, list_span: Span, fill: Value) -> Value {
let newlist = list
.into_iter()
.map(|value| match value {
Value::Float { val, .. } => {
if val.is_nan() {
fill.clone()
} else {
value
.map(|value| {
let span = value.span();
match value {
Value::Float { val, .. } => {
if val.is_nan() {
fill.clone()
} else {
value
}
}
Value::List { vals, .. } => Self::fill_list_nan(vals, span, fill.clone()),
_ => value,
}
Value::List { vals, span } => Self::fill_list_nan(vals, span, fill.clone()),
_ => value,
})
.collect::<Vec<Value>>();
Value::list(newlist, list_span)
@ -235,7 +227,7 @@ impl NuDataFrame {
if Self::can_downcast(&value) {
Ok(Self::get_df(value)?)
} else if NuLazyFrame::can_downcast(&value) {
let span = value.span()?;
let span = value.span();
let lazy = NuLazyFrame::try_from_value(value)?;
let df = lazy.collect(span)?;
Ok(df)
@ -243,15 +235,16 @@ impl NuDataFrame {
Err(ShellError::CantConvert {
to_type: "lazy or eager dataframe".into(),
from_type: value.get_type().to_string(),
span: value.span()?,
span: value.span(),
help: None,
})
}
}
pub fn get_df(value: Value) -> Result<Self, ShellError> {
let span = value.span();
match value {
Value::CustomValue { val, span } => match val.as_any().downcast_ref::<Self>() {
Value::CustomValue { val, .. } => match val.as_any().downcast_ref::<Self>() {
Some(df) => Ok(NuDataFrame {
df: df.df.clone(),
from_lazy: false,
@ -266,7 +259,7 @@ impl NuDataFrame {
x => Err(ShellError::CantConvert {
to_type: "dataframe".into(),
from_type: x.get_type().to_string(),
span: x.span()?,
span: x.span(),
help: None,
}),
}
@ -427,25 +420,15 @@ impl NuDataFrame {
let values = (0..size)
.map(|i| {
let mut cols = vec![];
let mut vals = vec![];
let mut record = Record::new();
cols.push("index".into());
vals.push(Value::Int {
val: (i + from_row) as i64,
span,
});
record.push("index", Value::int((i + from_row) as i64, span));
for (name, col) in &mut iterators {
cols.push(name.clone());
match col.next() {
Some(v) => vals.push(v),
None => vals.push(Value::Nothing { span }),
};
record.push(name.clone(), col.next().unwrap_or(Value::nothing(span)));
}
Value::Record { cols, vals, span }
Value::record(record, span)
})
.collect::<Vec<Value>>();
@ -476,12 +459,12 @@ impl NuDataFrame {
.expect("already checked that dataframe is different than 0");
// if unable to sort, then unable to compare
let lhs = match self.as_ref().sort(vec![*first_col], false) {
let lhs = match self.as_ref().sort(vec![*first_col], false, false) {
Ok(df) => df,
Err(_) => return None,
};
let rhs = match other.as_ref().sort(vec![*first_col], false) {
let rhs = match other.as_ref().sort(vec![*first_col], false, false) {
Ok(df) => df,
Err(_) => return None,
};

View File

@ -20,15 +20,13 @@ impl NuDataFrame {
op_span: Span,
right: &Value,
) -> Result<Value, ShellError> {
let rhs_span = right.span();
match right {
Value::CustomValue {
val: rhs,
span: rhs_span,
} => {
Value::CustomValue { val: rhs, .. } => {
let rhs = rhs.as_any().downcast_ref::<NuDataFrame>().ok_or_else(|| {
ShellError::DowncastNotPossible(
"Unable to create dataframe".to_string(),
*rhs_span,
rhs_span,
)
})?;
@ -38,7 +36,7 @@ impl NuDataFrame {
.as_series(lhs_span)
.expect("Already checked that is a series");
let rhs = &rhs
.as_series(*rhs_span)
.as_series(rhs_span)
.expect("Already checked that is a series");
if lhs.dtype() != rhs.dtype() {
@ -46,7 +44,7 @@ impl NuDataFrame {
left_message: format!("datatype {}", lhs.dtype()),
left_span: lhs_span,
right_message: format!("datatype {}", lhs.dtype()),
right_span: *rhs_span,
right_span: rhs_span,
});
}
@ -55,7 +53,7 @@ impl NuDataFrame {
left_message: format!("len {}", lhs.len()),
left_span: lhs_span,
right_message: format!("len {}", rhs.len()),
right_span: *rhs_span,
right_span: rhs_span,
});
}
@ -78,7 +76,7 @@ impl NuDataFrame {
left_message: format!("rows {}", self.df.height()),
left_span: lhs_span,
right_message: format!("rows {}", rhs.df.height()),
right_span: *rhs_span,
right_span: rhs_span,
});
}

View File

@ -20,10 +20,7 @@ impl CustomValue for NuExpression {
fn clone_value(&self, span: nu_protocol::Span) -> Value {
let cloned = NuExpression(self.0.clone());
Value::CustomValue {
val: Box::new(cloned),
span,
}
Value::custom_value(Box::new(cloned), span)
}
fn value_string(&self) -> String {
@ -31,7 +28,7 @@ impl CustomValue for NuExpression {
}
fn to_base_value(&self, span: Span) -> Result<Value, ShellError> {
Ok(self.to_value(span))
self.to_value(span)
}
fn as_any(&self) -> &dyn std::any::Any {
@ -56,31 +53,26 @@ fn compute_with_value(
op: Span,
right: &Value,
) -> Result<Value, ShellError> {
let rhs_span = right.span();
match right {
Value::CustomValue {
val: rhs,
span: rhs_span,
} => {
Value::CustomValue { val: rhs, .. } => {
let rhs = rhs.as_any().downcast_ref::<NuExpression>().ok_or_else(|| {
ShellError::DowncastNotPossible(
"Unable to create expression".to_string(),
*rhs_span,
)
ShellError::DowncastNotPossible("Unable to create expression".to_string(), rhs_span)
})?;
match rhs.as_ref() {
polars::prelude::Expr::Literal(..) => {
with_operator(operator, left, rhs, lhs_span, right.span()?, op)
with_operator(operator, left, rhs, lhs_span, right.span(), op)
}
_ => Err(ShellError::TypeMismatch {
err_message: "Only literal expressions or number".into(),
span: right.span()?,
span: right.span(),
}),
}
}
_ => {
let rhs = NuExpression::try_from_value(right.clone())?;
with_operator(operator, left, &rhs, lhs_span, right.span()?, op)
with_operator(operator, left, &rhs, lhs_span, right.span(), op)
}
}
}

View File

@ -1,6 +1,6 @@
mod custom_value;
use nu_protocol::{PipelineData, ShellError, Span, Value};
use nu_protocol::{record, PipelineData, ShellError, Span, Value};
use polars::prelude::{col, AggExpr, Expr, Literal};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
@ -55,15 +55,13 @@ impl From<Expr> for NuExpression {
impl NuExpression {
pub fn into_value(self, span: Span) -> Value {
Value::CustomValue {
val: Box::new(self),
span,
}
Value::custom_value(Box::new(self), span)
}
pub fn try_from_value(value: Value) -> Result<Self, ShellError> {
let span = value.span();
match value {
Value::CustomValue { val, span } => match val.as_any().downcast_ref::<Self>() {
Value::CustomValue { val, .. } => match val.as_any().downcast_ref::<Self>() {
Some(expr) => Ok(NuExpression(expr.0.clone())),
None => Err(ShellError::CantConvert {
to_type: "lazy expression".into(),
@ -79,7 +77,7 @@ impl NuExpression {
x => Err(ShellError::CantConvert {
to_type: "lazy expression".into(),
from_type: x.get_type().to_string(),
span: x.span()?,
span: x.span(),
help: None,
}),
}
@ -115,7 +113,7 @@ impl NuExpression {
f(expr, other).into()
}
pub fn to_value(&self, span: Span) -> Value {
pub fn to_value(&self, span: Span) -> Result<Value, ShellError> {
expr_to_value(self.as_ref(), span)
}
@ -157,111 +155,66 @@ impl ExtractedExpr {
x => Err(ShellError::CantConvert {
to_type: "expression".into(),
from_type: x.get_type().to_string(),
span: x.span()?,
span: x.span(),
help: None,
}),
}
}
}
pub fn expr_to_value(expr: &Expr, span: Span) -> Value {
let cols = vec!["expr".to_string(), "value".to_string()];
pub fn expr_to_value(expr: &Expr, span: Span) -> Result<Value, ShellError> {
match expr {
Expr::Alias(expr, alias) => {
let expr = expr_to_value(expr.as_ref(), span);
let alias = Value::String {
val: alias.as_ref().into(),
span,
};
let cols = vec!["expr".into(), "alias".into()];
Value::Record {
cols,
vals: vec![expr, alias],
span,
}
}
Expr::Column(name) => {
let expr_type = Value::String {
val: "column".to_string(),
span,
};
let value = Value::String {
val: name.to_string(),
span,
};
let vals = vec![expr_type, value];
Value::Record { cols, vals, span }
}
Expr::Alias(expr, alias) => Ok(Value::record(
record! {
"expr" => expr_to_value(expr.as_ref(), span)?,
"alias" => Value::string(alias.as_ref(), span),
},
span,
)),
Expr::Column(name) => Ok(Value::record(
record! {
"expr" => Value::string("column", span),
"value" => Value::string(name.to_string(), span),
},
span,
)),
Expr::Columns(columns) => {
let expr_type = Value::String {
val: "columns".into(),
let value = columns.iter().map(|col| Value::string(col, span)).collect();
Ok(Value::record(
record! {
"expr" => Value::string("columns", span),
"value" => Value::list(value, span),
},
span,
};
let value = Value::List {
vals: columns
.iter()
.map(|col| Value::String {
val: col.clone(),
span,
})
.collect(),
span,
};
let vals = vec![expr_type, value];
Value::Record { cols, vals, span }
}
Expr::Literal(literal) => {
let expr_type = Value::String {
val: "literal".into(),
span,
};
let value = Value::String {
val: format!("{literal:?}"),
span,
};
let vals = vec![expr_type, value];
Value::Record { cols, vals, span }
}
Expr::BinaryExpr { left, op, right } => {
let left_val = expr_to_value(left, span);
let right_val = expr_to_value(right, span);
let operator = Value::String {
val: format!("{op:?}"),
span,
};
let cols = vec!["left".into(), "op".into(), "right".into()];
Value::Record {
cols,
vals: vec![left_val, operator, right_val],
span,
}
))
}
Expr::Literal(literal) => Ok(Value::record(
record! {
"expr" => Value::string("literal", span),
"value" => Value::string(format!("{literal:?}"), span),
},
span,
)),
Expr::BinaryExpr { left, op, right } => Ok(Value::record(
record! {
"left" => expr_to_value(left, span)?,
"op" => Value::string(format!("{op:?}"), span),
"right" => expr_to_value(right, span)?,
},
span,
)),
Expr::Ternary {
predicate,
truthy,
falsy,
} => {
let predicate = expr_to_value(predicate.as_ref(), span);
let truthy = expr_to_value(truthy.as_ref(), span);
let falsy = expr_to_value(falsy.as_ref(), span);
let cols = vec!["predicate".into(), "truthy".into(), "falsy".into()];
Value::Record {
cols,
vals: vec![predicate, truthy, falsy],
span,
}
}
} => Ok(Value::record(
record! {
"predicate" => expr_to_value(predicate.as_ref(), span)?,
"truthy" => expr_to_value(truthy.as_ref(), span)?,
"falsy" => expr_to_value(falsy.as_ref(), span)?,
},
span,
)),
Expr::Agg(agg_expr) => {
let value = match agg_expr {
AggExpr::Min { input: expr, .. }
@ -281,311 +234,169 @@ pub fn expr_to_value(expr: &Expr, span: Span) -> Value {
expr,
quantile,
interpol,
} => {
let expr = expr_to_value(expr.as_ref(), span);
let quantile = expr_to_value(quantile.as_ref(), span);
let interpol = Value::String {
val: format!("{interpol:?}"),
span,
};
let cols = vec!["expr".into(), "quantile".into(), "interpol".into()];
Value::Record {
cols,
vals: vec![expr, quantile, interpol],
span,
}
}
} => Ok(Value::record(
record! {
"expr" => expr_to_value(expr.as_ref(), span)?,
"quantile" => expr_to_value(quantile.as_ref(), span)?,
"interpol" => Value::string(format!("{interpol:?}"), span),
},
span,
)),
};
let expr_type = Value::String {
val: "agg".into(),
Ok(Value::record(
record! {
"expr" => Value::string("agg", span),
"value" => value?,
},
span,
};
let vals = vec![expr_type, value];
Value::Record { cols, vals, span }
}
Expr::Count => {
let expr = Value::String {
val: "count".into(),
span,
};
let cols = vec!["expr".into()];
Value::Record {
cols,
vals: vec![expr],
span,
}
}
Expr::Wildcard => {
let expr = Value::String {
val: "wildcard".into(),
span,
};
let cols = vec!["expr".into()];
Value::Record {
cols,
vals: vec![expr],
span,
}
}
Expr::Explode(expr) => {
let expr = expr_to_value(expr.as_ref(), span);
let cols = vec!["expr".into()];
Value::Record {
cols,
vals: vec![expr],
span,
}
}
Expr::KeepName(expr) => {
let expr = expr_to_value(expr.as_ref(), span);
let cols = vec!["expr".into()];
Value::Record {
cols,
vals: vec![expr],
span,
}
}
Expr::Nth(i) => {
let expr = Value::int(*i, span);
let cols = vec!["expr".into()];
Value::Record {
cols,
vals: vec![expr],
span,
}
))
}
Expr::Count => Ok(Value::record(
record! { "expr" => Value::string("count", span) },
span,
)),
Expr::Wildcard => Ok(Value::record(
record! { "expr" => Value::string("wildcard", span) },
span,
)),
Expr::Explode(expr) => Ok(Value::record(
record! { "expr" => expr_to_value(expr.as_ref(), span)? },
span,
)),
Expr::KeepName(expr) => Ok(Value::record(
record! { "expr" => expr_to_value(expr.as_ref(), span)? },
span,
)),
Expr::Nth(i) => Ok(Value::record(
record! { "expr" => Value::int(*i, span) },
span,
)),
Expr::DtypeColumn(dtypes) => {
let vals = dtypes
.iter()
.map(|d| Value::String {
val: format!("{d}"),
span,
})
.map(|d| Value::string(format!("{d}"), span))
.collect();
Value::List { vals, span }
}
Expr::Sort { expr, options } => {
let expr = expr_to_value(expr.as_ref(), span);
let options = Value::String {
val: format!("{options:?}"),
span,
};
let cols = vec!["expr".into(), "options".into()];
Value::Record {
cols,
vals: vec![expr, options],
span,
}
Ok(Value::list(vals, span))
}
Expr::Sort { expr, options } => Ok(Value::record(
record! {
"expr" => expr_to_value(expr.as_ref(), span)?,
"options" => Value::string(format!("{options:?}"), span),
},
span,
)),
Expr::Cast {
expr,
data_type,
strict,
} => {
let expr = expr_to_value(expr.as_ref(), span);
let dtype = Value::String {
val: format!("{data_type:?}"),
span,
};
let strict = Value::Bool { val: *strict, span };
let cols = vec!["expr".into(), "dtype".into(), "strict".into()];
Value::Record {
cols,
vals: vec![expr, dtype, strict],
span,
}
}
Expr::Take { expr, idx } => {
let expr = expr_to_value(expr.as_ref(), span);
let idx = expr_to_value(idx.as_ref(), span);
let cols = vec!["expr".into(), "idx".into()];
Value::Record {
cols,
vals: vec![expr, idx],
span,
}
}
} => Ok(Value::record(
record! {
"expr" => expr_to_value(expr.as_ref(), span)?,
"dtype" => Value::string(format!("{data_type:?}"), span),
"strict" => Value::bool(*strict, span),
},
span,
)),
Expr::Take { expr, idx } => Ok(Value::record(
record! {
"expr" => expr_to_value(expr.as_ref(), span)?,
"idx" => expr_to_value(idx.as_ref(), span)?,
},
span,
)),
Expr::SortBy {
expr,
by,
descending,
} => {
let expr = expr_to_value(expr.as_ref(), span);
let by: Vec<Value> = by.iter().map(|b| expr_to_value(b, span)).collect();
let by = Value::List { vals: by, span };
let by: Result<Vec<Value>, ShellError> =
by.iter().map(|b| expr_to_value(b, span)).collect();
let descending: Vec<Value> = descending.iter().map(|r| Value::bool(*r, span)).collect();
let descending: Vec<Value> = descending
.iter()
.map(|r| Value::Bool { val: *r, span })
.collect();
let descending = Value::List {
vals: descending,
Ok(Value::record(
record! {
"expr" => expr_to_value(expr.as_ref(), span)?,
"by" => Value::list(by?, span),
"descending" => Value::list(descending, span),
},
span,
};
let cols = vec!["expr".into(), "by".into(), "descending".into()];
Value::Record {
cols,
vals: vec![expr, by, descending],
span,
}
}
Expr::Filter { input, by } => {
let input = expr_to_value(input.as_ref(), span);
let by = expr_to_value(by.as_ref(), span);
let cols = vec!["input".into(), "by".into()];
Value::Record {
cols,
vals: vec![input, by],
span,
}
))
}
Expr::Filter { input, by } => Ok(Value::record(
record! {
"input" => expr_to_value(input.as_ref(), span)?,
"by" => expr_to_value(by.as_ref(), span)?,
},
span,
)),
Expr::Slice {
input,
offset,
length,
} => {
let input = expr_to_value(input.as_ref(), span);
let offset = expr_to_value(offset.as_ref(), span);
let length = expr_to_value(length.as_ref(), span);
let cols = vec!["input".into(), "offset".into(), "length".into()];
Value::Record {
cols,
vals: vec![input, offset, length],
span,
}
}
} => Ok(Value::record(
record! {
"input" => expr_to_value(input.as_ref(), span)?,
"offset" => expr_to_value(offset.as_ref(), span)?,
"length" => expr_to_value(length.as_ref(), span)?,
},
span,
)),
Expr::Exclude(expr, excluded) => {
let expr = expr_to_value(expr.as_ref(), span);
let excluded = excluded
.iter()
.map(|e| Value::String {
val: format!("{e:?}"),
span,
})
.map(|e| Value::string(format!("{e:?}"), span))
.collect();
let excluded = Value::List {
vals: excluded,
span,
};
let cols = vec!["expr".into(), "excluded".into()];
Value::Record {
cols,
vals: vec![expr, excluded],
Ok(Value::record(
record! {
"expr" => expr_to_value(expr.as_ref(), span)?,
"excluded" => Value::list(excluded, span),
},
span,
}
}
Expr::RenameAlias { expr, function } => {
let expr = expr_to_value(expr.as_ref(), span);
let function = Value::String {
val: format!("{function:?}"),
span,
};
let cols = vec!["expr".into(), "function".into()];
Value::Record {
cols,
vals: vec![expr, function],
span,
}
))
}
Expr::RenameAlias { expr, function } => Ok(Value::record(
record! {
"expr" => expr_to_value(expr.as_ref(), span)?,
"function" => Value::string(format!("{function:?}"), span),
},
span,
)),
Expr::AnonymousFunction {
input,
function,
output_type,
options,
} => {
let input: Vec<Value> = input.iter().map(|e| expr_to_value(e, span)).collect();
let input = Value::List { vals: input, span };
let function = Value::String {
val: format!("{function:?}"),
let input: Result<Vec<Value>, ShellError> =
input.iter().map(|e| expr_to_value(e, span)).collect();
Ok(Value::record(
record! {
"input" => Value::list(input?, span),
"function" => Value::string(format!("{function:?}"), span),
"output_type" => Value::string(format!("{output_type:?}"), span),
"options" => Value::string(format!("{options:?}"), span),
},
span,
};
let output_type = Value::String {
val: format!("{output_type:?}"),
span,
};
let options = Value::String {
val: format!("{options:?}"),
span,
};
let cols = vec![
"input".into(),
"function".into(),
"output_type".into(),
"options".into(),
];
Value::Record {
cols,
vals: vec![input, function, output_type, options],
span,
}
))
}
Expr::Function {
input,
function,
options,
} => {
let input: Vec<Value> = input.iter().map(|e| expr_to_value(e, span)).collect();
let input = Value::List { vals: input, span };
let function = Value::String {
val: format!("{function:?}"),
let input: Result<Vec<Value>, ShellError> =
input.iter().map(|e| expr_to_value(e, span)).collect();
Ok(Value::record(
record! {
"input" => Value::list(input?, span),
"function" => Value::string(format!("{function:?}"), span),
"options" => Value::string(format!("{options:?}"), span),
},
span,
};
let options = Value::String {
val: format!("{options:?}"),
span,
};
let cols = vec!["input".into(), "function".into(), "options".into()];
Value::Record {
cols,
vals: vec![input, function, options],
span,
}
}
Expr::Cache { input, id } => {
let input = expr_to_value(input.as_ref(), span);
let id = Value::String {
val: format!("{id:?}"),
span,
};
let cols = vec!["input".into(), "id".into()];
Value::Record {
cols,
vals: vec![input, id],
span,
}
))
}
Expr::Window {
function,
@ -593,39 +404,34 @@ pub fn expr_to_value(expr: &Expr, span: Span) -> Value {
order_by,
options,
} => {
let function = expr_to_value(function, span);
let partition_by: Vec<Value> = partition_by
let partition_by: Result<Vec<Value>, ShellError> = partition_by
.iter()
.map(|e| expr_to_value(e, span))
.collect();
let partition_by = Value::List {
vals: partition_by,
span,
};
let order_by = order_by
.as_ref()
.map(|e| expr_to_value(e.as_ref(), span))
.transpose()?
.unwrap_or_else(|| Value::nothing(span));
let options = Value::String {
val: format!("{options:?}"),
Ok(Value::record(
record! {
"function" => expr_to_value(function, span)?,
"partition_by" => Value::list(partition_by?, span),
"order_by" => order_by,
"options" => Value::string(format!("{options:?}"), span),
},
span,
};
let cols = vec![
"function".into(),
"partition_by".into(),
"order_by".into(),
"options".into(),
];
Value::Record {
cols,
vals: vec![function, partition_by, order_by, options],
span,
}
))
}
// the parameter polars_plan::dsl::selector::Selector is not publicly exposed.
// I am not sure what we can meaningfully do with this at this time.
Expr::Selector(_) => Err(ShellError::UnsupportedInput(
"Expressions of type Selector to Nu Values is not yet supported".to_string(),
format!("Expression is {expr:?}"),
span,
Span::unknown(),
)),
}
}

View File

@ -1,5 +1,5 @@
use super::NuLazyFrame;
use nu_protocol::{CustomValue, ShellError, Span, Value};
use nu_protocol::{record, CustomValue, ShellError, Span, Value};
// CustomValue implementation for NuDataFrame
impl CustomValue for NuLazyFrame {
@ -18,10 +18,7 @@ impl CustomValue for NuLazyFrame {
schema: self.schema.clone(),
};
Value::CustomValue {
val: Box::new(cloned),
span,
}
Value::custom_value(Box::new(cloned), span)
}
fn value_string(&self) -> String {
@ -29,22 +26,18 @@ impl CustomValue for NuLazyFrame {
}
fn to_base_value(&self, span: Span) -> Result<Value, ShellError> {
let cols = vec!["plan".into(), "optimized_plan".into()];
let vals = vec![
Value::String {
val: self.as_ref().describe_plan(),
span,
},
Value::String {
val: self
.as_ref()
.describe_optimized_plan()
.unwrap_or_else(|_| "<NOT AVAILABLE>".to_string()),
span,
},
];
let optimized_plan = self
.as_ref()
.describe_optimized_plan()
.unwrap_or_else(|_| "<NOT AVAILABLE>".to_string());
Ok(Value::Record { cols, vals, span })
Ok(Value::record(
record! {
"plan" => Value::string(self.as_ref().describe_plan(), span),
"optimized_plan" => Value::string(optimized_plan, span),
},
span,
))
}
fn as_any(&self) -> &dyn std::any::Any {

View File

@ -90,15 +90,9 @@ impl NuLazyFrame {
pub fn into_value(self, span: Span) -> Result<Value, ShellError> {
if self.from_eager {
let df = self.collect(span)?;
Ok(Value::CustomValue {
val: Box::new(df),
span,
})
Ok(Value::custom_value(Box::new(df), span))
} else {
Ok(Value::CustomValue {
val: Box::new(self),
span,
})
Ok(Value::custom_value(Box::new(self), span))
}
}
@ -135,7 +129,7 @@ impl NuLazyFrame {
Err(ShellError::CantConvert {
to_type: "lazy or eager dataframe".into(),
from_type: value.get_type().to_string(),
span: value.span()?,
span: value.span(),
help: None,
})
}
@ -147,8 +141,9 @@ impl NuLazyFrame {
}
pub fn get_lazy_df(value: Value) -> Result<Self, ShellError> {
let span = value.span();
match value {
Value::CustomValue { val, span } => match val.as_any().downcast_ref::<Self>() {
Value::CustomValue { val, .. } => match val.as_any().downcast_ref::<Self>() {
Some(expr) => Ok(Self {
lazy: expr.lazy.clone(),
from_eager: false,
@ -164,7 +159,7 @@ impl NuLazyFrame {
x => Err(ShellError::CantConvert {
to_type: "lazy frame".into(),
from_type: x.get_type().to_string(),
span: x.span()?,
span: x.span(),
help: None,
}),
}

View File

@ -1,5 +1,5 @@
use super::NuLazyGroupBy;
use nu_protocol::{CustomValue, ShellError, Span, Value};
use nu_protocol::{record, CustomValue, ShellError, Span, Value};
// CustomValue implementation for NuDataFrame
impl CustomValue for NuLazyGroupBy {
@ -18,10 +18,7 @@ impl CustomValue for NuLazyGroupBy {
from_eager: self.from_eager,
};
Value::CustomValue {
val: Box::new(cloned),
span,
}
Value::custom_value(Box::new(cloned), span)
}
fn value_string(&self) -> String {
@ -29,13 +26,12 @@ impl CustomValue for NuLazyGroupBy {
}
fn to_base_value(&self, span: Span) -> Result<Value, ShellError> {
let cols = vec!["LazyGroupBy".into()];
let vals = vec![Value::String {
val: "apply aggregation to complete execution plan".into(),
Ok(Value::record(
record! {
"LazyGroupBy" => Value::string("apply aggregation to complete execution plan", span)
},
span,
}];
Ok(Value::Record { cols, vals, span })
))
}
fn as_any(&self) -> &dyn std::any::Any {

View File

@ -74,10 +74,7 @@ impl From<LazyGroupBy> for NuLazyGroupBy {
impl NuLazyGroupBy {
pub fn into_value(self, span: Span) -> Value {
Value::CustomValue {
val: Box::new(self),
span,
}
Value::custom_value(Box::new(self), span)
}
pub fn into_polars(self) -> LazyGroupBy {
@ -85,26 +82,25 @@ impl NuLazyGroupBy {
}
pub fn try_from_value(value: Value) -> Result<Self, ShellError> {
let span = value.span();
match value {
Value::CustomValue { val, span } => {
match val.as_any().downcast_ref::<NuLazyGroupBy>() {
Some(group) => Ok(Self {
group_by: group.group_by.clone(),
schema: group.schema.clone(),
from_eager: group.from_eager,
}),
None => Err(ShellError::CantConvert {
to_type: "lazy groupby".into(),
from_type: "custom value".into(),
span,
help: None,
}),
}
}
Value::CustomValue { val, .. } => match val.as_any().downcast_ref::<NuLazyGroupBy>() {
Some(group) => Ok(Self {
group_by: group.group_by.clone(),
schema: group.schema.clone(),
from_eager: group.from_eager,
}),
None => Err(ShellError::CantConvert {
to_type: "lazy groupby".into(),
from_type: "custom value".into(),
span,
help: None,
}),
},
x => Err(ShellError::CantConvert {
to_type: "lazy groupby".into(),
from_type: x.get_type().to_string(),
span: x.span()?,
span: x.span(),
help: None,
}),
}

View File

@ -14,10 +14,7 @@ impl CustomValue for NuWhen {
fn clone_value(&self, span: nu_protocol::Span) -> Value {
let cloned = self.clone();
Value::CustomValue {
val: Box::new(cloned),
span,
}
Value::custom_value(Box::new(cloned), span)
}
fn value_string(&self) -> String {
@ -25,12 +22,12 @@ impl CustomValue for NuWhen {
}
fn to_base_value(&self, span: Span) -> Result<Value, ShellError> {
let val = match self {
NuWhen::WhenThen(_) => "whenthen".into(),
NuWhen::WhenThenThen(_) => "whenthenthen".into(),
let val: String = match self {
NuWhen::Then(_) => "whenthen".into(),
NuWhen::ChainedThen(_) => "whenthenthen".into(),
};
let value = Value::String { val, span };
let value = Value::string(val, span);
Ok(value)
}

View File

@ -2,13 +2,13 @@ mod custom_value;
use core::fmt;
use nu_protocol::{ShellError, Span, Value};
use polars::prelude::{col, when, WhenThen, WhenThenThen};
use polars::prelude::{col, when, ChainedThen, Then};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Clone)]
pub enum NuWhen {
WhenThen(Box<WhenThen>),
WhenThenThen(WhenThenThen),
Then(Box<Then>),
ChainedThen(ChainedThen),
}
// Mocked serialization of the LazyFrame object
@ -27,7 +27,7 @@ impl<'de> Deserialize<'de> for NuWhen {
where
D: Deserializer<'de>,
{
Ok(NuWhen::WhenThen(Box::new(when(col("a")).then(col("b")))))
Ok(NuWhen::Then(Box::new(when(col("a")).then(col("b")))))
}
}
@ -37,29 +37,27 @@ impl fmt::Debug for NuWhen {
}
}
impl From<WhenThen> for NuWhen {
fn from(when_then: WhenThen) -> Self {
NuWhen::WhenThen(Box::new(when_then))
impl From<Then> for NuWhen {
fn from(then: Then) -> Self {
NuWhen::Then(Box::new(then))
}
}
impl From<WhenThenThen> for NuWhen {
fn from(when_then_then: WhenThenThen) -> Self {
NuWhen::WhenThenThen(when_then_then)
impl From<ChainedThen> for NuWhen {
fn from(chained_when: ChainedThen) -> Self {
NuWhen::ChainedThen(chained_when)
}
}
impl NuWhen {
pub fn into_value(self, span: Span) -> Value {
Value::CustomValue {
val: Box::new(self),
span,
}
Value::custom_value(Box::new(self), span)
}
pub fn try_from_value(value: Value) -> Result<Self, ShellError> {
let span = value.span();
match value {
Value::CustomValue { val, span } => match val.as_any().downcast_ref::<Self>() {
Value::CustomValue { val, .. } => match val.as_any().downcast_ref::<Self>() {
Some(expr) => Ok(expr.clone()),
None => Err(ShellError::CantConvert {
to_type: "when expression".into(),
@ -71,7 +69,7 @@ impl NuWhen {
x => Err(ShellError::CantConvert {
to_type: "when expression".into(),
from_type: x.get_type().to_string(),
span: x.span()?,
span: x.span(),
help: None,
}),
}

View File

@ -21,22 +21,25 @@ pub(crate) fn convert_columns(
Vec::new(),
)
})
.and_then(|v| v.span())?;
.map(|v| v.span())?;
let res = columns
.into_iter()
.map(|value| match value {
Value::String { val, span } => {
col_span = span_join(&[col_span, span]);
Ok(Spanned { item: val, span })
.map(|value| {
let span = value.span();
match value {
Value::String { val, .. } => {
col_span = span_join(&[col_span, span]);
Ok(Spanned { item: val, span })
}
_ => Err(ShellError::GenericError(
"Incorrect column format".into(),
"Only string as column name".into(),
Some(span),
None,
Vec::new(),
)),
}
_ => Err(ShellError::GenericError(
"Incorrect column format".into(),
"Only string as column name".into(),
Some(span),
None,
Vec::new(),
)),
})
.collect::<Result<Vec<Spanned<String>>, _>>()?;
@ -61,22 +64,25 @@ pub(crate) fn convert_columns_string(
Vec::new(),
)
})
.and_then(|v| v.span())?;
.map(|v| v.span())?;
let res = columns
.into_iter()
.map(|value| match value {
Value::String { val, span } => {
col_span = span_join(&[col_span, span]);
Ok(val)
.map(|value| {
let span = value.span();
match value {
Value::String { val, .. } => {
col_span = span_join(&[col_span, span]);
Ok(val)
}
_ => Err(ShellError::GenericError(
"Incorrect column format".into(),
"Only string as column name".into(),
Some(span),
None,
Vec::new(),
)),
}
_ => Err(ShellError::GenericError(
"Incorrect column format".into(),
"Only string as column name".into(),
Some(span),
None,
Vec::new(),
)),
})
.collect::<Result<Vec<String>, _>>()?;

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.84.0"
version = "0.85.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -13,11 +13,11 @@ version = "0.84.0"
bench = false
[dependencies]
nu-engine = { path = "../nu-engine", version = "0.84.0" }
nu-parser = { path = "../nu-parser", version = "0.84.0" }
nu-protocol = { path = "../nu-protocol", version = "0.84.0" }
nu-cmd-base = { path = "../nu-cmd-base", version = "0.84.0" }
nu-utils = { path = "../nu-utils", version = "0.84.0" }
nu-engine = { path = "../nu-engine", version = "0.85.0" }
nu-parser = { path = "../nu-parser", version = "0.85.0" }
nu-protocol = { path = "../nu-protocol", version = "0.85.0" }
nu-cmd-base = { path = "../nu-cmd-base", version = "0.85.0" }
nu-utils = { path = "../nu-utils", version = "0.85.0" }
# Potential dependencies for extras
Inflector = "0.11"
@ -25,10 +25,10 @@ num-traits = "0.2"
ahash = "0.8.3"
nu-ansi-term = "0.49.0"
fancy-regex = "0.11.0"
rust-embed = "6.7.0"
rust-embed = "8.0.0"
serde = "1.0.164"
nu-pretty-hex = { version = "0.84.0", path = "../nu-pretty-hex" }
nu-json = { version = "0.84.0", path = "../nu-json" }
nu-pretty-hex = { version = "0.85.0", path = "../nu-pretty-hex" }
nu-json = { version = "0.85.0", path = "../nu-json" }
serde_urlencoded = "0.7.1"
htmlescape = "0.3.1"
@ -37,6 +37,6 @@ extra = ["default"]
default = []
[dev-dependencies]
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.84.0" }
nu-command = { path = "../nu-command", version = "0.84.0" }
nu-test-support = { path = "../nu-test-support", version = "0.84.0" }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.85.0" }
nu-command = { path = "../nu-command", version = "0.85.0" }
nu-test-support = { path = "../nu-test-support", version = "0.85.0" }

View File

@ -15,8 +15,6 @@ mod test_examples {
check_example_input_and_output_types_match_command_signature,
};
use crate::MathEuler;
use crate::MathPi;
use nu_protocol::{
engine::{Command, EngineState, StateWorkingSet},
Type,
@ -64,9 +62,6 @@ mod test_examples {
working_set.add_decl(Box::new(nu_command::Enumerate));
working_set.add_decl(Box::new(nu_cmd_lang::If));
// math commands
working_set.add_decl(Box::new(MathEuler));
working_set.add_decl(Box::new(MathPi));
working_set.add_decl(Box::new(nu_command::MathRound));
// Adding the command that is being tested to the working set

View File

@ -68,31 +68,30 @@ impl Command for BitsAnd {
Example {
description: "Apply logical and to a list of numbers",
example: "[4 3 2] | bits and 2",
result: Some(Value::List {
vals: vec![Value::test_int(0), Value::test_int(2), Value::test_int(2)],
span: Span::test_data(),
}),
result: Some(Value::list(
vec![Value::test_int(0), Value::test_int(2), Value::test_int(2)],
Span::test_data(),
)),
},
]
}
}
fn operate(value: Value, target: i64, head: Span) -> Value {
let span = value.span();
match value {
Value::Int { val, span } => Value::Int {
val: val & target,
span,
},
Value::Int { val, .. } => Value::int(val & target, span),
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value,
other => Value::Error {
error: Box::new(ShellError::OnlySupportsThisInputType {
other => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "integer".into(),
wrong_type: other.get_type().to_string(),
dst_span: head,
src_span: other.expect_span(),
}),
},
src_span: other.span(),
},
head,
),
}
}

View File

@ -34,16 +34,16 @@ impl Command for Bits {
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
Ok(Value::String {
val: get_full_help(
Ok(Value::string(
get_full_help(
&Bits.signature(),
&Bits.examples(),
engine_state,
stack,
self.is_parser_keyword(),
),
span: call.head,
}
call.head,
)
.into_pipeline_data())
}
}

View File

@ -71,58 +71,51 @@ impl Command for BitsInto {
Example {
description: "convert a binary value into a string, padded to 8 places with 0s",
example: "01b | into bits",
result: Some(Value::String {
val: "00000001".to_string(),
span: Span::test_data(),
}),
result: Some(Value::string("00000001",
Span::test_data(),
)),
},
Example {
description: "convert an int into a string, padded to 8 places with 0s",
example: "1 | into bits",
result: Some(Value::String {
val: "00000001".to_string(),
span: Span::test_data(),
}),
result: Some(Value::string("00000001",
Span::test_data(),
)),
},
Example {
description: "convert a filesize value into a string, padded to 8 places with 0s",
example: "1b | into bits",
result: Some(Value::String {
val: "00000001".to_string(),
span: Span::test_data(),
}),
result: Some(Value::string("00000001",
Span::test_data(),
)),
},
Example {
description: "convert a duration value into a string, padded to 8 places with 0s",
example: "1ns | into bits",
result: Some(Value::String {
val: "00000001".to_string(),
span: Span::test_data(),
}),
result: Some(Value::string("00000001",
Span::test_data(),
)),
},
Example {
description: "convert a boolean value into a string, padded to 8 places with 0s",
example: "true | into bits",
result: Some(Value::String {
val: "00000001".to_string(),
span: Span::test_data(),
}),
result: Some(Value::string("00000001",
Span::test_data(),
)),
},
Example {
description: "convert a datetime value into a string, padded to 8 places with 0s",
example: "2023-04-17T01:02:03 | into bits",
result: Some(Value::String {
val: "01001101 01101111 01101110 00100000 01000001 01110000 01110010 00100000 00110001 00110111 00100000 00110000 00110001 00111010 00110000 00110010 00111010 00110000 00110011 00100000 00110010 00110000 00110010 00110011".to_string(),
span: Span::test_data(),
}),
result: Some(Value::string("01001101 01101111 01101110 00100000 01000001 01110000 01110010 00100000 00110001 00110111 00100000 00110000 00110001 00111010 00110000 00110010 00111010 00110000 00110011 00100000 00110010 00110000 00110010 00110011",
Span::test_data(),
)),
},
Example {
description: "convert a string into a raw binary string, padded with 0s to 8 places",
example: "'nushell.sh' | into bits",
result: Some(Value::String {
val: "01101110 01110101 01110011 01101000 01100101 01101100 01101100 00101110 01110011 01101000".to_string(),
span: Span::test_data(),
}),
result: Some(Value::string("01101110 01110101 01110011 01101000 01100101 01101100 01101100 00101110 01110011 01101000",
Span::test_data(),
)),
},
]
}
@ -139,22 +132,16 @@ fn into_bits(
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
match input {
PipelineData::ExternalStream { stdout: None, .. } => Ok(Value::Binary {
val: vec![],
span: head,
PipelineData::ExternalStream { stdout: None, .. } => {
Ok(Value::binary(vec![], head).into_pipeline_data())
}
.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_bytes()?;
Ok(Value::Binary {
val: output.item,
span: head,
}
.into_pipeline_data())
Ok(Value::binary(output.item, head).into_pipeline_data())
}
_ => {
let args = Arguments { cell_paths };
@ -170,40 +157,28 @@ fn convert_to_smallest_number_type(num: i64, span: Span) -> Value {
for ch in bytes {
raw_string.push_str(&format!("{:08b} ", ch));
}
Value::String {
val: raw_string.trim().to_string(),
span,
}
Value::string(raw_string.trim(), span)
} else if let Some(v) = num.to_i16() {
let bytes = v.to_ne_bytes();
let mut raw_string = "".to_string();
for ch in bytes {
raw_string.push_str(&format!("{:08b} ", ch));
}
Value::String {
val: raw_string.trim().to_string(),
span,
}
Value::string(raw_string.trim(), span)
} else if let Some(v) = num.to_i32() {
let bytes = v.to_ne_bytes();
let mut raw_string = "".to_string();
for ch in bytes {
raw_string.push_str(&format!("{:08b} ", ch));
}
Value::String {
val: raw_string.trim().to_string(),
span,
}
Value::string(raw_string.trim(), span)
} else {
let bytes = num.to_ne_bytes();
let mut raw_string = "".to_string();
for ch in bytes {
raw_string.push_str(&format!("{:08b} ", ch));
}
Value::String {
val: raw_string.trim().to_string(),
span,
}
Value::string(raw_string.trim(), span)
}
}
@ -214,10 +189,7 @@ pub fn action(input: &Value, _args: &Arguments, span: Span) -> Value {
for ch in val {
raw_string.push_str(&format!("{:08b} ", ch));
}
Value::String {
val: raw_string.trim().to_string(),
span,
}
Value::string(raw_string.trim(), span)
}
Value::Int { val, .. } => convert_to_smallest_number_type(*val, span),
Value::Filesize { val, .. } => convert_to_smallest_number_type(*val, span),
@ -228,10 +200,7 @@ pub fn action(input: &Value, _args: &Arguments, span: Span) -> Value {
for ch in raw_bytes {
raw_string.push_str(&format!("{:08b} ", ch));
}
Value::String {
val: raw_string.trim().to_string(),
span,
}
Value::string(raw_string.trim(), span)
}
Value::Bool { val, .. } => {
let v = <i64 as From<bool>>::from(*val);
@ -244,21 +213,19 @@ pub fn action(input: &Value, _args: &Arguments, span: Span) -> Value {
for ch in bytes {
raw_string.push_str(&format!("{:08b} ", ch));
}
Value::String {
val: raw_string.trim().to_string(),
span,
}
Value::string(raw_string.trim(), span)
}
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => input.clone(),
other => Value::Error {
error: Box::new(ShellError::OnlySupportsThisInputType {
other => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "integer, filesize, string, date, duration, binary or bool".into(),
wrong_type: other.get_type().to_string(),
dst_span: span,
src_span: other.expect_span(),
}),
},
src_span: other.span(),
},
span,
),
}
}

View File

@ -44,7 +44,7 @@ enum InputNumType {
SignedEight,
}
fn get_number_bytes(number_bytes: &Option<Spanned<String>>) -> NumberBytes {
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() {

View File

@ -57,7 +57,7 @@ impl Command for BitsNot {
let signed = call.has_flag("signed");
let number_bytes: Option<Spanned<String>> =
call.get_flag(engine_state, stack, "number-bytes")?;
let bytes_len = get_number_bytes(&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(
@ -84,50 +84,51 @@ impl Command for BitsNot {
Example {
description: "Apply logical negation to a list of numbers",
example: "[4 3 2] | bits not",
result: Some(Value::List {
vals: vec![
result: Some(Value::list(
vec![
Value::test_int(140737488355323),
Value::test_int(140737488355324),
Value::test_int(140737488355325),
],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description:
"Apply logical negation to a list of numbers, treat input as 2 bytes number",
example: "[4 3 2] | bits not -n '2'",
result: Some(Value::List {
vals: vec![
result: Some(Value::list(
vec![
Value::test_int(65531),
Value::test_int(65532),
Value::test_int(65533),
],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
Example {
description:
"Apply logical negation to a list of numbers, treat input as signed number",
example: "[4 3 2] | bits not -s",
result: Some(Value::List {
vals: vec![
result: Some(Value::list(
vec![
Value::test_int(-5),
Value::test_int(-4),
Value::test_int(-3),
],
span: Span::test_data(),
}),
Span::test_data(),
)),
},
]
}
}
fn operate(value: Value, head: Span, signed: bool, number_size: NumberBytes) -> Value {
let span = value.span();
match value {
Value::Int { val, span } => {
Value::Int { val, .. } => {
if signed || val < 0 {
Value::Int { val: !val, span }
Value::int(!val, span)
} else {
use NumberBytes::*;
let out_val = match number_size {
@ -149,20 +150,21 @@ fn operate(value: Value, head: Span, signed: bool, number_size: NumberBytes) ->
// This case shouldn't happen here, as it's handled before
Invalid => 0,
};
Value::Int { val: out_val, span }
Value::int(out_val, span)
}
}
other => match other {
// Propagate errors inside the value
Value::Error { .. } => other,
_ => Value::Error {
error: Box::new(ShellError::OnlySupportsThisInputType {
_ => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "integer".into(),
wrong_type: other.get_type().to_string(),
dst_span: head,
src_span: other.expect_span(),
}),
},
src_span: other.span(),
},
head,
),
},
}
}

View File

@ -68,31 +68,30 @@ impl Command for BitsOr {
Example {
description: "Apply logical or to a list of numbers",
example: "[8 3 2] | bits or 2",
result: Some(Value::List {
vals: vec![Value::test_int(10), Value::test_int(3), Value::test_int(2)],
span: Span::test_data(),
}),
result: Some(Value::list(
vec![Value::test_int(10), Value::test_int(3), Value::test_int(2)],
Span::test_data(),
)),
},
]
}
}
fn operate(value: Value, target: i64, head: Span) -> Value {
let span = value.span();
match value {
Value::Int { val, span } => Value::Int {
val: val | target,
span,
},
Value::Int { val, .. } => Value::int(val | target, span),
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value,
other => Value::Error {
error: Box::new(ShellError::OnlySupportsThisInputType {
other => Value::error(
ShellError::OnlySupportsThisInputType {
exp_input_type: "integer".into(),
wrong_type: other.get_type().to_string(),
dst_span: head,
src_span: other.expect_span(),
}),
},
src_span: other.span(),
},
head,
),
}
}

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