Compare commits

...

111 Commits

Author SHA1 Message Date
d2abb8603a Remove illegal star dependency (#10095)
The wildcard dev-dependency added in #9632 blocked us from publishing
the crate

Co-authored-by: JT <547158+jntrnr@users.noreply.github.com>
2023-08-23 09:09:23 +12:00
JT
894e0f7658 bump to 0.84 (#10093) 2023-08-22 21:23:39 +03:00
a5087c4966 remove Clippy flags from the PR template (#10087)
related to
- https://github.com/nushell/nushell/pull/10072
- https://github.com/nushell/nushell/pull/10073

cc/ @sholderbach 

# Description
i think the PR template was the missing place where a `cargo clippy`
appears 😏
2023-08-21 19:45:48 +02:00
ac4ab452d4 update install/build scripts to include --locked (#10086)
# Description

This PR updates the toolkit and the build/install scripts to include
`--locked`, also added `extra` feature to the _all_ scripts, and
`--force` to the install scripts.

# 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 -- -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-21 12:42:42 -05:00
JT
5378727049 Revert "pin serde to avoid https://github.com/serde-rs/serde/issues/2538" (#10078)
Reverts nushell/nushell#10061

The latest serde (1.0.184) reverts the binary requirement.
2023-08-22 05:04:34 +12:00
0786ddddbd allow help to return a Type::Table (#10082)
# Description

This PR changes the signature of the `help` command so that it can
return a `Type::Table`.

closes #10077 

# 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 -- -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-21 07:46:44 -05:00
7617084ca3 Polish CONTRIBUTING, add Rust style (#10071)
Add a table of contents and fix some imprecise information

Adds a proposed Rust style guide based on how things are reviewed at the
moment.
2023-08-21 17:17:18 +12:00
28941f1a06 Remove global clippy -A from toolkit.nu (#10073)
# Description
Same procedure as in #10072
2023-08-21 00:10:44 +02:00
43ceb3edec Remove clippy global -A from CI (#10072)
# Description
We allowed two default lints due to false positives. This should be
locally addressed with explicit information what causes either a false
positive or why a particular design choice in the code is made.


# User-Facing Changes
None

# Tests + Formatting
We should detect a few more things with clippy out of the box. If you
encounter a false positive you will need to address it on a case by case
basis.
2023-08-21 00:08:49 +02:00
bffd8e4dd2 Pin reedline to 0.23.0 (#10070)
See release notes:

https://github.com/nushell/reedline/releases/tag/v0.23.0
2023-08-20 23:45:36 +02:00
66023f6243 Remove "let config" warning (#10068)
If you have a `config` variable defined at some point after reading
config files, Nushell would print
```
warning: use `$env.config = ...` instead of `let config = ...`
```

I think it's long enough since we've used `$env.config` that we can
remove this. Furthermore, it should be printed during `let` parsing
because you can end up with a `config` constant after importing a
`config` module (that was my case). The warning thus can be misleading.
2023-08-20 22:02:52 +02:00
10fc32e3ef Simplify virtualenv testing (#10035)
Co-authored-by: Stefan Holderbach <sholderbach@users.noreply.github.com>
Co-authored-by: Antoine Stevan <44101798+amtoine@users.noreply.github.com>
2023-08-20 17:00:59 +03:00
3148acd3a4 Recursively export constants from modules (#10049)
<!--
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.
-->

https://github.com/nushell/nushell/pull/9773 introduced constants to
modules and allowed to export them, but only within one level. This PR:
* allows recursive exporting of constants from all submodules
* fixes submodule imports in a list import pattern
* makes sure exported constants are actual constants

Should unblock https://github.com/nushell/nushell/pull/9678

### Example:
```nushell
module spam {
    export module eggs {
        export module bacon {
            export const viking = 'eats'
        }
    }
}

use spam 
print $spam.eggs.bacon.viking  # prints 'eats'

use spam [eggs]
print $eggs.bacon.viking  # prints 'eats'

use spam eggs bacon viking
print $viking  # prints 'eats'
```

### Limitation 1:

Considering the above `spam` module, attempting to get `eggs bacon` from
`spam` module doesn't work directly:
```nushell
use spam [ eggs bacon ]  # attempts to load `eggs`, then `bacon`
use spam [ "eggs bacon" ]  # obviously wrong name for a constant, but doesn't work also for commands
```

Workaround (for example):
```nushell
use spam eggs
use eggs [ bacon ]

print $bacon.viking  # prints 'eats'
```

I'm thinking I'll just leave it in, as you can easily work around this.
It is also a limitation of the import pattern in general, not just
constants.

### Limitation 2:

`overlay use` successfully imports the constants, but `overlay hide`
does not hide them, even though it seems to hide normal variables
successfully. This needs more investigation.

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

Allows recursive constant exports from submodules.

# 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-20 14:51:35 +02:00
e6ce8a89be try and fix into datetime to accept more dt formats (#10063)
# Description

This PR tries to fix `into datetime`. The problem was that it didn't
support many input formats and the `--format` was clunky. `--format` is
still a bit clunky but can work. The big change here is that it first
tries to use `dtparse` to convert text into datetime.

### Before
```nushell
❯ '20220604' | into datetime
Thu, 01 Jan 1970 00:00:00 +0000 (53 years ago)
```
### After
```nushell
❯ '20220604' | into datetime
Sat, 04 Jun 2022 00:00:00 -0500 (a year ago)
```
## Supported Input Formats
`dtparse` should support all these formats. Taken from their
[repo](https://github.com/bspeice/dtparse/blob/master/build_pycompat.py).
```python
    'test_parse_default': [
        "Thu Sep 25 10:36:28",
        "Sep 10:36:28", "10:36:28", "10:36", "Sep 2003", "Sep", "2003",
        "10h36m28.5s", "10h36m28s", "10h36m", "10h", "10 h 36", "10 h 36.5",
        "36 m 5", "36 m 5 s", "36 m 05", "36 m 05 s", "10h am", "10h pm",
        "10am", "10pm", "10:00 am", "10:00 pm", "10:00am", "10:00pm",
        "10:00a.m", "10:00p.m", "10:00a.m.", "10:00p.m.",
        "October", "31-Dec-00", "0:01:02", "12h 01m02s am", "12:08 PM",
        "01h02m03", "01h02", "01h02s", "01m02", "01m02h", "2004 10 Apr 11h30m",
        # testPertain
        'Sep 03', 'Sep of 03',
        # test_hmBY - Note: This appears to be Python 3 only, no idea why
        '02:17NOV2017',
        # Weekdays
        "Thu Sep 10:36:28", "Thu 10:36:28", "Wed", "Wednesday"
    ],
    'test_parse_simple': [
        "Thu Sep 25 10:36:28 2003", "Thu Sep 25 2003", "2003-09-25T10:49:41",
        "2003-09-25T10:49", "2003-09-25T10", "2003-09-25", "20030925T104941",
        "20030925T1049", "20030925T10", "20030925", "2003-09-25 10:49:41,502",
        "199709020908", "19970902090807", "2003-09-25", "09-25-2003",
        "25-09-2003", "10-09-2003", "10-09-03", "2003.09.25", "09.25.2003",
        "25.09.2003", "10.09.2003", "10.09.03", "2003/09/25", "09/25/2003",
        "25/09/2003", "10/09/2003", "10/09/03", "2003 09 25", "09 25 2003",
        "25 09 2003", "10 09 2003", "10 09 03", "25 09 03", "03 25 Sep",
        "25 03 Sep", "  July   4 ,  1976   12:01:02   am  ",
        "Wed, July 10, '96", "1996.July.10 AD 12:08 PM", "July 4, 1976",
        "7 4 1976", "4 jul 1976", "7-4-76", "19760704",
        "0:01:02 on July 4, 1976", "0:01:02 on July 4, 1976",
        "July 4, 1976 12:01:02 am", "Mon Jan  2 04:24:27 1995",
        "04.04.95 00:22", "Jan 1 1999 11:23:34.578", "950404 122212",
        "3rd of May 2001", "5th of March 2001", "1st of May 2003",
        '0099-01-01T00:00:00', '0031-01-01T00:00:00',
        "20080227T21:26:01.123456789", '13NOV2017', '0003-03-04',
        'December.0031.30',
        # testNoYearFirstNoDayFirst
        '090107',
        # test_mstridx
        '2015-15-May',
    ],
    'test_parse_tzinfo': [
        'Thu Sep 25 10:36:28 BRST 2003', '2003 10:36:28 BRST 25 Sep Thu',
    ],
    'test_parse_offset': [
        'Thu, 25 Sep 2003 10:49:41 -0300', '2003-09-25T10:49:41.5-03:00',
        '2003-09-25T10:49:41-03:00', '20030925T104941.5-0300',
        '20030925T104941-0300',
        # dtparse-specific
        "2018-08-10 10:00:00 UTC+3", "2018-08-10 03:36:47 PM GMT-4", "2018-08-10 04:15:00 AM Z-02:00"
    ],
    'test_parse_dayfirst': [
        '10-09-2003', '10.09.2003', '10/09/2003', '10 09 2003',
        # testDayFirst
        '090107',
        # testUnambiguousDayFirst
        '2015 09 25'
    ],
    'test_parse_yearfirst': [
        '10-09-03', '10.09.03', '10/09/03', '10 09 03',
        # testYearFirst
        '090107',
        # testUnambiguousYearFirst
        '2015 09 25'
    ],
    'test_parse_dfyf': [
        # testDayFirstYearFirst
        '090107',
        # testUnambiguousDayFirstYearFirst
        '2015 09 25'
    ],
    'test_unspecified_fallback': [
        'April 2009', 'Feb 2007', 'Feb 2008'
    ],
    'test_parse_ignoretz': [
        'Thu Sep 25 10:36:28 BRST 2003', '1996.07.10 AD at 15:08:56 PDT',
        'Tuesday, April 12, 1952 AD 3:30:42pm PST',
        'November 5, 1994, 8:15:30 am EST', '1994-11-05T08:15:30-05:00',
        '1994-11-05T08:15:30Z', '1976-07-04T00:01:02Z', '1986-07-05T08:15:30z',
        'Tue Apr 4 00:22:12 PDT 1995'
    ],
    'test_fuzzy_tzinfo': [
        'Today is 25 of September of 2003, exactly at 10:49:41 with timezone -03:00.'
    ],
    'test_fuzzy_tokens_tzinfo': [
        'Today is 25 of September of 2003, exactly at 10:49:41 with timezone -03:00.'
    ],
    'test_fuzzy_simple': [
        'I have a meeting on March 1, 1974', # testFuzzyAMPMProblem
        'On June 8th, 2020, I am going to be the first man on Mars', # testFuzzyAMPMProblem
        'Meet me at the AM/PM on Sunset at 3:00 AM on December 3rd, 2003', # testFuzzyAMPMProblem
        'Meet me at 3:00 AM on December 3rd, 2003 at the AM/PM on Sunset', # testFuzzyAMPMProblem
        'Jan 29, 1945 14:45 AM I going to see you there?', # testFuzzyIgnoreAMPM
        '2017-07-17 06:15:', # test_idx_check
    ],
```
# 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 -- -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-20 07:32:48 -05:00
74f8081290 allow return to return any nushell value (#10067)
# Description

This PR allows the `return` command to return any nushell value.

### Before

![image](https://github.com/nushell/nushell/assets/343840/2c0a70d7-86e4-4c7f-bd3a-d7c7d74b1c1a)

### After

![image](https://github.com/nushell/nushell/assets/343840/f428d486-4a4f-4058-a29f-7d7a845e08f7)


# 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 -- -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-20 07:30:54 -05:00
JT
2ae1de2470 move 'bytes' back to commands (#10051)
# Description

Moves the `bytes XXXX` commands back to the default set.
2023-08-19 22:43:53 +02:00
028a327ce8 Revert "deprecate --format and --list in into datetime (#10017)" (#10055)
related to 
-
https://github.com/nushell/nushell/issues/10017#issuecomment-1683082039

# Description
this PR undeprecates `into datetime --format` and `into datetime
--list`.

this PR reverts commit f33b60c001.

# User-Facing Changes

# Tests + Formatting

# After Submitting
2023-08-19 14:34:16 -05:00
JT
318862aad6 pin serde to avoid https://github.com/serde-rs/serde/issues/2538 (#10061)
Context: https://github.com/serde-rs/serde/issues/2538

As other projects are investigating, this should pin serde to the last
stable release before binary requirements were introduced.

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

# 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 -- -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-20 05:50:26 +12:00
9f4510f2e1 make the charpage optional for std clip (#10053)
related to
-
https://discord.com/channels/601130461678272522/615253963645911060/1142060647358668841

# Description
in order to make the charpage for Windows as general as possible, `chcp`
will only run on Windows when `--charpage` is given an integer.

while i was at it, i fixed the system messages given to
`check-clipboard` because some of the were incorrect => see the second
commit 6865ec9a5

# User-Facing Changes
this is a breaking change as users relying on the fact that `std clip`
changed the page to `65001` by itself is not true anymore => they will
have to add `--charpage 65001`.

# Tests + Formatting

# After Submitting
2023-08-19 10:18:50 -05:00
98c7ab96b6 enable/update some example tests so they work again (#10058)
# Description

This PR updates some `Example` tests so that they work again. The only
one I couldn't figure out is the one in the `filter` command. It should
work but does not. However, I left the test in because it's valuable, it
just has a `None` result. I'd like to fix this but I'm not sure how.

# 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 -- -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-19 09:06:59 -05:00
13114e972b try to document the more obscure testbin commands (#10057)
# Description

This PR tries to document some of the more obscure testbin parameters
and what they do. I still don't grok all of them.

# 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 -- -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-19 08:23:11 -05:00
JT
4a1b3e26ef fix default-env after latest changes (#10052)
# Description

default env.nu is currently broken after the changes to `str replace`.
This PR should help fix it.

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

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -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-19 07:39:36 +12:00
1e3248dfe8 nu-table: fix issue with truncation and text border (#10050)
I did only few manual tests, so maybe shall be run before.

todo: maybe need to add a test case for it.

fix #9993
cc: @fdncred

---------

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2023-08-18 13:28:33 -05:00
2aa4cd5cc5 Add a few more fields to scope commands (#10045) 2023-08-18 20:47:38 +03:00
fb908df17d Add additional span to IncorrectValue error (#10036) 2023-08-18 20:47:05 +03:00
cdf09abcc0 Allow exporting extern-wrapped (#10025) 2023-08-18 20:45:33 +03:00
fe2c498a81 Fix wrong path expansion in save (#10046) 2023-08-18 20:45:10 +03:00
fe7122280d allow int as a cellpath for select (#10048)
Description

This PR allows ints to be used as cell paths.

### Before
```nushell
❯ let index = 0
❯ locations | select $index
Error: nu:🐚:cant_convert

  × Can't convert to cell path.
   ╭─[entry #26:1:1]
 1 │ locations | select $index
   ·                    ───┬──
   ·                       ╰── can't convert int to cell path
   ╰────
```

### After
```nushell
❯ let index = 0
❯ locations | select $index
╭#┬───────location────────┬city_column┬state_column┬country_column┬lat_column┬lon_column╮
│0│http://ip-api.com/json/│city       │region      │countryCode   │lat       │lon       │
╰─┴───────────────────────┴───────────┴────────────┴──────────────┴──────────┴──────────╯
```
# 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 -- -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-18 10:16:18 -05:00
2e0fb7c1a6 Change str replace to match substring by default (#10038) 2023-08-18 00:18:16 +03:00
f33b60c001 deprecate --format and --list in into datetime (#10017)
related to
-
https://discord.com/channels/601130461678272522/614593951969574961/1141009665266831470

# Description
this PR
- prints a colorful warning when a user uses either `--format` or
`--list` on `into datetime`
- does NOT remove the features for now, i.e. the two options still work
- redirect to the `format date` command instead

i propose to
- land this now
- prepare a removal PR right after this
- land the removal PR in between 0.84 and 0.85

# User-Facing Changes
`into datetime --format` and `into datetime --list` will be deprecated
in 0.85.

## how it looks
- `into datetime --list` in the REPL
```nushell
> into datetime --list | first
Error:   × Deprecated option
   ╭─[entry #1:1:1]
 1 │ into datetime --list | first
   · ──────┬──────
   ·       ╰── `into datetime --list` is deprecated and will be removed in 0.85
   ╰────
  help: see `format datetime --list` instead


╭───────────────┬────────────────────────────────────────────╮
│ Specification │ %Y                                         │
│ Example       │ 2023                                       │
│ Description   │ The full proleptic Gregorian year,         │
│               │ zero-padded to 4 digits.                   │
╰───────────────┴────────────────────────────────────────────╯
```

- `into datetime --list` in a script
```nushell
> nu /tmp/foo.nu
Error:   × Deprecated option
   ╭─[/tmp/foo.nu:4:1]
 4 │ #
 5 │ into datetime --list | first
   · ──────┬──────
   ·       ╰── `into datetime --list` is deprecated and will be removed in 0.85
   ╰────
  help: see `format datetime --list` instead


╭───────────────┬────────────────────────────────────────────╮
│ Specification │ %Y                                         │
│ Example       │ 2023                                       │
│ Description   │ The full proleptic Gregorian year,         │
│               │ zero-padded to 4 digits.                   │
╰───────────────┴────────────────────────────────────────────╯
```

- `help into datetime`


![baz](https://github.com/nushell/nushell/assets/44101798/08beece0-9c89-4665-bfe4-76a32207470f)

# Tests + Formatting

# After Submitting
2023-08-17 15:20:22 -05:00
7e48607820 Remove dead code from tests (#10040)
<!--
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.
-->

Removes some dead code that was left over

# 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 -- -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-17 15:08:35 -05:00
68a821c84a Change Winget Releaser job to ubuntu-latest (#10032)
<!--
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.
-->

Winget Releaser now supports non-Windows runners, and `ubuntu-latest` is
generally faster.
2023-08-17 10:12:16 -05:00
c5e59efa4d Sort entries in scope commands; Fix usage of externs (#10039)
# Description

* All output of `scope` commands is sorted by the "name" column. (`scope
externs` and some other commands had entries in a weird/random order)
* The output of `scope externs` does not have extra newlines (that was
due to wrong usage creation of known externals)
2023-08-17 16:37:01 +02:00
ec5b9b9f37 Make http -f display the request headers. Closes #9912 (#10022)
# Description
As described in https://github.com/nushell/nushell/issues/9912, the
`http` command could display the request headers with the `--full` flag,
which could help in debugging the requests. This PR adds such
functionality.

# User-Facing Changes
If `http get` or other `http` command which supports the `--full` flag
is invoked with the flag, it used to display the `headers` key which
contained an table of response headers. Now this key contains two nested
keys: `response` and `request`, each of them being a table of the
response and request headers accordingly.


![image](https://github.com/nushell/nushell/assets/24980/d3cfc4c3-6c27-4634-8552-2cdfbdfc7076)
2023-08-17 09:19:10 -05:00
e88a51e930 Refactor scope commands (#10023) 2023-08-17 11:58:38 +03:00
35f8d8548a Remove potential panic from path join (#10012)
Co-authored-by: amtoine <stevan.antoine@gmail.com>
2023-08-16 10:27:36 +03:00
7a123d3eb1 Expose polars avro support (#10019)
# Description

Exposes polars avro support via dfr open and dfr to-avro

---------

Co-authored-by: Jack Wright <jack.wright@disqo.com>
2023-08-15 20:31:49 -05:00
3ed45c7ba8 allow select to take a $variable with a list of columns (#9987)
# Description

This PR enables `select` to take a constructed list of columns as a
variable.

```nushell
> let cols = [name type];[[name type size]; [Cargo.toml toml 1kb] [Cargo.lock toml 2kb]] | select $cols
  ╭#┬───name───┬type╮
  │0│Cargo.toml│toml│
  │1│Cargo.lock│toml│
  ╰─┴──────────┴────╯
```
and rows
```nushell
> let rows = [0 2];[[name type size]; [Cargo.toml toml 1kb] [Cargo.lock toml 2kb] [file.json json 3kb]] | select $rows
  ╭#┬───name───┬type┬size╮
  │0│Cargo.toml│toml│1kb │
  │1│file.json │json│3kb │
  ╰─┴──────────┴────┴────╯
```

# 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 -- -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-15 07:01:45 -05:00
8b160f9850 Nushell table list columns -> dataframe list columns. Explode / Flatten dataframe support. (#9951)
# Description
- Adds support for conversion between nushell lists and polars lists
instead of treating them as a polars object.
- Fixed explode and flatten to work both as expressions or lazy
dataframe commands. The previous item was required to make this work.

---------

Co-authored-by: Jack Wright <jack.wright@disqo.com>
Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2023-08-15 06:54:37 -05:00
696b2cda4a nu-table: Fix padding 0 width issues (#10011)
close #10001

cc: @fdncred @amtoine 

note: make sure you rebase/squash

---------

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2023-08-14 19:07:34 -05:00
435348aa61 Rename misused "deprecation" to removal (#10000)
# Description
In the past we named the process of completely removing a command and
providing a basic error message pointing to the new alternative
"deprecation".

But this doesn't match the expectation of most users that have seen
deprecation _warnings_ that alert to either impending removal or
discouraged use after a stability promise.

# User-Facing Changes
Command category changed from `deprecated` to `removed`
2023-08-15 07:17:31 +12:00
0a5f41abc2 Bump quick-xml from 0.29.0 to 0.30.0 (#9870) 2023-08-14 13:58:15 +00:00
2b97bc54c5 Fix example for extern-wrapped (#10004)
Fixes example and some signature text of `extern-wrapped`.

# User-Facing Changes

Minor help text changes
2023-08-14 15:41:25 +02:00
ad49c17eba fix(nu-parser): do not update plugin.nu file on nu startup (#10007)
<!--
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

I've been investigating the [issue
mentioned](https://github.com/nushell/nushell/pull/9976#issuecomment-1673290467)
in my prev pr and I've found that plugin.nu file that is used to cache
plugins signatures gets overwritten on every nushell startup and that
may actually mess up with the file content if 2 or more instances of
nushell will run simultaneously.

To reproduce:
1. register at least 2 plugins in your local nushell
2. remember how many entries you have in plugin.nu with `open
$nu.plugin-path | find nu_plugin`
3. run 
    - either `cargo test` inside nushell repo
- or run smth like this `1..100 | par-each {|it| $"(random integer
1..100)ms" | into duration | sleep $in; nu -c "$nu.plugin-path"}` to
simulate parallel access. This approach is not so reliable to reproduce
as running test but still a good point that it may effect users actually
4. validate that your `plugin.nu` file was stripped

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

# Solution

In this pr I've refactored the code of handling the `register` command
to minimize code duplications and make sure that overwrite of
`plugin.nu` file is happen only when user calls the command and not on
nu startup

Another option would be to use temp `plugin.nu` when running tests, but
as the issue actually can affect users I've decided to prevent
unnecessary writing at all. Although having isolated `plugin.nu` still
worth of doing

# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->
It changes the behaviour actually as the call `register <plugin>
<signature>` now doesn't updates `plugin.nu` and just reads signatures
to the memory. But as I understand that kind of call with explicit
signature is meant to use only by nushell itself in the `plugin.nu` file
only. I've asked about it in
[discord](https://discordapp.com/channels/601130461678272522/615962413203718156/1140013448915325018)

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

Actually, I think the way plugins are stored might be reworked to
prevent or mitigate possible issues further:
- problem with writing to file may still arise if we try to register in
parallel as several instances will write to the same file so the lock
for the file might be required
- using additional parameters to command like `register` to implement
some internal logic could be misleading to the users
- `register` call actually affects global state of nushell that sounds a
little bit inconsistent with immutability and isolation of other parts
of the nu. See issues
[1](https://github.com/nushell/nushell/issues/8581),
[2](https://github.com/nushell/nushell/issues/8960)
2023-08-14 08:39:23 -05:00
f1e88d95c1 Fix a crash when moving the cursor after accepting a suggestion from the help menu (#9784)
<!--
if this PR closes one or more issues, you can automatically link the PR
with
them by using one of the [*linking
keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword),
e.g.
- this PR should close #xxxx
- fixes #xxxx

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

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

Description of your pull request goes here. **Provide examples and/or
screenshots** if your changes affect the user experience.
-->
Fixes #9627 
Related nushell/reedline#602 nushell/reedline#612

# 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 -- -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-14 05:58:39 -05:00
6eac9bfd0f test: clear parent envs to prevent leakage to tests (#9976)
Running tests locally from nushell with customizations (i.e.
$env.PROMPT_COMMAND etc) may lead to failing tests as that customization
leaks to the sandboxed nu itself.

Remove `FILE_PWD` from env

# Tests + Formatting

Tests are now passing locally without issue in my case
2023-08-14 12:49:55 +02:00
5d94b16d71 Improve I/O types of into decimal(/float) (#9998)
# Description
- Add identity cast to `into decimal` (float->float)
- Correct `into decimal` output to concrete float

# User-Facing Changes
`1.23 | into decimal` will now work.
By fixing the output type it can now be used in conjunction with
commands that expect `float`/`list<float>`

# Tests + Formatting
Adapts example to do identity cast and heterogeneous cast
2023-08-13 20:29:17 +02:00
3bd46fe27a Add search terms to reject (#9996)
# Description
This may be easy to find/confuse with `drop`


# User-Facing Changes
Users coming from SQL will be happier when using `help -f` or `F1`

# Tests + Formatting
None
2023-08-13 20:27:29 +02:00
7b1c7debcb Fix watch not handling all file changes (#9990)
Closes https://github.com/nushell/nushell/issues/9910

I noticed that`watch` was not catching all filesystem changes, because
some are reported as `ModifyKind::Data(DataChange::Any)` and we were
only handling `ModifyKind::Data(DataChange::Content)`. Easy fix.

This was happening on Ubuntu 23.04, ext4.
2023-08-12 14:34:40 -07:00
JT
e77a0a48aa Rename main to script name when running scripts (#9948)
# Description

This PR does three related changes:

* Keeps the originally declared name in help outputs.
* Updates the name of the commands called `main` in the user script to
the name of the script.
* Fixes the source of signature information in multiple places. This
allows scripts to have more complete help output.

Combined, the above allow the user to see the script name in the help
output of scripts, like so:


![image](https://github.com/nushell/nushell/assets/547158/741d192c-0a39-45a7-8f36-3a0dc8eeae2b)

NOTE: You still declare and call the definition `main`, so from inside
the script `main` is still the correct name. But multiple folks agreed
that seeing `main` in the script help was confusing, so this PR changes
that.

# User-Facing Changes

One potential minor breaking change is that module renames will be shown
as their originally defined name rather than the renamed name. I believe
this to be a better default.

# 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-12 05:58:49 +12:00
aa37572ddc nu-table/ Add table.indent configuration (#9983)
Hi there.

Am I got it right?

ref: https://github.com/zhiburt/tabled/issues/358
cc: @fdncred

---------

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2023-08-11 08:37:16 -05:00
a0cecf7658 Move format duration/filesize back into core (#9978)
# Description
Those two commands are very complementary to `into duration` and `into
filesize` when you want to coerce a particular string output.

This keeps the old `format` command with its separate formatting syntax
still in `nu-cmd-extra`.

# User-Facing Changes
`format filesize` is back accessible with the default build. The new
`format duration` command is also available to everybody

# Tests + Formatting
2023-08-11 06:01:47 +12:00
23170ff368 fix the signature of input list (#9977)
# Description
in its documentation, `input list` says it only accepts the following
signatures
- `list<any> -> list<any>`
- `list<string> -> string`

however this is incorrect as the following is allowed and even in the
help page
```nushell
[1 2 3] | input list  # -> returns an `int`
```

this PR fixes the signature of `input list`.
- with no option or `--fuzzy`, `input list` takes a `list<any>` and
outputs a single `any`
- with `--multi`, `input list` takes a `list<any>` and outputs a
`list<any>`

# User-Facing Changes
the input output signature of `input list` is now
```
  ╭───┬───────────┬───────────╮
  │ # │   input   │  output   │
  ├───┼───────────┼───────────┤
  │ 0 │ list<any> │ list<any> │
  │ 1 │ list<any> │ any       │
  ╰───┴───────────┴───────────╯
```
# Tests + Formatting
this shouldn't change anything as `[1 2 3] | input list` already works.

# After Submitting
2023-08-10 16:44:59 +02:00
f9ffd9ae29 Fixup dataframe build after #9971 (#9974)
# Description
Building broke silently.

`nu` needs to enable the `dataframe` feature of `nu-cmd-dataframe`

# User-Facing Changes
Building with `cargo build --features dataframe` works again.

# Tests + Formatting
Still worth investigating if we can harden the CI against this.
2023-08-10 08:27:20 -05:00
d5fa7b8a55 Put heavy dataframe dependencies behind feature flag (#9971)
Context from Discord:
https://discord.com/channels/601130461678272522/615962413203718156/1138694933545504819

I was working on Nu for the first time in a while and I noticed that
sometimes rust-analyzer takes a really long time to run `cargo check` on
the entire workspace. I dug in and it was checking a bunch of
dataframe-related dependencies even though the `dataframe` feature is
not built by default.

It looks like this is a regression of sorts, introduced by
https://github.com/nushell/nushell/pull/9241. Thankfully the fix is
pretty easy, we can make it so everything important in
`nu-cmd-dataframe` is only used when the `dataframe` feature is enabled.

### Impact on `cargo check --workspace`

Before this PR: 635 crates, 33.59s
After this PR: 498 crates, ~20s

(with the `mold` linker and a `cargo clean` before each run, the
relative difference for incremental checks will likely be much larger)
2023-08-09 22:36:09 -07:00
f94df58486 Fix cross-compiling with cross-rs (#9972)
I cross-compiled Nushell (from x64 to ARM64) for the first time in a
while and noticed that our [`cross-rs`](https://github.com/cross-rs)
setup was no longer working. I've fixed that by following [the latest
`cross-rs`
docs](https://github.com/cross-rs/cross/wiki/Recipes#openssl).
2023-08-09 22:08:35 -07:00
6f5bd62a97 update strip-ansi-escapes to 0.2.0 and the latest reedline (#9970)
# Description

This PR fixes the semver issues with `strip-ansi-escapes` and updates it
to 0.2.0 as well as updating to the latest reedline which just landed an
identical patch.

# 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 -- -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-09 12:33:07 -05:00
bb3cc9e153 fix the default config for explore (#9962)
according to
0674d4960b/crates/nu-explore/src/commands/table.rs (L132-L135)

the config should be called `$env.config.explore.table.show_cursor`
instead of the current `$env.config.explore.table.cursor` 😮

this PR fixes this in the default config.
2023-08-09 08:18:12 -05:00
202dfdaee2 fix panic with lines on an error (#9967)
should close https://github.com/nushell/nushell/issues/9965

# Description
this PR implements the `todo!()` left in `lines`.

# User-Facing Changes
### before
```nushell
> open . | lines
thread 'main' panicked at 'not yet implemented', crates/nu-command/src/filters/lines.rs:248:35
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```

### after
```nushell
> open . | lines
Error: nu:🐚:io_error

  × I/O error
  help: Is a directory (os error 21)
```

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

this PR adds the `lines_on_error` test to make sure this does not happen
again 😌

# After Submitting
2023-08-09 14:12:58 +02:00
0674d4960b Fix match example whitespace (#9961)
I was looking up `match` documentation and noticed that the formatting
was a bit off for the last example (starts on the wrong line, is several
columns too far to the right).

## Before:

![image](https://github.com/nushell/nushell/assets/26268125/cea55875-894c-442f-aa93-d5c18a0cdfa5)

## After:


![image](https://github.com/nushell/nushell/assets/26268125/064c9f80-6a70-4748-a877-5344ec6e6a80)
2023-08-09 07:13:02 +02:00
85c2035016 update strip-ansi-escapes to use new api (#9958)
# Description

This PR updates `strip-ansi-escapes` to support their new API. This also
updates nushell to the latest reedline after the same fix
https://github.com/nushell/reedline/pull/617

closes #9957 

# 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 -- -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-08 15:20:37 -05:00
02be83efbf Bump rstest from 0.17.0 to 0.18.1 (#9782) 2023-08-08 17:11:05 +00:00
b964347895 add a test to make sure "nothing" shows up as "nothing" in help (#9941)
related to 
- https://github.com/nushell/nushell/pull/9935

# Description
this PR just adds a test to make sure type annotations in `def`s show as
`nothing` in the help pages of commands.

# User-Facing Changes

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

# After Submitting
2023-08-09 05:10:34 +12:00
56ed1eb807 parse: collect external stream chunks before matching (#9950)
<!--
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
-->

# Description
This PR implements the workaround discussed in #9795, i.e. having
`parse` collect an external stream before operating on it with a regex.

- Should close #9795 

# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->
- `parse` will give the correct output for external streams
- increased memory and time overhead due to collecting the entire stream
(no short-circuiting)

# 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
> ```
-->
- formatting is checked
- clippy is happy
- no tests that weren't already broken fail
- added test case

# 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-08 06:48:13 -05:00
570175f95d Fix duration type to not report months or years (#9632)
<!--
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!
-->
This PR should close #8036, #9028 (in the negative) and #9118.

Fix for #9118 is a bit pedantic.  As reported, the issue is:
```
> 2023-05-07T04:08:45+12:00 - 2019-05-10T09:59:12+12:00
3yr 12month 2day 18hr 9min 33sec
```
with this PR, you now get:
```
> 2023-05-07T04:08:45+12:00 - 2019-05-10T09:59:12+12:00
208wk 1day 18hr 9min 33sec
```
Which is strictly correct, but could still fairly be called "weird date
arithmetic".

# Description
* [x] Abide by constraint that Value::Duration remains a number of
nanoseconds with no additional fields.
* [x] `to_string()` only displays weeks .. nanoseconds. Duration doesn't
have base date to compute months or years from.
* [x] `duration | into record` likewise only has fields for weeks ..
nanoseconds.
* [x] `string | into duration` now accepts compound form of duration
to_string() (e.g '2day 3hr`, not just '2day')
* [x] `duration | into string` now works (and produces the same
representation as to_string(), which may be compound).

# User-Facing Changes
## duration -> string -> duration
Now you can "round trip" an arbitrary duration value: convert it to a
string that may include multiple time units (a "compound" value), then
convert that string back into a duration. This required changes to
`string | into duration` and the addition of `duration | into string'.
```
> 2day + 3hr
2day 3hr # the "to_string()" representation (in this case, a compound value)
> 2day + 3hr | into string
2day 3hr # string value
> 2day + 3hr | into string | into duration
2day 3hr # round-trip duration -> string -> duration
```
Note that `to nuon` and `from nuon` already round-tripped durations, but
use a different string representation.

## potentially breaking changes
* string rendering of a duration no longer has 'yr' or 'month' phrases.
* record from `duration | into record` no longer has 'year' or 'month'
fields.
The excess duration is all lumped into the `week` field, which is the
largest time unit you can
convert to without knowing the datetime from which the duration was
calculated.

Scripts that depended on month or year time units on output will need to
be changed.

### Examples
```
> 365day
52wk 1day
## Used to be: 
## 1yr

> 365day | into record
╭──────┬────╮
│ week │ 52 │
│ day  │ 1  │
│ sign │ +  │
╰──────┴────╯

## used to be:
##╭──────┬───╮
##│ year │ 1 │
##│ sign │ + │
##╰──────┴───╯

> (365day + 4wk + 5day + 6hr + 7min + 8sec + 9ms + 10us + 11ns)
56wk 6day 6hr 7min 8sec 9ms 10µs 11ns
## used to be:
## 1yr 1month 3day 6hr 7min 8sec 9ms 10µs 11ns
## which looks reasonable, but was actually only correct in 75% of the years and 25% of the months in the last 4 years.

> (365day + 4wk + 5day + 6hr + 7min + 8sec + 9ms + 10us + 11ns) | into record
╭─────────────┬────╮
│ week        │ 56 │
│ day         │ 6  │
│ hour        │ 6  │
│ minute      │ 7  │
│ second      │ 8  │
│ millisecond │ 9  │
│ microsecond │ 10 │
│ nanosecond  │ 11 │
│ sign        │ +  │
╰─────────────┴────╯
```
Strictly speaking, these changes could break an existing user script.
Losing years and months as time units is arguably a regression in
behavior.

Also, the corrected duration calculation could break an existing script
that was calibrated using the old algorithm.

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->

---------

Co-authored-by: Bob Hyman <bobhy@localhost.localdomain>
2023-08-08 06:24:09 -05:00
JT
839010b89d Auto-expand table based on terminal width (#9934)
# Description

This PR adds back the functionality to auto-expand tables based on the
terminal width, using the logic that if the terminal is over 100 columns
to expand.

This sets the default config value in both the Rust and the default
nushell config.

To do so, it also adds back the ability for hooks to be strings of code
and not just code blocks.

Fixed a couple tests: two which assumed that the builtin display hook
didn't use a table -e, and one that assumed a hook couldn't be a string.

# 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 -- -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-08 05:47:23 -05:00
JT
7694d09d14 fix the Cargo.lock file (#9955)
# 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.
-->

# 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 -- -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-08 05:46:56 -05:00
JT
4accc67843 Move help commands to use more structure in signatures (#9949)
# Description

Signatures in `help commands` will now have more structure for params
and input/output pairs.

Example:

Improved params

![image](https://github.com/nushell/nushell/assets/547158/f5dacaf2-861b-4b44-aaa6-e17b4bcb953e)

Improved input/output pairs

![image](https://github.com/nushell/nushell/assets/547158/844a6e9c-dbfc-4c07-b0ef-fefd835a4cf0)


# User-Facing Changes

This is technically a breaking change if previous code assumed the shape
of things in `help commands`.

# 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-08 08:33:01 +12:00
c070e2d6f7 Make Value::columns return slice instead of cloned Vec (#9927)
# Description
This PR changes `Value::columns` to return a slice of columns instead of
cloning said columns. If the caller needs an owned copy, they can use
`slice::to_vec` or the like. This eliminates unnecessary Vec clones
(e.g., in `update cells`).

# User-Facing Changes
Breaking change for `nu_protocol` API.
2023-08-07 21:43:32 +02:00
d302d63030 str-expand: update bracoxide to v0.1.2, fixes #9913 (#9940)
Fixes: #9913 

Changes:

- updated crate bracoxide from v0.1.1 to v0.1.2
2023-08-07 21:40:38 +02:00
a2e117f8b0 force version to update when installing with toolkit (#9947)
# Description
`version` has always been a bit off regarding the `commit_hash`
😕

i think it was @fdncred who found this trick: `touch`ing the
`crates/nu-cmd-lang/build.rs` file
- won't change the Git index
- will force Nushell to recompile the `version` information correctly

this PR adds a call to `touch` on that file to `toolkit install`.

# User-Facing Changes
`version` should be correct when installing locally with the `toolkit`.

# Tests + Formatting

# After Submitting
2023-08-07 12:25:24 -05:00
b1974fae39 Categorification: move commands histogram and version out of the default category (#9946)
* histogram to chart
* version to core

This completes moving commands out of the *Default* category...

When you run 

```rust
nu -n --no-std-lib
```

```rust
help commands | where category == "default"
```

You now get an *Empty List* 😄
2023-08-07 09:23:53 -07:00
7248de1167 Categorification: move from Default category to Filters (#9945)
The following *Filters* commands were incorrectly in the category
*Default*

* group-by
* join
* reduce
* split-by
* transpose

This continues the effort of moving commands out of default and into
their proper category...
2023-08-07 08:33:30 -07:00
a9582e1c62 Nothing return type (#9935)
# Description
Fix #9928. When parsing input/output types `nothing` was incorrectly
coerced to `any`. This is addressed by changing how
[to_type](0ad1ad4277/crates/nu-protocol/src/syntax_shape.rs (L121))
method handles `nothing` syntax shape. Also `range` syntax shape is
addressed the same way.

# User-Facing Changes
`nothing` and `range` are correctly displayed in help and strictly
processed by type checking. This will break definitions that were not in
fact output nothing or range and incorrect uses of functions which input
nothing or range.

Examples of correctly defined functions:

![image](https://github.com/nushell/nushell/assets/17511668/d9f73438-d8a7-487f-981a-7e791b42766e)

![image](https://github.com/nushell/nushell/assets/17511668/2d5fe3a2-94be-4d25-9522-2ea38e528fe4)

Examples of incorrect definitions and uses of functions:

![image](https://github.com/nushell/nushell/assets/17511668/6a2f9fba-abfa-47fe-8b53-bb348e532cd8)

![image](https://github.com/nushell/nushell/assets/17511668/b1fbf9f6-fd75-4b80-9f38-26cc7c2ecc25)

![image](https://github.com/nushell/nushell/assets/17511668/718ef98b-3d7a-433d-af97-39a225ef34e5)


# 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-07 18:10:01 +12:00
bb6335830a Categorification: move Path commands out of the default category (#9937)
Path commands were incorrectly located in the default category...

This PR moves all of the *Path* commands into their own Category called
*Path*
2023-08-07 16:03:23 +12:00
JT
c8f3799c20 Fix a couple clippy warnings (#9936)
<!--
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.
-->

# 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 -- -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-07 06:23:11 +12:00
bd3a61a2f7 Categorification: graduate nuon --- from the experimental category to the formats category (#9932)
@jntrnr and I discussed the fact that we can now *graduate* nuon to be a
first class citizen...

This PR moves 

* from nuon
* to nuon

out of the *experimental* stage and into *formats*
2023-08-07 05:09:44 +12:00
JT
077643cadf Add tests for script subcommands (#9933)
# Description

Add a few tests to ensure that you can add subcommands to scripts. We've
supported this for a long time, though I'm not sure if anyone has
actually tried it. As we weren't testing the support, this PR adds a few
tests to ensure it stays working.

Example script subcommand:

```
def "main addten" [x: int] {
  print ($x + 10)
}
```

then call it with:

```
> nu ./script.nu addten 5
```

# 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 -- -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-07 05:09:20 +12:00
fa2d9a8a58 Categorification: move uncategorized String commands to Category::Strings (#9931)
In an effort to go through and review all of the remaining commands to
find anything else that could possibly
be moved to *nu-cmd-extra*

I noticed that there are still some commands that have not been
categorized...

I am going to *Categorize* the remaining commands that still *do not
have Category homes*

In PR land I will call this *Categorification* as a play off of
*Cratification*

* str substring
* str trim
* str upcase

were in the *default* category because for some reason they had not yet
been categorized.
I went ahead and moved them to the

```rust
.category(Category::Strings)
```
2023-08-07 04:08:45 +12:00
58f98a4260 Cratification: move some str case commands to nu-cmd-extra (#9926)
I am moving the following str case commands to nu-cmd-extra (as
discussed in the core team meeting the other day)

* camel-case
* kebab-case
* pascal-case
* screaming-snake-case
* snake-case
* title-case
2023-08-06 06:40:44 -07:00
066790552a add keybinding for search-history (#9930)
# Description

This PR adds a keybinding in the rust code for `search-history` aka
reverse-search as `ctrl+q` so it does not overwrite `history-search`
with `ctrl+r` as it does now.

This PR supercedes #9862. Thanks to @SUPERCILEX for bringing this to our
attention.

# 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 -- -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-06 06:59:06 -05:00
dcb1a1996c remove old deprecated commands (#9840)
# Description
in this PR i propose to remove the following old deprecated commands
- `hash base64` -> `encode base64`
- `math eval` -> `math <sub>`
- `str to-datetime` -> `into datetime`
- `str to-decimal` -> `into decimal`
- `str find-replace` -> `str replace`
- `str to-int` -> `into int`
- `keep` -> `take`
- `match` -> `find`
- `nth` -> `select`
- `pivot` -> `transpose`
- `unalias` -> `hide`
- `all?` -> `all`
- `any?` -> `any`
- `empty?` -> `is-empty`
- `build-string` -> `str join` / string concatenation with `+`
- `str lpad` -> `fill`
- `str rpad` -> `fill`
- `str collect` -> `str join`
- `old-alias` -> `alias`

so old i do not remember them at all 😮

i left the following four commands because they have been moved much
more recently i think!
- `fetch` -> `http get`
- `post` -> `http post`
- `benchmark` -> `timeit`
- `let-env`
- `date format` -> `format date`

# User-Facing Changes

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

# After Submitting
2023-08-06 06:42:16 -05:00
6b4d06d8a7 do not emit None mid-stream during parse (#9925)
<!--
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 #issue 

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

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

Description of your pull request goes here. **Provide examples and/or
screenshots** if your changes affect the user experience.
-->
Currently `parse` acts like a `.filter` over an iterator, except that it
emits `None` for elements that can't be parsed. This causes consumers of
the adapted iterator to stop iterating too early. The correct behaviour
is to keep pulling the inner iterator until either the end of it is
reached or an element can be parsed.

- this PR should close #9906 

# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->
List streams won't be truncated anymore after the first parse failure.

# 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 -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
> ```
-->
- [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 -A
clippy::needless_collect -A clippy::result_large_err` to check that
you're using the standard code style
- [x] `cargo test --workspace` to check that all tests pass
  - 11 tests fail, but the same 11 tests fail on main as well
- [x] `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library

# 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-06 06:17:03 -05:00
f615038938 Enable macOS foreground process handling (#9909)
# Description
Currently, foreground process management is disabled for macOS, since
the original code had issues (see #7068).
This PR re-enables process management on macOS in combination with the
changes from #9693.

# User-Facing Changes
Fixes hang on exit for nested nushells on macOS (issue #9859). Nushell
should now manage processes in the same way on macOS and other unix
systems.
2023-08-04 15:43:35 -05:00
71b74a284a add header_on_separator options to default_config.nu (#9922)
# Description

This PR adds the `header_on_separator` table option as `false` to the
`default_config.nu` file.

# 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 -- -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-05 07:24:20 +12:00
2b431f994f updates let-env signature to remove required params (#9917)
# Description

This PR changes the signature of the deprecated command `let-env` so
that it does not mislead people when invoking it without parameters.

### Before
```nushell
> let-env
Error: nu::parser::missing_positional

  × Missing required positional argument.
   ╭─[entry #2:1:1]
 1 │ let-env
   ╰────
  help: Usage: let-env <var_name> = <initial_value>
```

### After
```nushell
❯ let-env
Error: nu:🐚:deprecated_command

  × Deprecated command let-env
   ╭─[entry #1:1:1]
 1 │ let-env
   · ───┬───
   ·    ╰── 'let-env' is deprecated. Please use '$env.<environment variable> = ...' instead.
   ╰────
```

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

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -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-04 14:06:41 -05:00
7e096e61d7 Add an option to set header on border (style) (#9920)
fix #9796

Sorry that you've had the issues.
I've actually encountered them yesterday too (seems like they have
appeared after some refactoring in the middle) but was not able to fix
that rapid.

Created a bunch of tests.

cc: @fdncred 

Note:

This option will be certainly slower then a default ones. (could be
fixed but ... maybe later).
Maybe it shall be cited somewhere.

PS: Haven't tested on a wrapped/expanded tables.

---------

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2023-08-04 13:50:47 -05:00
9d7a1097f2 Fix default prompt indicators (#9914)
related to
- https://github.com/nushell/nushell/pull/9907

# Description
https://github.com/nushell/nushell/pull/9907 removed the front space
from all `PROMPT_INDICATOR`s but this is not what the default behaviour
of Nushell is, i.e. in `nu --no-config-file`.

this PR
- removes the space that is prepended by Nushell before the prompt
indicator to match the `default_env.nu`
- swaps INSERT and NORMAL in the Rust code to match the `:` and `>`
respectively in `default_env.nu`

## 🔍 try the changes
> **Warning**
> i had to comment out in my config all the `$env.PROMPT_INDICATOR... =
...` to avoid these variables to propagate to `cargo run -- -n`

in either `cargo run -- -n` or `cargo run -- --config
crates/nu-utils/src/sample_config/default_config.nu --env-config
crates/nu-utils/src/sample_config/default_env.nu`,
- see `/path/to/nushell>` as the prompt with the default `emacs` edit
mode
- run `$env.config.edit_mode = vi`
- see `/path/to/nushell:` as the INSERT prompt in Vi mode
- press Escape to go into NORMAL mode
- see `/path/to/nushell>` as the NORMAL prompt in Vi mode
- press I to go back into INSERT mode
- see `/path/to/nushell:` as the INSERT prompt in Vi mode

# User-Facing Changes
the prompts in `nu --no-config-file` and `nu --config default_config.nu
--env-config default_env.nu` should be the same 😌

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

# After Submitting
2023-08-05 04:47:46 +12:00
JT
a98b3124c5 Revert "Add an option to move header on borders" (#9908)
Reverts nushell/nushell#9796

This is just draft since we're seeing some issues with the latest fixes
to table drawing that just landed with #9796. We're hoping to get these
fixed, but if we're not able to fix them before the next release, we'll
need to revert (hence this PR, just in case we need it).
2023-08-03 14:52:12 -05:00
JT
572698bf3e Re-align how prompt indicators work (#9907)
# Description

An extra space slipped into the config alignment PR, and this fixes that
extra space.

# 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 -- -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-04 07:33:47 +12:00
7162289d77 Add an option to move header on borders (#9796)
A patch to play with.
Need to make a few tests after all.

The question is what shall be done with `table.mode = none`, as it has
no borders.

```nu
$env.config.table.move_header = true
```


![image](https://github.com/nushell/nushell/assets/20165848/cdcffa6d-989c-4368-a436-fdf7d3400e31)

cc: @fdncred

---------

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2023-08-04 07:03:20 +12:00
14bf25da14 rename from date format to format date (#9902)
# Description
Closes: #9891
I also think it's good to keep command name consistency.

And moving `date format` to deprecated.

# User-Facing Changes
Running `date format` will lead to deprecate message:
```nushell
❯ "2021-10-22 20:00:12 +01:00" | date format
Error: nu:🐚:deprecated_command

  × Deprecated command date format
   ╭─[entry #28:1:1]
 1 │ "2021-10-22 20:00:12 +01:00" | date format
   ·                                ─────┬─────
   ·                                     ╰── 'date format' is deprecated. Please use 'format date' instead.
   ╰────
```
2023-08-04 06:06:00 +12:00
a455e2e5eb remove vectorize_over_list from python plugin (#9905)
# Description

This PR brings our python plugin example inline with our new signature
by removing `vectorize_over_list` from the plugin.
2023-08-03 16:46:48 +02:00
JT
840b4b854b Simplify default style and match Rust code to config (#9900)
# Description

This PR aligns the default config in the Rust code to the default config
in the nushell file.

To do so, it removes closures from the default file, opting instead to
pick a simple style as default. This allows easier maintenance of both
Rust and Nushell code without removing the ability to use closures for
styling in your configuration.

The default theme is now "dark mode" in both the Rust and nushell config
code.

Obligatory screenshot:


![image](https://github.com/nushell/nushell/assets/547158/233b11af-3b81-4513-8a69-3e7b1cac3865)


# 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 -- -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-03 08:06:51 +12:00
ec4941c8ac update format signature to allow record to be passed in (#9898)
# Description

This PR updates the signature of `format` to allow records to be passed
in.

Closes #9897 

### Before
```nushell
{name: Downloads} | format "{name}"

  × Command does not support record<name: string> input.
   ╭─[entry #12:1:1]
 1 │ {name: Downloads} | format "{name}"
   ·                       ───┬──
   ·                          ╰── command doesn't support record<name: string> input
   ╰────
```

### After
```nushell
{name: Downloads} | format "{name}"
Downloads
```

# 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 -- -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-02 10:57:58 -05:00
dd86f14a5a update items signature to allow any output (#9896)
# Description

This PR updates the `items` command to allow `any` output. items takes a
closure so theoretically, any value type of output could be valid.

### Before
```nushell
{a: 1 b: 2} | items {|k,v| {key: $k value: $v}} | transpose
Error: nu::parser::input_type_mismatch

  × Command does not support list<string> input.
   ╭─[entry #2:1:1]
 1 │ {a: 1 b: 2} | items {|k,v| {key: $k value: $v}} | transpose
   ·                                                   ────┬────
   ·                                                       ╰── command doesn't support list<string> input
   ╰────
```

### After
```nushell
❯ {a: 1 b: 2} | items {|k,v| {key: $k value: $v}} | transpose
╭───┬─────────┬─────────┬─────────╮
│ # │ column0 │ column1 │ column2 │
├───┼─────────┼─────────┼─────────┤
│ 0 │ key     │ a       │ b       │
│ 1 │ value   │       1 │       2 │
╰───┴─────────┴─────────┴─────────╯
```
# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -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-02 08:42:26 -05:00
63103580d2 update char signature with Table (#9895)
# Description

This PR updates the `char` command to allow `Table` output due to the
`--list` parameter.

### Before
```nushell
char --list | transpose
Error: nu::parser::input_type_mismatch

  × Command does not support string input.
   ╭─[entry #6:1:1]
 1 │ char --list | transpose
   ·               ────┬────
   ·                   ╰── command doesn't support string input
   ╰────
```

### After
```nushell
❯ char --list | transpose
╭───┬───────────┬─────────┬─────────┬─────────┬───────────┬─────────┬─────────────┬─────────┬─────────┬─────────┬──────────┬──────────┬──────────┬────────────┬──────────┬─────────────┬──────────┬────────────┬──────────┬──────────┬─────╮
│ # │  column0  │ column1 │ column2 │ column3 │  column4  │ column5 │   column6   │ column7 │ column8 │ column9 │ column10 │ column11 │ column12 │  column13  │ column14 │  column15   │ column16 │  column17  │ column18 │ column19 │ ... │
├───┼───────────┼─────────┼─────────┼─────────┼───────────┼─────────┼─────────────┼─────────┼─────────┼─────────┼──────────┼──────────┼──────────┼────────────┼──────────┼─────────────┼──────────┼────────────┼──────────┼──────────┼─────┤
│ 0 │ name      │ newline │ enter   │ nl      │ line_feed │ lf      │ carriage_re │ cr      │ crlf    │ tab     │ sp       │ space    │ pipe     │ left_brace │ lbrace   │ right_brace │ rbrace   │ left_paren │ lp       │ lparen   │ ... │
│   │           │         │         │         │           │         │ turn        │         │         │         │          │          │          │            │          │             │          │            │          │          │     │
│ 1 │ character │         │         │         │           │         │             │         │         │         │          │          │ |        │ {          │ {        │ }           │ }        │ (          │ (        │ (        │ ... │
│   │           │         │         │         │           │         │             │         │         │         │          │          │          │            │          │             │          │            │          │          │     │
│ 2 │ unicode   │ a       │ a       │ a       │ a         │ a       │ d           │ d       │ d a     │ 9       │ 20       │ 20       │ 7c       │ 7b         │ 7b       │ 7d          │ 7d       │ 28         │ 28       │ 28       │ ... │
╰───┴───────────┴─────────┴─────────┴─────────┴───────────┴─────────┴─────────────┴─────────┴─────────┴─────────┴──────────┴──────────┴──────────┴────────────┴──────────┴─────────────┴──────────┴────────────┴──────────┴──────────┴─────╯
```

# 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 -- -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-02 08:42:13 -05:00
JT
d25df9c00b Revert 9693 to prevent CPU hangs (#9893)
# Description

This reverts #9693 as it lead to CPU hangs. (btw, did the revert by hand
as it couldn't be done automatically. Hopefully I didn't miss anything 😅
)

Fixes #9859

cc @IanManske 

# 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 -- -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-02 11:24:28 +12:00
778a00efa1 update to current reedline (#9877)
# Description

This PR updates nushell to use the latest reedline. I swear that was the
only change I made. The other reordering stuff is by my vscode extension
I guess.

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

# 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 -- -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-01 15:30:31 -05:00
fea822792f Fixed the panic when type a statement similar to let f = 'f' $ in the nushell (#9851)
- this PR should close #9596 
- fixes #9596 
- this PR should close #9826 
- fixes #9826 

fixed the following bugs:
```nu
# type following statements in the nushell
let f = 'f' $;
mut f = 'f' $;
const f = 'f' $;

# then remove variable f, it will panics
let = 'f' $;
mut  = 'f' $;
const = 'f' $;
```
2023-08-02 04:21:40 +12:00
f6033ac5af Module: support defining const and use const variables inside of function (#9773)
<!--
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.
-->
Relative: #8248 

After this pr, user can define const variable inside a module.

![image](https://github.com/nushell/nushell/assets/22256154/e3e03e56-c4b5-4144-a944-d1b20bec1cbd)

And user can export const variables, the following screenshot shows how
it works (it follows
https://github.com/nushell/nushell/issues/8248#issuecomment-1637442612):

![image](https://github.com/nushell/nushell/assets/22256154/b2c14760-3f27-41cc-af77-af70a4367f2a)

## About the change
1. To make module support const, we need to change `parse_module_block`
to support `const` keyword.
2. To suport export `const`, we need to make module tracking variables,
so we add `variables` attribute to `Module`
3. During eval, the const variable may not exists in `stack`, because we
don't eval `const` when we define a module, so we need to find variables
which are already registered in `engine_state`

## One more thing to note about the const value.
Consider the following code
```
module foo { const b = 3; export def bar [] { $b } }
use foo bar
const b = 4;
bar
```
The result will be 3 (which is defined in module) rather than 4. I think
it's expected behavior.

It's something like [dynamic
binding](https://www.gnu.org/software/emacs/manual/html_node/elisp/Dynamic-Binding-Tips.html)
vs [lexical
binding](https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html)
in lisp like language, and lexical binding should be right behavior
which generates more predicable result, and it doesn't introduce really
subtle bugs in nushell code.

What if user want dynamic-binding?(For example: the example code returns
`4`)
There is no way to do this, user should consider passing the value as
argument to custom command rather than const.

## TODO
- [X] adding tests for the feature.
- [X] support export const out of module to use.

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

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -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-01 07:09:52 +08:00
583ef8674e Replace &Span with Span since Span is Copy (#9770)
# Description
`Span` is `Copy`, so we probably should not be passing references of
`Span` around. This PR replaces all instances of `&Span` with `Span`,
copying spans where necessary.

# User-Facing Changes
This alters some public functions to take `Span` instead of `&Span` as
input. Namely, `EngineState::get_span_contents`,
`nu_protocol::extract_value`, a bunch of the math commands, and
`Gstat::gstat`.
2023-07-31 21:47:46 +02:00
94bec72079 str-expand: add path flag (#9856)
Related issues: #9838

Changes:

- added `--path` flag, for ease of use if the piped data is Path
(replaces all backslashes with double backslashes)
2023-07-31 07:48:29 -05:00
28ed21864d fixed the bug ~ | path type return empty string (#9853)
- this PR should close #9849 
- fixes #9849
2023-07-31 07:47:18 -05:00
e16ce1df36 str-expand: Add Escaping Example (#9841)
**Related Issue: #9838**

Adds an **example**, how bracoxide/str-expand handles the escaping char
`\`.
2023-07-31 07:45:39 -05:00
87abfee268 Merged overloaded commands (#9860)
- fixes #9807

# Description

This pull request merges all overloaded dfr commands into one command:

eager:
dfr first -> eager/first.rs
dfr last -> eager/last.rs
dfr into-nu -> eager/to_nu.rs (merged)

lazy:
dfr min -> expressions/expressions_macro.rs lazy_expressions_macro
dfr max -> expressions/expressions_macro.rs lazy_expressions_macro
dfr sum -> expressions/expressions_macro.rs lazy_expressions_macro
dfr mean -> expressions/expressions_macro.rs lazy_expressions_macro
dfr std -> expressions/expressions_macro.rs lazy_expressions_macro
dfr var   -> expressions/expressions_macro.rs lazy_expressions_macro

series:
dfr n-unique -> series/n_unique.rs
dfr is-not-null -> series/masks/is_not_null.rs
dfr is-null -> series/masks/is_null.rs

# User-Facing Changes
No user facing changes

---------

Co-authored-by: Jack Wright <jack.wright@disqo.com>
2023-07-31 07:34:12 -05:00
ba0f069c31 Turn bare URLs into cliclable links (#9854)
This PR adds angle brackets to URLs, making them clickable when reading
documentation.
2023-07-30 22:50:25 +02:00
154856066f Accept records for http subcommand headers (-H) (#9771)
# Description

See also: #9743 
Before: 
`http <subcommand> -H` took a list in the form:

```nushell
[my-header-key-A my-header-value-A my-header-key-B my-header-value-B]
```

Now:
In addition to the old format, Records can be passed, For example,
```nushell
> let reqHeaders = {
    Cookie:  "acc=barfoo",
    User-Agent: "Mozilla/7.0 (Windows NT 33.0; Win64; x64) AppleWebKit/1038.90 (KHTML, like Gecko)"
}
> http get -H $reqHeaders https://example.com
```

is now equivalent to
```nushell
http get -H [Cookie "acc=barfoo" User-Agent "Mozilla/7.0 (Windows NT 33.0; Win64; x64) AppleWebKit/1038.90 (KHTML, like Gecko)"] https://example.com
```

# User-Facing Changes
No breaking changes, but Records can now also be passed to `http
<subcommand> -H`.

# Tests + Formatting
# After Submitting
2023-07-30 22:28:48 +02:00
f91713b714 Add format duration to replace into duration --convert (#9788)
# Description
Add `format duration` cmd to choose output unit.

This takes the previous `into duration --convert ...` behavior which
returned a string into its own `format duration` command.
This was suprising and not fitting with the general type signature for
the `into ...` commands.

This command for now lives in the `nu-cmd-extra` nursery.

# User-Facing Changes
## Breaking change
Removes formatting behavior from `into duration`
Now use `format duration` instead of `into duration --convert`
## Usage:
```
1sec | format duration us # Output data in microseconds
"2ms" | into duration | format duration sec # go from string to string
```


# Tests + Formatting
Basic example testing (including basic broadcast)
2023-07-30 22:23:36 +02:00
f1bf485b2a Update unicode-linebreak to 0.1.5 (#9814)
# Description
This deduplicates `ahash` as it was previously an outdated
build-dependency of `unicode-linebreak`

Should provide a small benefit to initial from scratch compile.


# User-Facing Changes
None
2023-07-30 22:17:36 +02:00
955de76116 bump to dev version 0.83.2 (#9866)
# Description

This PR bumps the development version of nushell to version 0.83.2.
2023-07-30 22:16:57 +02:00
299 changed files with 8021 additions and 5083 deletions

View File

@ -24,7 +24,7 @@ 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 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

View File

@ -9,7 +9,7 @@ name: continuous-integration
env:
NUSHELL_CARGO_TARGET: ci
NU_LOG_LEVEL: DEBUG
CLIPPY_OPTIONS: "-D warnings -D clippy::unwrap_used -A clippy::needless_collect -A clippy::result_large_err"
CLIPPY_OPTIONS: "-D warnings -D clippy::unwrap_used"
jobs:
fmt-clippy:
@ -115,21 +115,12 @@ jobs:
with:
python-version: "3.10"
- run: python -m pip install tox
- name: Install virtualenv
run: git clone https://github.com/pypa/virtualenv.git
run: pip install virtualenv
shell: bash
- name: Test Nushell in virtualenv
run: |
cd virtualenv
# if we encounter problems with bleeding edge tests pin to the latest tag
# git checkout $(git describe --tags | cut -d - -f 1)
# We need to disable failing on coverage levels.
nu -c "open pyproject.toml | upsert tool.coverage.report.fail_under 1 | save patchproject.toml"
mv patchproject.toml pyproject.toml
tox -e ${{ matrix.py }} -- -k nushell
run: nu scripts/test_virtualenv.nu
shell: bash
plugins:

View File

@ -14,7 +14,7 @@ jobs:
winget:
name: Publish winget package
runs-on: windows-latest
runs-on: ubuntu-latest
steps:
- name: Submit package to Windows Package Manager Community Repository
uses: vedantmgoyal2009/winget-releaser@v2

View File

@ -2,7 +2,20 @@
Welcome to Nushell and thank you for considering contributing!
## Review Process
## Table of contents
- [Proposing design changes](#proposing-design-changes)
- [Developing](#developing)
- [Setup](#setup)
- [Tests](#tests)
- [Useful commands](#useful-commands)
- [Debugging tips](#debugging-tips)
- [Git etiquette](#git-etiquette)
- [Our Rust style](#our-rust-style)
- [Generally discouraged](#generally-discouraged)
- [Things we want to get better at](#things-we-want-to-get-better-at)
- [License](#license)
## Proposing design changes
First of all, before diving into the code, if you want to create a new feature, change something significantly, and especially if the change is user-facing, it is a good practice to first get an approval from the core team before starting to work on it.
This saves both your and our time if we realize the change needs to go another direction before spending time on it.
@ -41,10 +54,13 @@ Tests can be found in different places:
* command examples
* crate-specific tests
The most comprehensive test suite we have is the `nu-test-support` crate. For testing specific features, such as running Nushell in a REPL mode, we have so called "testbins". For simple tests, you can find `run_test()` and `fail_test()` functions.
Most of the tests are built upon the `nu-test-support` crate. For testing specific features, such as running Nushell in a REPL mode, we have so called "testbins". For simple tests, you can find `run_test()` and `fail_test()` functions.
### Useful Commands
As Nushell is build using a cargo workspace consisting of multiple crates keep in mind that you may need to pass additional flags compared to how you may be used to it from a single crate project.
Read cargo's documentation for more details: https://doc.rust-lang.org/cargo/reference/workspaces.html
- Build and run Nushell:
```shell
@ -59,7 +75,7 @@ The most comprehensive test suite we have is the `nu-test-support` crate. For te
- Run Clippy on Nushell:
```shell
cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect -A clippy::result_large_err
cargo clippy --workspace -- -D warnings -D clippy::unwrap_used
```
or via the `toolkit.nu` command:
```shell
@ -220,7 +236,52 @@ You can help us to make the review process a smooth experience:
- Choose what simplifies having confidence in the conflict resolution and the review. **Merge commits in your branch are OK** in the squash model.
- Feel free to notify your reviewers or affected PR authors if your change might cause larger conflicts with another change.
- During the rollup of multiple PRs, we may choose to resolve merge conflicts and CI failures ourselves. (Allow maintainers to push to your branch to enable us to do this quickly.)
## Our Rust style
To make the collaboration on a project the scale of Nushell easy, we want to work towards a style of Rust code that can easily be understood by all of our contributors. We conservatively rely on most of [`clippy`s suggestions](https://github.com/rust-lang/rust-clippy) to get to the holy grail of "idiomatic" code. Good code in our eyes is not the most clever use of all available language features or with the most unique personal touch but readable and strikes a balance between being concise, and also unsurprising and explicit in the places where it matters.
One example of this philosophy is that we generally avoid to fight the borrow-checker in our data model but rather try to get to a correct and simple solution first and then figure out where we should reuse data to achieve the necessary performance. As we are still pre-1.0 this served us well to be able to quickly refactor or change larger parts of the code base.
### License
### Generally discouraged
#### `+nightly` language features or things only available in the most recent `+stable`
To make life for the people easier that maintain the Nushell packages in various distributions with their own release cycle of `rustc` we typically rely on slightly older Rust versions. We do not make explicit guarantees how far back in the past we live but you can find out in our [`rust-toolchain.toml`](https://github.com/nushell/nushell/blob/main/rust-toolchain.toml)
(As a rule of thumb this has been typically been approximately 2 releases behind the newest stable compiler.)
The use of nightly features is prohibited.
#### Panicking
As Nushell aims to provide a reliable foundational way for folks to interact with their computer, we cannot carelessly crash the execution of their work by panicking Nushell.
Thus panicking is not an allowed error handling strategy for anything that could be triggered by user input OR behavior of the outside system. If Nushell panics this is a bug or we are against all odds already in an unrecoverable state (The system stopped cooperating, we went out of memory). The use of `.unwrap()` is thus outright banned and any uses of `.expect()` or related panicking macros like `unreachable!` should include a helpful description which assumptions have been violated.
#### `unsafe` code
For any use of `unsafe` code we need to require even higher standards and additional review. If you add or alter `unsafe` blocks you have to be familiar with the promises you need to uphold as found in the [Rustonomicon](https://doc.rust-lang.org/nomicon/intro.html). All `unsafe` uses should include `// SAFETY:` comments explaining how the invariants are upheld and thus alerting you what to watch out for when making a change.
##### FFI with system calls and the outside world
As a shell Nushell needs to interact with system APIs in several places, for which FFI code with unsafe blocks may be necessary. In some cases this can be handled by safe API wrapper crates but in some cases we may choose to directly do those calls.
If you do so you need to document the system behavior on top of the Rust memory model guarantees that you uphold. This means documenting whether using a particular system call is safe to use in a particular context and all failure cases are properly recovered.
##### Implementing self-contained data structures
Another motivation for reaching to `unsafe` code might be to try to implement a particular data structure that is not expressible on safe `std` library APIs. Doing so in the Nushell code base would have to clear a high bar for need based on profiling results. Also you should first do a survey of the [crate ecosystem](https://crates.io) that there doesn't exist a usable well vetted crate that already provides safe APIs to the desired datastructure.
##### Make things go faster by removing checks
This is probably a bad idea if you feel tempted to do so. Don't
#### Macros
Another advanced feature people feel tempted to use to work around perceived limitations of Rusts syntax and we are not particularly fans of are custom macros.
They have clear downsides not only in terms of readability if they locally introduce a different syntax. Most tooling apart from the compiler will struggle more with them. This limits for example consistent automatic formatting or automated refactors with `rust-analyzer`.
That you can fluently read `macro_rules!` is less likely than regular code. This can lead people to introduce funky behavior when using a macro. Be it because a macro is not following proper hygiene rules or because it introduces excessive work at compile time.
So we generally discourage the addition of macros. In a lot of cases your macro may start do something that can be expressed with functions or generics in a much more reusable fashion.
The only exceptions we may allow need to demonstrate that the macro can fix something that is otherwise extremely unreadable, error-prone, or consistently worse at compile time.
### Things we want to get better at
These are things we did pretty liberally to get Nushell off the ground, that make things harder for a high quality stable product. You may run across them but shouldn't take them as an endorsed example.
#### Liberal use of third-party dependencies
The amazing variety of crates on [crates.io](https://crates.io) allowed us to quickly get Nushell into a feature rich state but it left us with a bunch of baggage to clean up.
Each dependency introduces a compile time cost and duplicated code can add to the overall binary size. Also vetting more for correct and secure implementations takes unreasonably more time as this is also a continuous process of reacting to updates or potential vulnerabilities.
Thus we only want to accept dependencies that are essential and well tested implementations of a particular requirement of Nushells codebase.
Also as a project for the move to 1.0 we will try to unify among a set of dependencies if they possibly implement similar things in an area. We don't need three different crates with potentially perfect fit for three problems but rather one reliable crate with a maximized overlap between what it provides and what we need.
We will favor crates that are well tested and used and promise to be more stable and still frequently maintained.
#### Deeply nested code
As Nushell uses a lot of enums in its internal data representation there are a lot of `match` expressions. Combined with the need to handle a lot of edge cases and be defensive about any errors this has led to some absolutely hard to read deeply nested code (e.g. in the parser but also in the implementation of several commands).
This can be observed both as a "rightward drift" where the main part of the code is found after many levels of indentations or by long function bodies with several layers of branching with seemingly repeated branching inside the higher branch level.
This can also be exacerbated by "quick" bugfixes/enhancements that may just try to add a special case to catch a previously unexpected condition. The likelihood of introducing a bug in a sea of code duplication is high.
To combat this, consider using the early-`return` pattern to reject invalid data early in one place instead of building a tree through Rust's expression constructs with a lot of duplicated paths. Unpacking data into a type that expresses that the necessary things already have been checked and using functions to properly deal with separate and common behavior can also help.
## License
We use the [MIT License](https://github.com/nushell/nushell/blob/main/LICENSE) in all of our Nushell projects. If you are including or referencing a crate that uses the [GPL License](https://www.gnu.org/licenses/gpl-3.0.en.html#license-text) unfortunately we will not be able to accept your PR.

229
Cargo.lock generated
View File

@ -28,15 +28,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "ahash"
version = "0.7.6"
name = "adler32"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
dependencies = [
"getrandom",
"once_cell",
"version_check",
]
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
name = "ahash"
@ -123,7 +118,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "220044e6a1bb31ddee4e3db724d29767f352de47445a6cd75e1a173142136c83"
dependencies = [
"nom",
"vte",
"vte 0.10.1",
]
[[package]]
@ -175,8 +170,9 @@ version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15ae0428d69ab31d7b2adad22a752d6f11fef2e901d2262d0cad4f5cb08b7093"
dependencies = [
"ahash 0.8.3",
"ahash",
"arrow-format",
"avro-schema",
"base64",
"bytemuck",
"chrono",
@ -284,6 +280,20 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "avro-schema"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5281855b39aba9684d2f47bf96983fbfd8f1725f12fabb0513a8ab879647bbd"
dependencies = [
"crc",
"fallible-streaming-iterator",
"libflate",
"serde",
"serde_json",
"snap",
]
[[package]]
name = "backtrace"
version = "0.3.68"
@ -372,9 +382,9 @@ dependencies = [
[[package]]
name = "bracoxide"
version = "0.1.1"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae76c117551a0459f61c57b573271778214287482c346d14591d2ea250ecbea5"
checksum = "d8654ced31d3071e01cee9112fb25f241798b17b08d083512f8da2afa3da076b"
[[package]]
name = "brotli"
@ -751,6 +761,21 @@ dependencies = [
"libc",
]
[[package]]
name = "crc"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49fc9a695bca7f35f5f4c15cddc84415f66a74ea78eef08e90c5024f2b540e23"
dependencies = [
"crc-catalog",
]
[[package]]
name = "crc-catalog"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403"
[[package]]
name = "crc32fast"
version = "1.3.2"
@ -1393,6 +1418,12 @@ version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
[[package]]
name = "futures-timer"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
[[package]]
name = "futures-util"
version = "0.3.28"
@ -1550,9 +1581,6 @@ name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
dependencies = [
"ahash 0.7.6",
]
[[package]]
name = "hashbrown"
@ -1560,7 +1588,7 @@ version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
dependencies = [
"ahash 0.8.3",
"ahash",
"rayon",
]
@ -1570,7 +1598,7 @@ version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
dependencies = [
"ahash 0.8.3",
"ahash",
"allocator-api2",
]
@ -2030,6 +2058,26 @@ version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "libflate"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ff4ae71b685bbad2f2f391fe74f6b7659a34871c08b210fdc039e43bee07d18"
dependencies = [
"adler32",
"crc32fast",
"libflate_lz77",
]
[[package]]
name = "libflate_lz77"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a52d3a8bfc85f250440e4424db7d857e241a3aebbbe301f3eb606ab15c39acbf"
dependencies = [
"rle-decode-fast",
]
[[package]]
name = "libgit2-sys"
version = "0.15.2+1.6.4"
@ -2502,7 +2550,7 @@ dependencies = [
[[package]]
name = "nu"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"assert_cmd",
"criterion",
@ -2559,7 +2607,7 @@ dependencies = [
[[package]]
name = "nu-cli"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"chrono",
"crossterm",
@ -2590,7 +2638,7 @@ dependencies = [
[[package]]
name = "nu-cmd-base"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"indexmap 2.0.0",
"nu-engine",
@ -2600,7 +2648,7 @@ dependencies = [
[[package]]
name = "nu-cmd-dataframe"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"chrono",
"fancy-regex",
@ -2612,15 +2660,17 @@ dependencies = [
"nu-test-support",
"num 0.4.0",
"polars",
"polars-io",
"serde",
"sqlparser",
]
[[package]]
name = "nu-cmd-extra"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"ahash 0.8.3",
"Inflector",
"ahash",
"fancy-regex",
"htmlescape",
"nu-ansi-term",
@ -2642,7 +2692,7 @@ dependencies = [
[[package]]
name = "nu-cmd-lang"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"fancy-regex",
"itertools",
@ -2656,7 +2706,7 @@ dependencies = [
[[package]]
name = "nu-color-config"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"nu-ansi-term",
"nu-engine",
@ -2669,9 +2719,8 @@ dependencies = [
[[package]]
name = "nu-command"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"Inflector",
"alphanumeric-sort",
"base64",
"bracoxide",
@ -2734,7 +2783,7 @@ dependencies = [
"percent-encoding",
"powierza-coefficient",
"print-positions",
"quick-xml 0.29.0",
"quick-xml 0.30.0",
"quickcheck",
"quickcheck_macros",
"rand",
@ -2769,7 +2818,7 @@ dependencies = [
[[package]]
name = "nu-engine"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"nu-glob",
"nu-path",
@ -2780,7 +2829,7 @@ dependencies = [
[[package]]
name = "nu-explore"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"ansi-str",
"crossterm",
@ -2800,14 +2849,14 @@ dependencies = [
[[package]]
name = "nu-glob"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"doc-comment",
]
[[package]]
name = "nu-json"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"linked-hash-map",
"num-traits",
@ -2816,7 +2865,7 @@ dependencies = [
[[package]]
name = "nu-parser"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"bytesize",
"chrono",
@ -2832,7 +2881,7 @@ dependencies = [
[[package]]
name = "nu-path"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"dirs-next",
"omnipath",
@ -2841,7 +2890,7 @@ dependencies = [
[[package]]
name = "nu-plugin"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"bincode",
"nu-engine",
@ -2853,7 +2902,7 @@ dependencies = [
[[package]]
name = "nu-pretty-hex"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"heapless",
"nu-ansi-term",
@ -2862,7 +2911,7 @@ dependencies = [
[[package]]
name = "nu-protocol"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"byte-unit",
"chrono",
@ -2874,6 +2923,7 @@ dependencies = [
"nu-test-support",
"nu-utils",
"num-format",
"rstest",
"serde",
"serde_json",
"strum 0.25.0",
@ -2884,7 +2934,7 @@ dependencies = [
[[package]]
name = "nu-std"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"miette",
"nu-engine",
@ -2894,7 +2944,7 @@ dependencies = [
[[package]]
name = "nu-system"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"chrono",
"is-terminal",
@ -2911,7 +2961,7 @@ dependencies = [
[[package]]
name = "nu-table"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"nu-ansi-term",
"nu-color-config",
@ -2923,7 +2973,7 @@ dependencies = [
[[package]]
name = "nu-term-grid"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"nu-utils",
"unicode-width",
@ -2931,7 +2981,7 @@ dependencies = [
[[package]]
name = "nu-test-support"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"hamcrest2",
"nu-glob",
@ -2944,7 +2994,7 @@ dependencies = [
[[package]]
name = "nu-utils"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"crossterm_winapi",
"log",
@ -2966,7 +3016,7 @@ dependencies = [
[[package]]
name = "nu_plugin_example"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"nu-plugin",
"nu-protocol",
@ -2974,7 +3024,7 @@ dependencies = [
[[package]]
name = "nu_plugin_formats"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"eml-parser",
"ical",
@ -2986,7 +3036,7 @@ dependencies = [
[[package]]
name = "nu_plugin_gstat"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"git2",
"nu-plugin",
@ -2995,7 +3045,7 @@ dependencies = [
[[package]]
name = "nu_plugin_inc"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"nu-plugin",
"nu-protocol",
@ -3004,7 +3054,7 @@ dependencies = [
[[package]]
name = "nu_plugin_query"
version = "0.83.1"
version = "0.84.0"
dependencies = [
"gjson",
"nu-engine",
@ -3303,9 +3353,9 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
[[package]]
name = "papergrid"
version = "0.9.1"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae7891b22598926e4398790c8fe6447930c72a67d36d983a49d6ce682ce83290"
checksum = "a2ccbe15f2b6db62f9a9871642746427e297b0ceb85f9a7f1ee5ff47d184d0c8"
dependencies = [
"ansi-str",
"ansitok",
@ -3611,7 +3661,7 @@ version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b7216aa3336fd2a7b5ebfa66748f3770682b28cd682930d1abf59b53b670e0"
dependencies = [
"ahash 0.8.3",
"ahash",
"arrow2",
"bitflags 1.3.2",
"chrono",
@ -3654,7 +3704,7 @@ version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "270650704e08bef37d227a6904b36c4bdad2d013536ea3c57f40007c19ad2ebc"
dependencies = [
"ahash 0.8.3",
"ahash",
"arrow2",
"async-trait",
"bytes",
@ -3689,7 +3739,7 @@ version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7370203bca4ee29da6da4210200894eea6abf81d7c430e192159dabcba8441a4"
dependencies = [
"ahash 0.8.3",
"ahash",
"arrow2",
"fallible-streaming-iterator",
"hashbrown 0.13.2",
@ -3707,7 +3757,7 @@ version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2a8fe41263496b5212098f19d0cdddc11f75c71957a09d2ce300a8fdb4407e3"
dependencies = [
"ahash 0.8.3",
"ahash",
"bitflags 1.3.2",
"glob",
"once_cell",
@ -3767,7 +3817,7 @@ version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a7d0f48bdd7fa9474f718ecb99fc12d97671933707091a249bb0da96b30f291"
dependencies = [
"ahash 0.8.3",
"ahash",
"arrow2",
"once_cell",
"polars-arrow",
@ -3834,7 +3884,7 @@ version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "145a59f928f8317fcf543407ef1b83e827448462e05e2fc6444162fcec84386a"
dependencies = [
"ahash 0.8.3",
"ahash",
"hashbrown 0.13.2",
"once_cell",
"rayon",
@ -3986,9 +4036,9 @@ dependencies = [
[[package]]
name = "quick-xml"
version = "0.29.0"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81b9228215d82c7b61490fec1de287136b5de6f5700f6e58ea9ad61a7964ca51"
checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956"
dependencies = [
"memchr",
]
@ -4130,9 +4180,9 @@ dependencies = [
[[package]]
name = "reedline"
version = "0.22.0"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2fde955d11817fdcb79d703932fb6b473192cb36b6a92ba21f7f4ac0513374e"
checksum = "3defc4467a8909614bcb02cb304a3e8472c31f7a44e6c6c287eb9575b212bc4d"
dependencies = [
"chrono",
"crossterm",
@ -4191,6 +4241,18 @@ version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846"
[[package]]
name = "relative-path"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bf2521270932c3c7bed1a59151222bd7643c79310f2916f01925e1e16255698"
[[package]]
name = "rle-decode-fast"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422"
[[package]]
name = "rmp"
version = "0.8.11"
@ -4224,25 +4286,30 @@ dependencies = [
[[package]]
name = "rstest"
version = "0.17.0"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de1bb486a691878cd320c2f0d319ba91eeaa2e894066d8b5f8f117c000e9d962"
checksum = "2b96577ca10cb3eade7b337eb46520108a67ca2818a24d0b63f41fd62bc9651c"
dependencies = [
"futures",
"futures-timer",
"rstest_macros",
"rustc_version",
]
[[package]]
name = "rstest_macros"
version = "0.17.0"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290ca1a1c8ca7edb7c3283bd44dc35dd54fdec6253a3912e201ba1072018fca8"
checksum = "225e674cf31712b8bb15fdbca3ec0c1b9d825c5a24407ff2b7e005fb6a29ba03"
dependencies = [
"cfg-if",
"glob",
"proc-macro2",
"quote",
"regex",
"relative-path",
"rustc_version",
"syn 1.0.109",
"syn 2.0.23",
"unicode-ident",
]
@ -4418,7 +4485,7 @@ version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c95a930e03325234c18c7071fd2b60118307e025d6fff3e12745ffbf63a3d29c"
dependencies = [
"ahash 0.8.3",
"ahash",
"cssparser",
"ego-tree",
"html5ever",
@ -4651,7 +4718,7 @@ version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3d0815e7ff0f1f05e09d4b029f86d8a330f0ab15b35b28736f3758325f59e14"
dependencies = [
"ahash 0.8.3",
"ahash",
"halfbrown",
"lexical-core",
"once_cell",
@ -4819,11 +4886,11 @@ dependencies = [
[[package]]
name = "strip-ansi-escapes"
version = "0.1.1"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "011cbb39cf7c1f62871aea3cc46e5817b0937b49e9447370c93cacbe93a766d8"
checksum = "55ff8ef943b384c414f54aefa961dd2bd853add74ec75e7ac74cf91dba62bcfa"
dependencies = [
"vte",
"vte 0.11.1",
]
[[package]]
@ -4962,9 +5029,9 @@ dependencies = [
[[package]]
name = "tabled"
version = "0.12.2"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce69a5028cd9576063ec1f48edb2c75339fd835e6094ef3e05b3a079bf594a6"
checksum = "dfe9c3632da101aba5131ed63f9eed38665f8b3c68703a6bb18124835c1a5d22"
dependencies = [
"ansi-str",
"ansitok",
@ -5358,13 +5425,9 @@ checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73"
[[package]]
name = "unicode-linebreak"
version = "0.1.4"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5faade31a542b8b35855fff6e8def199853b2da8da256da52f52f1316ee3137"
dependencies = [
"hashbrown 0.12.3",
"regex",
]
checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
[[package]]
name = "unicode-normalization"
@ -5489,6 +5552,16 @@ dependencies = [
"vte_generate_state_changes",
]
[[package]]
name = "vte"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197"
dependencies = [
"utf8parse",
"vte_generate_state_changes",
]
[[package]]
name = "vte_generate_state_changes"
version = "0.1.1"

View File

@ -11,7 +11,7 @@ license = "MIT"
name = "nu"
repository = "https://github.com/nushell/nushell"
rust-version = "1.60"
version = "0.83.1"
version = "0.84.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -46,35 +46,34 @@ members = [
]
[dependencies]
nu-cli = { path = "./crates/nu-cli", version = "0.83.1" }
nu-color-config = { path = "./crates/nu-color-config", version = "0.83.1" }
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.83.1" }
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.83.1" }
nu-cmd-dataframe = { path = "./crates/nu-cmd-dataframe", version = "0.83.1", optional = true }
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.83.1", optional = true }
nu-command = { path = "./crates/nu-command", version = "0.83.1" }
nu-engine = { path = "./crates/nu-engine", version = "0.83.1" }
nu-explore = { path = "./crates/nu-explore", version = "0.83.1" }
nu-json = { path = "./crates/nu-json", version = "0.83.1" }
nu-parser = { path = "./crates/nu-parser", version = "0.83.1" }
nu-path = { path = "./crates/nu-path", version = "0.83.1" }
nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.83.1" }
nu-pretty-hex = { path = "./crates/nu-pretty-hex", version = "0.83.1" }
nu-protocol = { path = "./crates/nu-protocol", version = "0.83.1" }
nu-system = { path = "./crates/nu-system", version = "0.83.1" }
nu-table = { path = "./crates/nu-table", version = "0.83.1" }
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.83.1" }
nu-std = { path = "./crates/nu-std", version = "0.83.1" }
nu-utils = { path = "./crates/nu-utils", version = "0.83.1" }
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-ansi-term = "0.49.0"
reedline = { version = "0.22.0", features = ["bashisms", "sqlite"]}
mimalloc = { version = "0.1.37", default-features = false, optional = true}
reedline = { version = "0.23.0", features = ["bashisms", "sqlite"]}
crossterm = "0.26"
ctrlc = "3.4"
log = "0.4"
miette = { version = "5.10", features = ["fancy-no-backtrace"] }
mimalloc = { version = "0.1.37", default-features = false, optional = true}
serde_json = "1.0"
simplelog = "0.12"
time = "0.3"
@ -97,13 +96,13 @@ nix = { version = "0.26", default-features = false, features = [
is-terminal = "0.4.8"
[dev-dependencies]
nu-test-support = { path = "./crates/nu-test-support", version = "0.83.1" }
tempfile = "3.7"
nu-test-support = { path = "./crates/nu-test-support", version = "0.84.0" }
assert_cmd = "2.0"
criterion = "0.5"
pretty_assertions = "1.4"
rstest = { version = "0.18", default-features = false }
serial_test = "2.0"
rstest = { version = "0.17", default-features = false }
tempfile = "3.7"
[features]
plugin = [

View File

@ -1,9 +1,18 @@
# Configuration for cross-rs: https://github.com/cross-rs/cross
# Run cross-rs like this:
# cross build --target aarch64-unknown-linux-musl --release
# cross build --target aarch64-unknown-linux-gnu --release
# or
# cross build --target aarch64-unknown-linux-musl --release --features=static-link-openssl
[target.aarch64-unknown-linux-gnu]
dockerfile = "./docker/cross-rs/aarch64-unknown-linux-gnu.dockerfile"
pre-build = [
"dpkg --add-architecture $CROSS_DEB_ARCH",
"apt-get update && apt-get install --assume-yes libssl-dev:$CROSS_DEB_ARCH clang"
]
# NOTE: for musl you will need to build with --features=static-link-openssl
[target.aarch64-unknown-linux-musl]
dockerfile = "./docker/cross-rs/aarch64-unknown-linux-musl.dockerfile"
pre-build = [
"dpkg --add-architecture $CROSS_DEB_ARCH",
"apt-get update && apt-get install --assume-yes clang"
]

View File

@ -5,27 +5,27 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cli"
edition = "2021"
license = "MIT"
name = "nu-cli"
version = "0.83.1"
version = "0.84.0"
[lib]
bench = false
[dev-dependencies]
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.83.1" }
nu-test-support = { path = "../nu-test-support", version = "0.83.1" }
rstest = { version = "0.17.0", default-features = false }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.84.0" }
nu-test-support = { path = "../nu-test-support", version = "0.84.0" }
rstest = { version = "0.18.1", default-features = false }
[dependencies]
nu-cmd-base = { path = "../nu-cmd-base", version = "0.83.1" }
nu-command = { path = "../nu-command", version = "0.83.1" }
nu-engine = { path = "../nu-engine", version = "0.83.1" }
nu-path = { path = "../nu-path", version = "0.83.1" }
nu-parser = { path = "../nu-parser", version = "0.83.1" }
nu-protocol = { path = "../nu-protocol", version = "0.83.1" }
nu-utils = { path = "../nu-utils", version = "0.83.1" }
nu-color-config = { path = "../nu-color-config", version = "0.83.1" }
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-ansi-term = "0.49.0"
reedline = { version = "0.22.0", features = ["bashisms", "sqlite"]}
reedline = { version = "0.23.0", features = ["bashisms", "sqlite"]}
chrono = { default-features = false, features = ["std"], version = "0.4" }
crossterm = "0.26"

View File

@ -62,11 +62,11 @@ impl Command for KeybindingsList {
let all_options = ["modifiers", "keycodes", "edits", "modes", "events"];
all_options
.iter()
.flat_map(|argument| get_records(argument, &call.head))
.flat_map(|argument| get_records(argument, call.head))
.collect()
} else {
call.named_iter()
.flat_map(|(argument, _, _)| get_records(argument.item.as_str(), &call.head))
.flat_map(|(argument, _, _)| get_records(argument.item.as_str(), call.head))
.collect()
};
@ -78,7 +78,7 @@ impl Command for KeybindingsList {
}
}
fn get_records(entry_type: &str, span: &Span) -> Vec<Value> {
fn get_records(entry_type: &str, span: Span) -> Vec<Value> {
let values = match entry_type {
"modifiers" => get_reedline_keybinding_modifiers().sorted(),
"keycodes" => get_reedline_keycodes().sorted(),
@ -95,15 +95,15 @@ fn get_records(entry_type: &str, span: &Span) -> Vec<Value> {
.collect()
}
fn convert_to_record(edit: &str, entry_type: &str, span: &Span) -> Value {
let entry_type = Value::string(entry_type, *span);
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);
let name = Value::string(edit, span);
Value::Record {
cols: vec!["type".to_string(), "name".to_string()],
vals: vec![entry_type, name],
span: *span,
span,
}
}

View File

@ -67,7 +67,7 @@ impl NuCompleter {
) -> Option<Vec<Suggestion>> {
let stack = self.stack.clone();
let block = self.engine_state.get_block(block_id);
let mut callee_stack = stack.gather_captures(&block.captures);
let mut callee_stack = stack.gather_captures(&self.engine_state, &block.captures);
// Line
if let Some(pos_arg) = block.signature.required_positional.get(0) {

View File

@ -2,6 +2,7 @@ use crate::util::eval_source;
use log::info;
use log::trace;
use miette::{IntoDiagnostic, Result};
use nu_engine::eval_block_with_early_return;
use nu_engine::{convert_env_values, current_dir};
use nu_parser::parse;
use nu_path::canonicalize_with;
@ -98,23 +99,59 @@ pub fn evaluate_file(
Value::string(file_path.to_string_lossy(), Span::unknown()),
);
let source_filename = file_path
.file_name()
.expect("internal error: script missing filename");
let mut working_set = StateWorkingSet::new(engine_state);
trace!("parsing file: {}", file_path_str);
let _ = parse(&mut working_set, Some(file_path_str), &file, false);
let block = parse(&mut working_set, Some(file_path_str), &file, false);
if working_set.find_decl(b"main").is_some() {
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..]);
}
}
let _ = engine_state.merge_delta(working_set.delta);
if engine_state.find_decl(b"main", &[]).is_some() {
let args = format!("main {}", args.join(" "));
if !eval_source(
let pipeline_data = eval_block_with_early_return(
engine_state,
stack,
&file,
file_path_str,
&block,
PipelineData::empty(),
true,
) {
false,
false,
)
.unwrap_or_else(|e| {
let working_set = StateWorkingSet::new(engine_state);
report_error(&working_set, &e);
std::process::exit(1);
});
let result = pipeline_data.print(engine_state, stack, true, false);
match result {
Err(err) => {
let working_set = StateWorkingSet::new(engine_state);
report_error(&working_set, &err);
std::process::exit(1);
}
Ok(exit_code) => {
if exit_code != 0 {
std::process::exit(exit_code as i32);
}
}
}
if !eval_source(
engine_state,
stack,

View File

@ -646,7 +646,10 @@ impl Menu for DescriptionMenu {
|lb| {
lb.replace_range(start..end, replacement);
let mut offset = lb.insertion_point();
offset += lb.len().saturating_sub(end.saturating_sub(start));
offset += lb
.len()
.saturating_sub(end.saturating_sub(start))
.saturating_sub(start);
lb.set_insertion_point(offset);
},
UndoBehavior::CreateUndoPoint,

View File

@ -109,8 +109,7 @@ impl Prompt for NushellPrompt {
let prompt = default
.render_prompt_left()
.to_string()
.replace('\n', "\r\n")
+ " ";
.replace('\n', "\r\n");
prompt.into()
}
@ -144,11 +143,11 @@ impl Prompt for NushellPrompt {
PromptEditMode::Vi(vi_mode) => match vi_mode {
PromptViMode::Normal => match &self.default_vi_normal_prompt_indicator {
Some(indicator) => indicator,
None => ": ",
None => "> ",
},
PromptViMode::Insert => match &self.default_vi_insert_prompt_indicator {
Some(indicator) => indicator,
None => "> ",
None => ": ",
},
}
.into(),

View File

@ -131,7 +131,7 @@ fn add_menu(
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 layout = extract_value("layout", cols, vals, *span)?.into_string("", config);
match layout.as_str() {
"columnar" => add_columnar_menu(line_editor, menu, engine_state, stack, config),
@ -155,7 +155,7 @@ fn add_menu(
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) {
$menu = match extract_value($name, $cols, $vals, *$span) {
Ok(text) => {
let style = match text {
Value::String { val, .. } => lookup_ansi_color_style(&val),
@ -181,7 +181,7 @@ pub(crate) fn add_columnar_menu(
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) {
columnar_menu = match extract_value("columns", cols, vals, *span) {
Ok(columns) => {
let columns = columns.as_int()?;
columnar_menu.with_columns(columns as u16)
@ -189,7 +189,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", cols, vals, *span) {
Ok(col_width) => {
let col_width = col_width.as_int()?;
columnar_menu.with_column_width(Some(col_width as usize))
@ -197,7 +197,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", cols, vals, *span) {
Ok(col_padding) => {
let col_padding = col_padding.as_int()?;
columnar_menu.with_column_padding(col_padding as usize)
@ -283,7 +283,7 @@ pub(crate) fn add_list_menu(
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) {
list_menu = match extract_value("page_size", cols, vals, *span) {
Ok(page_size) => {
let page_size = page_size.as_int()?;
list_menu.with_page_size(page_size as usize)
@ -369,7 +369,7 @@ pub(crate) fn add_description_menu(
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) {
description_menu = match extract_value("columns", cols, vals, *span) {
Ok(columns) => {
let columns = columns.as_int()?;
description_menu.with_columns(columns as u16)
@ -377,7 +377,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", cols, vals, *span) {
Ok(col_width) => {
let col_width = col_width.as_int()?;
description_menu.with_column_width(Some(col_width as usize))
@ -385,7 +385,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", cols, vals, *span) {
Ok(col_padding) => {
let col_padding = col_padding.as_int()?;
description_menu.with_column_padding(col_padding as usize)
@ -393,7 +393,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", cols, vals, *span) {
Ok(selection_rows) => {
let selection_rows = selection_rows.as_int()?;
description_menu.with_selection_rows(selection_rows as u16)
@ -401,7 +401,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", cols, vals, *span) {
Ok(description_rows) => {
let description_rows = description_rows.as_int()?;
description_menu.with_description_rows(description_rows as usize)
@ -523,6 +523,12 @@ fn add_menu_keybindings(keybindings: &mut Keybindings) {
KeyCode::F(1),
ReedlineEvent::Menu("help_menu".to_string()),
);
keybindings.add_binding(
KeyModifiers::CONTROL,
KeyCode::Char('q'),
ReedlineEvent::SearchHistory,
);
}
pub enum KeybindingsMode {
@ -719,26 +725,26 @@ impl<'config> EventType<'config> {
fn try_from_columns(
cols: &'config [String],
vals: &'config [Value],
span: &'config Span,
span: Span,
) -> Result<Self, ShellError> {
extract_value("send", cols, vals, 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))
.map_err(|_| ShellError::MissingConfigValue("send, edit or until".to_string(), *span))
.map_err(|_| ShellError::MissingConfigValue("send, edit or until".to_string(), span))
}
}
fn parse_event(value: &Value, config: &Config) -> Result<Option<ReedlineEvent>, ShellError> {
match value {
Value::Record { cols, vals, span } => {
match EventType::try_from_columns(cols, vals, span)? {
match EventType::try_from_columns(cols, vals, *span)? {
EventType::Send(value) => event_from_record(
value.into_string("", config).to_lowercase().as_str(),
cols,
vals,
config,
span,
*span,
)
.map(Some),
EventType::Edit(value) => {
@ -747,7 +753,7 @@ fn parse_event(value: &Value, config: &Config) -> Result<Option<ReedlineEvent>,
cols,
vals,
config,
span,
*span,
)?;
Ok(Some(ReedlineEvent::Edit(vec![edit])))
}
@ -810,7 +816,7 @@ fn event_from_record(
cols: &[String],
vals: &[Value],
config: &Config,
span: &Span,
span: Span,
) -> Result<ReedlineEvent, ShellError> {
let event = match name {
"none" => ReedlineEvent::None,
@ -853,7 +859,7 @@ fn event_from_record(
return Err(ShellError::UnsupportedConfigValue(
"Reedline event".to_string(),
v.to_string(),
*span,
span,
))
}
};
@ -866,7 +872,7 @@ fn edit_from_record(
cols: &[String],
vals: &[Value],
config: &Config,
span: &Span,
span: Span,
) -> Result<EditCommand, ShellError> {
let edit = match name {
"movetostart" => EditCommand::MoveToStart,
@ -968,7 +974,7 @@ fn edit_from_record(
return Err(ShellError::UnsupportedConfigValue(
"reedline EditCommand".to_string(),
e.to_string(),
*span,
span,
))
}
};
@ -995,7 +1001,7 @@ mod test {
let vals = vec![Value::test_string("Enter")];
let span = Span::test_data();
let b = EventType::try_from_columns(&cols, &vals, &span).unwrap();
let b = EventType::try_from_columns(&cols, &vals, span).unwrap();
assert!(matches!(b, EventType::Send(_)));
let event = Value::Record {
@ -1015,7 +1021,7 @@ mod test {
let vals = vec![Value::test_string("Clear")];
let span = Span::test_data();
let b = EventType::try_from_columns(&cols, &vals, &span).unwrap();
let b = EventType::try_from_columns(&cols, &vals, span).unwrap();
assert!(matches!(b, EventType::Edit(_)));
let event = Value::Record {
@ -1041,7 +1047,7 @@ mod test {
];
let span = Span::test_data();
let b = EventType::try_from_columns(&cols, &vals, &span).unwrap();
let b = EventType::try_from_columns(&cols, &vals, span).unwrap();
assert!(matches!(b, EventType::Send(_)));
let event = Value::Record {
@ -1091,7 +1097,7 @@ mod test {
}];
let span = Span::test_data();
let b = EventType::try_from_columns(&cols, &vals, &span).unwrap();
let b = EventType::try_from_columns(&cols, &vals, span).unwrap();
assert!(matches!(b, EventType::Until(_)));
let event = Value::Record {
@ -1159,7 +1165,7 @@ mod test {
let vals = vec![Value::test_string("Enter")];
let span = Span::test_data();
let b = EventType::try_from_columns(&cols, &vals, &span);
let b = EventType::try_from_columns(&cols, &vals, span);
assert!(matches!(b, Err(ShellError::MissingConfigValue(_, _))));
}
}

View File

@ -59,7 +59,7 @@ impl Highlighter for NuHighlighter {
($shape:expr, $span:expr, $text:expr) => {{
let spans = split_span_by_highlight_positions(
line,
&$span,
$span,
&matching_brackets_pos,
global_span_offset,
);
@ -143,7 +143,7 @@ impl Highlighter for NuHighlighter {
fn split_span_by_highlight_positions(
line: &str,
span: &Span,
span: Span,
highlight_positions: &Vec<usize>,
global_span_offset: usize,
) -> Vec<(Span, bool)> {

View File

@ -105,7 +105,7 @@ fn gather_env_vars(
span: full_span,
} = token
{
let contents = engine_state.get_span_contents(&full_span);
let contents = engine_state.get_span_contents(full_span);
let (parts, _) = lex(contents, full_span.start, &[], &[b'='], true);
let name = if let Some(Token {

View File

@ -5,12 +5,12 @@ edition = "2021"
license = "MIT"
name = "nu-cmd-base"
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-base"
version = "0.83.1"
version = "0.84.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.83.1" }
nu-path = { path = "../nu-path", version = "0.83.1" }
nu-protocol = { version = "0.83.1", path = "../nu-protocol" }
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" }
indexmap = { version = "2.0" }

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.83.1"
version = "0.84.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -13,9 +13,9 @@ version = "0.83.1"
bench = false
[dependencies]
nu-engine = { path = "../nu-engine", version = "0.83.1" }
nu-parser = { path = "../nu-parser", version = "0.83.1" }
nu-protocol = { path = "../nu-protocol", version = "0.83.1" }
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" }
# Potential dependencies for extras
chrono = { version = "0.4", features = ["std", "unstable-locales"], default-features = false }
@ -24,6 +24,7 @@ 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"] }
[dependencies.polars]
features = [
@ -50,15 +51,15 @@ features = [
"serde",
"serde-lazy",
"strings",
"to_dummies",
"to_dummies"
]
optional = true
version = "0.30.0"
[features]
dataframe = ["default"]
default = ["num", "polars", "sqlparser"]
dataframe = ["num", "polars", "sqlparser"]
default = []
[dev-dependencies]
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.83.1" }
nu-test-support = { path = "../nu-test-support", version = "0.83.1" }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.84.0" }
nu-test-support = { path = "../nu-test-support", version = "0.84.0" }

View File

@ -1,4 +1,4 @@
use super::super::values::{Column, NuDataFrame};
use super::super::values::{Column, NuDataFrame, NuExpression};
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
@ -15,7 +15,7 @@ impl Command for FirstDF {
}
fn usage(&self) -> &str {
"Show only the first number of rows."
"Show only the first number of rows or create a first expression"
}
fn signature(&self) -> Signature {
@ -25,10 +25,16 @@ impl Command for FirstDF {
SyntaxShape::Int,
"starting from the front, the number of rows to return",
)
.input_output_type(
Type::Custom("dataframe".into()),
Type::Custom("dataframe".into()),
)
.input_output_types(vec![
(
Type::Custom("expression".into()),
Type::Custom("expression".into()),
),
(
Type::Custom("dataframe".into()),
Type::Custom("dataframe".into()),
),
])
.category(Category::Custom("dataframe".into()))
}
@ -64,6 +70,11 @@ impl Command for FirstDF {
.into_value(Span::test_data()),
),
},
Example {
description: "Creates a first expression from a column",
example: "dfr col a | dfr first",
result: None,
},
]
}
@ -74,8 +85,19 @@ impl Command for FirstDF {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
command(engine_state, stack, call, df)
let value = input.into_value(call.head);
if NuDataFrame::can_downcast(&value) {
let df = NuDataFrame::try_from_value(value)?;
command(engine_state, stack, call, df)
} else {
let expr = NuExpression::try_from_value(value)?;
let expr: NuExpression = expr.into_polars().first().into();
Ok(PipelineData::Value(
NuExpression::into_value(expr, call.head),
None,
))
}
}
}
@ -97,11 +119,25 @@ fn command(
#[cfg(test)]
mod test {
use super::super::super::test_dataframe::test_dataframe;
use super::super::super::test_dataframe::{build_test_engine_state, test_dataframe_example};
use super::*;
use crate::dataframe::lazy::aggregate::LazyAggregate;
use crate::dataframe::lazy::groupby::ToLazyGroupBy;
#[test]
fn test_examples() {
test_dataframe(vec![Box::new(FirstDF {})])
fn test_examples_dataframe() {
let mut engine_state = build_test_engine_state(vec![Box::new(FirstDF {})]);
test_dataframe_example(&mut engine_state, &FirstDF.examples()[0]);
test_dataframe_example(&mut engine_state, &FirstDF.examples()[1]);
}
#[test]
fn test_examples_expression() {
let mut engine_state = build_test_engine_state(vec![
Box::new(FirstDF {}),
Box::new(LazyAggregate {}),
Box::new(ToLazyGroupBy {}),
]);
test_dataframe_example(&mut engine_state, &FirstDF.examples()[2]);
}
}

View File

@ -1,4 +1,4 @@
use super::super::values::{utils::DEFAULT_ROWS, Column, NuDataFrame};
use super::super::values::{utils::DEFAULT_ROWS, Column, NuDataFrame, NuExpression};
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
@ -21,26 +21,39 @@ impl Command for LastDF {
fn signature(&self) -> Signature {
Signature::build(self.name())
.optional("rows", SyntaxShape::Int, "Number of rows for tail")
.input_output_type(
Type::Custom("dataframe".into()),
Type::Custom("dataframe".into()),
)
.input_output_types(vec![
(
Type::Custom("expression".into()),
Type::Custom("expression".into()),
),
(
Type::Custom("dataframe".into()),
Type::Custom("dataframe".into()),
),
])
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Create new dataframe with last rows",
example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr last 1",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new("a".to_string(), vec![Value::test_int(3)]),
Column::new("b".to_string(), vec![Value::test_int(4)]),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
}]
vec![
Example {
description: "Create new dataframe with last rows",
example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr last 1",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new("a".to_string(), vec![Value::test_int(3)]),
Column::new("b".to_string(), vec![Value::test_int(4)]),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},
Example {
description: "Creates a last expression from a column",
example: "dfr col a | dfr last",
result: None,
},
]
}
fn run(
@ -50,8 +63,19 @@ impl Command for LastDF {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
command(engine_state, stack, call, df)
let value = input.into_value(call.head);
if NuDataFrame::can_downcast(&value) {
let df = NuDataFrame::try_from_value(value)?;
command(engine_state, stack, call, df)
} else {
let expr = NuExpression::try_from_value(value)?;
let expr: NuExpression = expr.into_polars().last().into();
Ok(PipelineData::Value(
NuExpression::into_value(expr, call.head),
None,
))
}
}
}
@ -73,11 +97,24 @@ fn command(
#[cfg(test)]
mod test {
use super::super::super::test_dataframe::test_dataframe;
use super::super::super::test_dataframe::{build_test_engine_state, test_dataframe_example};
use super::*;
use crate::dataframe::lazy::aggregate::LazyAggregate;
use crate::dataframe::lazy::groupby::ToLazyGroupBy;
#[test]
fn test_examples() {
test_dataframe(vec![Box::new(LastDF {})])
fn test_examples_dataframe() {
let mut engine_state = build_test_engine_state(vec![Box::new(LastDF {})]);
test_dataframe_example(&mut engine_state, &LastDF.examples()[0]);
}
#[test]
fn test_examples_expression() {
let mut engine_state = build_test_engine_state(vec![
Box::new(LastDF {}),
Box::new(LazyAggregate {}),
Box::new(ToLazyGroupBy {}),
]);
test_dataframe_example(&mut engine_state, &LastDF.examples()[1]);
}
}

View File

@ -22,6 +22,7 @@ mod sql_expr;
mod summary;
mod take;
mod to_arrow;
mod to_avro;
mod to_csv;
mod to_df;
mod to_json_lines;
@ -55,6 +56,7 @@ pub use sql_expr::parse_sql_expr;
pub use summary::Summary;
pub use take::TakeDF;
pub use to_arrow::ToArrow;
pub use to_avro::ToAvro;
pub use to_csv::ToCSV;
pub use to_df::ToDataFrame;
pub use to_json_lines::ToJsonLines;
@ -96,6 +98,7 @@ pub fn add_eager_decls(working_set: &mut StateWorkingSet) {
SliceDF,
TakeDF,
ToArrow,
ToAvro,
ToCSV,
ToDataFrame,
ToNu,

View File

@ -13,6 +13,8 @@ use polars::prelude::{
LazyFrame, ParallelStrategy, ParquetReader, ScanArgsIpc, ScanArgsParquet, SerReader,
};
use polars_io::avro::AvroReader;
#[derive(Clone)]
pub struct OpenDataFrame;
@ -22,7 +24,7 @@ impl Command for OpenDataFrame {
}
fn usage(&self) -> &str {
"Opens CSV, JSON, JSON lines, arrow, or parquet file to create dataframe."
"Opens CSV, JSON, JSON lines, arrow, avro, or parquet file to create dataframe."
}
fn signature(&self) -> Signature {
@ -36,7 +38,7 @@ impl Command for OpenDataFrame {
.named(
"type",
SyntaxShape::String,
"File type: csv, tsv, json, parquet, arrow. If omitted, derive from file extension",
"File type: csv, tsv, json, parquet, arrow, avro. If omitted, derive from file extension",
Some('t'),
)
.named(
@ -118,6 +120,7 @@ fn command(
"ipc" | "arrow" => from_ipc(engine_state, stack, call),
"json" => from_json(engine_state, stack, call),
"jsonl" => from_jsonl(engine_state, stack, call),
"avro" => from_avro(engine_state, stack, call),
_ => Err(ShellError::FileNotFoundCustom(
format!("{msg}. Supported values: csv, tsv, parquet, ipc, arrow, json"),
blamed,
@ -199,6 +202,46 @@ fn from_parquet(
}
}
fn from_avro(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
) -> Result<Value, ShellError> {
let file: Spanned<PathBuf> = call.req(engine_state, stack, 0)?;
let columns: Option<Vec<String>> = call.get_flag(engine_state, stack, "columns")?;
let r = File::open(&file.item).map_err(|e| {
ShellError::GenericError(
"Error opening file".into(),
e.to_string(),
Some(file.span),
None,
Vec::new(),
)
})?;
let reader = AvroReader::new(r);
let reader = match columns {
None => reader,
Some(columns) => reader.with_columns(Some(columns)),
};
let df: NuDataFrame = reader
.finish()
.map_err(|e| {
ShellError::GenericError(
"Avro reader error".into(),
format!("{e:?}"),
Some(call.head),
None,
Vec::new(),
)
})?
.into();
Ok(df.into_value(call.head))
}
fn from_ipc(
engine_state: &EngineState,
stack: &mut Stack,

View File

@ -0,0 +1,123 @@
use std::{fs::File, path::PathBuf};
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Type, Value,
};
use polars_io::avro::{AvroCompression, AvroWriter};
use polars_io::SerWriter;
use super::super::values::NuDataFrame;
#[derive(Clone)]
pub struct ToAvro;
impl Command for ToAvro {
fn name(&self) -> &str {
"dfr to-avro"
}
fn usage(&self) -> &str {
"Saves dataframe to avro file."
}
fn signature(&self) -> Signature {
Signature::build(self.name())
.named(
"compression",
SyntaxShape::String,
"use compression, supports deflate or snappy",
Some('c'),
)
.required("file", SyntaxShape::Filepath, "file path to save dataframe")
.input_output_type(Type::Custom("dataframe".into()), Type::Any)
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Saves dataframe to avro file",
example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr to-avro test.avro",
result: None,
}]
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
command(engine_state, stack, call, input)
}
}
fn get_compression(call: &Call) -> Result<Option<AvroCompression>, ShellError> {
if let Some((compression, span)) = call
.get_flag_expr("compression")
.and_then(|e| e.as_string().map(|s| (s, e.span)))
{
match compression.as_ref() {
"snappy" => Ok(Some(AvroCompression::Snappy)),
"deflate" => Ok(Some(AvroCompression::Deflate)),
_ => Err(ShellError::IncorrectValue {
msg: "compression must be one of deflate or snappy".to_string(),
val_span: span,
call_span: span,
}),
}
} else {
Ok(None)
}
}
fn command(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let file_name: Spanned<PathBuf> = call.req(engine_state, stack, 0)?;
let compression = get_compression(call)?;
let mut df = NuDataFrame::try_from_pipeline(input, call.head)?;
let file = File::create(&file_name.item).map_err(|e| {
ShellError::GenericError(
"Error with file name".into(),
e.to_string(),
Some(file_name.span),
None,
Vec::new(),
)
})?;
AvroWriter::new(file)
.with_compression(compression)
.finish(df.as_mut())
.map_err(|e| {
ShellError::GenericError(
"Error saving file".into(),
e.to_string(),
Some(file_name.span),
None,
Vec::new(),
)
})?;
let file_value = Value::String {
val: format!("saved {:?}", &file_name.item),
span: file_name.span,
};
Ok(PipelineData::Value(
Value::List {
vals: vec![file_value],
span: call.head,
},
None,
))
}

View File

@ -1,7 +1,7 @@
/// Definition of multiple Expression commands using a macro rule
/// All of these expressions have an identical body and only require
/// to have a change in the name, description and expression function
use crate::dataframe::values::{Column, NuDataFrame, NuExpression};
use crate::dataframe::values::{Column, NuDataFrame, NuExpression, NuLazyFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
@ -134,6 +134,186 @@ macro_rules! expr_command {
};
}
// The structs defined in this file are structs that form part of other commands
// since they share a similar name
macro_rules! lazy_expr_command {
($command: ident, $name: expr, $desc: expr, $examples: expr, $func: ident, $test: ident) => {
#[derive(Clone)]
pub struct $command;
impl Command for $command {
fn name(&self) -> &str {
$name
}
fn usage(&self) -> &str {
$desc
}
fn signature(&self) -> Signature {
Signature::build(self.name())
.input_output_types(vec![
(
Type::Custom("expression".into()),
Type::Custom("expression".into()),
),
(
Type::Custom("dataframe".into()),
Type::Custom("dataframe".into()),
),
])
.category(Category::Custom("expression".into()))
}
fn examples(&self) -> Vec<Example> {
$examples
}
fn run(
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let value = input.into_value(call.head);
if NuDataFrame::can_downcast(&value) {
let lazy = NuLazyFrame::try_from_value(value)?;
let lazy = NuLazyFrame::new(lazy.from_eager, lazy.into_polars().$func());
Ok(PipelineData::Value(lazy.into_value(call.head)?, None))
} else {
let expr = NuExpression::try_from_value(value)?;
let expr: NuExpression = expr.into_polars().$func().into();
Ok(PipelineData::Value(
NuExpression::into_value(expr, call.head),
None,
))
}
}
}
#[cfg(test)]
mod $test {
use super::super::super::test_dataframe::{
build_test_engine_state, test_dataframe_example,
};
use super::*;
use crate::dataframe::lazy::aggregate::LazyAggregate;
use crate::dataframe::lazy::groupby::ToLazyGroupBy;
#[test]
fn test_examples_dataframe() {
// the first example should be a for the dataframe case
let example = &$command.examples()[0];
let mut engine_state = build_test_engine_state(vec![Box::new($command {})]);
test_dataframe_example(&mut engine_state, &example)
}
#[test]
fn test_examples_expressions() {
// the second example should be a for the dataframe case
let example = &$command.examples()[1];
let mut engine_state = build_test_engine_state(vec![
Box::new($command {}),
Box::new(LazyAggregate {}),
Box::new(ToLazyGroupBy {}),
]);
test_dataframe_example(&mut engine_state, &example)
}
}
};
($command: ident, $name: expr, $desc: expr, $examples: expr, $func: ident, $test: ident, $ddof: expr) => {
#[derive(Clone)]
pub struct $command;
impl Command for $command {
fn name(&self) -> &str {
$name
}
fn usage(&self) -> &str {
$desc
}
fn signature(&self) -> Signature {
Signature::build(self.name())
.input_output_types(vec![
(
Type::Custom("expression".into()),
Type::Custom("expression".into()),
),
(
Type::Custom("dataframe".into()),
Type::Custom("dataframe".into()),
),
])
.category(Category::Custom("expression".into()))
}
fn examples(&self) -> Vec<Example> {
$examples
}
fn run(
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let value = input.into_value(call.head);
if NuDataFrame::can_downcast(&value) {
let lazy = NuLazyFrame::try_from_value(value)?;
let lazy = NuLazyFrame::new(lazy.from_eager, lazy.into_polars().$func($ddof));
Ok(PipelineData::Value(lazy.into_value(call.head)?, None))
} else {
let expr = NuExpression::try_from_value(value)?;
let expr: NuExpression = expr.into_polars().$func($ddof).into();
Ok(PipelineData::Value(
NuExpression::into_value(expr, call.head),
None,
))
}
}
}
#[cfg(test)]
mod $test {
use super::super::super::test_dataframe::{
build_test_engine_state, test_dataframe_example,
};
use super::*;
use crate::dataframe::lazy::aggregate::LazyAggregate;
use crate::dataframe::lazy::groupby::ToLazyGroupBy;
#[test]
fn test_examples_dataframe() {
// the first example should be a for the dataframe case
let example = &$command.examples()[0];
let mut engine_state = build_test_engine_state(vec![Box::new($command {})]);
test_dataframe_example(&mut engine_state, &example)
}
#[test]
fn test_examples_expressions() {
// the second example should be a for the dataframe case
let example = &$command.examples()[1];
let mut engine_state = build_test_engine_state(vec![
Box::new($command {}),
Box::new(LazyAggregate {}),
Box::new(ToLazyGroupBy {}),
]);
test_dataframe_example(&mut engine_state, &example)
}
}
};
}
// ExprList command
// Expands to a command definition for a list expression
expr_command!(
@ -164,36 +344,6 @@ expr_command!(
test_groups
);
// ExprFlatten command
// Expands to a command definition for a flatten expression
expr_command!(
ExprFlatten,
"dfr flatten",
"creates a flatten expression",
vec![Example {
description: "",
example: "",
result: None,
}],
flatten,
test_flatten
);
// ExprExplode command
// Expands to a command definition for a explode expression
expr_command!(
ExprExplode,
"dfr explode",
"creates an explode expression",
vec![Example {
description: "",
example: "",
result: None,
}],
explode,
test_explode
);
// ExprCount command
// Expands to a command definition for a count expression
expr_command!(
@ -209,81 +359,6 @@ expr_command!(
test_count
);
// ExprFirst command
// Expands to a command definition for a count expression
expr_command!(
ExprFirst,
"dfr first",
"creates a first expression",
vec![Example {
description: "Creates a first expression from a column",
example: "dfr col a | dfr first",
result: None,
},],
first,
test_first
);
// ExprLast command
// Expands to a command definition for a count expression
expr_command!(
ExprLast,
"dfr last",
"creates a last expression",
vec![Example {
description: "Creates a last expression from a column",
example: "dfr col a | dfr last",
result: None,
},],
last,
test_last
);
// ExprNUnique command
// Expands to a command definition for a n-unique expression
expr_command!(
ExprNUnique,
"dfr n-unique",
"creates a n-unique expression",
vec![Example {
description: "Creates a is n-unique expression from a column",
example: "dfr col a | dfr n-unique",
result: None,
},],
n_unique,
test_nunique
);
// ExprIsNotNull command
// Expands to a command definition for a n-unique expression
expr_command!(
ExprIsNotNull,
"dfr is-not-null",
"creates a is not null expression",
vec![Example {
description: "Creates a is not null expression from a column",
example: "dfr col a | dfr is-not-null",
result: None,
},],
is_not_null,
test_is_not_null
);
// ExprIsNull command
// Expands to a command definition for a n-unique expression
expr_command!(
ExprIsNull,
"dfr is-null",
"creates a is null expression",
vec![Example {
description: "Creates a is null expression from a column",
example: "dfr col a | dfr is-null",
result: None,
},],
is_null,
test_is_null
);
// ExprNot command
// Expands to a command definition for a not expression
expr_command!(
@ -301,124 +376,180 @@ expr_command!(
// ExprMax command
// Expands to a command definition for max aggregation
expr_command!(
lazy_expr_command!(
ExprMax,
"dfr max",
"Creates a max expression",
vec![Example {
description: "Max aggregation for a group-by",
example: r#"[[a b]; [one 2] [one 4] [two 1]]
"Creates a max expression or aggregates columns to their max value",
vec![
Example {
description: "Max value from columns in a dataframe",
example: "[[a b]; [6 2] [1 4] [4 1]] | dfr into-df | dfr max",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new("a".to_string(), vec![Value::test_int(6)],),
Column::new("b".to_string(), vec![Value::test_int(4)],),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},
Example {
description: "Max aggregation for a group-by",
example: r#"[[a b]; [one 2] [one 4] [two 1]]
| dfr into-df
| dfr group-by a
| dfr agg (dfr col b | dfr max)"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_string("one"), Value::test_string("two")],
),
Column::new(
"b".to_string(),
vec![Value::test_int(4), Value::test_int(1)],
),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},],
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_string("one"), Value::test_string("two")],
),
Column::new(
"b".to_string(),
vec![Value::test_int(4), Value::test_int(1)],
),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},
],
max,
test_max
);
// ExprMin command
// Expands to a command definition for min aggregation
expr_command!(
lazy_expr_command!(
ExprMin,
"dfr min",
"Creates a min expression",
vec![Example {
description: "Min aggregation for a group-by",
example: r#"[[a b]; [one 2] [one 4] [two 1]]
"Creates a min expression or aggregates columns to their min value",
vec![
Example {
description: "Min value from columns in a dataframe",
example: "[[a b]; [6 2] [1 4] [4 1]] | dfr into-df | dfr min",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new("a".to_string(), vec![Value::test_int(1)],),
Column::new("b".to_string(), vec![Value::test_int(1)],),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},
Example {
description: "Min aggregation for a group-by",
example: r#"[[a b]; [one 2] [one 4] [two 1]]
| dfr into-df
| dfr group-by a
| dfr agg (dfr col b | dfr min)"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_string("one"), Value::test_string("two")],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(1)],
),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},],
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_string("one"), Value::test_string("two")],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(1)],
),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},
],
min,
test_min
);
// ExprSum command
// Expands to a command definition for sum aggregation
expr_command!(
lazy_expr_command!(
ExprSum,
"dfr sum",
"Creates a sum expression for an aggregation",
vec![Example {
description: "Sum aggregation for a group-by",
example: r#"[[a b]; [one 2] [one 4] [two 1]]
"Creates a sum expression for an aggregation or aggregates columns to their sum value",
vec![
Example {
description: "Sums all columns in a dataframe",
example: "[[a b]; [6 2] [1 4] [4 1]] | dfr into-df | dfr sum",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new("a".to_string(), vec![Value::test_int(11)],),
Column::new("b".to_string(), vec![Value::test_int(7)],),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},
Example {
description: "Sum aggregation for a group-by",
example: r#"[[a b]; [one 2] [one 4] [two 1]]
| dfr into-df
| dfr group-by a
| dfr agg (dfr col b | dfr sum)"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_string("one"), Value::test_string("two")],
),
Column::new(
"b".to_string(),
vec![Value::test_int(6), Value::test_int(1)],
),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},],
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_string("one"), Value::test_string("two")],
),
Column::new(
"b".to_string(),
vec![Value::test_int(6), Value::test_int(1)],
),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},
],
sum,
test_sum
);
// ExprMean command
// Expands to a command definition for mean aggregation
expr_command!(
lazy_expr_command!(
ExprMean,
"dfr mean",
"Creates a mean expression for an aggregation",
vec![Example {
description: "Mean aggregation for a group-by",
example: r#"[[a b]; [one 2] [one 4] [two 1]]
"Creates a mean expression for an aggregation or aggregates columns to their mean value",
vec![
Example {
description: "Mean value from columns in a dataframe",
example: "[[a b]; [6 2] [4 2] [2 2]] | dfr into-df | dfr mean",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new("a".to_string(), vec![Value::test_float(4.0)],),
Column::new("b".to_string(), vec![Value::test_float(2.0)],),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},
Example {
description: "Mean aggregation for a group-by",
example: r#"[[a b]; [one 2] [one 4] [two 1]]
| dfr into-df
| dfr group-by a
| dfr agg (dfr col b | dfr mean)"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_string("one"), Value::test_string("two")],
),
Column::new(
"b".to_string(),
vec![Value::test_float(3.0), Value::test_float(1.0)],
),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},],
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_string("one"), Value::test_string("two")],
),
Column::new(
"b".to_string(),
vec![Value::test_float(3.0), Value::test_float(1.0)],
),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},
],
mean,
test_mean
);
@ -456,64 +587,93 @@ expr_command!(
// ExprStd command
// Expands to a command definition for std aggregation
expr_command!(
lazy_expr_command!(
ExprStd,
"dfr std",
"Creates a std expression for an aggregation",
vec![Example {
description: "Std aggregation for a group-by",
example: r#"[[a b]; [one 2] [one 2] [two 1] [two 1]]
"Creates a std expression for an aggregation of std value from columns in a dataframe",
vec![
Example {
description: "Std value from columns in a dataframe",
example: "[[a b]; [6 2] [4 2] [2 2]] | dfr into-df | dfr std",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new("a".to_string(), vec![Value::test_float(2.0)],),
Column::new("b".to_string(), vec![Value::test_float(0.0)],),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},
Example {
description: "Std aggregation for a group-by",
example: r#"[[a b]; [one 2] [one 2] [two 1] [two 1]]
| dfr into-df
| dfr group-by a
| dfr agg (dfr col b | dfr std)"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_string("one"), Value::test_string("two")],
),
Column::new(
"b".to_string(),
vec![Value::test_float(0.0), Value::test_float(0.0)],
),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},],
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_string("one"), Value::test_string("two")],
),
Column::new(
"b".to_string(),
vec![Value::test_float(0.0), Value::test_float(0.0)],
),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},
],
std,
test_std,
0
1
);
// ExprVar command
// Expands to a command definition for var aggregation
expr_command!(
lazy_expr_command!(
ExprVar,
"dfr var",
"Create a var expression for an aggregation",
vec![Example {
description: "Var aggregation for a group-by",
example: r#"[[a b]; [one 2] [one 2] [two 1] [two 1]]
vec![
Example {
description:
"Var value from columns in a dataframe or aggregates columns to their var value",
example: "[[a b]; [6 2] [4 2] [2 2]] | dfr into-df | dfr var",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new("a".to_string(), vec![Value::test_float(4.0)],),
Column::new("b".to_string(), vec![Value::test_float(0.0)],),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},
Example {
description: "Var aggregation for a group-by",
example: r#"[[a b]; [one 2] [one 2] [two 1] [two 1]]
| dfr into-df
| dfr group-by a
| dfr agg (dfr col b | dfr var)"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_string("one"), Value::test_string("two")],
),
Column::new(
"b".to_string(),
vec![Value::test_float(0.0), Value::test_float(0.0)],
),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},],
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_string("one"), Value::test_string("two")],
),
Column::new(
"b".to_string(),
vec![Value::test_float(0.0), Value::test_float(0.0)],
),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},
],
var,
test_var,
0
1
);

View File

@ -47,15 +47,8 @@ pub fn add_expressions(working_set: &mut StateWorkingSet) {
ExprQuantile,
ExprList,
ExprAggGroups,
ExprFlatten,
ExprExplode,
ExprCount,
ExprFirst,
ExprLast,
ExprNUnique,
ExprIsIn,
ExprIsNotNull,
ExprIsNull,
ExprNot,
ExprMax,
ExprMin,

View File

@ -0,0 +1,158 @@
use crate::dataframe::values::{Column, NuDataFrame, NuExpression, NuLazyFrame};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
#[derive(Clone)]
pub struct LazyExplode;
impl Command for LazyExplode {
fn name(&self) -> &str {
"dfr explode"
}
fn usage(&self) -> &str {
"Explodes a dataframe or creates a explode expression."
}
fn signature(&self) -> Signature {
Signature::build(self.name())
.rest(
"columns",
SyntaxShape::String,
"columns to explode, only applicable for dataframes",
)
.input_output_types(vec![
(
Type::Custom("expression".into()),
Type::Custom("expression".into()),
),
(
Type::Custom("dataframe".into()),
Type::Custom("dataframe".into()),
),
])
.category(Category::Custom("lazyframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "Explode the specified dataframe",
example: "[[id name hobbies]; [1 Mercy [Cycling Knitting]] [2 Bob [Skiing Football]]] | dfr into-df | dfr explode hobbies | dfr collect",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"id".to_string(),
vec![
Value::test_int(1),
Value::test_int(1),
Value::test_int(2),
Value::test_int(2),
]),
Column::new(
"name".to_string(),
vec![
Value::test_string("Mercy"),
Value::test_string("Mercy"),
Value::test_string("Bob"),
Value::test_string("Bob"),
]),
Column::new(
"hobbies".to_string(),
vec![
Value::test_string("Cycling"),
Value::test_string("Knitting"),
Value::test_string("Skiing"),
Value::test_string("Football"),
]),
]).expect("simple df for test should not fail")
.into_value(Span::test_data()),
)
},
Example {
description: "Select a column and explode the values",
example: "[[id name hobbies]; [1 Mercy [Cycling Knitting]] [2 Bob [Skiing Football]]] | dfr into-df | dfr select (dfr col hobbies | dfr explode)",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"hobbies".to_string(),
vec![
Value::test_string("Cycling"),
Value::test_string("Knitting"),
Value::test_string("Skiing"),
Value::test_string("Football"),
]),
]).expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},
]
}
fn run(
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
explode(call, input)
}
}
pub(crate) fn explode(call: &Call, input: PipelineData) -> Result<PipelineData, ShellError> {
let value = input.into_value(call.head);
if NuDataFrame::can_downcast(&value) {
let df = NuLazyFrame::try_from_value(value)?;
let columns: Vec<String> = call
.positional_iter()
.filter_map(|e| e.as_string())
.collect();
let exploded = df
.into_polars()
.explode(columns.iter().map(AsRef::as_ref).collect::<Vec<&str>>());
Ok(PipelineData::Value(
NuLazyFrame::from(exploded).into_value(call.head)?,
None,
))
} else {
let expr = NuExpression::try_from_value(value)?;
let expr: NuExpression = expr.into_polars().explode().into();
Ok(PipelineData::Value(
NuExpression::into_value(expr, call.head),
None,
))
}
}
#[cfg(test)]
mod test {
use super::super::super::test_dataframe::{build_test_engine_state, test_dataframe_example};
use super::*;
use crate::dataframe::lazy::aggregate::LazyAggregate;
use crate::dataframe::lazy::groupby::ToLazyGroupBy;
#[test]
fn test_examples_dataframe() {
let mut engine_state = build_test_engine_state(vec![Box::new(LazyExplode {})]);
test_dataframe_example(&mut engine_state, &LazyExplode.examples()[0]);
}
#[ignore]
#[test]
fn test_examples_expression() {
let mut engine_state = build_test_engine_state(vec![
Box::new(LazyExplode {}),
Box::new(LazyAggregate {}),
Box::new(ToLazyGroupBy {}),
]);
test_dataframe_example(&mut engine_state, &LazyExplode.examples()[1]);
}
}

View File

@ -0,0 +1,132 @@
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use crate::dataframe::values::{Column, NuDataFrame};
use super::explode::explode;
#[derive(Clone)]
pub struct LazyFlatten;
impl Command for LazyFlatten {
fn name(&self) -> &str {
"dfr flatten"
}
fn usage(&self) -> &str {
"An alias for dfr explode"
}
fn signature(&self) -> Signature {
Signature::build(self.name())
.rest(
"columns",
SyntaxShape::String,
"columns to flatten, only applicable for dataframes",
)
.input_output_types(vec![
(
Type::Custom("expression".into()),
Type::Custom("expression".into()),
),
(
Type::Custom("dataframe".into()),
Type::Custom("dataframe".into()),
),
])
.category(Category::Custom("lazyframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "Flatten the specified dataframe",
example: "[[id name hobbies]; [1 Mercy [Cycling Knitting]] [2 Bob [Skiing Football]]] | dfr into-df | dfr flatten hobbies | dfr collect",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"id".to_string(),
vec![
Value::test_int(1),
Value::test_int(1),
Value::test_int(2),
Value::test_int(2),
]),
Column::new(
"name".to_string(),
vec![
Value::test_string("Mercy"),
Value::test_string("Mercy"),
Value::test_string("Bob"),
Value::test_string("Bob"),
]),
Column::new(
"hobbies".to_string(),
vec![
Value::test_string("Cycling"),
Value::test_string("Knitting"),
Value::test_string("Skiing"),
Value::test_string("Football"),
]),
]).expect("simple df for test should not fail")
.into_value(Span::test_data()),
)
},
Example {
description: "Select a column and flatten the values",
example: "[[id name hobbies]; [1 Mercy [Cycling Knitting]] [2 Bob [Skiing Football]]] | dfr into-df | dfr select (dfr col hobbies | dfr flatten)",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"hobbies".to_string(),
vec![
Value::test_string("Cycling"),
Value::test_string("Knitting"),
Value::test_string("Skiing"),
Value::test_string("Football"),
]),
]).expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},
]
}
fn run(
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
explode(call, input)
}
}
#[cfg(test)]
mod test {
use super::super::super::test_dataframe::{build_test_engine_state, test_dataframe_example};
use super::*;
use crate::dataframe::lazy::aggregate::LazyAggregate;
use crate::dataframe::lazy::groupby::ToLazyGroupBy;
#[test]
fn test_examples_dataframe() {
let mut engine_state = build_test_engine_state(vec![Box::new(LazyFlatten {})]);
test_dataframe_example(&mut engine_state, &LazyFlatten.examples()[0]);
}
#[ignore]
#[test]
fn test_examples_expression() {
let mut engine_state = build_test_engine_state(vec![
Box::new(LazyFlatten {}),
Box::new(LazyAggregate {}),
Box::new(ToLazyGroupBy {}),
]);
test_dataframe_example(&mut engine_state, &LazyFlatten.examples()[1]);
}
}

View File

@ -157,94 +157,6 @@ lazy_command!(
test_cache
);
// LazyMax command
// Expands to a command definition for max aggregation
lazy_command!(
LazyMax,
"dfr max",
"Aggregates columns to their max value",
vec![Example {
description: "Max value from columns in a dataframe",
example: "[[a b]; [6 2] [1 4] [4 1]] | dfr into-df | dfr max",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new("a".to_string(), vec![Value::test_int(6)],),
Column::new("b".to_string(), vec![Value::test_int(4)],),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},],
max,
test_max
);
// LazyMin command
// Expands to a command definition for min aggregation
lazy_command!(
LazyMin,
"dfr min",
"Aggregates columns to their min value",
vec![Example {
description: "Min value from columns in a dataframe",
example: "[[a b]; [6 2] [1 4] [4 1]] | dfr into-df | dfr min",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new("a".to_string(), vec![Value::test_int(1)],),
Column::new("b".to_string(), vec![Value::test_int(1)],),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},],
min,
test_min
);
// LazySum command
// Expands to a command definition for sum aggregation
lazy_command!(
LazySum,
"dfr sum",
"Aggregates columns to their sum value",
vec![Example {
description: "Sums all columns in a dataframe",
example: "[[a b]; [6 2] [1 4] [4 1]] | dfr into-df | dfr sum",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new("a".to_string(), vec![Value::test_int(11)],),
Column::new("b".to_string(), vec![Value::test_int(7)],),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},],
sum,
test_sum
);
// LazyMean command
// Expands to a command definition for mean aggregation
lazy_command!(
LazyMean,
"dfr mean",
"Aggregates columns to their mean value",
vec![Example {
description: "Mean value from columns in a dataframe",
example: "[[a b]; [6 2] [4 2] [2 2]] | dfr into-df | dfr mean",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new("a".to_string(), vec![Value::test_float(4.0)],),
Column::new("b".to_string(), vec![Value::test_float(2.0)],),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},],
mean,
test_mean
);
// LazyMedian command
// Expands to a command definition for median aggregation
lazy_command!(
@ -266,49 +178,3 @@ lazy_command!(
median,
test_median
);
// LazyStd command
// Expands to a command definition for std aggregation
lazy_command!(
LazyStd,
"dfr std",
"Aggregates columns to their std value",
vec![Example {
description: "Std value from columns in a dataframe",
example: "[[a b]; [6 2] [4 2] [2 2]] | dfr into-df | dfr std",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new("a".to_string(), vec![Value::test_float(2.0)],),
Column::new("b".to_string(), vec![Value::test_float(0.0)],),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},],
std,
test_std,
1
);
// LazyVar command
// Expands to a command definition for var aggregation
lazy_command!(
LazyVar,
"dfr var",
"Aggregates columns to their var value",
vec![Example {
description: "Var value from columns in a dataframe",
example: "[[a b]; [6 2] [4 2] [2 2]] | dfr into-df | dfr var",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new("a".to_string(), vec![Value::test_float(4.0)],),
Column::new("b".to_string(), vec![Value::test_float(0.0)],),
])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},],
var,
test_var,
1
);

View File

@ -1,9 +1,11 @@
pub mod aggregate;
mod collect;
mod explode;
mod fetch;
mod fill_nan;
mod fill_null;
mod filter;
mod flatten;
pub mod groupby;
mod join;
mod macro_commands;
@ -27,6 +29,8 @@ use crate::dataframe::lazy::quantile::LazyQuantile;
pub(crate) use crate::dataframe::lazy::select::LazySelect;
use crate::dataframe::lazy::sort_by_expr::LazySortBy;
pub use crate::dataframe::lazy::to_lazy::ToLazyFrame;
pub use explode::LazyExplode;
pub use flatten::LazyFlatten;
pub fn add_lazy_decls(working_set: &mut StateWorkingSet) {
macro_rules! bind_command {
@ -49,17 +53,13 @@ pub fn add_lazy_decls(working_set: &mut StateWorkingSet) {
LazyFilter,
LazyJoin,
LazyQuantile,
LazyMax,
LazyMin,
LazySum,
LazyMean,
LazyMedian,
LazyStd,
LazyVar,
LazyReverse,
LazySelect,
LazySortBy,
ToLazyFrame,
ToLazyGroupBy
ToLazyGroupBy,
LazyExplode,
LazyFlatten
);
}

View File

@ -1,4 +1,4 @@
use super::super::super::values::{Column, NuDataFrame};
use super::super::super::values::{Column, NuDataFrame, NuExpression};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
@ -20,33 +20,46 @@ impl Command for IsNotNull {
fn signature(&self) -> Signature {
Signature::build(self.name())
.input_output_type(
Type::Custom("dataframe".into()),
Type::Custom("dataframe".into()),
)
.input_output_types(vec![
(
Type::Custom("expression".into()),
Type::Custom("expression".into()),
),
(
Type::Custom("dataframe".into()),
Type::Custom("dataframe".into()),
),
])
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Create mask where values are not null",
example: r#"let s = ([5 6 0 8] | dfr into-df);
vec![
Example {
description: "Create mask where values are not null",
example: r#"let s = ([5 6 0 8] | dfr into-df);
let res = ($s / $s);
$res | dfr is-not-null"#,
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"is_not_null".to_string(),
vec![
Value::test_bool(true),
Value::test_bool(true),
Value::test_bool(false),
Value::test_bool(true),
],
)])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
}]
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"is_not_null".to_string(),
vec![
Value::test_bool(true),
Value::test_bool(true),
Value::test_bool(false),
Value::test_bool(true),
],
)])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},
Example {
description: "Creates a is not null expression from a column",
example: "dfr col a | dfr is-not-null",
result: None,
},
]
}
fn run(
@ -56,8 +69,19 @@ impl Command for IsNotNull {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
command(engine_state, stack, call, df)
let value = input.into_value(call.head);
if NuDataFrame::can_downcast(&value) {
let df = NuDataFrame::try_from_value(value)?;
command(engine_state, stack, call, df)
} else {
let expr = NuExpression::try_from_value(value)?;
let expr: NuExpression = expr.into_polars().is_not_null().into();
Ok(PipelineData::Value(
NuExpression::into_value(expr, call.head),
None,
))
}
}
}
@ -76,11 +100,24 @@ fn command(
#[cfg(test)]
mod test {
use super::super::super::super::test_dataframe::test_dataframe;
use super::*;
use crate::dataframe::lazy::aggregate::LazyAggregate;
use crate::dataframe::lazy::groupby::ToLazyGroupBy;
use crate::dataframe::test_dataframe::{build_test_engine_state, test_dataframe_example};
#[test]
fn test_examples() {
test_dataframe(vec![Box::new(IsNotNull {})])
fn test_examples_dataframe() {
let mut engine_state = build_test_engine_state(vec![Box::new(IsNotNull {})]);
test_dataframe_example(&mut engine_state, &IsNotNull.examples()[0]);
}
#[test]
fn test_examples_expression() {
let mut engine_state = build_test_engine_state(vec![
Box::new(IsNotNull {}),
Box::new(LazyAggregate {}),
Box::new(ToLazyGroupBy {}),
]);
test_dataframe_example(&mut engine_state, &IsNotNull.examples()[1]);
}
}

View File

@ -1,4 +1,4 @@
use super::super::super::values::{Column, NuDataFrame};
use super::super::super::values::{Column, NuDataFrame, NuExpression};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
@ -20,33 +20,46 @@ impl Command for IsNull {
fn signature(&self) -> Signature {
Signature::build(self.name())
.input_output_type(
Type::Custom("dataframe".into()),
Type::Custom("dataframe".into()),
)
.input_output_types(vec![
(
Type::Custom("expression".into()),
Type::Custom("expression".into()),
),
(
Type::Custom("dataframe".into()),
Type::Custom("dataframe".into()),
),
])
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Create mask where values are null",
example: r#"let s = ([5 6 0 8] | dfr into-df);
vec![
Example {
description: "Create mask where values are null",
example: r#"let s = ([5 6 0 8] | dfr into-df);
let res = ($s / $s);
$res | dfr is-null"#,
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"is_null".to_string(),
vec![
Value::test_bool(false),
Value::test_bool(false),
Value::test_bool(true),
Value::test_bool(false),
],
)])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
}]
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"is_null".to_string(),
vec![
Value::test_bool(false),
Value::test_bool(false),
Value::test_bool(true),
Value::test_bool(false),
],
)])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},
Example {
description: "Creates a is null expression from a column",
example: "dfr col a | dfr is-null",
result: None,
},
]
}
fn run(
@ -56,8 +69,19 @@ impl Command for IsNull {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
command(engine_state, stack, call, df)
let value = input.into_value(call.head);
if NuDataFrame::can_downcast(&value) {
let df = NuDataFrame::try_from_value(value)?;
command(engine_state, stack, call, df)
} else {
let expr = NuExpression::try_from_value(value)?;
let expr: NuExpression = expr.into_polars().is_null().into();
Ok(PipelineData::Value(
NuExpression::into_value(expr, call.head),
None,
))
}
}
}
@ -76,11 +100,24 @@ fn command(
#[cfg(test)]
mod test {
use super::super::super::super::test_dataframe::test_dataframe;
use super::*;
use crate::dataframe::lazy::aggregate::LazyAggregate;
use crate::dataframe::lazy::groupby::ToLazyGroupBy;
use crate::dataframe::test_dataframe::{build_test_engine_state, test_dataframe_example};
#[test]
fn test_examples() {
test_dataframe(vec![Box::new(IsNull {})])
fn test_examples_dataframe() {
let mut engine_state = build_test_engine_state(vec![Box::new(IsNull {})]);
test_dataframe_example(&mut engine_state, &IsNull.examples()[0]);
}
#[test]
fn test_examples_expression() {
let mut engine_state = build_test_engine_state(vec![
Box::new(IsNull {}),
Box::new(LazyAggregate {}),
Box::new(ToLazyGroupBy {}),
]);
test_dataframe_example(&mut engine_state, &IsNull.examples()[1]);
}
}

View File

@ -1,4 +1,4 @@
use super::super::values::{Column, NuDataFrame};
use super::super::values::{Column, NuDataFrame, NuExpression};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
@ -19,26 +19,39 @@ impl Command for NUnique {
fn signature(&self) -> Signature {
Signature::build(self.name())
.input_output_type(
Type::Custom("dataframe".into()),
Type::Custom("dataframe".into()),
)
.input_output_types(vec![
(
Type::Custom("expression".into()),
Type::Custom("expression".into()),
),
(
Type::Custom("dataframe".into()),
Type::Custom("dataframe".into()),
),
])
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Counts unique values",
example: "[1 1 2 2 3 3 4] | dfr into-df | dfr n-unique",
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"count_unique".to_string(),
vec![Value::test_int(4)],
)])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
}]
vec![
Example {
description: "Counts unique values",
example: "[1 1 2 2 3 3 4] | dfr into-df | dfr n-unique",
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"count_unique".to_string(),
vec![Value::test_int(4)],
)])
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},
Example {
description: "Creates a is n-unique expression from a column",
example: "dfr col a | dfr n-unique",
result: None,
},
]
}
fn run(
@ -48,8 +61,19 @@ impl Command for NUnique {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
command(engine_state, stack, call, df)
let value = input.into_value(call.head);
if NuDataFrame::can_downcast(&value) {
let df = NuDataFrame::try_from_value(value)?;
command(engine_state, stack, call, df)
} else {
let expr = NuExpression::try_from_value(value)?;
let expr: NuExpression = expr.into_polars().n_unique().into();
Ok(PipelineData::Value(
NuExpression::into_value(expr, call.head),
None,
))
}
}
}
@ -77,11 +101,24 @@ fn command(
#[cfg(test)]
mod test {
use super::super::super::test_dataframe::test_dataframe;
use super::super::super::test_dataframe::{build_test_engine_state, test_dataframe_example};
use super::*;
use crate::dataframe::lazy::aggregate::LazyAggregate;
use crate::dataframe::lazy::groupby::ToLazyGroupBy;
#[test]
fn test_examples() {
test_dataframe(vec![Box::new(NUnique {})])
fn test_examples_dataframe() {
let mut engine_state = build_test_engine_state(vec![Box::new(NUnique {})]);
test_dataframe_example(&mut engine_state, &NUnique.examples()[0]);
}
#[test]
fn test_examples_expression() {
let mut engine_state = build_test_engine_state(vec![
Box::new(NUnique {}),
Box::new(LazyAggregate {}),
Box::new(ToLazyGroupBy {}),
]);
test_dataframe_example(&mut engine_state, &NUnique.examples()[1]);
}
}

View File

@ -2,7 +2,7 @@ use nu_engine::eval_block;
use nu_parser::parse;
use nu_protocol::{
engine::{Command, EngineState, Stack, StateWorkingSet},
PipelineData, Span,
Example, PipelineData, Span,
};
use super::eager::ToDataFrame;
@ -17,6 +17,14 @@ pub fn test_dataframe(cmds: Vec<Box<dyn Command + 'static>>) {
// The first element in the cmds vector must be the one tested
let examples = cmds[0].examples();
let mut engine_state = build_test_engine_state(cmds.clone());
for example in examples {
test_dataframe_example(&mut engine_state, &example);
}
}
pub fn build_test_engine_state(cmds: Vec<Box<dyn Command + 'static>>) -> Box<EngineState> {
let mut engine_state = Box::new(EngineState::new());
let delta = {
@ -41,54 +49,55 @@ pub fn test_dataframe(cmds: Vec<Box<dyn Command + 'static>>) {
.merge_delta(delta)
.expect("Error merging delta");
for example in examples {
// Skip tests that don't have results to compare to
if example.result.is_none() {
continue;
engine_state
}
pub fn test_dataframe_example(engine_state: &mut Box<EngineState>, example: &Example) {
// Skip tests that don't have results to compare to
if example.result.is_none() {
return;
}
let start = std::time::Instant::now();
let (block, delta) = {
let mut working_set = StateWorkingSet::new(engine_state);
let output = parse(&mut working_set, None, example.example.as_bytes(), false);
if let Some(err) = working_set.parse_errors.first() {
panic!("test parse error in `{}`: {:?}", example.example, err)
}
let start = std::time::Instant::now();
let (block, delta) = {
let mut working_set = StateWorkingSet::new(&engine_state);
let output = parse(&mut working_set, None, example.example.as_bytes(), false);
(output, working_set.render())
};
if let Some(err) = working_set.parse_errors.first() {
panic!("test parse error in `{}`: {:?}", example.example, err)
}
engine_state
.merge_delta(delta)
.expect("Error merging delta");
(output, working_set.render())
};
let mut stack = Stack::new();
engine_state
.merge_delta(delta)
.expect("Error merging delta");
let result = eval_block(
engine_state,
&mut stack,
&block,
PipelineData::empty(),
true,
true,
)
.unwrap_or_else(|err| panic!("test eval error in `{}`: {:?}", example.example, err))
.into_value(Span::test_data());
let mut stack = Stack::new();
println!("input: {}", example.example);
println!("result: {result:?}");
println!("done: {:?}", start.elapsed());
let result = eval_block(
&engine_state,
&mut stack,
&block,
PipelineData::empty(),
true,
true,
)
.unwrap_or_else(|err| panic!("test eval error in `{}`: {:?}", example.example, err))
.into_value(Span::test_data());
println!("input: {}", example.example);
println!("result: {result:?}");
println!("done: {:?}", start.elapsed());
// Note. Value implements PartialEq for Bool, Int, Float, String and Block
// If the command you are testing requires to compare another case, then
// you need to define its equality in the Value struct
if let Some(expected) = example.result {
if result != expected {
panic!(
"the example result is different to expected value: {result:?} != {expected:?}"
)
}
// Note. Value implements PartialEq for Bool, Int, Float, String and Block
// If the command you are testing requires to compare another case, then
// you need to define its equality in the Value struct
if let Some(expected) = example.result.clone() {
if result != expected {
panic!("the example result is different to expected value: {result:?} != {expected:?}")
}
}
}

View File

@ -1,2 +1,4 @@
#[cfg(feature = "dataframe")]
pub mod dataframe;
#[cfg(feature = "dataframe")]
pub use dataframe::*;

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

View File

@ -1,5 +1,4 @@
mod bits;
mod bytes;
mod conversions;
mod filters;
mod formats;
@ -7,19 +6,6 @@ mod math;
mod platform;
mod strings;
pub use bytes::Bytes;
pub use bytes::BytesAdd;
pub use bytes::BytesAt;
pub use bytes::BytesBuild;
pub use bytes::BytesCollect;
pub use bytes::BytesEndsWith;
pub use bytes::BytesIndexOf;
pub use bytes::BytesLen;
pub use bytes::BytesRemove;
pub use bytes::BytesReplace;
pub use bytes::BytesReverse;
pub use bytes::BytesStartsWith;
pub use bits::Bits;
pub use bits::BitsAnd;
pub use bits::BitsInto;
@ -85,9 +71,15 @@ pub fn add_extra_command_context(mut engine_state: EngineState) -> EngineState {
bind_command!(
strings::format::Format,
strings::format::FileSize,
strings::encode_decode::EncodeHex,
strings::encode_decode::DecodeHex
strings::encode_decode::DecodeHex,
strings::str_::case::Str,
strings::str_::case::StrCamelCase,
strings::str_::case::StrKebabCase,
strings::str_::case::StrPascalCase,
strings::str_::case::StrScreamingSnakeCase,
strings::str_::case::StrSnakeCase,
strings::str_::case::StrTitleCase
);
bind_command!(formats::ToHtml, formats::FromUrl);
@ -105,22 +97,6 @@ pub fn add_extra_command_context(mut engine_state: EngineState) -> EngineState {
BitsXor
}
// Bytes
bind_command! {
Bytes,
BytesLen,
BytesStartsWith,
BytesEndsWith,
BytesReverse,
BytesReplace,
BytesAdd,
BytesAt,
BytesIndexOf,
BytesCollect,
BytesRemove,
BytesBuild
}
// Math
bind_command! {
MathArcSin,

View File

@ -129,13 +129,13 @@ fn operate(
input.map(
move |v| {
if column_paths.is_empty() {
action(&v, fgs_hex, fge_hex, bgs_hex, bge_hex, &head)
action(&v, fgs_hex, fge_hex, bgs_hex, bge_hex, head)
} else {
let mut ret = v;
for path in &column_paths {
let r = ret.update_cell_path(
&path.members,
Box::new(move |old| action(old, fgs_hex, fge_hex, bgs_hex, bge_hex, &head)),
Box::new(move |old| action(old, fgs_hex, fge_hex, bgs_hex, bge_hex, head)),
);
if let Err(error) = r {
return Value::Error {
@ -156,10 +156,11 @@ fn action(
fg_end: Option<Rgb>,
bg_start: Option<Rgb>,
bg_end: Option<Rgb>,
command_span: &Span,
command_span: Span,
) -> Value {
match input {
Value::String { val, span } => {
let span = *span;
match (fg_start, fg_end, bg_start, bg_end) {
(None, None, None, None) => {
// Error - no colors
@ -167,7 +168,7 @@ fn action(
error: Box::new(ShellError::MissingParameter {
param_name:
"please supply foreground and/or background color parameters".into(),
span: *command_span,
span: command_span,
}),
}
}
@ -176,27 +177,27 @@ fn action(
let bg_start = Rgb::new(0, 0, 0);
let gradient = Gradient::new(bg_start, bg_end);
let gradient_string = gradient.build(val, TargetGround::Background);
Value::string(gradient_string, *span)
Value::string(gradient_string, span)
}
(None, None, Some(bg_start), None) => {
// Error - missing bg_end, so assume black
let bg_end = Rgb::new(0, 0, 0);
let gradient = Gradient::new(bg_start, bg_end);
let gradient_string = gradient.build(val, TargetGround::Background);
Value::string(gradient_string, *span)
Value::string(gradient_string, span)
}
(None, None, Some(bg_start), Some(bg_end)) => {
// Background Only
let gradient = Gradient::new(bg_start, bg_end);
let gradient_string = gradient.build(val, TargetGround::Background);
Value::string(gradient_string, *span)
Value::string(gradient_string, span)
}
(None, Some(fg_end), None, None) => {
// Error - missing fg_start, so assume black
let fg_start = Rgb::new(0, 0, 0);
let gradient = Gradient::new(fg_start, fg_end);
let gradient_string = gradient.build(val, TargetGround::Foreground);
Value::string(gradient_string, *span)
Value::string(gradient_string, span)
}
(None, Some(fg_end), None, Some(bg_end)) => {
// missing fg_start and bg_start, so assume black
@ -205,7 +206,7 @@ fn action(
let fg_gradient = Gradient::new(fg_start, fg_end);
let bg_gradient = Gradient::new(bg_start, bg_end);
let gradient_string = build_all_gradient_text(val, fg_gradient, bg_gradient);
Value::string(gradient_string, *span)
Value::string(gradient_string, span)
}
(None, Some(fg_end), Some(bg_start), None) => {
// Error - missing fg_start and bg_end
@ -214,7 +215,7 @@ fn action(
let fg_gradient = Gradient::new(fg_start, fg_end);
let bg_gradient = Gradient::new(bg_start, bg_end);
let gradient_string = build_all_gradient_text(val, fg_gradient, bg_gradient);
Value::string(gradient_string, *span)
Value::string(gradient_string, span)
}
(None, Some(fg_end), Some(bg_start), Some(bg_end)) => {
// Error - missing fg_start, so assume black
@ -222,14 +223,14 @@ fn action(
let fg_gradient = Gradient::new(fg_start, fg_end);
let bg_gradient = Gradient::new(bg_start, bg_end);
let gradient_string = build_all_gradient_text(val, fg_gradient, bg_gradient);
Value::string(gradient_string, *span)
Value::string(gradient_string, span)
}
(Some(fg_start), None, None, None) => {
// Error - missing fg_end, so assume black
let fg_end = Rgb::new(0, 0, 0);
let gradient = Gradient::new(fg_start, fg_end);
let gradient_string = gradient.build(val, TargetGround::Foreground);
Value::string(gradient_string, *span)
Value::string(gradient_string, span)
}
(Some(fg_start), None, None, Some(bg_end)) => {
// Error - missing fg_end, bg_start, so assume black
@ -238,7 +239,7 @@ fn action(
let fg_gradient = Gradient::new(fg_start, fg_end);
let bg_gradient = Gradient::new(bg_start, bg_end);
let gradient_string = build_all_gradient_text(val, fg_gradient, bg_gradient);
Value::string(gradient_string, *span)
Value::string(gradient_string, span)
}
(Some(fg_start), None, Some(bg_start), None) => {
// Error - missing fg_end, bg_end, so assume black
@ -247,7 +248,7 @@ fn action(
let fg_gradient = Gradient::new(fg_start, fg_end);
let bg_gradient = Gradient::new(bg_start, bg_end);
let gradient_string = build_all_gradient_text(val, fg_gradient, bg_gradient);
Value::string(gradient_string, *span)
Value::string(gradient_string, span)
}
(Some(fg_start), None, Some(bg_start), Some(bg_end)) => {
// Error - missing fg_end, so assume black
@ -255,13 +256,13 @@ fn action(
let fg_gradient = Gradient::new(fg_start, fg_end);
let bg_gradient = Gradient::new(bg_start, bg_end);
let gradient_string = build_all_gradient_text(val, fg_gradient, bg_gradient);
Value::string(gradient_string, *span)
Value::string(gradient_string, span)
}
(Some(fg_start), Some(fg_end), None, None) => {
// Foreground Only
let gradient = Gradient::new(fg_start, fg_end);
let gradient_string = gradient.build(val, TargetGround::Foreground);
Value::string(gradient_string, *span)
Value::string(gradient_string, span)
}
(Some(fg_start), Some(fg_end), None, Some(bg_end)) => {
// Error - missing bg_start, so assume black
@ -269,7 +270,7 @@ fn action(
let fg_gradient = Gradient::new(fg_start, fg_end);
let bg_gradient = Gradient::new(bg_start, bg_end);
let gradient_string = build_all_gradient_text(val, fg_gradient, bg_gradient);
Value::string(gradient_string, *span)
Value::string(gradient_string, span)
}
(Some(fg_start), Some(fg_end), Some(bg_start), None) => {
// Error - missing bg_end, so assume black
@ -277,14 +278,14 @@ fn action(
let fg_gradient = Gradient::new(fg_start, fg_end);
let bg_gradient = Gradient::new(bg_start, bg_end);
let gradient_string = build_all_gradient_text(val, fg_gradient, bg_gradient);
Value::string(gradient_string, *span)
Value::string(gradient_string, span)
}
(Some(fg_start), Some(fg_end), Some(bg_start), Some(bg_end)) => {
// Foreground and Background Gradient
let fg_gradient = Gradient::new(fg_start, fg_end);
let bg_gradient = Gradient::new(bg_start, bg_end);
let gradient_string = build_all_gradient_text(val, fg_gradient, bg_gradient);
Value::string(gradient_string, *span)
Value::string(gradient_string, span)
}
}
}
@ -294,7 +295,7 @@ fn action(
Value::Error {
error: Box::new(ShellError::TypeMismatch {
err_message: got,
span: other.span().unwrap_or(*command_span),
span: other.span().unwrap_or(command_span),
}),
}
}
@ -326,7 +327,7 @@ mod tests {
Some(fg_end),
None,
None,
&Span::test_data(),
Span::test_data(),
);
assert_eq!(actual, expected);
}

View File

@ -98,12 +98,12 @@ fn operate(
if column_paths.is_empty() {
input.map(
move |v| process_value(&v, &text, &command_span),
move |v| process_value(&v, &text, command_span),
engine_state.ctrlc.clone(),
)
} else {
input.map(
move |v| process_each_path(v, &column_paths, &text, &command_span),
move |v| process_each_path(v, &column_paths, &text, command_span),
engine_state.ctrlc.clone(),
)
}
@ -113,7 +113,7 @@ fn process_each_path(
mut value: Value,
column_paths: &Vec<CellPath>,
text: &Option<String>,
command_span: &Span,
command_span: Span,
) -> Value {
for path in column_paths {
let ret = value.update_cell_path(
@ -129,7 +129,7 @@ fn process_each_path(
value
}
fn process_value(value: &Value, text: &Option<String>, command_span: &Span) -> Value {
fn process_value(value: &Value, text: &Option<String>, command_span: Span) -> Value {
match value {
Value::String { val, span } => {
let text = text.as_deref().unwrap_or(val.as_str());
@ -142,7 +142,7 @@ fn process_value(value: &Value, text: &Option<String>, command_span: &Span) -> V
Value::Error {
error: Box::new(ShellError::TypeMismatch {
err_message: got,
span: other.span().unwrap_or(*command_span),
span: other.span().unwrap_or(command_span),
}),
}
}

View File

@ -1,3 +1,5 @@
use std::vec;
use nu_engine::{eval_expression, CallExt};
use nu_parser::parse_expression;
use nu_protocol::ast::{Call, PathMember};
@ -17,15 +19,16 @@ impl Command for Format {
fn signature(&self) -> Signature {
Signature::build("format")
.input_output_types(vec![(
Type::Table(vec![]),
Type::List(Box::new(Type::String)),
)])
.input_output_types(vec![
(Type::Table(vec![]), Type::List(Box::new(Type::String))),
(Type::Record(vec![]), Type::Any),
])
.required(
"pattern",
SyntaxShape::String,
"the pattern to output. e.g.) \"{foo}: {bar}\"",
)
.allow_variants_without_examples(true)
.category(Category::Strings)
}

View File

@ -1,5 +1,3 @@
mod command;
mod filesize;
pub(crate) use command::Format;
pub(crate) use filesize::FileSize;

View File

@ -1,2 +1,3 @@
pub(crate) mod encode_decode;
pub(crate) mod format;
pub(crate) mod str_;

View File

@ -5,7 +5,7 @@ use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use crate::operate;
use super::operate;
#[derive(Clone)]
pub struct SubCommand;

View File

@ -5,7 +5,7 @@ use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use crate::operate;
use super::operate;
#[derive(Clone)]
pub struct SubCommand;

View File

@ -0,0 +1,74 @@
mod camel_case;
mod kebab_case;
mod pascal_case;
mod screaming_snake_case;
mod snake_case;
mod str_;
mod title_case;
pub use camel_case::SubCommand as StrCamelCase;
pub use kebab_case::SubCommand as StrKebabCase;
pub use pascal_case::SubCommand as StrPascalCase;
pub use screaming_snake_case::SubCommand as StrScreamingSnakeCase;
pub use snake_case::SubCommand as StrSnakeCase;
pub use str_::Str;
pub use title_case::SubCommand as StrTitleCase;
use nu_engine::CallExt;
use nu_cmd_base::input_handler::{operate as general_operate, CmdArgument};
use nu_protocol::ast::{Call, CellPath};
use nu_protocol::engine::{EngineState, Stack};
use nu_protocol::{PipelineData, ShellError, Span, Value};
struct Arguments<F: Fn(&str) -> String + Send + Sync + 'static> {
case_operation: &'static F,
cell_paths: Option<Vec<CellPath>>,
}
impl<F: Fn(&str) -> String + Send + Sync + 'static> CmdArgument for Arguments<F> {
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
self.cell_paths.take()
}
}
pub fn operate<F>(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
case_operation: &'static F,
) -> Result<PipelineData, ShellError>
where
F: Fn(&str) -> String + Send + Sync + 'static,
{
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
let args = Arguments {
case_operation,
cell_paths,
};
general_operate(action, args, input, call.head, engine_state.ctrlc.clone())
}
fn action<F>(input: &Value, args: &Arguments<F>, head: Span) -> Value
where
F: Fn(&str) -> String + Send + Sync + 'static,
{
let case_operation = args.case_operation;
match input {
Value::String { val, .. } => Value::String {
val: case_operation(val),
span: head,
},
Value::Error { .. } => input.clone(),
_ => Value::Error {
error: Box::new(ShellError::OnlySupportsThisInputType {
exp_input_type: "string".into(),
wrong_type: input.get_type().to_string(),
dst_span: head,
src_span: input.expect_span(),
}),
},
}
}

View File

@ -5,7 +5,7 @@ use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use crate::operate;
use super::operate;
#[derive(Clone)]
pub struct SubCommand;

View File

@ -5,7 +5,8 @@ use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use crate::operate;
use super::operate;
#[derive(Clone)]
pub struct SubCommand;

View File

@ -5,7 +5,7 @@ use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use crate::operate;
use super::operate;
#[derive(Clone)]
pub struct SubCommand;

View File

@ -0,0 +1,49 @@
use nu_engine::get_full_help;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, IntoPipelineData, PipelineData, ShellError, Signature, Type, Value,
};
#[derive(Clone)]
pub struct Str;
impl Command for Str {
fn name(&self) -> &str {
"str"
}
fn signature(&self) -> Signature {
Signature::build("str")
.category(Category::Strings)
.input_output_types(vec![(Type::Nothing, Type::String)])
}
fn usage(&self) -> &str {
"Various commands for working with string data."
}
fn extra_usage(&self) -> &str {
"You must use one of the following subcommands. Using this command as-is will only produce this help message."
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
Ok(Value::String {
val: get_full_help(
&Str.signature(),
&Str.examples(),
engine_state,
stack,
self.is_parser_keyword(),
),
span: call.head,
}
.into_pipeline_data())
}
}

View File

@ -5,7 +5,7 @@ use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use crate::operate;
use super::operate;
#[derive(Clone)]
pub struct SubCommand;

View File

@ -0,0 +1,3 @@
pub(crate) mod case;
pub use case::*;

View File

@ -6,16 +6,16 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-lang"
edition = "2021"
license = "MIT"
name = "nu-cmd-lang"
version = "0.83.1"
version = "0.84.0"
[lib]
bench = false
[dependencies]
nu-engine = { path = "../nu-engine", version = "0.83.1" }
nu-parser = { path = "../nu-parser", version = "0.83.1" }
nu-protocol = { path = "../nu-protocol", version = "0.83.1" }
nu-utils = { path = "../nu-utils", version = "0.83.1" }
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-utils = { path = "../nu-utils", version = "0.84.0" }
nu-ansi-term = "0.49.0"
fancy-regex = "0.11"

View File

@ -0,0 +1,66 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
};
#[derive(Clone)]
pub struct ExportConst;
impl Command for ExportConst {
fn name(&self) -> &str {
"export const"
}
fn usage(&self) -> &str {
"Use parse-time constant from a module and export them from this module."
}
fn signature(&self) -> nu_protocol::Signature {
Signature::build("export const")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.allow_variants_without_examples(true)
.required("const_name", SyntaxShape::VarWithOptType, "constant name")
.required(
"initial_value",
SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::MathExpression)),
"equals sign followed by constant value",
)
.category(Category::Core)
}
fn extra_usage(&self) -> &str {
r#"This command is a parser keyword. For details, check:
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
}
fn run(
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
_call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Re-export a command from another module",
example: r#"module spam { export const foo = 3; }
module eggs { export use spam foo }
use eggs foo
foo
"#,
result: Some(Value::test_int(3)),
}]
}
fn search_terms(&self) -> Vec<&str> {
vec!["reexport", "import", "module"]
}
}

View File

@ -0,0 +1,56 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type};
#[derive(Clone)]
pub struct ExportExternWrapped;
impl Command for ExportExternWrapped {
fn name(&self) -> &str {
"export extern-wrapped"
}
fn usage(&self) -> &str {
"Define an extern with a custom code block and export it from a module."
}
fn signature(&self) -> nu_protocol::Signature {
Signature::build("export extern-wrapped")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.required("def_name", SyntaxShape::String, "definition name")
.required("params", SyntaxShape::Signature, "parameters")
.required("body", SyntaxShape::Block, "wrapper code block")
.category(Category::Core)
}
fn extra_usage(&self) -> &str {
r#"This command is a parser keyword. For details, check:
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
}
fn run(
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
_call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Export the signature for an external command",
example: r#"export extern-wrapped my-echo [...rest] { echo $rest }"#,
result: None,
}]
}
fn search_terms(&self) -> Vec<&str> {
vec!["signature", "module", "declare"]
}
}

View File

@ -1,6 +1,8 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
};
#[derive(Clone)]
pub struct ExternWrapped;
@ -11,15 +13,16 @@ impl Command for ExternWrapped {
}
fn usage(&self) -> &str {
"Define a signature for an external command."
"Define a signature for an external command with a custom code block."
}
fn signature(&self) -> nu_protocol::Signature {
Signature::build("extern-wrapped")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.allow_variants_without_examples(true)
.required("def_name", SyntaxShape::String, "definition name")
.required("params", SyntaxShape::Signature, "parameters")
.required("body", SyntaxShape::Block, "wrapper function block")
.required("body", SyntaxShape::Block, "wrapper code block")
.category(Category::Core)
}
@ -44,9 +47,19 @@ impl Command for ExternWrapped {
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Write a signature for an external command",
example: r#"extern-wrapped echo [text: string] { print $text }"#,
result: None,
description: "Define a custom wrapper for an external command",
example: r#"extern-wrapped my-echo [...rest] { echo $rest }; my-echo spam"#,
result: Some(Value::test_list(vec![Value::test_string("spam")])),
}]
}
}
#[cfg(test)]
mod test {
#[test]
fn test_examples() {
use super::ExternWrapped;
use crate::test_examples;
test_examples(ExternWrapped {})
}
}

View File

@ -121,12 +121,11 @@ impl Command for Match {
},
Example {
description: "Match with a guard",
example: "
match [1 2 3] {
[$x, ..$y] if $x == 1 => { 'good list' },
_ => { 'not a very good list' }
}
",
example: "match [1 2 3] {
[$x, ..$y] if $x == 1 => { 'good list' },
_ => { 'not a very good list' }
}
",
result: Some(Value::test_string("good list")),
},
]

View File

@ -11,9 +11,11 @@ mod echo;
mod error_make;
mod export;
mod export_alias;
mod export_const;
mod export_def;
mod export_def_env;
mod export_extern;
mod export_extern_wrapped;
mod export_module;
mod export_use;
mod extern_;
@ -50,9 +52,11 @@ pub use echo::Echo;
pub use error_make::ErrorMake;
pub use export::ExportCommand;
pub use export_alias::ExportAlias;
pub use export_const::ExportConst;
pub use export_def::ExportDef;
pub use export_def_env::ExportDefEnv;
pub use export_extern::ExportExtern;
pub use export_extern_wrapped::ExportExternWrapped;
pub use export_module::ExportModule;
pub use export_use::ExportUse;
pub use extern_::Extern;

View File

@ -68,7 +68,7 @@ impl Command for OverlayUse {
let maybe_origin_module_id =
if let Some(overlay_expr) = call.get_parser_info("overlay_expr") {
if let Expr::Overlay(module_id) = overlay_expr.expr {
if let Expr::Overlay(module_id) = &overlay_expr.expr {
module_id
} else {
return Err(ShellError::NushellFailedSpanned {
@ -106,11 +106,11 @@ impl Command for OverlayUse {
};
if let Some(module_id) = maybe_origin_module_id {
// Add environment variables only if:
// Add environment variables only if (determined by parser):
// a) adding a new overlay
// b) refreshing an active overlay (the origin module changed)
let module = engine_state.get_module(module_id);
let module = engine_state.get_module(*module_id);
// Evaluate the export-env block (if any) and keep its environment
if let Some(block_id) = module.env_block {
@ -122,7 +122,7 @@ impl Command for OverlayUse {
)?;
let block = engine_state.get_block(block_id);
let mut callee_stack = caller_stack.gather_captures(&block.captures);
let mut callee_stack = caller_stack.gather_captures(engine_state, &block.captures);
if let Some(path) = &maybe_path {
// Set the currently evaluated directory, if the argument is a valid path

View File

@ -19,7 +19,7 @@ impl Command for Return {
fn signature(&self) -> nu_protocol::Signature {
Signature::build("return")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.input_output_types(vec![(Type::Nothing, Type::Any)])
.optional("return_value", SyntaxShape::Any, "optional value to return")
.category(Category::Core)
}

View File

@ -35,7 +35,7 @@ impl Command for ScopeAliases {
let ctrlc = engine_state.ctrlc.clone();
let mut scope_data = ScopeData::new(engine_state, stack);
scope_data.populate_all();
scope_data.populate_decls();
Ok(scope_data.collect_aliases(span).into_pipeline_data(ctrlc))
}

View File

@ -35,7 +35,7 @@ impl Command for ScopeCommands {
let ctrlc = engine_state.ctrlc.clone();
let mut scope_data = ScopeData::new(engine_state, stack);
scope_data.populate_all();
scope_data.populate_decls();
Ok(scope_data.collect_commands(span).into_pipeline_data(ctrlc))
}

View File

@ -31,8 +31,7 @@ impl Command for ScopeEngineStats {
) -> Result<PipelineData, ShellError> {
let span = call.head;
let mut scope_data = ScopeData::new(engine_state, stack);
scope_data.populate_all();
let scope_data = ScopeData::new(engine_state, stack);
Ok(scope_data.collect_engine_state(span).into_pipeline_data())
}

View File

@ -0,0 +1,62 @@
use nu_engine::scope::ScopeData;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Type,
};
#[derive(Clone)]
pub struct ScopeExterns;
impl Command for ScopeExterns {
fn name(&self) -> &str {
"scope externs"
}
fn signature(&self) -> Signature {
Signature::build("scope externs")
.input_output_types(vec![(Type::Nothing, Type::Any)])
.allow_variants_without_examples(true)
.category(Category::Filters)
}
fn usage(&self) -> &str {
"Output info on the known externals in the current scope."
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let span = call.head;
let ctrlc = engine_state.ctrlc.clone();
let mut scope_data = ScopeData::new(engine_state, stack);
scope_data.populate_decls();
Ok(scope_data.collect_externs(span).into_pipeline_data(ctrlc))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Show the known externals in the current scope",
example: "scope externs",
result: None,
}]
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_examples() {
use crate::test_examples;
test_examples(ScopeExterns {})
}
}

View File

@ -2,6 +2,7 @@ mod aliases;
mod command;
mod commands;
mod engine_stats;
mod externs;
mod modules;
mod variables;
@ -9,5 +10,6 @@ pub use aliases::*;
pub use command::*;
pub use commands::*;
pub use engine_stats::*;
pub use externs::*;
pub use modules::*;
pub use variables::*;

View File

@ -35,7 +35,7 @@ impl Command for ScopeVariables {
let ctrlc = engine_state.ctrlc.clone();
let mut scope_data = ScopeData::new(engine_state, stack);
scope_data.populate_all();
scope_data.populate_vars();
Ok(scope_data.collect_vars(span).into_pipeline_data(ctrlc))
}

View File

@ -63,15 +63,30 @@ This command is a parser keyword. For details, check:
};
if let Some(module_id) = import_pattern.head.id {
let module = engine_state.get_module(module_id);
// Add constants
for var_id in &import_pattern.constants {
let var = engine_state.get_var(*var_id);
if let Some(constval) = &var.const_val {
caller_stack.add_var(*var_id, constval.clone());
} else {
return Err(ShellError::NushellFailedSpanned {
msg: "Missing Constant".to_string(),
label: "constant not added by the parser".to_string(),
span: var.declaration_span,
});
}
}
// Evaluate the export-env block if there is one
let module = engine_state.get_module(module_id);
if let Some(block_id) = module.env_block {
let block = engine_state.get_block(block_id);
// See if the module is a file
let module_arg_str = String::from_utf8_lossy(
engine_state.get_span_contents(&import_pattern.head.span),
engine_state.get_span_contents(import_pattern.head.span),
);
let maybe_file_path = find_in_dirs_env(
@ -84,7 +99,7 @@ This command is a parser keyword. For details, check:
.as_ref()
.and_then(|path| path.parent().map(|p| p.to_path_buf()));
let mut callee_stack = caller_stack.gather_captures(&block.captures);
let mut callee_stack = caller_stack.gather_captures(engine_state, &block.captures);
// If so, set the currently evaluated directory (file-relative PWD)
if let Some(parent) = maybe_parent {

View File

@ -1,6 +1,8 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Example, IntoPipelineData, PipelineData, ShellError, Signature, Type, Value};
use nu_protocol::{
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Type, Value,
};
use shadow_rs::shadow;
shadow!(build);
@ -17,6 +19,7 @@ impl Command for Version {
Signature::build("version")
.input_output_types(vec![(Type::Nothing, Type::Record(vec![]))])
.allow_variants_without_examples(true)
.category(Category::Core)
}
fn usage(&self) -> &str {

View File

@ -29,9 +29,11 @@ pub fn create_default_context() -> EngineState {
ErrorMake,
ExportAlias,
ExportCommand,
ExportConst,
ExportDef,
ExportDefEnv,
ExportExtern,
ExportExternWrapped,
ExportUse,
ExportModule,
Extern,
@ -57,6 +59,7 @@ pub fn create_default_context() -> EngineState {
ScopeAliases,
ScopeCommands,
ScopeEngineStats,
ScopeExterns,
ScopeModules,
ScopeVariables,
Try,

View File

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

View File

@ -143,13 +143,13 @@ impl<'a> StyleComputer<'a> {
let mut map: StyleMapping = [
("separator".to_string(), ComputableStyle::Static(Color::White.normal())),
("leading_trailing_space_bg".to_string(), ComputableStyle::Static(Style::default().on(Color::Rgb(128, 128, 128)))),
("header".to_string(), ComputableStyle::Static(Color::White.normal())),
("empty".to_string(), ComputableStyle::Static(Color::White.normal())),
("bool".to_string(), ComputableStyle::Static(Color::White.normal())),
("header".to_string(), ComputableStyle::Static(Color::Green.bold())),
("empty".to_string(), ComputableStyle::Static(Color::Blue.normal())),
("bool".to_string(), ComputableStyle::Static(Color::LightCyan.normal())),
("int".to_string(), ComputableStyle::Static(Color::White.normal())),
("filesize".to_string(), ComputableStyle::Static(Color::White.normal())),
("filesize".to_string(), ComputableStyle::Static(Color::Cyan.normal())),
("duration".to_string(), ComputableStyle::Static(Color::White.normal())),
("date".to_string(), ComputableStyle::Static(Color::White.normal())),
("date".to_string(), ComputableStyle::Static(Color::Purple.normal())),
("range".to_string(), ComputableStyle::Static(Color::White.normal())),
("float".to_string(), ComputableStyle::Static(Color::White.normal())),
("string".to_string(), ComputableStyle::Static(Color::White.normal())),

View File

@ -5,7 +5,7 @@ edition = "2021"
license = "MIT"
name = "nu-command"
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-command"
version = "0.83.1"
version = "0.84.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -14,21 +14,20 @@ bench = false
[dependencies]
nu-ansi-term = "0.49.0"
nu-cmd-base = { path = "../nu-cmd-base", version = "0.83.1" }
nu-color-config = { path = "../nu-color-config", version = "0.83.1" }
nu-engine = { path = "../nu-engine", version = "0.83.1" }
nu-glob = { path = "../nu-glob", version = "0.83.1" }
nu-json = { path = "../nu-json", version = "0.83.1" }
nu-parser = { path = "../nu-parser", version = "0.83.1" }
nu-path = { path = "../nu-path", version = "0.83.1" }
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.83.1" }
nu-protocol = { path = "../nu-protocol", version = "0.83.1" }
nu-system = { path = "../nu-system", version = "0.83.1" }
nu-table = { path = "../nu-table", version = "0.83.1" }
nu-term-grid = { path = "../nu-term-grid", version = "0.83.1" }
nu-utils = { path = "../nu-utils", version = "0.83.1" }
nu-cmd-base = { path = "../nu-cmd-base", version = "0.84.0" }
nu-color-config = { path = "../nu-color-config", version = "0.84.0" }
nu-engine = { path = "../nu-engine", version = "0.84.0" }
nu-glob = { path = "../nu-glob", version = "0.84.0" }
nu-json = { path = "../nu-json", version = "0.84.0" }
nu-parser = { path = "../nu-parser", version = "0.84.0" }
nu-path = { path = "../nu-path", version = "0.84.0" }
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.84.0" }
nu-protocol = { path = "../nu-protocol", version = "0.84.0" }
nu-system = { path = "../nu-system", version = "0.84.0" }
nu-table = { path = "../nu-table", version = "0.84.0" }
nu-term-grid = { path = "../nu-term-grid", version = "0.84.0" }
nu-utils = { path = "../nu-utils", version = "0.84.0" }
Inflector = "0.11"
alphanumeric-sort = "1.5"
base64 = "0.21"
byteorder = "1.4"
@ -70,7 +69,7 @@ pathdiff = "0.2"
percent-encoding = "2.3"
powierza-coefficient = "1.0"
print-positions = "0.6"
quick-xml = "0.29"
quick-xml = "0.30"
rand = "0.8"
rayon = "1.7"
regex = "1.7"
@ -84,7 +83,7 @@ serde_yaml = "0.9"
sha2 = "0.10"
sqlparser = { version = "0.34", features = ["serde"], optional = true }
sysinfo = "0.29"
tabled = { version = "0.12.2", features = ["color"], default-features = false }
tabled = { version = "0.14.0", features = ["color"], default-features = false }
terminal_size = "0.2"
titlecase = "2.0"
toml = "0.7"
@ -94,7 +93,7 @@ url = "2.2"
uuid = { version = "1.3", features = ["v4"] }
wax = { version = "0.5" }
which = { version = "4.4", optional = true }
bracoxide = "0.1.1"
bracoxide = "0.1.2"
[target.'cfg(windows)'.dependencies]
winreg = "0.50"
@ -125,11 +124,11 @@ trash-support = ["trash"]
which-support = ["which"]
[dev-dependencies]
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.83.1" }
nu-test-support = { path = "../nu-test-support", version = "0.83.1" }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.84.0" }
nu-test-support = { path = "../nu-test-support", version = "0.84.0" }
dirs-next = "2.0"
mockito = { version = "1.1", default-features = false }
quickcheck = "1.0"
quickcheck_macros = "1.0"
rstest = { version = "0.17", default-features = false }
rstest = { version = "0.18", default-features = false }

5
crates/nu-command/src/charting/histogram.rs Normal file → Executable file
View File

@ -4,8 +4,8 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape,
Type, Value,
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Spanned,
SyntaxShape, Type, Value,
};
use std::collections::HashMap;
use std::iter;
@ -29,6 +29,7 @@ impl Command for Histogram {
.optional("column-name", SyntaxShape::String, "column name to calc frequency, no need to provide if input is just a list")
.optional("frequency-column-name", SyntaxShape::String, "histogram's frequency column, default to be frequency column output")
.named("percentage-type", SyntaxShape::String, "percentage calculate method, can be 'normalize' or 'relative', in 'normalize', defaults to be 'normalize'", Some('t'))
.category(Category::Chart)
}
fn usage(&self) -> &str {

View File

@ -87,7 +87,7 @@ impl Command for SubCommand {
.named(
"format",
SyntaxShape::String,
"Specify expected format of string input to parse to datetime. Use --list to see options",
"Specify expected format of INPUT string to parse to datetime. Use --list to see options",
Some('f'),
)
.switch(
@ -236,6 +236,20 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
let timezone = &args.zone_options;
let dateformat = &args.format_options;
// Let's try dtparse first
if matches!(input, Value::String { .. }) && dateformat.is_none() {
if let Ok(input_val) = input.as_spanned_string() {
match parse_date_from_string(&input_val.item, input_val.span) {
Ok(date) => {
return Value::Date {
val: date,
span: input_val.span,
}
}
Err(err) => err,
};
}
}
const HOUR: i32 = 60 * 60;
// Check to see if input looks like a Unix timestamp (i.e. can it be parsed to an int?)
@ -256,51 +270,72 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
}
};
if let Ok(ts) = timestamp {
macro_rules! match_datetime {
($expr:expr) => {
match $expr {
dt => Value::Date {
val: dt.into(),
span: head,
if dateformat.is_none() {
if let Ok(ts) = timestamp {
return match timezone {
// note all these `.timestamp_nanos()` could overflow if we didn't check range in `<date> | into int`.
// default to UTC
None => Value::Date {
val: Utc.timestamp_nanos(ts).into(),
span: head,
},
Some(Spanned { item, span }) => match item {
Zone::Utc => {
let dt = Utc.timestamp_nanos(ts);
Value::Date {
val: dt.into(),
span: *span,
}
}
Zone::Local => {
let dt = Local.timestamp_nanos(ts);
Value::Date {
val: dt.into(),
span: *span,
}
}
Zone::East(i) => match FixedOffset::east_opt((*i as i32) * HOUR) {
Some(eastoffset) => {
let dt = eastoffset.timestamp_nanos(ts);
Value::Date {
val: dt,
span: *span,
}
}
None => Value::Error {
error: Box::new(ShellError::DatetimeParseError(
input.debug_value(),
*span,
)),
},
},
}
Zone::West(i) => match FixedOffset::west_opt((*i as i32) * HOUR) {
Some(westoffset) => {
let dt = westoffset.timestamp_nanos(ts);
Value::Date {
val: dt,
span: *span,
}
}
None => Value::Error {
error: Box::new(ShellError::DatetimeParseError(
input.debug_value(),
*span,
)),
},
},
Zone::Error => Value::Error {
// This is an argument error, not an input error
error: Box::new(ShellError::TypeMismatch {
err_message: "Invalid timezone or offset".to_string(),
span: *span,
}),
},
},
};
}
return match timezone {
// note all these `.timestamp_nanos()` could overflow if we didn't check range in `<date> | into int`.
// default to UTC
None => Value::Date {
val: Utc.timestamp_nanos(ts).into(),
span: head,
},
Some(Spanned { item, span }) => match item {
Zone::Utc => match_datetime!(Utc.timestamp_nanos(ts)),
Zone::Local => match_datetime!(Local.timestamp_nanos(ts)),
Zone::East(i) => match FixedOffset::east_opt((*i as i32) * HOUR) {
Some(eastoffset) => match_datetime!(eastoffset.timestamp_nanos(ts)),
None => Value::Error {
error: Box::new(ShellError::DatetimeParseError(input.debug_value(), *span)),
},
},
Zone::West(i) => match FixedOffset::west_opt((*i as i32) * HOUR) {
Some(westoffset) => match_datetime!(westoffset.timestamp_nanos(ts)),
None => Value::Error {
error: Box::new(ShellError::DatetimeParseError(input.debug_value(), *span)),
},
},
Zone::Error => Value::Error {
// This is an argument error, not an input error
error: Box::new(ShellError::TypeMismatch {
err_message: "Invalid timezone or offset".to_string(),
span: *span,
}),
},
},
};
};
}
// If input is not a timestamp, try parsing it as a string
match input {
@ -314,6 +349,7 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
}
}
},
// Tries to automatically parse the date
// (i.e. without a format string)
// and assumes the system's local timezone if none is specified

View File

@ -17,14 +17,15 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("into decimal")
.input_output_types(vec![
(Type::Int, Type::Number),
(Type::String, Type::Number),
(Type::Bool, Type::Number),
(Type::Int, Type::Float),
(Type::String, Type::Float),
(Type::Bool, Type::Float),
(Type::Float, Type::Float),
(Type::Table(vec![]), Type::Table(vec![])),
(Type::Record(vec![]), Type::Record(vec![])),
(
Type::List(Box::new(Type::Any)),
Type::List(Box::new(Type::Number)),
Type::List(Box::new(Type::Float)),
),
])
.rest(
@ -76,9 +77,12 @@ impl Command for SubCommand {
result: Some(Value::test_float(1.345)),
},
Example {
description: "Convert decimal to decimal",
example: "'-5.9' | into decimal",
result: Some(Value::test_float(-5.9)),
description: "Coerce list of ints and floats to float",
example: "[4 -5.9] | into decimal",
result: Some(Value::test_list(vec![
Value::test_float(4.0),
Value::test_float(-5.9),
])),
},
Example {
description: "Convert boolean to decimal",
@ -91,6 +95,7 @@ impl Command for SubCommand {
fn action(input: &Value, _args: &CellPathOnlyArgs, head: Span) -> Value {
match input {
Value::Float { .. } => input.clone(),
Value::String { val: s, span } => {
let other = s.trim();

View File

@ -3,10 +3,10 @@ use nu_parser::{parse_unit_value, DURATION_UNIT_GROUPS};
use nu_protocol::{
ast::{Call, CellPath, Expr},
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Unit,
Value,
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Unit, Value,
};
const NS_PER_SEC: i64 = 1_000_000_000;
#[derive(Clone)]
pub struct SubCommand;
@ -20,19 +20,11 @@ impl Command for SubCommand {
.input_output_types(vec![
(Type::String, Type::Duration),
(Type::Duration, Type::Duration),
// TODO: --convert option should be implemented as `format duration`
(Type::String, Type::String),
(Type::Duration, Type::String),
(Type::Table(vec![]), Type::Table(vec![])),
(Type::Record(vec![]), Type::Record(vec![])),
//todo: record<hour,minute,sign> | into duration -> Duration
//(Type::Record(vec![]), Type::Record(vec![])),
])
.allow_variants_without_examples(true)
.named(
"convert",
SyntaxShape::String,
"convert duration into another duration",
Some('c'),
)
//.allow_variants_without_examples(true)
.rest(
"rest",
SyntaxShape::CellPath,
@ -46,7 +38,7 @@ impl Command for SubCommand {
}
fn extra_usage(&self) -> &str {
"This command does not take leap years into account, and every month is assumed to have 30 days."
"Max duration value is i64::MAX nanoseconds; max duration time unit is wk (weeks)."
}
fn search_terms(&self) -> Vec<&str> {
@ -67,7 +59,23 @@ impl Command for SubCommand {
let span = Span::test_data();
vec![
Example {
description: "Convert string to duration in table",
description: "Convert duration string to duration value",
example: "'7min' | into duration",
result: Some(Value::Duration {
val: 7 * 60 * NS_PER_SEC,
span,
}),
},
Example {
description: "Convert compound duration string to duration value",
example: "'1day 2hr 3min 4sec' | into duration",
result: Some(Value::Duration {
val: (((((/* 1 * */24) + 2) * 60) + 3) * 60 + 4) * NS_PER_SEC,
span,
}),
},
Example {
description: "Convert table of duration strings to table of duration values",
example:
"[[value]; ['1sec'] ['2min'] ['3hr'] ['4day'] ['5wk']] | into duration value",
result: Some(Value::List {
@ -75,7 +83,7 @@ impl Command for SubCommand {
Value::Record {
cols: vec!["value".to_string()],
vals: vec![Value::Duration {
val: 1000 * 1000 * 1000,
val: NS_PER_SEC,
span,
}],
span,
@ -83,7 +91,7 @@ impl Command for SubCommand {
Value::Record {
cols: vec!["value".to_string()],
vals: vec![Value::Duration {
val: 2 * 60 * 1000 * 1000 * 1000,
val: 2 * 60 * NS_PER_SEC,
span,
}],
span,
@ -91,7 +99,7 @@ impl Command for SubCommand {
Value::Record {
cols: vec!["value".to_string()],
vals: vec![Value::Duration {
val: 3 * 60 * 60 * 1000 * 1000 * 1000,
val: 3 * 60 * 60 * NS_PER_SEC,
span,
}],
span,
@ -99,7 +107,7 @@ impl Command for SubCommand {
Value::Record {
cols: vec!["value".to_string()],
vals: vec![Value::Duration {
val: 4 * 24 * 60 * 60 * 1000 * 1000 * 1000,
val: 4 * 24 * 60 * 60 * NS_PER_SEC,
span,
}],
span,
@ -107,7 +115,7 @@ impl Command for SubCommand {
Value::Record {
cols: vec!["value".to_string()],
vals: vec![Value::Duration {
val: 5 * 7 * 24 * 60 * 60 * 1000 * 1000 * 1000,
val: 5 * 7 * 24 * 60 * 60 * NS_PER_SEC,
span,
}],
span,
@ -116,59 +124,11 @@ impl Command for SubCommand {
span,
}),
},
Example {
description: "Convert string to duration",
example: "'7min' | into duration",
result: Some(Value::Duration {
val: 7 * 60 * 1000 * 1000 * 1000,
span,
}),
},
Example {
description: "Convert string to the requested duration as a string",
example: "'7min' | into duration --convert sec",
result: Some(Value::String {
val: "420 sec".to_string(),
span,
}),
},
Example {
description: "Convert duration to duration",
example: "420sec | into duration",
result: Some(Value::Duration {
val: 7 * 60 * 1000 * 1000 * 1000,
span,
}),
},
Example {
description: "Convert duration to the requested duration as a string",
example: "420sec | into duration --convert ms",
result: Some(Value::String {
val: "420000 ms".to_string(),
span,
}),
},
Example {
description: "Convert µs duration to the requested duration as a string",
example: "1000000µs | into duration --convert sec",
result: Some(Value::String {
val: "1 sec".to_string(),
span,
}),
},
Example {
description: "Convert duration to the µs duration as a string",
example: "1sec | into duration --convert µs",
result: Some(Value::String {
val: "1000000 µs".to_string(),
span,
}),
},
Example {
description: "Convert duration to µs as a string if unit asked for was us",
example: "1sec | into duration --convert us",
result: Some(Value::String {
val: "1000000 µs".to_string(),
val: 7 * 60 * NS_PER_SEC,
span,
}),
},
@ -186,23 +146,17 @@ fn into_duration(
Some(t) => t,
None => call.head,
};
let convert_to_unit: Option<Spanned<String>> = call.get_flag(engine_state, stack, "convert")?;
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
let config = engine_state.get_config();
let float_precision = config.float_precision as usize;
input.map(
move |v| {
if column_paths.is_empty() {
action(&v, &convert_to_unit, float_precision, span)
action(&v, span)
} else {
let mut ret = v;
for path in &column_paths {
let d = convert_to_unit.clone();
let r = ret.update_cell_path(
&path.members,
Box::new(move |old| action(old, &d, float_precision, span)),
);
let r =
ret.update_cell_path(&path.members, Box::new(move |old| action(old, span)));
if let Err(error) = r {
return Value::Error {
error: Box::new(error),
@ -217,199 +171,32 @@ fn into_duration(
)
}
fn convert_str_from_unit_to_unit(
val: i64,
from_unit: &str,
to_unit: &str,
span: Span,
value_span: Span,
) -> Result<f64, ShellError> {
match (from_unit, to_unit) {
("ns", "ns") => Ok(val as f64),
("ns", "us") => Ok(val as f64 / 1000.0),
("ns", "µs") => Ok(val as f64 / 1000.0), // Micro sign
("ns", "μs") => Ok(val as f64 / 1000.0), // Greek small letter
("ns", "ms") => Ok(val as f64 / 1000.0 / 1000.0),
("ns", "sec") => Ok(val as f64 / 1000.0 / 1000.0 / 1000.0),
("ns", "min") => Ok(val as f64 / 1000.0 / 1000.0 / 1000.0 / 60.0),
("ns", "hr") => Ok(val as f64 / 1000.0 / 1000.0 / 1000.0 / 60.0 / 60.0),
("ns", "day") => Ok(val as f64 / 1000.0 / 1000.0 / 1000.0 / 60.0 / 60.0 / 24.0),
("ns", "wk") => Ok(val as f64 / 1000.0 / 1000.0 / 1000.0 / 60.0 / 60.0 / 24.0 / 7.0),
("ns", "month") => Ok(val as f64 / 1000.0 / 1000.0 / 1000.0 / 60.0 / 60.0 / 24.0 / 30.0),
("ns", "yr") => Ok(val as f64 / 1000.0 / 1000.0 / 1000.0 / 60.0 / 60.0 / 24.0 / 365.0),
("ns", "dec") => {
Ok(val as f64 / 10.0 / 1000.0 / 1000.0 / 1000.0 / 60.0 / 60.0 / 24.0 / 365.0)
}
("us", "ns") => Ok(val as f64 * 1000.0),
("us", "us") => Ok(val as f64),
("us", "µs") => Ok(val as f64), // Micro sign
("us", "μs") => Ok(val as f64), // Greek small letter
("us", "ms") => Ok(val as f64 / 1000.0),
("us", "sec") => Ok(val as f64 / 1000.0 / 1000.0),
("us", "min") => Ok(val as f64 / 1000.0 / 1000.0 / 60.0),
("us", "hr") => Ok(val as f64 / 1000.0 / 1000.0 / 60.0 / 60.0),
("us", "day") => Ok(val as f64 / 1000.0 / 1000.0 / 60.0 / 60.0 / 24.0),
("us", "wk") => Ok(val as f64 / 1000.0 / 1000.0 / 60.0 / 60.0 / 24.0 / 7.0),
("us", "month") => Ok(val as f64 / 1000.0 / 1000.0 / 60.0 / 60.0 / 24.0 / 30.0),
("us", "yr") => Ok(val as f64 / 1000.0 / 1000.0 / 60.0 / 60.0 / 24.0 / 365.0),
("us", "dec") => Ok(val as f64 / 10.0 / 1000.0 / 1000.0 / 60.0 / 60.0 / 24.0 / 365.0),
// Micro sign
("µs", "ns") => Ok(val as f64 * 1000.0),
("µs", "us") => Ok(val as f64),
("µs", "µs") => Ok(val as f64), // Micro sign
("µs", "μs") => Ok(val as f64), // Greek small letter
("µs", "ms") => Ok(val as f64 / 1000.0),
("µs", "sec") => Ok(val as f64 / 1000.0 / 1000.0),
("µs", "min") => Ok(val as f64 / 1000.0 / 1000.0 / 60.0),
("µs", "hr") => Ok(val as f64 / 1000.0 / 1000.0 / 60.0 / 60.0),
("µs", "day") => Ok(val as f64 / 1000.0 / 1000.0 / 60.0 / 60.0 / 24.0),
("µs", "wk") => Ok(val as f64 / 1000.0 / 1000.0 / 60.0 / 60.0 / 24.0 / 7.0),
("µs", "month") => Ok(val as f64 / 1000.0 / 1000.0 / 60.0 / 60.0 / 24.0 / 30.0),
("µs", "yr") => Ok(val as f64 / 1000.0 / 1000.0 / 60.0 / 60.0 / 24.0 / 365.0),
("µs", "dec") => Ok(val as f64 / 10.0 / 1000.0 / 1000.0 / 60.0 / 60.0 / 24.0 / 365.0),
// Greek small letter
("μs", "ns") => Ok(val as f64 * 1000.0),
("μs", "us") => Ok(val as f64),
("μs", "µs") => Ok(val as f64), // Micro sign
("μs", "μs") => Ok(val as f64), // Greek small letter
("μs", "ms") => Ok(val as f64 / 1000.0),
("μs", "sec") => Ok(val as f64 / 1000.0 / 1000.0),
("μs", "min") => Ok(val as f64 / 1000.0 / 1000.0 / 60.0),
("μs", "hr") => Ok(val as f64 / 1000.0 / 1000.0 / 60.0 / 60.0),
("μs", "day") => Ok(val as f64 / 1000.0 / 1000.0 / 60.0 / 60.0 / 24.0),
("μs", "wk") => Ok(val as f64 / 1000.0 / 1000.0 / 60.0 / 60.0 / 24.0 / 7.0),
("μs", "month") => Ok(val as f64 / 1000.0 / 1000.0 / 60.0 / 60.0 / 24.0 / 30.0),
("μs", "yr") => Ok(val as f64 / 1000.0 / 1000.0 / 60.0 / 60.0 / 24.0 / 365.0),
("μs", "dec") => Ok(val as f64 / 10.0 / 1000.0 / 1000.0 / 60.0 / 60.0 / 24.0 / 365.0),
("ms", "ns") => Ok(val as f64 * 1000.0 * 1000.0),
("ms", "us") => Ok(val as f64 * 1000.0),
("ms", "µs") => Ok(val as f64 * 1000.0), // Micro sign
("ms", "μs") => Ok(val as f64 * 1000.0), // Greek small letter
("ms", "ms") => Ok(val as f64),
("ms", "sec") => Ok(val as f64 / 1000.0),
("ms", "min") => Ok(val as f64 / 1000.0 / 60.0),
("ms", "hr") => Ok(val as f64 / 1000.0 / 60.0 / 60.0),
("ms", "day") => Ok(val as f64 / 1000.0 / 60.0 / 60.0 / 24.0),
("ms", "wk") => Ok(val as f64 / 1000.0 / 60.0 / 60.0 / 24.0 / 7.0),
("ms", "month") => Ok(val as f64 / 1000.0 / 60.0 / 60.0 / 24.0 / 30.0),
("ms", "yr") => Ok(val as f64 / 1000.0 / 60.0 / 60.0 / 24.0 / 365.0),
("ms", "dec") => Ok(val as f64 / 10.0 / 1000.0 / 60.0 / 60.0 / 24.0 / 365.0),
("sec", "ns") => Ok(val as f64 * 1000.0 * 1000.0 * 1000.0),
("sec", "us") => Ok(val as f64 * 1000.0 * 1000.0),
("sec", "µs") => Ok(val as f64 * 1000.0 * 1000.0), // Micro sign
("sec", "μs") => Ok(val as f64 * 1000.0 * 1000.0), // Greek small letter
("sec", "ms") => Ok(val as f64 * 1000.0),
("sec", "sec") => Ok(val as f64),
("sec", "min") => Ok(val as f64 / 60.0),
("sec", "hr") => Ok(val as f64 / 60.0 / 60.0),
("sec", "day") => Ok(val as f64 / 60.0 / 60.0 / 24.0),
("sec", "wk") => Ok(val as f64 / 60.0 / 60.0 / 24.0 / 7.0),
("sec", "month") => Ok(val as f64 / 60.0 / 60.0 / 24.0 / 30.0),
("sec", "yr") => Ok(val as f64 / 60.0 / 60.0 / 24.0 / 365.0),
("sec", "dec") => Ok(val as f64 / 10.0 / 60.0 / 60.0 / 24.0 / 365.0),
("min", "ns") => Ok(val as f64 * 1000.0 * 1000.0 * 1000.0 * 60.0),
("min", "us") => Ok(val as f64 * 1000.0 * 1000.0 * 60.0),
("min", "µs") => Ok(val as f64 * 1000.0 * 1000.0 * 60.0), // Micro sign
("min", "μs") => Ok(val as f64 * 1000.0 * 1000.0 * 60.0), // Greek small letter
("min", "ms") => Ok(val as f64 * 1000.0 * 60.0),
("min", "sec") => Ok(val as f64 * 60.0),
("min", "min") => Ok(val as f64),
("min", "hr") => Ok(val as f64 / 60.0),
("min", "day") => Ok(val as f64 / 60.0 / 24.0),
("min", "wk") => Ok(val as f64 / 60.0 / 24.0 / 7.0),
("min", "month") => Ok(val as f64 / 60.0 / 24.0 / 30.0),
("min", "yr") => Ok(val as f64 / 60.0 / 24.0 / 365.0),
("min", "dec") => Ok(val as f64 / 10.0 / 60.0 / 24.0 / 365.0),
("hr", "ns") => Ok(val as f64 * 1000.0 * 1000.0 * 1000.0 * 60.0 * 60.0),
("hr", "us") => Ok(val as f64 * 1000.0 * 1000.0 * 60.0 * 60.0),
("hr", "µs") => Ok(val as f64 * 1000.0 * 1000.0 * 60.0 * 60.0), // Micro sign
("hr", "μs") => Ok(val as f64 * 1000.0 * 1000.0 * 60.0 * 60.0), // Greek small letter
("hr", "ms") => Ok(val as f64 * 1000.0 * 60.0 * 60.0),
("hr", "sec") => Ok(val as f64 * 60.0 * 60.0),
("hr", "min") => Ok(val as f64 * 60.0),
("hr", "hr") => Ok(val as f64),
("hr", "day") => Ok(val as f64 / 24.0),
("hr", "wk") => Ok(val as f64 / 24.0 / 7.0),
("hr", "month") => Ok(val as f64 / 24.0 / 30.0),
("hr", "yr") => Ok(val as f64 / 24.0 / 365.0),
("hr", "dec") => Ok(val as f64 / 10.0 / 24.0 / 365.0),
("day", "ns") => Ok(val as f64 * 1000.0 * 1000.0 * 1000.0 * 60.0 * 60.0 * 24.0),
("day", "us") => Ok(val as f64 * 1000.0 * 1000.0 * 60.0 * 60.0 * 24.0),
("day", "µs") => Ok(val as f64 * 1000.0 * 1000.0 * 60.0 * 60.0 * 24.0), // Micro sign
("day", "μs") => Ok(val as f64 * 1000.0 * 1000.0 * 60.0 * 60.0 * 24.0), // Greek small letter
("day", "ms") => Ok(val as f64 * 1000.0 * 60.0 * 60.0 * 24.0),
("day", "sec") => Ok(val as f64 * 60.0 * 60.0 * 24.0),
("day", "min") => Ok(val as f64 * 60.0 * 24.0),
("day", "hr") => Ok(val as f64 * 24.0),
("day", "day") => Ok(val as f64),
("day", "wk") => Ok(val as f64 / 7.0),
("day", "month") => Ok(val as f64 / 30.0),
("day", "yr") => Ok(val as f64 / 365.0),
("day", "dec") => Ok(val as f64 / 10.0 / 365.0),
("wk", "ns") => Ok(val as f64 * 1000.0 * 1000.0 * 1000.0 * 60.0 * 60.0 * 24.0 * 7.0),
("wk", "us") => Ok(val as f64 * 1000.0 * 1000.0 * 60.0 * 60.0 * 24.0 * 7.0),
("wk", "µs") => Ok(val as f64 * 1000.0 * 1000.0 * 60.0 * 60.0 * 24.0 * 7.0), // Micro sign
("wk", "μs") => Ok(val as f64 * 1000.0 * 1000.0 * 60.0 * 60.0 * 24.0 * 7.0), // Greek small letter
("wk", "ms") => Ok(val as f64 * 1000.0 * 60.0 * 60.0 * 24.0 * 7.0),
("wk", "sec") => Ok(val as f64 * 60.0 * 60.0 * 24.0 * 7.0),
("wk", "min") => Ok(val as f64 * 60.0 * 24.0 * 7.0),
("wk", "hr") => Ok(val as f64 * 24.0 * 7.0),
("wk", "day") => Ok(val as f64 * 7.0),
("wk", "wk") => Ok(val as f64),
("wk", "month") => Ok(val as f64 / 4.0),
("wk", "yr") => Ok(val as f64 / 52.0),
("wk", "dec") => Ok(val as f64 / 10.0 / 52.0),
("month", "ns") => Ok(val as f64 * 1000.0 * 1000.0 * 1000.0 * 60.0 * 60.0 * 24.0 * 30.0),
("month", "us") => Ok(val as f64 * 1000.0 * 1000.0 * 60.0 * 60.0 * 24.0 * 30.0),
("month", "µs") => Ok(val as f64 * 1000.0 * 1000.0 * 60.0 * 60.0 * 24.0 * 30.0), // Micro sign
("month", "μs") => Ok(val as f64 * 1000.0 * 1000.0 * 60.0 * 60.0 * 24.0 * 30.0), // Greek small letter
("month", "ms") => Ok(val as f64 * 1000.0 * 60.0 * 60.0 * 24.0 * 30.0),
("month", "sec") => Ok(val as f64 * 60.0 * 60.0 * 24.0 * 30.0),
("month", "min") => Ok(val as f64 * 60.0 * 24.0 * 30.0),
("month", "hr") => Ok(val as f64 * 24.0 * 30.0),
("month", "day") => Ok(val as f64 * 30.0),
("month", "wk") => Ok(val as f64 * 4.0),
("month", "month") => Ok(val as f64),
("month", "yr") => Ok(val as f64 / 12.0),
("month", "dec") => Ok(val as f64 / 10.0 / 12.0),
("yr", "ns") => Ok(val as f64 * 1000.0 * 1000.0 * 1000.0 * 60.0 * 60.0 * 24.0 * 365.0),
("yr", "us") => Ok(val as f64 * 1000.0 * 1000.0 * 60.0 * 60.0 * 24.0 * 365.0),
("yr", "µs") => Ok(val as f64 * 1000.0 * 1000.0 * 60.0 * 60.0 * 24.0 * 365.0), // Micro sign
("yr", "μs") => Ok(val as f64 * 1000.0 * 1000.0 * 60.0 * 60.0 * 24.0 * 365.0), // Greek small letter
("yr", "ms") => Ok(val as f64 * 1000.0 * 60.0 * 60.0 * 24.0 * 365.0),
("yr", "sec") => Ok(val as f64 * 60.0 * 60.0 * 24.0 * 365.0),
("yr", "min") => Ok(val as f64 * 60.0 * 24.0 * 365.0),
("yr", "hr") => Ok(val as f64 * 24.0 * 365.0),
("yr", "day") => Ok(val as f64 * 365.0),
("yr", "wk") => Ok(val as f64 * 52.0),
("yr", "month") => Ok(val as f64 * 12.0),
("yr", "yr") => Ok(val as f64),
("yr", "dec") => Ok(val as f64 / 10.0),
_ => Err(ShellError::CantConvertToDuration {
details: to_unit.to_string(),
dst_span: span,
src_span: value_span,
help: Some(
"supported units are ns, us/µs, ms, sec, min, hr, day, wk, month, yr, and dec"
.to_string(),
),
}),
}
// convert string list of duration values to duration NS.
// technique for getting substrings and span based on: https://stackoverflow.com/a/67098851/2036651
#[inline]
fn addr_of(s: &str) -> usize {
s.as_ptr() as usize
}
fn string_to_duration(s: &str, span: Span, value_span: Span) -> Result<i64, ShellError> {
fn split_whitespace_indices(s: &str, span: Span) -> impl Iterator<Item = (&str, Span)> {
s.split_whitespace().map(move |sub| {
let start_offset = span.start + addr_of(sub) - addr_of(s);
(sub, Span::new(start_offset, start_offset + sub.len()))
})
}
fn compound_to_duration(s: &str, span: Span) -> Result<i64, ShellError> {
let mut duration_ns: i64 = 0;
for (substring, substring_span) in split_whitespace_indices(s, span) {
let sub_ns = string_to_duration(substring, substring_span)?;
duration_ns += sub_ns;
}
Ok(duration_ns)
}
fn string_to_duration(s: &str, span: Span) -> Result<i64, ShellError> {
if let Some(Ok(expression)) = parse_unit_value(
s.as_bytes(),
span,
@ -423,11 +210,11 @@ fn string_to_duration(s: &str, span: Span, value_span: Span) -> Result<i64, Shel
Unit::Nanosecond => return Ok(x),
Unit::Microsecond => return Ok(x * 1000),
Unit::Millisecond => return Ok(x * 1000 * 1000),
Unit::Second => return Ok(x * 1000 * 1000 * 1000),
Unit::Minute => return Ok(x * 60 * 1000 * 1000 * 1000),
Unit::Hour => return Ok(x * 60 * 60 * 1000 * 1000 * 1000),
Unit::Day => return Ok(x * 24 * 60 * 60 * 1000 * 1000 * 1000),
Unit::Week => return Ok(x * 7 * 24 * 60 * 60 * 1000 * 1000 * 1000),
Unit::Second => return Ok(x * NS_PER_SEC),
Unit::Minute => return Ok(x * 60 * NS_PER_SEC),
Unit::Hour => return Ok(x * 60 * 60 * NS_PER_SEC),
Unit::Day => return Ok(x * 24 * 60 * 60 * NS_PER_SEC),
Unit::Week => return Ok(x * 7 * 24 * 60 * 60 * NS_PER_SEC),
_ => {}
}
}
@ -437,154 +224,23 @@ fn string_to_duration(s: &str, span: Span, value_span: Span) -> Result<i64, Shel
Err(ShellError::CantConvertToDuration {
details: s.to_string(),
dst_span: span,
src_span: value_span,
help: Some(
"supported units are ns, us/µs, ms, sec, min, hr, day, wk, month, yr, and dec"
.to_string(),
),
src_span: span,
help: Some("supported units are ns, us/µs, ms, sec, min, hr, day, and wk".to_string()),
})
}
fn string_to_unit_duration(
s: &str,
span: Span,
value_span: Span,
) -> Result<(&str, i64), ShellError> {
if let Some(Ok(expression)) = parse_unit_value(
s.as_bytes(),
span,
DURATION_UNIT_GROUPS,
Type::Duration,
|x| x,
) {
if let Expr::ValueWithUnit(value, unit) = expression.expr {
if let Expr::Int(x) = value.expr {
match unit.item {
Unit::Nanosecond => return Ok(("ns", x)),
Unit::Microsecond => return Ok(("µs", x)),
Unit::Millisecond => return Ok(("ms", x)),
Unit::Second => return Ok(("sec", x)),
Unit::Minute => return Ok(("min", x)),
Unit::Hour => return Ok(("hr", x)),
Unit::Day => return Ok(("day", x)),
Unit::Week => return Ok(("wk", x)),
_ => return Ok(("ns", 0)),
}
}
}
}
Err(ShellError::CantConvertToDuration {
details: s.to_string(),
dst_span: span,
src_span: value_span,
help: Some(
"supported units are ns, us/µs, ms, sec, min, hr, day, wk, month, yr, and dec"
.to_string(),
),
})
}
fn action(
input: &Value,
convert_to_unit: &Option<Spanned<String>>,
float_precision: usize,
span: Span,
) -> Value {
fn action(input: &Value, span: Span) -> Value {
match input {
Value::Duration {
val: val_num,
span: value_span,
} => {
if let Some(to_unit) = convert_to_unit {
let from_unit = "ns";
let duration = *val_num;
match convert_str_from_unit_to_unit(
duration,
from_unit,
&to_unit.item,
span,
*value_span,
) {
Ok(d) => {
let unit = if &to_unit.item == "us" {
"µs"
} else {
&to_unit.item
};
if d.fract() == 0.0 {
Value::String {
val: format!("{} {}", d, unit),
span: *value_span,
}
} else {
Value::String {
val: format!("{:.float_precision$} {}", d, unit),
span: *value_span,
}
}
}
Err(e) => Value::Error { error: Box::new(e) },
}
} else {
input.clone()
}
}
Value::Duration { .. } => input.clone(),
Value::String {
val,
span: value_span,
} => {
if let Some(to_unit) = convert_to_unit {
if let Ok(dur) = string_to_unit_duration(val, span, *value_span) {
let from_unit = dur.0;
let duration = dur.1;
match convert_str_from_unit_to_unit(
duration,
from_unit,
&to_unit.item,
span,
*value_span,
) {
Ok(d) => {
let unit = if &to_unit.item == "us" {
"µs"
} else {
&to_unit.item
};
if d.fract() == 0.0 {
Value::String {
val: format!("{} {}", d, unit),
span: *value_span,
}
} else {
Value::String {
val: format!("{:.float_precision$} {}", d, unit),
span: *value_span,
}
}
}
Err(e) => Value::Error { error: Box::new(e) },
}
} else {
Value::Error {
error: Box::new(ShellError::CantConvert {
to_type: "string".into(),
from_type: "duration".into(),
span,
help: None,
}),
}
}
} else {
match string_to_duration(val, span, *value_span) {
Ok(val) => Value::Duration { val, span },
Err(error) => Value::Error {
error: Box::new(error),
},
}
}
}
} => match compound_to_duration(val, *value_span) {
Ok(val) => Value::Duration { val, span },
Err(error) => Value::Error {
error: Box::new(error),
},
},
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => input.clone(),
other => Value::Error {
@ -601,6 +257,7 @@ fn action(
#[cfg(test)]
mod test {
use super::*;
use rstest::rstest;
#[test]
fn test_examples() {
@ -609,140 +266,33 @@ mod test {
test_examples(SubCommand {})
}
#[test]
fn turns_ns_to_duration() {
let span = Span::new(0, 2);
let word = Value::test_string("3ns");
let expected = Value::Duration { val: 3, span };
let convert_duration = None;
const NS_PER_SEC: i64 = 1_000_000_000;
let actual = action(&word, &convert_duration, 2, span);
assert_eq!(actual, expected);
}
#[rstest]
#[case("3ns", 3)]
#[case("4us", 4*1000)]
#[case("4\u{00B5}s", 4*1000)] // micro sign
#[case("4\u{03BC}s", 4*1000)] // mu symbol
#[case("5ms", 5 * 1000 * 1000)]
#[case("1sec", 1 * NS_PER_SEC)]
#[case("7min", 7 * 60 * NS_PER_SEC)]
#[case("42hr", 42 * 60 * 60 * NS_PER_SEC)]
#[case("123day", 123 * 24 * 60 * 60 * NS_PER_SEC)]
#[case("3wk", 3 * 7 * 24 * 60 * 60 * NS_PER_SEC)]
#[case("86hr 26ns", 86 * 3600 * NS_PER_SEC + 26)] // compound duration string
#[case("14ns 3hr 17sec", 14 + 3 * 3600 * NS_PER_SEC + 17 * NS_PER_SEC)] // compound string with units in random order
#[test]
fn turns_us_to_duration() {
let span = Span::new(0, 2);
let word = Value::test_string("4us");
let expected = Value::Duration {
val: 4 * 1000,
span,
};
let convert_duration = None;
let actual = action(&word, &convert_duration, 2, span);
assert_eq!(actual, expected);
}
#[test]
fn turns_micro_sign_s_to_duration() {
let span = Span::new(0, 2);
let word = Value::test_string("4\u{00B5}s");
let expected = Value::Duration {
val: 4 * 1000,
span,
};
let convert_duration = None;
let actual = action(&word, &convert_duration, 2, span);
assert_eq!(actual, expected);
}
#[test]
fn turns_mu_s_to_duration() {
let span = Span::new(0, 2);
let word = Value::test_string("4\u{03BC}s");
let expected = Value::Duration {
val: 4 * 1000,
span,
};
let convert_duration = None;
let actual = action(&word, &convert_duration, 2, span);
assert_eq!(actual, expected);
}
#[test]
fn turns_ms_to_duration() {
let span = Span::new(0, 2);
let word = Value::test_string("5ms");
let expected = Value::Duration {
val: 5 * 1000 * 1000,
span,
};
let convert_duration = None;
let actual = action(&word, &convert_duration, 2, span);
assert_eq!(actual, expected);
}
#[test]
fn turns_sec_to_duration() {
let span = Span::new(0, 3);
let word = Value::test_string("1sec");
let expected = Value::Duration {
val: 1000 * 1000 * 1000,
span,
};
let convert_duration = None;
let actual = action(&word, &convert_duration, 2, span);
assert_eq!(actual, expected);
}
#[test]
fn turns_min_to_duration() {
let span = Span::new(0, 3);
let word = Value::test_string("7min");
let expected = Value::Duration {
val: 7 * 60 * 1000 * 1000 * 1000,
span,
};
let convert_duration = None;
let actual = action(&word, &convert_duration, 2, span);
assert_eq!(actual, expected);
}
#[test]
fn turns_hr_to_duration() {
let span = Span::new(0, 3);
let word = Value::test_string("42hr");
let expected = Value::Duration {
val: 42 * 60 * 60 * 1000 * 1000 * 1000,
span,
};
let convert_duration = None;
let actual = action(&word, &convert_duration, 2, span);
assert_eq!(actual, expected);
}
#[test]
fn turns_day_to_duration() {
let span = Span::new(0, 5);
let word = Value::test_string("123day");
let expected = Value::Duration {
val: 123 * 24 * 60 * 60 * 1000 * 1000 * 1000,
span,
};
let convert_duration = None;
let actual = action(&word, &convert_duration, 2, span);
assert_eq!(actual, expected);
}
#[test]
fn turns_wk_to_duration() {
let span = Span::new(0, 2);
let word = Value::test_string("3wk");
let expected = Value::Duration {
val: 3 * 7 * 24 * 60 * 60 * 1000 * 1000 * 1000,
span,
};
let convert_duration = None;
let actual = action(&word, &convert_duration, 2, span);
assert_eq!(actual, expected);
fn turns_string_to_duration(#[case] phrase: &str, #[case] expected_duration_val: i64) {
let actual = action(&Value::test_string(phrase), Span::new(0, phrase.len()));
match actual {
Value::Duration {
val: observed_val, ..
} => {
assert_eq!(expected_duration_val, observed_val, "expected != observed")
}
other => {
panic!("Expected Value::Duration, observed {other:?}");
}
}
}
}

View File

@ -252,7 +252,10 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {
Value::Int { val: 0, span }
}
}
Value::Date { val, .. } => {
Value::Date {
val,
span: val_span,
} => {
if val
< &FixedOffset::east_opt(0)
.expect("constant")
@ -267,7 +270,8 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {
Value::Error {
error: Box::new(ShellError::IncorrectValue {
msg: "DateTime out of range for timestamp: 1677-09-21T00:12:43Z to 2262-04-11T23:47:16".to_string(),
span
val_span: *val_span,
call_span: span,
}),
}
} else {

View File

@ -83,21 +83,21 @@ impl Command for SubCommand {
}),
},
Example {
description: "convert duration to record",
example: "-500day | into record",
description: "convert duration to record (weeks max)",
example: "(-500day - 4hr - 5sec) | into record",
result: Some(Value::Record {
cols: vec![
"year".into(),
"month".into(),
"week".into(),
"day".into(),
"hour".into(),
"second".into(),
"sign".into(),
],
vals: vec![
Value::Int { val: 1, span },
Value::Int { val: 71, span },
Value::Int { val: 3, span },
Value::Int { val: 4, span },
Value::Int { val: 2, span },
Value::Int { val: 1, span },
Value::Int { val: 5, span },
Value::String {
val: "-".into(),
span,
@ -261,8 +261,6 @@ fn parse_duration_into_record(duration: i64, span: Span) -> Value {
"hr" => "hour".into(),
"day" => "day".into(),
"wk" => "week".into(),
"month" => "month".into(),
"yr" => "year".into(),
_ => "unknown".into(),
});

View File

@ -40,6 +40,7 @@ impl Command for SubCommand {
(Type::Bool, Type::String),
(Type::Filesize, Type::String),
(Type::Date, Type::String),
(Type::Duration, Type::String),
(
Type::List(Box::new(Type::Any)),
Type::List(Box::new(Type::String)),
@ -129,12 +130,11 @@ impl Command for SubCommand {
example: "true | into string",
result: Some(Value::test_string("true")),
},
// TODO: This should work but does not; see https://github.com/nushell/nushell/issues/7032
// Example {
// description: "convert date to string",
// example: "'2020-10-10 10:00:00 +02:00' | into datetime | into string",
// result: Some(Value::test_string("Sat Oct 10 10:00:00 2020")),
// },
Example {
description: "convert date to string",
example: "'2020-10-10 10:00:00 +02:00' | into datetime | into string",
result: Some(Value::test_string("Sat Oct 10 10:00:00 2020")),
},
Example {
description: "convert filepath to string",
example: "ls Cargo.toml | get name | into string",
@ -145,6 +145,11 @@ impl Command for SubCommand {
example: "1KiB | into string",
result: Some(Value::test_string("1,024 B")),
},
Example {
description: "convert duration to string",
example: "9day | into string",
result: Some(Value::test_string("1wk 2day")),
},
]
}
}
@ -239,6 +244,11 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {
val: input.into_string(", ", config),
span,
},
Value::Duration { val: _, .. } => Value::String {
val: input.into_string("", config),
span,
},
Value::Error { error } => Value::String {
val: into_code(error).unwrap_or_default(),
span,

View File

@ -1,475 +0,0 @@
use chrono::{DateTime, Local, Locale, TimeZone};
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type,
Value,
};
use nu_utils::locale::get_system_locale_string;
use std::fmt::{Display, Write};
use super::utils::parse_date_from_string;
#[derive(Clone)]
pub struct SubCommand;
impl Command for SubCommand {
fn name(&self) -> &str {
"date format"
}
fn signature(&self) -> Signature {
Signature::build("date format")
.input_output_types(vec![
(Type::Date, Type::String),
(Type::String, Type::String),
])
.allow_variants_without_examples(true) // https://github.com/nushell/nushell/issues/7032
.switch("list", "lists strftime cheatsheet", Some('l'))
.optional(
"format string",
SyntaxShape::String,
"the desired date format",
)
.category(Category::Date)
}
fn usage(&self) -> &str {
"Format a given date using a format string."
}
fn search_terms(&self) -> Vec<&str> {
vec!["fmt", "strftime"]
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let head = call.head;
if call.has_flag("list") {
return Ok(PipelineData::Value(
generate_strftime_list(head, false),
None,
));
}
let format = call.opt::<Spanned<String>>(engine_state, stack, 0)?;
// This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) {
return Err(ShellError::PipelineEmpty { dst_span: head });
}
input.map(
move |value| match &format {
Some(format) => format_helper(value, format.item.as_str(), format.span, head),
None => format_helper_rfc2822(value, head),
},
engine_state.ctrlc.clone(),
)
}
fn examples(&self) -> Vec<Example> {
vec![
// TODO: This should work but does not; see https://github.com/nushell/nushell/issues/7032
// Example {
// description: "Format a given date-time using the default format (RFC 2822).",
// example: r#"'2021-10-22 20:00:12 +01:00' | into datetime | date format"#,
// result: Some(Value::String {
// val: "Fri, 22 Oct 2021 20:00:12 +0100".to_string(),
// span: Span::test_data(),
// }),
// },
Example {
description:
"Format a given date-time as a string using the default format (RFC 2822).",
example: r#""2021-10-22 20:00:12 +01:00" | date format"#,
result: Some(Value::String {
val: "Fri, 22 Oct 2021 20:00:12 +0100".to_string(),
span: Span::test_data(),
}),
},
Example {
description: "Format the current date-time using a given format string.",
example: r#"date now | date format "%Y-%m-%d %H:%M:%S""#,
result: None,
},
Example {
description: "Format the current date using a given format string.",
example: r#"date now | date format "%Y-%m-%d %H:%M:%S""#,
result: None,
},
Example {
description: "Format a given date using a given format string.",
example: r#""2021-10-22 20:00:12 +01:00" | date format "%Y-%m-%d""#,
result: Some(Value::test_string("2021-10-22")),
},
]
}
}
fn format_from<Tz: TimeZone>(date_time: DateTime<Tz>, formatter: &str, span: Span) -> Value
where
Tz::Offset: Display,
{
let mut formatter_buf = String::new();
let locale: Locale = get_system_locale_string()
.map(|l| l.replace('-', "_")) // `chrono::Locale` needs something like `xx_xx`, rather than `xx-xx`
.unwrap_or_else(|| String::from("en_US"))
.as_str()
.try_into()
.unwrap_or(Locale::en_US);
let format = date_time.format_localized(formatter, locale);
match formatter_buf.write_fmt(format_args!("{format}")) {
Ok(_) => Value::String {
val: formatter_buf,
span,
},
Err(_) => Value::Error {
error: Box::new(ShellError::TypeMismatch {
err_message: "invalid format".to_string(),
span,
}),
},
}
}
fn format_helper(value: Value, formatter: &str, formatter_span: Span, head_span: Span) -> Value {
match value {
Value::Date { val, .. } => format_from(val, formatter, formatter_span),
Value::String { val, .. } => {
let dt = parse_date_from_string(&val, formatter_span);
match dt {
Ok(x) => format_from(x, formatter, formatter_span),
Err(e) => e,
}
}
_ => Value::Error {
error: Box::new(ShellError::DatetimeParseError(
value.debug_value(),
head_span,
)),
},
}
}
fn format_helper_rfc2822(value: Value, span: Span) -> Value {
match value {
Value::Date { val, span: _ } => Value::String {
val: val.to_rfc2822(),
span,
},
Value::String {
val,
span: val_span,
} => {
let dt = parse_date_from_string(&val, val_span);
match dt {
Ok(x) => Value::String {
val: x.to_rfc2822(),
span,
},
Err(e) => e,
}
}
_ => Value::Error {
error: Box::new(ShellError::DatetimeParseError(value.debug_value(), span)),
},
}
}
/// Generates a table containing available datetime format specifiers
///
/// # Arguments
/// * `head` - use the call's head
/// * `show_parse_only_formats` - whether parse-only format specifiers (that can't be outputted) should be shown. Should only be used for `into datetime`, not `date format`
pub(crate) fn generate_strftime_list(head: Span, show_parse_only_formats: bool) -> Value {
let column_names = vec![
"Specification".into(),
"Example".into(),
"Description".into(),
];
let now = Local::now();
struct FormatSpecification<'a> {
spec: &'a str,
description: &'a str,
}
let specifications = vec![
FormatSpecification {
spec: "%Y",
description: "The full proleptic Gregorian year, zero-padded to 4 digits.",
},
FormatSpecification {
spec: "%C",
description: "The proleptic Gregorian year divided by 100, zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%y",
description: "The proleptic Gregorian year modulo 100, zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%m",
description: "Month number (01--12), zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%b",
description: "Abbreviated month name. Always 3 letters.",
},
FormatSpecification {
spec: "%B",
description: "Full month name. Also accepts corresponding abbreviation in parsing.",
},
FormatSpecification {
spec: "%h",
description: "Same as %b.",
},
FormatSpecification {
spec: "%d",
description: "Day number (01--31), zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%e",
description: "Same as %d but space-padded. Same as %_d.",
},
FormatSpecification {
spec: "%a",
description: "Abbreviated weekday name. Always 3 letters.",
},
FormatSpecification {
spec: "%A",
description: "Full weekday name. Also accepts corresponding abbreviation in parsing.",
},
FormatSpecification {
spec: "%w",
description: "Sunday = 0, Monday = 1, ..., Saturday = 6.",
},
FormatSpecification {
spec: "%u",
description: "Monday = 1, Tuesday = 2, ..., Sunday = 7. (ISO 8601)",
},
FormatSpecification {
spec: "%U",
description: "Week number starting with Sunday (00--53), zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%W",
description:
"Same as %U, but week 1 starts with the first Monday in that year instead.",
},
FormatSpecification {
spec: "%G",
description: "Same as %Y but uses the year number in ISO 8601 week date.",
},
FormatSpecification {
spec: "%g",
description: "Same as %y but uses the year number in ISO 8601 week date.",
},
FormatSpecification {
spec: "%V",
description: "Same as %U but uses the week number in ISO 8601 week date (01--53).",
},
FormatSpecification {
spec: "%j",
description: "Day of the year (001--366), zero-padded to 3 digits.",
},
FormatSpecification {
spec: "%D",
description: "Month-day-year format. Same as %m/%d/%y.",
},
FormatSpecification {
spec: "%x",
description: "Locale's date representation (e.g., 12/31/99).",
},
FormatSpecification {
spec: "%F",
description: "Year-month-day format (ISO 8601). Same as %Y-%m-%d.",
},
FormatSpecification {
spec: "%v",
description: "Day-month-year format. Same as %e-%b-%Y.",
},
FormatSpecification {
spec: "%H",
description: "Hour number (00--23), zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%k",
description: "Same as %H but space-padded. Same as %_H.",
},
FormatSpecification {
spec: "%I",
description: "Hour number in 12-hour clocks (01--12), zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%l",
description: "Same as %I but space-padded. Same as %_I.",
},
FormatSpecification {
spec: "%P",
description: "am or pm in 12-hour clocks.",
},
FormatSpecification {
spec: "%p",
description: "AM or PM in 12-hour clocks.",
},
FormatSpecification {
spec: "%M",
description: "Minute number (00--59), zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%S",
description: "Second number (00--60), zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%f",
description: "The fractional seconds (in nanoseconds) since last whole second.",
},
FormatSpecification {
spec: "%.f",
description: "Similar to .%f but left-aligned. These all consume the leading dot.",
},
FormatSpecification {
spec: "%.3f",
description: "Similar to .%f but left-aligned but fixed to a length of 3.",
},
FormatSpecification {
spec: "%.6f",
description: "Similar to .%f but left-aligned but fixed to a length of 6.",
},
FormatSpecification {
spec: "%.9f",
description: "Similar to .%f but left-aligned but fixed to a length of 9.",
},
FormatSpecification {
spec: "%3f",
description: "Similar to %.3f but without the leading dot.",
},
FormatSpecification {
spec: "%6f",
description: "Similar to %.6f but without the leading dot.",
},
FormatSpecification {
spec: "%9f",
description: "Similar to %.9f but without the leading dot.",
},
FormatSpecification {
spec: "%R",
description: "Hour-minute format. Same as %H:%M.",
},
FormatSpecification {
spec: "%T",
description: "Hour-minute-second format. Same as %H:%M:%S.",
},
FormatSpecification {
spec: "%X",
description: "Locale's time representation (e.g., 23:13:48).",
},
FormatSpecification {
spec: "%r",
description: "Hour-minute-second format in 12-hour clocks. Same as %I:%M:%S %p.",
},
FormatSpecification {
spec: "%Z",
description:
"Local time zone name. Skips all non-whitespace characters during parsing.",
},
FormatSpecification {
spec: "%z",
description: "Offset from the local time to UTC (with UTC being +0000).",
},
FormatSpecification {
spec: "%:z",
description: "Same as %z but with a colon.",
},
FormatSpecification {
spec: "%c",
description: "Locale's date and time (e.g., Thu Mar 3 23:05:25 2005).",
},
FormatSpecification {
spec: "%+",
description: "ISO 8601 / RFC 3339 date & time format.",
},
FormatSpecification {
spec: "%s",
description: "UNIX timestamp, the number of seconds since 1970-01-01",
},
FormatSpecification {
spec: "%t",
description: "Literal tab (\\t).",
},
FormatSpecification {
spec: "%n",
description: "Literal newline (\\n).",
},
FormatSpecification {
spec: "%%",
description: "Literal percent sign.",
},
];
let mut records = specifications
.iter()
.map(|s| Value::Record {
cols: column_names.clone(),
vals: vec![
Value::string(s.spec, head),
Value::string(now.format(s.spec).to_string(), head),
Value::string(s.description, head),
],
span: head,
})
.collect::<Vec<Value>>();
if show_parse_only_formats {
// now.format("%#z") will panic since it is parse-only
// so here we emulate how it will look:
let example = now
.format("%:z") // e.g. +09:30
.to_string()
.get(0..3) // +09:30 -> +09
.unwrap_or("")
.to_string();
records.push(Value::Record {
cols: column_names,
vals: vec![
Value::string("%#z", head),
Value::String {
val: example,
span: head,
},
Value::string(
"Parsing only: Same as %z but allows minutes to be missing or present.",
head,
),
],
span: head,
});
}
Value::List {
vals: records,
span: head,
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_examples() {
use crate::test_examples;
test_examples(SubCommand {})
}
}

View File

@ -1,5 +1,4 @@
mod date_;
mod format;
mod humanize;
mod list_timezone;
mod now;
@ -10,12 +9,10 @@ mod to_timezone;
mod utils;
pub use date_::Date;
pub(crate) use format::generate_strftime_list;
pub use format::SubCommand as DateFormat;
pub use humanize::SubCommand as DateHumanize;
pub use list_timezone::SubCommand as DateListTimezones;
pub use now::SubCommand as DateNow;
pub use to_record::SubCommand as DateToRecord;
pub use to_table::SubCommand as DateToTable;
pub use to_timezone::SubCommand as DateToTimezone;
pub(crate) use utils::parse_date_from_string;
pub(crate) use utils::{generate_strftime_list, parse_date_from_string};

View File

@ -46,7 +46,7 @@ impl Command for SubCommand {
vec![
Example {
description: "Get the current date and display it in a given format string.",
example: r#"date now | date format "%Y-%m-%d %H:%M:%S""#,
example: r#"date now | format date "%Y-%m-%d %H:%M:%S""#,
result: None,
},
Example {

View File

@ -81,6 +81,34 @@ impl Command for SubCommand {
Some(Value::Record { cols, vals, span })
};
let example_result_2 = || {
let span = Span::test_data();
let cols = vec![
"year".into(),
"month".into(),
"day".into(),
"hour".into(),
"minute".into(),
"second".into(),
"nanosecond".into(),
"timezone".into(),
];
let vals = vec![
Value::Int { val: 2020, span },
Value::Int { val: 4, span },
Value::Int { val: 12, span },
Value::Int { val: 22, span },
Value::Int { val: 10, span },
Value::Int { val: 57, span },
Value::Int { val: 0, span },
Value::String {
val: "+02:00".to_string(),
span,
},
];
Some(Value::Record { cols, vals, span })
};
vec![
Example {
description: "Convert the current date into a record.",
@ -97,12 +125,11 @@ impl Command for SubCommand {
example: "'2020-04-12T22:10:57.123+02:00' | date to-record",
result: example_result_1(),
},
// TODO: This should work but does not; see https://github.com/nushell/nushell/issues/7032
// Example {
// description: "Convert a date into a record.",
// example: "'2020-04-12 22:10:57 +0200' | into datetime | date to-record",
// result: example_result_1(),
// },
Example {
description: "Convert a date into a record.",
example: "'2020-04-12 22:10:57 +0200' | into datetime | date to-record",
result: example_result_2(),
},
]
}
}

View File

@ -81,6 +81,37 @@ impl Command for SubCommand {
})
};
let example_result_2 = || {
let span = Span::test_data();
let cols = vec![
"year".into(),
"month".into(),
"day".into(),
"hour".into(),
"minute".into(),
"second".into(),
"nanosecond".into(),
"timezone".into(),
];
let vals = vec![
Value::Int { val: 2020, span },
Value::Int { val: 4, span },
Value::Int { val: 12, span },
Value::Int { val: 22, span },
Value::Int { val: 10, span },
Value::Int { val: 57, span },
Value::Int { val: 0, span },
Value::String {
val: "+02:00".to_string(),
span,
},
];
Some(Value::List {
vals: vec![Value::Record { cols, vals, span }],
span,
})
};
vec![
Example {
description: "Convert the current date into a table.",
@ -94,17 +125,14 @@ impl Command for SubCommand {
},
Example {
description: "Convert a given date into a table.",
//todo: resolve https://github.com/bspeice/dtparse/issues/40, which truncates nanosec bits
// for now, change the example to use date literal rather than string conversion, as workaround
example: "2020-04-12T22:10:57.000000789+02:00 | date to-table",
result: example_result_1(),
},
// TODO: This should work but does not; see https://github.com/nushell/nushell/issues/7032
// Example {
// description: "Convert a given date into a table.",
// example: "'2020-04-12 22:10:57 +0200' | into datetime | date to-table",
// result: example_result_1(),
// },
Example {
description: "Convert a given date into a table.",
example: "'2020-04-12 22:10:57 +0200' | into datetime | date to-table",
result: example_result_2(),
},
]
}
}

View File

@ -99,12 +99,11 @@ impl Command for SubCommand {
example: r#""2020-10-10 10:00:00 +02:00" | date to-timezone "+0500""#,
result: example_result_1(),
},
// TODO: This should work but does not; see https://github.com/nushell/nushell/issues/7032
// Example {
// description: "Get the current date in Hawaii, from a datetime object",
// example: r#""2020-10-10 10:00:00 +02:00" | into datetime | date to-timezone "+0500""#,
// result: example_result_1(),
// },
Example {
description: "Get the current date in Hawaii, from a datetime object",
example: r#""2020-10-10 10:00:00 +02:00" | into datetime | date to-timezone "+0500""#,
result: example_result_1(),
},
]
}
}

View File

@ -24,3 +24,280 @@ pub(crate) fn parse_date_from_string(
}),
}
}
/// Generates a table containing available datetime format specifiers
///
/// # Arguments
/// * `head` - use the call's head
/// * `show_parse_only_formats` - whether parse-only format specifiers (that can't be outputted) should be shown. Should only be used for `into datetime`, not `format date`
pub(crate) fn generate_strftime_list(head: Span, show_parse_only_formats: bool) -> Value {
let column_names = vec![
"Specification".into(),
"Example".into(),
"Description".into(),
];
let now = Local::now();
struct FormatSpecification<'a> {
spec: &'a str,
description: &'a str,
}
let specifications = vec![
FormatSpecification {
spec: "%Y",
description: "The full proleptic Gregorian year, zero-padded to 4 digits.",
},
FormatSpecification {
spec: "%C",
description: "The proleptic Gregorian year divided by 100, zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%y",
description: "The proleptic Gregorian year modulo 100, zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%m",
description: "Month number (01--12), zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%b",
description: "Abbreviated month name. Always 3 letters.",
},
FormatSpecification {
spec: "%B",
description: "Full month name. Also accepts corresponding abbreviation in parsing.",
},
FormatSpecification {
spec: "%h",
description: "Same as %b.",
},
FormatSpecification {
spec: "%d",
description: "Day number (01--31), zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%e",
description: "Same as %d but space-padded. Same as %_d.",
},
FormatSpecification {
spec: "%a",
description: "Abbreviated weekday name. Always 3 letters.",
},
FormatSpecification {
spec: "%A",
description: "Full weekday name. Also accepts corresponding abbreviation in parsing.",
},
FormatSpecification {
spec: "%w",
description: "Sunday = 0, Monday = 1, ..., Saturday = 6.",
},
FormatSpecification {
spec: "%u",
description: "Monday = 1, Tuesday = 2, ..., Sunday = 7. (ISO 8601)",
},
FormatSpecification {
spec: "%U",
description: "Week number starting with Sunday (00--53), zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%W",
description:
"Same as %U, but week 1 starts with the first Monday in that year instead.",
},
FormatSpecification {
spec: "%G",
description: "Same as %Y but uses the year number in ISO 8601 week date.",
},
FormatSpecification {
spec: "%g",
description: "Same as %y but uses the year number in ISO 8601 week date.",
},
FormatSpecification {
spec: "%V",
description: "Same as %U but uses the week number in ISO 8601 week date (01--53).",
},
FormatSpecification {
spec: "%j",
description: "Day of the year (001--366), zero-padded to 3 digits.",
},
FormatSpecification {
spec: "%D",
description: "Month-day-year format. Same as %m/%d/%y.",
},
FormatSpecification {
spec: "%x",
description: "Locale's date representation (e.g., 12/31/99).",
},
FormatSpecification {
spec: "%F",
description: "Year-month-day format (ISO 8601). Same as %Y-%m-%d.",
},
FormatSpecification {
spec: "%v",
description: "Day-month-year format. Same as %e-%b-%Y.",
},
FormatSpecification {
spec: "%H",
description: "Hour number (00--23), zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%k",
description: "Same as %H but space-padded. Same as %_H.",
},
FormatSpecification {
spec: "%I",
description: "Hour number in 12-hour clocks (01--12), zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%l",
description: "Same as %I but space-padded. Same as %_I.",
},
FormatSpecification {
spec: "%P",
description: "am or pm in 12-hour clocks.",
},
FormatSpecification {
spec: "%p",
description: "AM or PM in 12-hour clocks.",
},
FormatSpecification {
spec: "%M",
description: "Minute number (00--59), zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%S",
description: "Second number (00--60), zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%f",
description: "The fractional seconds (in nanoseconds) since last whole second.",
},
FormatSpecification {
spec: "%.f",
description: "Similar to .%f but left-aligned. These all consume the leading dot.",
},
FormatSpecification {
spec: "%.3f",
description: "Similar to .%f but left-aligned but fixed to a length of 3.",
},
FormatSpecification {
spec: "%.6f",
description: "Similar to .%f but left-aligned but fixed to a length of 6.",
},
FormatSpecification {
spec: "%.9f",
description: "Similar to .%f but left-aligned but fixed to a length of 9.",
},
FormatSpecification {
spec: "%3f",
description: "Similar to %.3f but without the leading dot.",
},
FormatSpecification {
spec: "%6f",
description: "Similar to %.6f but without the leading dot.",
},
FormatSpecification {
spec: "%9f",
description: "Similar to %.9f but without the leading dot.",
},
FormatSpecification {
spec: "%R",
description: "Hour-minute format. Same as %H:%M.",
},
FormatSpecification {
spec: "%T",
description: "Hour-minute-second format. Same as %H:%M:%S.",
},
FormatSpecification {
spec: "%X",
description: "Locale's time representation (e.g., 23:13:48).",
},
FormatSpecification {
spec: "%r",
description: "Hour-minute-second format in 12-hour clocks. Same as %I:%M:%S %p.",
},
FormatSpecification {
spec: "%Z",
description:
"Local time zone name. Skips all non-whitespace characters during parsing.",
},
FormatSpecification {
spec: "%z",
description: "Offset from the local time to UTC (with UTC being +0000).",
},
FormatSpecification {
spec: "%:z",
description: "Same as %z but with a colon.",
},
FormatSpecification {
spec: "%c",
description: "Locale's date and time (e.g., Thu Mar 3 23:05:25 2005).",
},
FormatSpecification {
spec: "%+",
description: "ISO 8601 / RFC 3339 date & time format.",
},
FormatSpecification {
spec: "%s",
description: "UNIX timestamp, the number of seconds since 1970-01-01",
},
FormatSpecification {
spec: "%t",
description: "Literal tab (\\t).",
},
FormatSpecification {
spec: "%n",
description: "Literal newline (\\n).",
},
FormatSpecification {
spec: "%%",
description: "Literal percent sign.",
},
];
let mut records = specifications
.iter()
.map(|s| Value::Record {
cols: column_names.clone(),
vals: vec![
Value::string(s.spec, head),
Value::string(now.format(s.spec).to_string(), head),
Value::string(s.description, head),
],
span: head,
})
.collect::<Vec<Value>>();
if show_parse_only_formats {
// now.format("%#z") will panic since it is parse-only
// so here we emulate how it will look:
let example = now
.format("%:z") // e.g. +09:30
.to_string()
.get(0..3) // +09:30 -> +09
.unwrap_or("")
.to_string();
records.push(Value::Record {
cols: column_names,
vals: vec![
Value::string("%#z", head),
Value::String {
val: example,
span: head,
},
Value::string(
"Parsing only: Same as %z but allows minutes to be missing or present.",
head,
),
],
span: head,
});
}
Value::List {
vals: records,
span: head,
}
}

View File

@ -70,10 +70,10 @@ pub fn get_pipeline_elements(
while i < pipeline.elements.len() {
let pipeline_element = &pipeline.elements[i];
let pipeline_expression = pipeline_element.expression().clone();
let pipeline_span = &pipeline_element.span();
let pipeline_span = pipeline_element.span();
let element_str =
String::from_utf8_lossy(engine_state.get_span_contents(pipeline_span));
let value = Value::string(element_str.to_string(), *pipeline_span);
let value = Value::string(element_str.to_string(), pipeline_span);
let expr = pipeline_expression.expr.clone();
let (command_name, command_args_value) = if let Expr::Call(call) = expr {
let command = engine_state.get_decl(call.decl_id);

View File

@ -41,7 +41,7 @@ impl Command for ViewSource {
let block = engine_state.get_block(block_id);
if let Some(span) = block.span {
let contents = engine_state.get_span_contents(&span);
let contents = engine_state.get_span_contents(span);
Ok(Value::string(String::from_utf8_lossy(contents), call.head)
.into_pipeline_data())
} else {
@ -61,7 +61,7 @@ impl Command for ViewSource {
if let Some(block_id) = decl.get_block_id() {
let block = engine_state.get_block(block_id);
if let Some(block_span) = block.span {
let contents = engine_state.get_span_contents(&block_span);
let contents = engine_state.get_span_contents(block_span);
// name of function
let mut final_contents = format!("def {val} [ ");
for n in vec_of_required {
@ -117,7 +117,7 @@ impl Command for ViewSource {
// arg is a module
let module = engine_state.get_module(module_id);
if let Some(module_span) = module.span {
let contents = engine_state.get_span_contents(&module_span);
let contents = engine_state.get_span_contents(module_span);
Ok(Value::string(String::from_utf8_lossy(contents), call.head)
.into_pipeline_data())
} else {

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