Compare commits

...

193 Commits

Author SHA1 Message Date
f5f21aca2d Bump to 0.90 (#11730)
<!--
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` to
check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-02-06 22:42:43 +02:00
9342ad6ae1 Pin reedline to version 0.29.0 (#11782)
<!--
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!
-->

See full release notes:
https://github.com/nushell/reedline/releases/tag/v0.29.0

# 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` to
check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-02-06 22:23:41 +02:00
cb4ca157fd Bump crate-ci/typos from 1.17.2 to 1.18.0 (#11743) 2024-02-05 01:00:27 +00:00
d1c807230b default to having border in ide_menu 2024-02-04 08:19:09 -06:00
4e5d3db952 allow strings with thousands separators to be converted to filesize or ints (#11724)
# Description

This PR changes `into int` and `into filesize` so that they allow
thousands separators.

### Before
```nushell
❯ '1,000' | into filesize
Error: nu:🐚:cant_convert

  × Can't convert to int.
   ╭─[entry #1:1:1]
 1 │ '1,000' | into filesize
   · ───┬───
   ·    ╰── can't convert string to int
   ╰────

❯ '1,000' | into int
Error: nu:🐚:cant_convert

  × Can't convert to int.
   ╭─[entry #2:1:1]
 1 │ '1,000' | into int
   ·           ────┬───
   ·               ╰── can't convert string to int
   ╰────
  help: string "1,000" does not represent a valid integer
```
### After
```nushell
❯ '1,000' | into filesize
1.0 KB
❯ '1,000' | into int
1000
```

This works by getting the system locale and from that, determining what
the thousands separator is. So, hopefully, this will work across
locales.
# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-02-03 10:42:44 -06:00
b8d37a7541 Fix panic in rotate; Add safe record creation function (#11718)
<!--
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 https://github.com/nushell/nushell/issues/11716

The problem is in our [record creation
API](0d518bf813/crates/nu-protocol/src/value/record.rs (L33))
which panics if the numbers of columns and values are different. I added
a safe variant that returns a `Result` and used it in the `rotate`
command.

## TODO in another PR:

Go through all `from_raw_cols_vals_unchecked()` (this includes the
`record!` macro which uses the unchecked version) and make sure that
either
a) it is guaranteed the number of cols and vals is the same, or
b) convert the call to `from_raw_cols_vals()`

Reason: Nushell should never panic.

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-02-03 13:23:16 +02:00
c7a8aac883 Tighten def body parsing (#11719)
<!--
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 https://github.com/nushell/nushell/issues/11711

Previously, syntax `def a [] (echo 4)` was allowed to parse and then
failed with panic duting eval.

Current error:
```
Error: nu::parser::parse_mismatch

  × Parse mismatch during operation.
   ╭─[entry #1:1:1]
 1 │ def a [] (echo 4)
   ·          ────┬───
   ·              ╰── expected definition body closure { ... }
   ╰────
```

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-02-03 13:20:40 +02:00
0d518bf813 query web --query should return list<list<string>> like the scraper crate's ElementRef::text() (#11705)
<!--
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.
-->
## Problem
I tried converting one of my Rust web scrapers to Nushell just to see
how it would be done, but quickly ran into an issue that proved annoying
to fix without diving into the source.

For instance, let's say we have the following HTML
```html
<p>Hello there, <span style="color: red;">World</span></p>
```
and we want to extract only the text within the `p` element, but not the
`span`. With the current version of nu_plugin_query, if we run this code
```nushell
echo `<p>Hello there, <span style="color: red;">World</span></p>` | query web -q "p" | get 0
# returns "Hello there, World"

# but we want only "Hello there, "
```
we will get back a `list<string>` that contains 1 string `Hello there,
World`.
To avoid scraping the span, we would have to do something like this
```nushell
const html = `<p>Hello there, <span style="color: red;">World</span></p>`
$html
| query web -q "p"
| get 0
| str replace ($html | query web -q "p > span" | get 0) ""
# returns "Hello there, "
```
In other words, we would have to make a sub scrape of the text we
*don't* want in order to subtract it from the text we *do* want.

## Solution
I didn't like this behavior, so I decided to change it. I modified the
`execute_selector_query` function to collect all text nodes in the HTML
element matching the query. Now `query web --query` will return a
`list<list<string>>`
```nushell
echo `<p>Hello there, <span style="color: red;">World</span></p>` | query web -q "p" | get 0 | to json --raw
# returns ["Hello there, ","World"]
```
This also brings `query web --query`'s behavior more in line with
[scraper's
ElementRef::text()](https://docs.rs/scraper/latest/scraper/element_ref/struct.ElementRef.html#method.text)
which "Returns an iterator over descendent text nodes", allowing you to
choose how much of an element's text you want to scrape without
resorting to string substitutions.

## Consequences
As this is a user-facing change, the usage examples will produce
different results than before. For example
```nushell
http get https://phoronix.com | query web --query 'header'
```
will return a list of lists of 1 string each, whereas before it was just
a list of strings.

I only modified the 3rd example
```nushell
# old
http get https://www.nushell.sh | query web --query 'h2, h2 + p' | group 2 | each {rotate --ccw tagline description} | flatten
# new
http get https://www.nushell.sh | query web --query 'h2, h2 + p' | each {str join} | group 2 | each {rotate --ccw tagline description} | flatten
```
to make it behave like before because I thought this one ought to show
the same results as before.
However, the second reason I changed the 3rd example is because it
otherwise panics! If we run the original 3rd example with my
modifications, we get a panic
```
thread 'main' panicked at crates/nu-protocol/src/value/record.rs:34:9:
assertion `left == right` failed
  left: 2
 right: 17
```
This happens because `rotate` receives a list of lists where the inner
lists have a different number of elements.

However this panic is unrelated to the changes I've made, because it can
be triggered easily without using the plugin. For instance
```nushell
# this is fine
[[[one] [two]] [[three] [four]]] | each {rotate --ccw tagline description}

# this panics!
[[[one] [two]] [[three] [four five]]] | each {rotate --ccw tagline description}
```
Though beyond the scope of this PR, I thought I'd mention this bug since
I found it while testing the usage examples. However, I intend to make a
proper issue about it tomorrow.

# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->
`query web --query "css selector"` now returns a `list<list<string>>`
instead of a `list<string>` to make it more in line with [scraper's
ElementRef::text()](https://docs.rs/scraper/latest/scraper/element_ref/struct.ElementRef.html#method.text).

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

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

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

> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->
I ran `cargo fmt --all -- --check`, `cargo clippy --workspace -- -D
warnings -D clippy::unwrap_used` and the tests in the plugin.

# 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.
-->
PR that updates the documentation to match the new 3rd example:
https://github.com/nushell/nushell.github.io/pull/1235
2024-02-02 19:40:47 -06:00
e083b75aef update to latest reedline after column menu fix (#11715)
# Description

This PR updates to the latest reedline after the column menu fix.

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-02-03 08:30:28 +08:00
2e5a857983 update query web wiki example (#11709)
# Description

This PR tries to make `query web` more resilient and easier to debug
with the `--inspect` parameter when trying to scrape tables. Previously
it would just fail, now at least it tries to give you a hint.

This is some example output now of when something went wrong.
```
❯ http get https://en.wikipedia.org/wiki/List_of_cities_in_India_by_population | query web --as-table [Rank City 'Population(2011)[3]' 'Population(2001)[3][a]' 'State or union territory'] --inspect
Passed in Column Headers = ["Rank", "City", "Population(2011)[3]", "Population(2001)[3][a]", "State or union territory"]

First 2048 HTML chars = <!DOCTYPE html>
<html class="client-nojs vector-feature-language-in-header-enabled vector-feature-language-in-main-page-header-disabled vector-feature-sticky-header-disabled vector-feature-page-tools-pinned-disabled vector-feature-toc-pinned-clientpref-1 vector-feature-main-menu-pinned-disabled vector-feature-limited-width-clientpref-1 vector-feature-limited-width-content-enabled vector-feature-custom-font-size-clientpref-0 vector-feature-client-preferences-disabled vector-feature-client-prefs-pinned-disabled vector-toc-available" lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<title>List of cities in India by population - Wikipedia</title>
<script>(function(){var className="client-js vector-feature-language-in-header-enabled vector-feature-language-in-main-page-header-disabled vector-feature-sticky-header-disabled vector-feature-page-tools-pinned-disabled vector-feature-toc-pinned-clientpref-1 vector-feature-main-menu-pinned-disabled vector-feature-limited-width-clientpref-1 vector-feature-limited-width-content-enabled vector-feature-custom-font-size-clientpref-0 vector-feature-client-preferences-disabled vector-feature-client-prefs-pinned-disabled vector-toc-available";var cookie=document.cookie.match(/(?:^|; )enwikimwclientpreferences=([^;]+)/);if(cookie){cookie[1].split('%2C').forEach(function(pref){className=className.replace(new RegExp('(^| )'+pref.replace(/-clientpref-\w+$|[^\w-]+/g,'')+'-clientpref-\\w+( |$)'),'$1'+pref+'$2');});}document.documentElement.className=className;}());RLCONF={"wgBreakFrames":false,"wgSeparatorTransformTable":["",""],"wgDigitTransformTable":["",""],"wgDefaultDateFormat":"dmy","wgMonthNames":["",
"January","February","March","April","May","June","July","August","September","October","November","December"],"wgRequestId":"9ecdad8f-2dbd-4245-b54d-9c57aea5ca45","wgCanonicalNamespace":"","wgCanonicalSpecialPageName":false,"wgNamespaceNumber":0,"wgPageName":"List_of_cities_in_India_by_population","wgTitle":"List of cities in India by population","wgCurRevisionId":1192093210,"wgRev

Potential HTML Headers = ["City", "Population(2011)[3]", "Population(2001)[3][a]", "State or unionterritory", "Ref"]

Potential HTML Headers = ["City", "Population(2011)[5]", "Population(2001)", "State or unionterritory"]

Potential HTML Headers = [".mw-parser-output .navbar{display:inline;font-size:88%;font-weight:normal}.mw-parser-output .navbar-collapse{float:left;text-align:left}.mw-parser-output .navbar-boxtext{word-spacing:0}.mw-parser-output .navbar ul{display:inline-block;white-space:nowrap;line-height:inherit}.mw-parser-output .navbar-brackets::before{margin-right:-0.125em;content:\"[ \"}.mw-parser-output .navbar-brackets::after{margin-left:-0.125em;content:\" ]\"}.mw-parser-output .navbar li{word-spacing:-0.125em}.mw-parser-output .navbar a>span,.mw-parser-output .navbar a>abbr{text-decoration:inherit}.mw-parser-output .navbar-mini abbr{font-variant:small-caps;border-bottom:none;text-decoration:none;cursor:inherit}.mw-parser-output .navbar-ct-full{font-size:114%;margin:0 7em}.mw-parser-output .navbar-ct-mini{font-size:114%;margin:0 4em}vtePopulation of cities in India"]

Potential HTML Headers = ["vteGeography of India"]

╭──────────────────────────┬─────────────────────────────────────────────────────╮
│ Rank                     │ error: no data found (column name may be incorrect) │
│ City                     │ error: no data found (column name may be incorrect) │
│ Population(2011)[3]      │ error: no data found (column name may be incorrect) │
│ Population(2001)[3][a]   │ error: no data found (column name may be incorrect) │
│ State or union territory │ error: no data found (column name may be incorrect) │
╰──────────────────────────┴─────────────────────────────────────────────────────╯
```
The key here is to look at the `Passed in Column Headers` and compare
them to the `Potential HTML Headers` and couple that with the error
table at the bottom should give you a hint that, in this situation,
wikipedia has changed the column names, yet again. So we need to update
our query web statement's tables to get closer to what we want.

```
❯ http get https://en.wikipedia.org/wiki/List_of_cities_in_India_by_population | query web --as-table [City 'Population(2011)[3]' 'Population(2001)[3][a]' 'State or unionterritory' 'Ref']
╭─#──┬───────City───────┬─Population(2011)[3]─┬─Population(2001)[3][a]─┬─State or unionterritory─┬──Ref───╮
│ 0  │ Mumbai           │ 12,442,373          │ 11,978,450             │ Maharashtra             │ [3]    │
│ 1  │ Delhi            │ 11,034,555          │ 9,879,172              │ Delhi                   │ [3]    │
│ 2  │ Bangalore        │ 8,443,675           │ 5,682,293              │ Karnataka               │ [3]    │
│ 3  │ Hyderabad        │ 6,993,262           │ 5,496,960              │ Telangana               │ [3]    │
│ 4  │ Ahmedabad        │ 5,577,940           │ 4,470,006              │ Gujarat                 │ [3]    │
│ 5  │ Chennai          │ 4,646,732           │ 4,343,645              │ Tamil Nadu              │ [3]    │
│ 6  │ Kolkata          │ 4,496,694           │ 4,580,546              │ West Bengal             │ [3]    │
│ 7  │ Surat            │ 4,467,797           │ 2,788,126              │ Gujarat                 │ [3]    │
│ 8  │ Pune             │ 3,124,458           │ 2,538,473              │ Maharashtra             │ [3]    │
│ 9  │ Jaipur           │ 3,046,163           │ 2,322,575              │ Rajasthan               │ [3]    │
│ 10 │ Lucknow          │ 2,817,105           │ 2,185,927              │ Uttar Pradesh           │ [3]    │
│ 11 │ Kanpur           │ 2,765,348           │ 2,551,337              │ Uttar Pradesh           │ [3]    │
│ 12 │ Nagpur           │ 2,405,665           │ 2,052,066              │ Maharashtra             │ [3]    │
```
# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-02-02 09:03:28 -06:00
0b6f15b69e Disable riscv64 build target temporarily to make release and nightly-build work (#11700)
Let's disable riscv64 build target temporarily to make release and
nightly-build workflow work, close #11604
We will add this target later if the related issue got fixed
2024-02-01 06:44:07 -06:00
16f3d9b4e1 cp: expand target path before checking (#11692)
# Description
Fixes: #11683

# User-Facing Changes
NaN

# Tests + Formatting
~~I don't think we need to add a test, or else it'll copy some file to
user's directory, it seems bad.~~
Done.

# After Submitting
NaN
2024-02-01 09:06:03 +08:00
3e0fa8ff85 Allow 'url join' to print username without password (#11697)
<!--
if this PR closes one or more issues, you can automatically link the PR
with
them by using one of the [*linking
keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword),
e.g.
- this PR should close #xxxx
- fixes #xxxx

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

# Description
Fixes: https://github.com/nushell/nushell/issues/11677
<!--
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` to
check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library
> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->
```
'https://example.com' | url parse | update scheme ssh | upda
te username user | url join
# => ssh://user@example.com/
'https://example.com' | url parse | update scheme ssh | upda
te password hackme | url join
# => ssh://example.com/
'https://example.com' | url parse | update scheme ssh | update username user | update password hackme | url join
# => ssh://user:hackme@example.com/
```
# 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: Richard Westhaver <ellis@rwest.io>
2024-01-31 16:52:23 -06:00
d40019a141 Tidy up the REPL main loop (#11655)
While working on #11288 I was having some trouble tracking the main REPL
loop, so I've sent in a bunch of tiny refactorings on this branch.

These are almost all of the "move code from one place to another"
variety, and each commit is meant to be independent, _except for the
last one_, which is trying to be a bit more clever to handle the
decision of autocd'ing vs running a command. Feel free to just go
through each commit and cherry pick the ones that look good.

This leads to `evaluate_repl` going from ending on line 715 to ending on
line 395. Again, this is mostly just moving code around, but I think
this set of changes will make other changes around juggling the stack to
avoid cloning easier to review.
2024-01-31 09:32:19 -08:00
d9b324c5d3 rollback polars 0.37.0 (#11695)
# Description

This PR rolls back the polars updates to 0.37.0 back to 0.36.2 since it
won't compile yet for some reason.

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-31 08:39:38 -06:00
00176c5666 Bump wayland (#11694)
# Description
Bumps wayland, and remove `quick-xml v0.30.0` and duplicate `nix
v0.26.4`.
2024-01-31 08:06:59 -06:00
f16ac886a8 change update cells column param from Table to List (#11691)
# Description

This PR fixes `update cells` parameter `--columns`/`-c` so that it takes
a `SyntaxShape::List` instead of `SyntaxShape::Table`.

closes #11689

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-30 19:36:03 -06:00
c77ec0b667 Bump polars-arrow from 0.36.2 to 0.37.0 (#11660) 2024-01-30 22:26:42 +00:00
6779b248e4 Bump sqlparser from 0.41.0 to 0.43.1 (#11662) 2024-01-30 22:26:31 +00:00
0a355db5c0 make the ansi command const (#11682)
# Description

This PR changes the `ansi` command to be a `const` command. 

- ~~It's breaking because I found that I had to change the way `ansi` is
used in scripts a little bit.
https://github.com/nushell/nu_scripts/pull/751~~

- I had to change one of the examples because apparently `const` can't
be tested yet.

- ~~I'm not sure this is right at all
https://github.com/nushell/nushell/pull/11682/files#diff-ba932369a40eb40d6e1985eac1c784af403dab4500a7f0568e593900bf6cd740R654-R655.
I just didn't want to duplicate a ton of code. Maybe if I duplicated the
code it wouldn't be a breaking change because it would have a run and
run_const?~~

- I had to add `opt_const` to CallExt.

/cc @kubouch Can you take a look at this? I'm a little iffy if I'm doing
this right, or even if we should do this at all.

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-30 16:09:43 -06:00
cf9813cbf8 Refactor lines command (#11685)
# Description
This PR uses `str::lines` to simplify the `lines` command (and one other
section of code). This has two main benefits:
1. We no longer need to use regex to split on lines, as `str::lines`
splits on `\r\n` or `\n`.
2. We no longer need to handle blank empty lines at the end. E.g.,
`str::lines` results in `["text"]` for both `"test\n"` and `"text"`.

These changes give a slight boost to performance for the following
benchmarks:
1. lines of `Value::String`:
    ```nushell
    let data = open Cargo.lock
    1..10000 | each { $data | timeit { lines } } | math avg 
    ```
    current main: 392µs
    this PR: 270µs
2. lines of external stream:
    ```nushell
    1..10000 | each { open Cargo.lock | timeit { lines } } | math avg 
    ```
    current main: 794µs
    this PR: 489µs
2024-01-30 15:56:19 -06:00
c371d1a535 fix exit_code handling when running a scripts with ctrlc (#11466)
# Description
Fixes: #11394

When run `^sleep 3` we have an `exit_code ListStream`, and when we press
ctrl-c, this `ListStream` will return None. But it's not expected,
because `exit_code` sender in `run_external` always send an exit code
out.

This pr is trying to fix the issue by introducing a `first_guard` into
ListStream, it will always generate a value from underlying stream if
`first_guard` is true, so it's guarantee to have at least one value to
return.

And the pr also do a little refactor, which makes use of
`ListStream::from_stream` rather than construct it manually.

# User-Facing Changes
## Before
```
> nu -c "^sleep 3"  # press ctrl-c
> echo $env.LAST_EXIT_CODE
0
```

## After
```
> nu -c "^sleep 3"  # press ctrl-c
> echo $env.LAST_EXIT_CODE
255
```

# Tests + Formatting
None, sorry that I don't think it's easy to test the ctrlc behavior.

# After Submitting
None
2024-01-30 22:41:14 +08:00
4e0a65c822 Strict JSON parsing (#11592)
# Description
Adds the `--strict` flag for `from json` which will try to parse text
while following the exact JSON specification (e.g., no comments or
trailing commas allowed). Fixes issue #11548.
2024-01-30 08:10:19 -06:00
6530403ff8 Highlights find upgrade (#11509)
this PR should close #9105

# Description
I have implemented highlights for find which work for all strings. The
implementation also works for lists, but with exceptions (for example,
it does not work for list of lists). The implementation is also not
implemented for --regex.

---------

Co-authored-by: Georgiana <geo@LAPTOP-EQP6H37N>
Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2024-01-30 08:06:20 -06:00
c08f46f836 Respect SyntaxShape when parsing spread operator (#11674)
<!--
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 fixes an issue brought up by nihilander in
[Discord](https://discord.com/channels/601130461678272522/614593951969574961/1201594105986285649).

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

Nushell panics when the spread operator is used like this (the
`...$rest` shouldn't actually be parsed as a spread operator at all):

```nu
$ def foo [...rest: string] {...$rest}                      
$ foo bar baz                                               
thread 'main' panicked at /root/.cargo/registry/src/index.crates.io-6f17d22bba15001f/nu-protocol-0.89.0/src/signature.rs:650:9:
Internal error: can't run a predeclaration without a body
stack backtrace:
   0: rust_begin_unwind
   1: core::panicking::panic_fmt
   2: <nu_protocol::signature::Predeclaration as nu_protocol::engine::command::Command>::run
   3: nu_engine::eval::eval_call
   4: nu_engine::eval::eval_expression_with_input
   5: nu_engine::eval::eval_element_with_input
   6: nu_engine::eval::eval_block
   7: nu_cli::util::eval_source
   8: nu_cli::repl::evaluate_repl
   9: nu::run::run_repl
  10: nu::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
```

The problem was that whenever the parser saw something like `{...$`,
`{...(`, or `{...[`, it would treat that as a record with a spread
expression, ignoring the syntax shape of the block it was parsing. This
should now be fixed, and the snippet above instead gives the following
error:

```nu
Error: nu:🐚:external_command

  × External command failed
   ╭─[entry #1:1:1]
 1 │  def foo [...rest] {...$rest}
   ·                     ────┬───
   ·                         ╰── executable was not found
   ╰────
  help: No such file or directory (os error 2)
```

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

Stuff like `do { ...$rest }` will now try to run a command `...$rest`
rather than complaining that variable `$rest` doesn't exist.

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

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

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

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

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

Sorry about the issue, I am not touching the parser again for a long
time :)
2024-01-30 13:49:42 +08:00
175dab4898 "[11611] fixing dataframe column comparisons" (#11676)
fixes #11611

Co-authored-by: Jack Wright <jack.wright@disqo.com>
2024-01-29 17:28:12 -06:00
798ae7b251 Fix precedence of 'not' operator (#11672)
<!--
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

A bit hackish but this fixes the precedence of the `not` operator.

Before: `not false and false` => true

Now: `not false and false` => false

Fixes #11633

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

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

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

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

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

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

---------

Co-authored-by: Jakub Žádník <kubouch@gmail.com>
2024-01-29 21:42:27 +02:00
f879c00f9d The ability to specify a schema when using dfr open and dfr into-df (#11634)
# Description

There are times where explicitly specifying a schema for a dataframe is
needed such as:
- Opening CSV and JSON lines files and needing provide more information
to polars to keep it from failing or in a desire to override default
type conversion
- When converting a nushell value to a dataframe and wanting to override
the default conversion behaviors.

This pull requests provides:
- A flag to allow specifying a schema when using dfr into-df
- A flag to allow specifying a schema when using dfr open that works for
CSV and JSON types
- A new command `dfr schema` which displays schema information and will
allow display support schema dtypes

Schema is specified creating a record that has the key value and the
dtype. Examples usages:

```
{a:1, b:{a:2}} | dfr into-df -s {a: u8, b: {a: i32}} | dfr schema
{a: 1, b: {a: [1 2 3]}, c: [a b c]} | dfr into-df -s {a: u8, b: {a: list<u64>}, c: list<str>} | dfr schema
 dfr open -s {pid: i32, ppid: i32, name: str, status: str, cpu: f64, mem: i64, virtual: i64} /tmp/ps.jsonl  | dfr schema
```

Supported dtypes:
null                                                   
bool                                                   
u8                                                     
u16                                                    
u32                                                    
u64                                                    
i8                                                     
i16                                                    
i32                                                    
i64                                                    
f32                                                    
f64                                                    
str                                                    
binary                                                 
date                                                   
datetime[time_unit: (ms, us, ns) timezone (optional)]  
duration[time_unit: (ms, us, ns)]                      
time                                                   
object                                                 
unknown                                                
list[dtype]


structs are also supported but are specified via another record:
{a: u8, b: {d: str}}

Another feature with the dfr schema command is that it returns the data
back in a format that can be passed to provide a valid schema that can
be passed in as schema argument:

<img width="638" alt="Screenshot 2024-01-29 at 10 23 58"
src="https://github.com/nushell/nushell/assets/56345/b49c3bff-5cda-4c86-975a-dfd91d991373">

---------

Co-authored-by: Jack Wright <jack.wright@disqo.com>
2024-01-29 13:26:04 -06:00
d03ad6a257 update to latest reedline for the quick completions fix (#11673)
# Description

This PR updates nushell to the latest reedline main to fix the quick
completions.

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-29 13:22:07 -06:00
14e4d05a9f use constant instead of <0 for ls fix (#11642)
https://github.com/nushell/nushell/pull/10558#issuecomment-1911076784

more correct than <0.  safer check.
2024-01-29 13:17:04 -06:00
86dd045554 add match-text style + config setting for ide menu (#11670)
the match-text style (https://github.com/nushell/reedline/pull/730) is
now configurable via the config.nu file.
the option ``correct_cursor_pos`` can now also be set in the config.nu
file.
2024-01-29 09:59:01 -06:00
0e023eaa84 add str escape-glob command (#11664)
# Description
This pr is a follow up to #11621, it introduces a `str escape-glob`
command as a workaround for the case:

```nushell
let f = "a[123]b"
ls $f
```

It will glob `a[123]b`, we can get rid of the behavior through `str
escape-glob` command:

```nushll
let f = "a[123]b"
ls ($f | str escape-glob)
```

It's more useful in the `each` context:
`ls | get name | str escape-glob | each {|it| ls $it}`

# User-Facing Changes
NaN

# Tests + Formatting
Done

# After Submitting

---------

Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2024-01-29 23:00:15 +08:00
427857a78e Fix wrong error for raw streams in into record (#11668)
Fix #11632
2024-01-29 08:32:43 -06:00
eea3f79c3c Bump ical from 0.9.0 to 0.10.0 (#11661)
Bumps [ical](https://github.com/Peltoche/ical-rs) from 0.9.0 to 0.10.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/Peltoche/ical-rs/releases">ical's
releases</a>.</em></p>
<blockquote>
<h2>v0.10.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix newlines by <a
href="https://github.com/westy92"><code>@​westy92</code></a> in <a
href="https://redirect.github.com/Peltoche/ical-rs/pull/56">Peltoche/ical-rs#56</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/Peltoche/ical-rs/compare/v0.9.0...v0.10.0">https://github.com/Peltoche/ical-rs/compare/v0.9.0...v0.10.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="2e83429867"><code>2e83429</code></a>
chore: Release ical version 0.10.0</li>
<li><a
href="6c265a53f0"><code>6c265a5</code></a>
Add test to verify parser handles \r\n.</li>
<li><a
href="79b0e6501b"><code>79b0e65</code></a>
Fixes &amp; clippy.</li>
<li><a
href="821bd46bfb"><code>821bd46</code></a>
Fix split lines.</li>
<li><a
href="8bb242a4ba"><code>8bb242a</code></a>
Fix newlines.</li>
<li>See full diff in <a
href="https://github.com/Peltoche/ical-rs/compare/v0.9.0...v0.10.0">compare
view</a></li>
</ul>
</details>
<br />


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

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

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

---

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

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


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-29 09:34:06 +08:00
b004e80f77 Bump Reedline for the Menu Refactor (#11658)
* [Refactor Menu System with Composition of Menu
Functions](https://github.com/nushell/reedline/issues/706)
* Move Description Menu over to Reedline to consolidate location of the
Menus which will simplify further changes and maintenance to the Menu
system going forward
* Removes lots of code duplication in the Menu system on the Reedline
side which should ease a developers ability to develop new cool menus
for Reedline moving forward
2024-01-28 08:26:03 -08:00
25b62c2ac3 fix force rm: should suppress error if directory is not found (#11656)
# Description
Fix a breaking change which is introduced by #11621

`rm -f /tmp/aaa` shouldn't return error if `/tmp/aaa/` doesn't exist.

# User-Facing Changes
NaN

# Tests + Formatting
Done
2024-01-28 09:01:19 -06:00
859f7b3dc7 add $.extra_usage to modules (#11649)
- should fix https://github.com/nushell/nushell/issues/11648

# Description
this PR
- adds a test that should pass but fails
- adds `$.extra_usage` to the output of `scope modules`, fixing both the
new test and the linked issue

# User-Facing Changes
`$.extra_usage` is now a column in the output of `scope modules`

# Tests + Formatting
a new test case has been added to `correct_scope_modules_fields`

# After Submitting
2024-01-27 17:49:21 +02:00
39b020037d update Reedline so we can begin testing the menu refactor (#11647)
We would like to update Reedline to the latest code on the main
branch...

So we can start testing the menu refactor work...
2024-01-26 16:33:15 -08:00
1334de72b0 make the input_output_types match on each and par-each (#11645)
# Description
@Yethal had a strange problem where a script would work with `each` but
not `par-each`. I found this to be because the `input_output_types` were
different. These io types are weird and I don't think they're correct
but at least they're the same now.

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-26 08:45:02 -06:00
56acebb826 making empty list matches list<int> types (#11596)
# Description
Fixes: #11595

The original issue is caused by #11475, we also need to make empty list
matches `list type` or `table type`

cc @amtoine 

# User-Facing Changes
Nan

# Tests + Formatting
Done
2024-01-26 22:24:17 +08:00
d646903161 Unify glob behavior on open, rm, cp-old, mv, umv, cp and du commands (#11621)
# Description
This pr is a follow up to
[#11569](https://github.com/nushell/nushell/pull/11569#issuecomment-1902279587)
> Revert the logic in https://github.com/nushell/nushell/pull/10694 and
apply the logic in this pr to mv, cp, rv will require a larger change, I
need to think how to achieve the bahavior

And sorry @bobhy for reverting some of your changes.

This pr is going to unify glob behavior on the given commands:
* open
* rm
* cp-old
* mv
* umv
* cp
* du

So they have the same behavior to `ls`, which is:
If given parameter is quoted by single quote(`'`) or double quote(`"`),
don't auto-expand the glob pattern. If not quoted, auto-expand the glob
pattern.

Fixes: #9558  Fixes: #10211 Fixes: #9310 Fixes: #10364 

# TODO
But there is one thing remains: if we give a variable to the command, it
will always auto-expand the glob pattern, e.g:
```nushell
let path = "a[123]b"
rm $path
```
I don't think it's expected. But I also think user might want to
auto-expand the glob pattern in variables.

So I'll introduce a new command called `glob escape`, then if user
doesn't want to auto-expand the glob pattern, he can just do this: `rm
($path | glob escape)`

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

# Tests + Formatting
Done

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

## NOTE
This pr changes the semantic of `GlobPattern`, before this pr, it will
`expand path` after evaluated, this makes `nu_engine::glob_from` have no
chance to glob things right if a path contains glob pattern.

e.g: [#9310
](https://github.com/nushell/nushell/issues/9310#issuecomment-1886824030)
#10211

I think changing the semantic is fine, because it makes glob works if
path contains something like '*'.

It maybe a breaking change if a custom command's argument are annotated
by `: glob`.
2024-01-26 21:57:35 +08:00
e43d893ea3 fix panic caused by ls \\.\pipe (#10558)
wrap chrono in panic hooks to handle panic'ing unwraps on Jan 1, 1601
00:00 UTC and other reasons unknown. An overflow if time_u64 is smaller
than EPOCH_AS_FILETIME has been wrapped.

Further discussion
https://github.com/nushell/nushell/issues/10464

There are two issues that are associated with Chrono. I did not test. It
may not relate, but it could.
thread 'main' panicked at 'SystemTimeToFileTime failed with: The
parameter is incorrect.
https://github.com/nushell/nushell/issues/6574
https://github.com/nushell/nushell/issues/9470

# Description

I'm not a fan of this code that was pulled from chrono. negative seconds
and nano seconds?
```rust
    // Adapted from https://github.com/chronotope/chrono/blob/v0.4.19/src/datetime.rs#L755-L767.
    let (sec, nsec, was_success) = match t.duration_since(UNIX_EPOCH) {
        Ok(dur) => {
            (dur.as_secs() as i64, dur.subsec_nanos(),true)
        },
        Err(e) => {
            // unlikely but should be handled
            let dur = e.duration();
            let (sec, nsec) = (dur.as_secs() as i64, dur.subsec_nanos());
            if nsec == 0 {
                (-sec, 0,false)
            } else {
                (-sec - 1, 1_000_000_000 - nsec,false)
            }
        }
    };
```

There's more on the #10464 ticket;


# User-Facing Changes

Use ls and it will not crash when listing windows pipes 
ls \\.\pipe.

# Tests + Formatting

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
DONE

- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to
check that you're using the standard code style
that command yields:

```rust
error: casting raw pointers to the same type and constness is unnecessary (`*mut u16` -> `*mut u16`)
   --> crates\nu-system\src\windows.rs:972:13
    |
972 |             name.as_mut_ptr() as *mut u16,
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `name.as_mut_ptr()`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast
    = note: `-D clippy::unnecessary-cast` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_cast)]`

error: casting raw pointers to the same type and constness is unnecessary (`*mut u16` -> `*mut u16`)
   --> crates\nu-system\src\windows.rs:974:13
    |
974 |             domainname.as_mut_ptr() as *mut u16,
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `domainname.as_mut_ptr()`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast

error: could not compile `nu-system` (lib) due to 2 previous errors
```


TBD
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library
2024-01-25 15:41:22 -06:00
f03d81b0c8 fix spreading of arguments to externals in toolkit (#11640)
as per title, that's just a simple change to avoid the deprecation
warning introduced recently and that will be removed in `0.91`
2024-01-25 19:40:51 +01:00
7f1fd7699e external completer: support style (#11442)
<!--
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

Adds style support.

Reverse highlighting is recommended for the
[completion-menu](https://www.nushell.sh/book/line_editor.html#completion-menu):
```nushell
style: {
    text: white
    selected_text: {
        attr: r
    }
    description_text: white_dimmed
}
```

needs https://github.com/nushell/reedline/pull/691
related https://github.com/nushell/nushell/issues/5292
fix https://github.com/rsteube/carapace/issues/967

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

Style support for values during completion:


![image](https://github.com/nushell/nushell/assets/9090290/f5e4440e-61db-4eeb-87b3-f887b6918c50)


![image](https://github.com/nushell/nushell/assets/9090290/e59065a6-58c2-4f5f-82ea-e2b9c2464b9a)

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-25 08:21:28 -06:00
a3f1116ea8 cleanup hide testing PR (#11638)
# Description

This PR cleans up https://github.com/nushell/nushell/pull/11331. One
line was missed that caused the CI to break.

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-25 06:49:04 -06:00
ef1d70eb67 hide std testing (#11331)
follow-up to
- https://github.com/nushell/nushell/pull/11151

> **Important**
> land only between 0.89 and 0.90

# Description
this PR hides the `std testing` module from the outside.
- moves `nu-std/std/testing.nu` to `nu-std/testing.nu`
- removes the module from the standard library list of modules to parse
- fixes `toolkit.nu` and the CI

# User-Facing Changes
`std testing` won't be part of the standard library anymore.
# Tests + Formatting

# After Submitting
2024-01-25 12:50:07 +02:00
cffce7f4b2 properly convert env for buffer editor (#11636)
<!--
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

environment variables were not correctly passed to `buffer_editor`.
Previously the conversion (if you can call it that) is incorrectly done
by `.as_string()`, which works for the most part, but ignores important
things like `PATH`, which are not strings in value form by default

(this issue was introduced in #10269, merged in #10535)

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-25 09:31:46 +02:00
a4809d2f08 Remove --flag: bool support (#11541)
# Description
This is a follow up to: #11365

After this pr, `--flag: bool` is no longer allowed.

I think `ParseWarning::Deprecated` is useful when we want to deprecated
something at syntax level, so I just leave it there for now.

# User-Facing Changes
## Before
```
❯ def foo [--b: bool] {}
Error:   × Deprecated: --flag: bool
   ╭─[entry #15:1:1]
 1 │ def foo [--b: bool] {}
   ·               ──┬─
   ·                 ╰── `--flag: bool` is deprecated and will be removed in 0.90. Please use `--flag` instead, more info: https://www.nushell.sh/book/custom_commands.html
   ╰────
```

## After
```
❯ def foo [--b: bool] {}
Error:   × Type annotations are not allowed for boolean switches.
   ╭─[entry #2:1:1]
 1 │ def foo [--b: bool] {}
   ·               ──┬─
   ·                 ╰── Remove the `: bool` type annotation.
   ╰────
```
# Tests + Formatting
Done
2024-01-25 14:16:49 +08:00
f286286510 update nu-ansi-term to 0.50, lscolors to 0.17, and add the Style attribute to Suggestion (#11635)
* update nu-ansi-term to 0.50.0
* update lscolors to 0.17.0
* add the Style attribute to Suggestion
* bump Reedline to the latest main
2024-01-24 20:57:15 -08:00
2a65d43c13 Add into cell-path for dynamic cell-path creation (#11322)
# Description

The `cell-path` is a type that can be created statically with
`$.nested.structure.5`, but can't be created from user input. This makes
it difficult to take advantage of commands that accept a cell-path to
operate on data structures.

This PR adds `into cell-path` for dynamic cell-path creation.

`into cell-path` accepts the following input shapes:
* Bare integer (equivalent to `$.1`)
* List of strings and integers
* List of records with entries `value` and `optional`
* String (parsed into a cell-path)

## Example usage

An example of where `into cell-path` can be used is in working with `git
config --list`. The git configuration has a tree structure that maps
well to nushell records. With dynamic cell paths it is easy to convert
`git config list` to a record:

```nushell
git config --list
| lines
| parse -r '^(?<key>[^=]+)=(?<value>.*)'
| reduce --fold {} {|entry, result|
  let path = $entry.key | into cell-path

  $result
  | upsert $path {||
    $entry.value
  }
}
| select remote
```

Output:

```
╭────────┬──────────────────────────────────────────────────────────────────╮
│        │ ╭──────────┬───────────────────────────────────────────────────╮ │
│ remote │ │          │ ╭───────┬───────────────────────────────────────╮ │ │
│        │ │ upstream │ │ url   │ git@github.com:nushell/nushell.git    │ │ │
│        │ │          │ │ fetch │ +refs/heads/*:refs/remotes/upstream/* │ │ │
│        │ │          │ ╰───────┴───────────────────────────────────────╯ │ │
│        │ │          │ ╭───────┬─────────────────────────────────────╮   │ │
│        │ │ origin   │ │ url   │ git@github.com:drbrain/nushell      │   │ │
│        │ │          │ │ fetch │ +refs/heads/*:refs/remotes/origin/* │   │ │
│        │ │          │ ╰───────┴─────────────────────────────────────╯   │ │
│        │ ╰──────────┴───────────────────────────────────────────────────╯ │
╰────────┴──────────────────────────────────────────────────────────────────╯
```

## Errors

`lex()` + `parse_cell_path()` are forgiving about what is allowed in a
cell-path so it will allow what appears to be nonsense to become a
cell-path:

```nushell
let table = [["!@$%^&*" value]; [key value]]

$table | get ("!@$%^&*.0" | into cell-path)
# => key
```

But it will reject bad cell-paths:

```
❯ "a b" | into cell-path
Error: nu:🐚:cant_convert

  × Can't convert to cell-path.
   ╭─[entry #14:1:1]
 1 │ "a b" | into cell-path
   ·         ───────┬──────
   ·                ╰── can't convert string to cell-path
   ╰────
  help: "a b" is not a valid cell-path (Parse mismatch during operation.)
```

# User-Facing Changes

New conversion command `into cell-path`

# Tests + Formatting

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

# After Submitting

Automatic documentation updates
2024-01-24 16:20:46 -06:00
0aabe84460 Added --index flag to input list (#11580)
# Description
This PR closes #11571 

Add `--index` flag to input list.

For example:

![image](https://github.com/nushell/nushell/assets/72006223/19efb011-1ff8-4916-b2bd-6f73e89cb186))
 
# Tests + Formatting
 Added new example for `--index` flag.
2024-01-24 11:57:29 -06:00
323207ca1d Adapt tests for internationalization (#11628)
I've noticed that two tests fail on my system when running `toolkit
check pr`. The reason for this is that my locale is set to German. `ls`
is translated, so checking the error message will only work on systems
set to English.

I've adapted the test to check the exit code instead.

Alternatively, we could set the locale, I am not sure if the `nu!` macro
supports that though.
2024-01-24 11:55:27 -06:00
e35376f1e7 Bump heapless from 0.7.17 to 0.8.0
Bumps [heapless](https://github.com/japaric/heapless) from 0.7.17 to 0.8.0.
- [Changelog](https://github.com/rust-embedded/heapless/blob/main/CHANGELOG.md)
- [Commits](https://github.com/japaric/heapless/compare/v0.7.17...v0.8.0)

---
updated-dependencies:
- dependency-name: heapless
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-24 16:24:17 +00:00
7e37e4bb5f Bump sqlparser from 0.39.0 to 0.41.0
Bumps [sqlparser](https://github.com/sqlparser-rs/sqlparser-rs) from 0.39.0 to 0.41.0.
- [Changelog](https://github.com/sqlparser-rs/sqlparser-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sqlparser-rs/sqlparser-rs/compare/v0.39.0...v0.41.0)

---
updated-dependencies:
- dependency-name: sqlparser
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-24 15:49:09 +00:00
a44ad949f1 Bump polars from 0.35 to 0.36 (#11624)
# Description
* release notes
 https://github.com/pola-rs/polars/releases/tag/rs-0.36.2

* dependencies 
remove `sysinfo` 0.29.11
add `polars-compute` 0.36.2

# User-Facing Changes
[Change value_counts resulting column name from counts to
count](https://github.com/pola-rs/polars/pull/12506)

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-24 09:27:06 -06:00
4105255a5a resolving external highlight should take current PATH into account (#11618)
<!--
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

When resolving external commands, the current `PATH` was not taken into
account.

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-24 09:02:53 -06:00
ff5815c0a3 remove cp-old (#11622)
# Description

The `cp-old` command has been deprecated for a few releases now. It
should be safe to remove it once and for all. Let's see.

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-24 07:38:15 +08:00
3af4f34f11 Bump shlex from 1.2.0 to 1.3.0 (#11616)
Bumps [shlex](https://github.com/comex/rust-shlex) from 1.2.0 to 1.3.0.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/comex/rust-shlex/blob/master/CHANGELOG.md">shlex's
changelog</a>.</em></p>
<blockquote>
<h1>1.3.0</h1>
<ul>
<li>Full fix for the high-severity security vulnerability <a
href="https://rustsec.org/advisories/RUSTSEC-2024-0006.html">RUSTSEC-2024-0006</a>
a.k.a. <a
href="https://github.com/comex/rust-shlex/security/advisories/GHSA-r7qv-8r2h-pg27">GHSA-r7qv-8r2h-pg27</a>:
<ul>
<li>Deprecates quote APIs in favor of <code>try_</code> equivalents that
complain about nul bytes.</li>
<li>Also adds a builder API, which allows re-enabling nul bytes without
using the deprecated interface, and in the future can allow other things
(as discussed in quoting_warning).</li>
<li>Adds documentation about various security risks that remain,
particularly with interactive shells.</li>
</ul>
</li>
<li>Adds explicit MSRV of 1.46.0.</li>
</ul>
<h1>1.2.1</h1>
<ul>
<li>Partial fix for the high-severity security vulnerability <a
href="https://rustsec.org/advisories/RUSTSEC-2024-0006.html">RUSTSEC-2024-0006</a>
a.k.a. <a
href="https://github.com/comex/rust-shlex/security/advisories/GHSA-r7qv-8r2h-pg27">GHSA-r7qv-8r2h-pg27</a>
without bumping MSRV:
<ul>
<li>The bytes <code>{</code> and <code>\xa0</code> are now escaped by
quoting functions.</li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/comex/rust-shlex/commits">compare view</a></li>
</ul>
</details>
<br />


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

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

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

---

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

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

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-22 16:21:02 -06:00
092d496ff5 Plugin explicit flags (#11581)
# Description
#11492 fixed flags for builtin commands but I missed that plugins don't
use the same `has_flag` that builtins do. This PR addresses this.

Unfortunately this means that return value of `has_flag` needs to change
from `bool` to `Result<bool, ShellError>` to produce an error when
explicit value is not a boolean (just like in case of `has_flag` for
builtin commands. It is not possible to check this in
`EvaluatedCall::try_from_call` because

# User-Facing Changes
Passing explicit values to flags of plugin commands (like `--flag=true`
`--flag=false`) should work now.
BREAKING: changed return value of `EvaluatedCall::has_flag` method from
`bool` to `Result<bool, ShellError>`

# Tests + Formatting
Added tests and updated documentation and examples
2024-01-22 15:00:43 -06:00
415ebf207f Remove duplicate which 4.4.2 (#11613)
# Description

`which` 5.0.0 is already in the dependency tree, so remove v4.4.2

Related: https://github.com/nushell/nushell/issues/8060
2024-01-22 09:28:47 -06:00
aaac273cd0 Fix regression in help menu introduced by #11488 (#11608)
<!--
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!
-->

For fixing #11599

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

Turns out I didn't properly test the description menu in #11488,
apologies for that. It turns out that `NuHelpCompleter`, which provides
completions for the description/help menu, was treating the position it
was given as the start of the line rather than the start. Flipping that
appears to fix the issue.

I missed not only `NuHelpCompleter` but also `NuMenuCompleter` in my
previous PR. If the menu's source is a closure and it doesn't return a
record with the start and end, then `pos` is again treated as the start,
so I've changed that too. External completers shouldn't need changing.

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

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

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

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

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

- [X] Test description menu
- [X] Test menu sources that return records that don't have `start` and
`end`
- [ ] <s>Test external completers if any changes have to be made
there</s> No changes needed, it looks like

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-22 07:01:45 -06:00
90d65bb987 Evaluate string interpolation at parse time (#11562)
<!--
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!
-->

Closes #11561

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

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

This PR will allow string interpolation at parse time.

Since the actual config hasn't been loaded at parse time, this uses the
`get_config()` method on `StateWorkingSet`. So file sizes and datetimes
(I think those are the only things whose string representations depend
on the config) may be formatted differently from how users have
configured things, which may come as a surprise to some. It does seem
unlikely that anyone would be formatting file sizes or date times at
parse time. Still, something to think about if/before this PR merged.

Also, I changed the `ModuleNotFound` error to include the name of the
module.

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

Users will be able to do stuff like:

```nu
const x = [1 2 3]
const y = $"foo($x)" // foo[1, 2, 3]
```

The main use case is `use`-ing and `source`-ing files at parse time:

```nu
const file = "foo.nu"
use $"($file)"
```

If the module isn't found, you'll see an error like this:
```
Error: nu::parser::module_not_found

  × Module not found.
   ╭─[entry #3:1:1]
 1 │  use $"($file)"
   ·      ─────┬────
   ·           ╰── module foo.nu not found
   ╰────
  help: module files and their paths must be available before your script is run as parsing occurs before anything is evaluated
```

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

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

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

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

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

Although there's user-facing changes, there's probably no need to change
the docs since people probably already expect string interpolation to
work at parse time.

Edit: @kubouch pointed out that we'd need to document the fact that
stuff like file sizes and datetimes won't get formatted according to
user's runtime configs, so I'll make a PR to nushell.github.io after
this one
2024-01-22 09:13:48 +02:00
4c5a8c1804 Bump crate-ci/typos from 1.17.1 to 1.17.2
Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.17.1 to 1.17.2.
- [Release notes](https://github.com/crate-ci/typos/releases)
- [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crate-ci/typos/compare/v1.17.1...v1.17.2)

---
updated-dependencies:
- dependency-name: crate-ci/typos
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-22 01:46:37 +00:00
188aca8fe6 Upgrade byte-unit from 4.0 to 5.1 (#11584)
<!--
if this PR closes one or more issues, you can automatically link the PR
with
them by using one of the [*linking
keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword),
e.g.
- this PR should close #xxxx
- fixes #xxxx

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

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

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

This PR is for using version 5.1 of
[byte_unit](https://docs.rs/byte-unit/latest/byte_unit/index.html)
instead of 4.0. dependabot opened
https://github.com/nushell/nushell/pull/11499 to do this but it's a
major version increment so some minor changes were necessary.

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

If something is on the boundary of a unit (e.g. 1024 bytes = 1
kibibytes), that will now be formatted as `1.0 KiB` where it used to be
formatted as `1,024 B`.

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-21 14:17:28 -06:00
c59d6d31bc do not attempt to glob expand if the file path is wrapped in quotes (#11569)
# Description
Fixes: #11455

### For arguments which is annotated with `:path/:directory/:glob`
To fix the issue, we need to have a way to know if a path is originally
quoted during runtime. So the information needed to be added at several
levels:
* parse time (from user input to expression)
We need to add quoted information into `Expr::Filepath`,
`Expr::Directory`, `Expr::GlobPattern`
* eval time
When convert from `Expr::Filepath`, `Expr::Directory`,
`Expr::GlobPattern` to `Value::String` during runtime, we won't auto
expanded the path if it's quoted

### For `ls`
It's really special, because it accepts a `String` as a pattern, and it
generates `glob` expression inside the command itself.

So the idea behind the change is introducing a special SyntaxShape to
ls: `SyntaxShape::LsGlobPattern`. So we can track if the pattern is
originally quoted easier, and we don't auto expand the path either.

Then when constructing a glob pattern inside ls, we check if input
pattern is quoted, if so: we escape the input pattern, so we can run `ls
a[123]b`, because it's already escaped.
Finally, to accomplish the checking process, we also need to introduce a
new value type called `Value::QuotedString` to differ from
`Value::String`, it's used to generate an enum called `NuPath`, which is
finally used in `ls` function. `ls` learned from `NuPath` to know if
user input is quoted.

# User-Facing Changes
Actually it contains several changes
### For arguments which is annotated with `:path/:directory/:glob`
#### Before
```nushell
> def foo [p: path] { echo $p }; print (foo "~/a"); print (foo '~/a')
/home/windsoilder/a
/home/windsoilder/a
> def foo [p: directory] { echo $p }; print (foo "~/a"); print (foo '~/a')
/home/windsoilder/a
/home/windsoilder/a
> def foo [p: glob] { echo $p }; print (foo "~/a"); print (foo '~/a')
/home/windsoilder/a
/home/windsoilder/a
```
#### After
```nushell
> def foo [p: path] { echo $p }; print (foo "~/a"); print (foo '~/a')
~/a
~/a
> def foo [p: directory] { echo $p }; print (foo "~/a"); print (foo '~/a')
~/a
~/a
> def foo [p: glob] { echo $p }; print (foo "~/a"); print (foo '~/a')
~/a
~/a
```
### For ls command
`touch '[uwu]'`
#### Before
```
❯ ls -D "[uwu]"
Error:   × No matches found for [uwu]
   ╭─[entry #6:1:1]
 1 │ ls -D "[uwu]"
   ·       ───┬───
   ·          ╰── Pattern, file or folder not found
   ╰────
  help: no matches found
```

#### After
```
❯ ls -D "[uwu]"
╭───┬───────┬──────┬──────┬──────────╮
│ # │ name  │ type │ size │ modified │
├───┼───────┼──────┼──────┼──────────┤
│ 0 │ [uwu] │ file │  0 B │ now      │
╰───┴───────┴──────┴──────┴──────────╯
```

# Tests + Formatting
Done

# After Submitting
NaN
2024-01-21 23:22:25 +08:00
64f34e0287 allow math avg to work with durations (#11598)
# Description

I ran into a problem where one of our benchmark tests in nu_scripts
wouldn't work because math avg wouldn't work with durations, so I made
these changes to support it. I'm confident that there are other math
commands that probably need this "fix".

Side note - we should really fix our inout_output_type system.

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-21 08:41:23 -06:00
6edf91dcae Allow string to copmpare with another string (#11590)
# Description

Nushell parser now reject comparison operator with 2 strings (e.g.
`"abc" < "cba"`). This pr fixes it.

## before

```nu
~
❯ "abc" < "bca"
Error: nu::parser::unsupported_operation

  × less-than comparison is not supported on values of type string
   ╭─[entry #43:1:1]
 1 │ "abc" < "bca"
   · ──┬── ┬
   ·   │   ╰── doesn't support this value
   ·   ╰── string
   ╰────


~
❯ def foo []: nothing -> string { "abc" }

~
❯ (foo) < "bca"
Error: nu::parser::unsupported_operation

  × less-than comparison is not supported on values of type string
   ╭─[entry #53:1:1]
 1 │ (foo) < "bca"
   · ──┬── ┬
   ·   │   ╰── doesn't support this value
   ·   ╰── string
   ╰────
```

## after

```nu
~
❯ "abc" < "bca"
true

~
❯ def foo []: nothing -> string { "abc" }

~
❯ (foo) < "bca"
true
```

# User-Facing Changes

Following pattern will be allowed.

| operator | type of lhs | type of rhs | result |
| -------- | ----------- | ----------- | ------ |
| `<`      | string      | string      | bool   |
| `<=`     | string      | string      | bool   |
| `>`      | string      | string      | bool   |
| `>=`     | string      | string      | bool   |

# Tests + Formatting

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

# After Submitting
2024-01-21 07:43:40 -06:00
bc872a1a2a update Cargo.lock with the latest reedline (#11594)
This updates the Cargo.lock file for reedline which will enable testing
of this Reedline PR

https://github.com/nushell/reedline/pull/653
2024-01-20 19:53:24 -08:00
ea1bd9f8f9 IDE style completion (#11593)
<!--
if this PR closes one or more issues, you can automatically link the PR
with
them by using one of the [*linking
keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword),
e.g.
- this PR should close #xxxx
- fixes #xxxx

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

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

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

Adds an IDE-Style completion menu

![grafik](https://github.com/nushell/nushell/assets/104733404/df7f1039-2bbc-42f7-9501-fe28507b5cfe)

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-20 18:14:02 -06:00
4458aae3d4 update reedline (#11589)
update to support the latest reedline changes from
https://github.com/nushell/reedline/pull/696
2024-01-20 08:39:20 -06:00
e7a4af14cd Add shift + navigation functionality through reedline (#11535)
This PR should close #1171

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

Description of your pull request goes here. **Provide examples and/or
screenshots** if your changes affect the user experience.
-->
This PR introduces the capability to select text using the existing
move.. `EditCommand`s of `reedline`. Those commands are extended with an
optional parameter specifying if text should be selected while
navigating. This enables a workflow familiar from a wide variety of text
editors, where holding `shift` while navigating selects all text between
the initial cursor position when pressing `shift` and the current cursor
position.

Before this PR can be merged the [sibling PR for
reedline](https://github.com/nushell/reedline/pull/689) has to land
first.

# User-Facing Changes
## Additional `EditCommand`s
1. `SelectAll`
2. `CutSelection`
3. `CopySelection`
## New optional parameter on existing `EditCommand`s
All `EditCommand`s of `EditType` `MoveCursor` have a new optional
parameter named `select` of type `bool`. If this parameter is not set by
a user it is treated as false, which corresponds to their behavior up to
now.

I am relatively new to `nushell` and as such may not know of existing
behavior that might change through this PR. However, I believe there
should be none. I come to this conclusion because
1. Existing commands are extended only with an *optional* additional
parameter, users who currently use these EditCommands keep their
existing behavior if they don't use it.
2. A few new commands are introduced which were previously not valid.
3. The default keybindings specified in `default_config.nu` are
untouched.

# Tests + Formatting
Tests for the new optional parameter for the move commands are included
to make sure that they truly are optional and an unused optional
parameter conforms to the previous behavior.
2024-01-20 08:04:06 -06:00
90095c72f6 Bump h2 from 0.3.22 to 0.3.24 (#11579)
Bumps [h2](https://github.com/hyperium/h2) from 0.3.22 to 0.3.24.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/hyperium/h2/releases">h2's
releases</a>.</em></p>
<blockquote>
<h2>v0.3.24</h2>
<h2>Fixed</h2>
<ul>
<li>Limit error resets for misbehaving connections.</li>
</ul>
<h2>v0.3.23</h2>
<h2>What's Changed</h2>
<ul>
<li>cherry-pick fix: streams awaiting capacity lockout in <a
href="https://redirect.github.com/hyperium/h2/pull/734">hyperium/h2#734</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/hyperium/h2/blob/v0.3.24/CHANGELOG.md">h2's
changelog</a>.</em></p>
<blockquote>
<h1>0.3.24 (January 17, 2024)</h1>
<ul>
<li>Limit error resets for misbehaving connections.</li>
</ul>
<h1>0.3.23 (January 10, 2024)</h1>
<ul>
<li>Backport fix from 0.4.1 for stream capacity assignment.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="7243ab5854"><code>7243ab5</code></a>
Prepare v0.3.24</li>
<li><a
href="d919cd6fd8"><code>d919cd6</code></a>
streams: limit error resets for misbehaving connections</li>
<li><a
href="a7eb14a487"><code>a7eb14a</code></a>
v0.3.23</li>
<li><a
href="b668c7fbe2"><code>b668c7f</code></a>
fix: streams awaiting capacity lockout (<a
href="https://redirect.github.com/hyperium/h2/issues/730">#730</a>) (<a
href="https://redirect.github.com/hyperium/h2/issues/734">#734</a>)</li>
<li>See full diff in <a
href="https://github.com/hyperium/h2/compare/v0.3.22...v0.3.24">compare
view</a></li>
</ul>
</details>
<br />


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

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

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

---

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

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

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-20 04:27:24 +08:00
f12f590d82 update deps calamine and quick-xml (#11582)
# Description

This PR updates a few outdated dependencies.

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-19 12:23:51 -06:00
c8f30fa3bf Fix parsing of strings with special characters (#11030)
<!--
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.
-->
If there were brackets in a string argument of a script it was always
interpreted as interpolation before the change. That lead to unexpected
outputs of such scripts. After this change arguments which are not
intended as interpolation (not starting with $) and containing brackets
will have implicitly added backticks for correct interpretation in the
scripts. This fixes #10908.

To fix other issues mentioned in #11035 I changed the deparsing logic.
Initially we added backticks for multi word variables and double quote
if there was \ or " in the string. My change would add double quotes any
time string starts with $ or contains any of character that might break
parsing. The characters I identified are white space, (, ', `, ",and \.
It's possible other characters should be added to this list.

I tested this solution with few simple scripts using both stand alone
arguments and flags and it seems to work but I would appreciate if
someone with more experience checked it with some more unusual cases I
missed.

# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->
Erroneous behaviour described  in the issue will no longer happen.

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-19 10:20:14 -06:00
ff290a5c3d Add self-closed tag support for to xml (#11577)
# Description
This PR closes #11524
Add `to xml --self-closed` flag to output empty tags as self close.
For example:

![image](https://github.com/nushell/nushell/assets/17511668/bdf040f7-8ac1-4e8b-80bb-0043d7cec7f9)


# User-Facing Changes
New `to xml` flag `--self-closed`.

# Tests + Formatting
Added new example for `to xml` command and new test for self-closed
tags.
2024-01-19 05:35:29 -06:00
56067da39c Send only absolute paths to uu_mv (#11576)
# Description
Fixes: #11127 

It's something similar to #11080, applying the same logic to `uu_mv`.

# User-Facing Changes

# After Submitting
2024-01-19 05:34:18 -06:00
5d63f47c85 Replace htmlescape with v_htmlescape (#11572)
# Description

`htmlescape` is unmaintained: https://crates.io/crates/htmlescape

while `v_htmlescape` is: https://crates.io/crates/v_htmlescape

and is used by two popular crates (`actix-files` and `minijinja`)

Let's use this instead - I'm packaging `nu` in Fedora and there is
understandable reluctance in bringing in an unmaintained crate if we can
avoid it.

# User-Facing Changes
Should not be any; drop-in replacement

# Tests + Formatting
Tested using:
- `cargo build` in the root folder (needed by some `nu-command` tests)
- `cargo test --features sqlite` in `crates/nu-command`
(`tests/commands/database/into_sqlite.rs` needs `rusqlite`)
- `cargo test` in `crates/nu-cmd-extra`

# 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.
-->
N/A

Signed-off-by: Michel Lind <salimma@fedoraproject.org>
2024-01-18 12:58:35 -06:00
ee6547dbb7 Initial implementation of umv from uutils (#10822)
<!--
if this PR closes one or more issues, you can automatically link the PR
with
them by using one of the [*linking
keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword),
e.g.
- this PR should close #xxxx
- fixes #xxxx

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

# Description
Hi,
This closes #10446 , wherein we start implementing `mv` from `uutils`.
There are some stuff to iron out, particularly
* Decide on behavior from ignored tests 
* Wait for release/PRs to be approved on `uutils` side, but still can be
tested for now. See [PR
approved](https://github.com/uutils/coreutils/pull/5428), and
[pending](https://github.com/uutils/coreutils/pull/5429).
* `--progress` does not seem to work on `uutils mv` either and have not
checked whether certain `X` size has to be achieved in order for it to
appear, thus something to investigate as well, but thought it wasnt
important enough to not make the PR.

See [issue
comment](https://github.com/nushell/nushell/issues/10446#issuecomment-1764497988),
on the possible strategy to follow, mainly copy what we did with `ucp`.

I still left some comments on purpose particularly on tests, which of
course would be removed before something is decided here. :) @fdncred
<!--
Thank you for improving Nushell. Please, check our [contributing
guide](../CONTRIBUTING.md) and talk to the core team before making major
changes.

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

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

# Tests + Formatting

Don't forget to add tests that cover your changes.

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-18 10:20:57 -06:00
19e76332fa fix: items doesn't support lazy records (#11567)
<!--
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.
-->
Implement support for lazy records for `items`, the same way `columns`
or `values` do.

# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->
Something like `sys | items {|k,v| $"($k): ($v)"}` used to fail with an
error. Now it works as expected.
# Tests + Formatting
<!--
Don't forget to add tests that cover your changes.

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-18 07:57:21 -06:00
55bf4d847f Add CLI flag to disable history (#11550)
# Description
Adds a CLI flag for nushell that disables reading and writing to the
history file. This will be useful for future testing and possibly our
users as well. To borrow `fish` shell's terminology, this allows users
to start nushell in "private" mode.

# User-Facing Changes
Breaking API change for `nu-protocol` (changed `Config`).
2024-01-17 09:40:59 -06:00
a4199ea312 Fix tarpaulin skip attribute to latest (#11552)
<!--
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
Updated the attribute as per the latest version of
[tarpaulin](https://github.com/xd009642/tarpaulin) to fix compilation
error when used as library with latest tarpaulin.

https://github.com/xd009642/tarpaulin/tree/develop?tab=readme-ov-file#ignoring-code-in-files

# User-Facing Changes
None

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-17 07:26:34 -06:00
afb7e1cf66 Allow tables and records as input to math commands (#11496)
# Description
The math functions `avg`, `max`, `median`, `min`, `product`, `stddev`,
`sum` and `variance` all takes a list as input and return a number.
<https://github.com/nushell/nushell/blob/main/crates/nu-command/src/math/utils.rs>
contains code that makes these functions work for tables (by running the
function on each column), but this functionality has not been accessible
because the input types are too strict. This PR remedies this.

The functions should also work on records, since a record is basically a
one-row table.

Most of these functions also make sense for durations and file sizes,
except `product` of course. There's an implementation issue with
`stddev` and `variance` for durations and file sizes, but they could in
principle support it.

# User-Facing Changes
This PR only adds supported types, and doesn't remove any, so there
should be no breaking changes.
2024-01-17 06:39:50 -06:00
61d5aed0a2 Fix deprecation in default_config.nu (#11547)
# Description
in https://github.com/nushell/nushell/pull/11289, spreading lists into
command invocations was made possible and its implicit version was
deprecated, but not everything was updated accordingly.

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


# After Submitting
After https://github.com/nushell/nushell/pull/11289, the mention of
carapace in the documentation wasn’t updated. See
https://github.com/nushell/nushell.github.io/pull/1211
2024-01-16 06:42:17 -06:00
41a7c351cb Bump zerocopy from 0.7.29 to 0.7.32 (#11545)
Bumps [zerocopy](https://github.com/google/zerocopy) from 0.7.29 to
0.7.32.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/google/zerocopy/releases">zerocopy's
releases</a>.</em></p>
<blockquote>
<h2>v0.7.32</h2>
<h2>What's Changed</h2>
<ul>
<li>[derive] Exclude large test files when publishing by <a
href="https://github.com/joshlf"><code>@​joshlf</code></a> in <a
href="https://redirect.github.com/google/zerocopy/pull/744">google/zerocopy#744</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/google/zerocopy/compare/v0.7.31...v0.7.32">https://github.com/google/zerocopy/compare/v0.7.31...v0.7.32</a></p>
<h2>v0.7.31</h2>
<p>This release fixes the soundness issue described in <a
href="https://redirect.github.com/google/zerocopy/issues/716">#716</a>.
The affected versions will soon be yanked.</p>
<p>This release is also described in security advisories <a
href="https://rustsec.org/advisories/RUSTSEC-2023-0074.html">RUSTSEC-2023-0074</a>
and <a
href="https://github.com/google/zerocopy/security/advisories/GHSA-3mv5-343c-w2qg">GHSA-3mv5-343c-w2qg</a>.</p>
<h2>What's Changed</h2>
<ul>
<li>Fix soundness hole in Ref::into_ref and into_mut by <a
href="https://github.com/joshlf"><code>@​joshlf</code></a> in <a
href="https://redirect.github.com/google/zerocopy/pull/721">google/zerocopy#721</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/google/zerocopy/compare/v0.7.30...v0.7.31">https://github.com/google/zerocopy/compare/v0.7.30...v0.7.31</a></p>
<h2>v0.7.30</h2>
<h2>What's Changed</h2>
<ul>
<li>[policies] Document yanking policy by <a
href="https://github.com/joshlf"><code>@​joshlf</code></a> in <a
href="https://redirect.github.com/google/zerocopy/pull/677">google/zerocopy#677</a></li>
<li>[ci] Roll pinned nightly toolchain by <a
href="https://github.com/google-pr-creation-bot"><code>@​google-pr-creation-bot</code></a>
in <a
href="https://redirect.github.com/google/zerocopy/pull/680">google/zerocopy#680</a></li>
<li>[readme] Link to GitHub Releases (<a
href="https://redirect.github.com/google/zerocopy/issues/692">#692</a>)
by <a href="https://github.com/joshlf"><code>@​joshlf</code></a> in <a
href="https://redirect.github.com/google/zerocopy/pull/693">google/zerocopy#693</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/google/zerocopy/compare/v0.7.29...v0.7.30">https://github.com/google/zerocopy/compare/v0.7.29...v0.7.30</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="94b7e0a44d"><code>94b7e0a</code></a>
[derive] Exclude large test files when publishing (<a
href="https://redirect.github.com/google/zerocopy/issues/744">#744</a>)</li>
<li><a
href="7d3a8f9ea6"><code>7d3a8f9</code></a>
Fix soundness hole in Ref::into_ref and into_mut (<a
href="https://redirect.github.com/google/zerocopy/issues/721">#721</a>)</li>
<li><a
href="961612f110"><code>961612f</code></a>
[readme] Link to GitHub Releases (<a
href="https://redirect.github.com/google/zerocopy/issues/692">#692</a>)
(<a
href="https://redirect.github.com/google/zerocopy/issues/693">#693</a>)</li>
<li><a
href="449b78c67f"><code>449b78c</code></a>
[ci] Roll pinned nightly toolchain (<a
href="https://redirect.github.com/google/zerocopy/issues/680">#680</a>)</li>
<li><a
href="8f7d88b90e"><code>8f7d88b</code></a>
[policies] Document yanking policy (<a
href="https://redirect.github.com/google/zerocopy/issues/677">#677</a>)</li>
<li>See full diff in <a
href="https://github.com/google/zerocopy/compare/v0.7.29...v0.7.32">compare
view</a></li>
</ul>
</details>
<br />


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

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

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

---

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

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

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-16 14:30:22 +08:00
7ac3e97bfe Fix memory consumption of into sqlite (#10232)
# Description

Currently, the `into sqlite` command collects the entire input stream
into a single Value, which soaks up the entire input into memory, before
it ever tries to write anything to the DB. This is very problematic for
large inputs; for example, I tried transforming a multi-gigabyte CSV
file into SQLite, and before I knew what was happening, my system's
memory was completely exhausted, and I had to hard reboot to recover.

This PR fixes this problem by working directly with the pipeline stream,
inserting into the DB as values are read from the stream.

In order to facilitate working with the stream directly, I introduced a
new `Table` struct to store the connection and a few configuration
parameters, as well as to make it easier to lazily create the table on
the first read value.

In addition to the purely functional fixes, a few other changes were
made to the serialization and user facing behavior.

### Serialization

Much of the preexisting code was focused on generating the exact text
needed for a SQL statement. This is unneeded and less safe than using
the `rusqlite` crate's serialization for native Rust types along with
prepared statements.

### User-Facing Changes

Currently, the command is very liberal in the input types it accepts.
The strategy is basically if it is a record, try to follow its structure
and make an analogous SQL row, which is pretty reasonable. However, when
it's not a record, it basically tries to guess what the user wanted and
just makes a single column table and serializes the value into that one
column, whatever type it may be.

This has been changed so that it only accepts records as input. If the
user wants to serialize non-record types into SQL, then they must
explicitly opt into doing this by constructing a record or table with it
first. For a utility for inserting data into SQL, I think it makes more
sense to let the user choose how to convert their data, rather than make
a choice for them that may surprise them.

However, I understand this may be a controversial change. If the
maintainers don't agree, I can change this back.

#### Long switch names

The `file_name` and `table_name` long form switches are currently
snake_case and expect to be as such at the command line. These have been
changed to kebab-case to be more conventional.

# Tests + Formatting

To test the memory consumption, I used [this publicly available index of
all Wikipedia articles](https://dumps.wikimedia.org/enwiki/20230820/),
using the first 10,000, 100,000, and 1,000,000 entries, in that order. I
ran the following script to benchmark the changes against the current
stable release:

```nu
#!/usr/bin/nu

# let shellbin = $"($env.HOME)/src/nushell/target/aarch64-linux-android/release/nu"
let shellbin = "nu"
const dbpath = 'enwiki-index.db'

[10000, 100000, 1000000]
  | each {|rows|
      rm -f $dbpath;
      do { time -f '%M %e %U %S' $shellbin -c (
        $"bzip2 -cdk ~/enwiki-20230820-pages-articles-multistream-index.txt.bz2
            | head -n ($rows)
            | lines
            | parse '{offset}:{id}:{title}'
            | update cells -c [offset, id] { into int }
            | into sqlite ($dbpath)"
        )
      }
      | complete
      | get stderr
      | str trim
      | parse '{rss_max} {real} {user} {kernel}'
      | update cells -c [rss_max] { $"($in)kb" | into filesize }
      | update cells -c [real, user, kernel] { $"($in)sec" | into duration }
      | insert rows $rows
      | roll right
    }
  | flatten
  | to nuon
```

This yields the following results

Current stable release:

|rows|rss_max|real|user|kernel|
|-|-|-|-|-|
|10000|53.6 MiB|770ms|460ms|420ms|
|100000|209.6 MiB|6sec 940ms|3sec 740ms|4sec 380ms|
|1000000|1.7 GiB|1min 8sec 810ms|38sec 690ms|42sec 550ms|

This PR:

|rows|rss_max|real|user|kernel|
|-|-|-|-|-|
|10000|38.2 MiB|780ms|440ms|410ms|
|100000|39.8 MiB|6sec 450ms|3sec 530ms|4sec 160ms|
|1000000|39.8 MiB|1min 3sec 230ms|37sec 440ms|40sec 180ms|

# Note

I started this branch kind of at the same time as my others, but I
understand the feedback that smaller PRs are preferred. Let me know if
it would be better to split this up.

I do think the scope of the changes are on the bigger side even without
the behavior changes I mentioned, so I'm not sure if that will help this
particular PR very much, but I'm happy to oblige on request.
2024-01-15 21:41:25 -06:00
924986576d Do not block signals for child processes (#11402)
# Description / User-Facing Changes
Signals are no longer blocked for child processes launched from both
interactive and non-interactive mode. The only exception is that
`SIGTSTP`, `SIGTTIN`, and `SIGTTOU` remain blocked for child processes
launched only from **interactive** mode. This is to help prevent nushell
from getting into an unrecoverable state, since we don't support
background jobs. Anyways, this fully fixes #9026.

# Other Notes
- Needs Rust version `>= 1.66` for a fix in
`std::process::Command::spawn`, but it looks our current Rust version is
way above this.
- Uses `sigaction` instead of `signal`, since the behavior of `signal`
can apparently differ across systems. Also, the `sigaction` man page
says:
> The sigaction() function supersedes the signal() function, and should
be used in preference.

Additionally, using both `sigaction` and `signal` is not recommended.
Since we were already using `sigaction` in some places (and possibly
some of our dependencies as well), this PR replaces all usages of
`signal`.

# Tests
Might want to wait for #11178 for testing.
2024-01-15 16:08:21 -06:00
7071617f18 Allow plugins to receive configuration from the nushell configuration (#10955)
# Description

When nushell calls a plugin it now sends a configuration `Value` from
the nushell config under `$env.config.plugins.PLUGIN_SHORT_NAME`. This
allows plugin authors to read configuration provided by plugin users.

The `PLUGIN_SHORT_NAME` must match the registered filename after
`nu_plugin_`. If you register `target/debug/nu_plugin_config` the
`PLUGIN_NAME` will be `config` and the nushell config will loook like:

        $env.config = {
          # ...
          plugins: {
            config: [
              some
              values
            ]
          }
        }

Configuration may also use a closure which allows passing values from
`$env` to a plugin:

        $env.config = {
          # ...
          plugins: {
            config: {||
              $env.some_value
            }
          }
        }

This is a breaking change for the plugin API as the `Plugin::run()`
function now accepts a new configuration argument which is an
`&Option<Value>`. If no configuration was supplied the value is `None`.

Plugins compiled after this change should work with older nushell, and
will behave as if the configuration was not set.

Initially discussed in #10867

# User-Facing Changes

* Plugins can read configuration data stored in `$env.config.plugins`
* The plugin `CallInfo` now includes a `config` entry, existing plugins
will require updates

# Tests + Formatting

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

# After Submitting

- [ ] Update [Creating a plugin (in
Rust)](https://www.nushell.sh/contributor-book/plugins.html#creating-a-plugin-in-rust)
[source](https://github.com/nushell/nushell.github.io/blob/main/contributor-book/plugins.md)
- [ ] Add "Configuration" section to [Plugins
documentation](https://www.nushell.sh/contributor-book/plugins.html)
2024-01-15 16:59:47 +08:00
e72a4116ec adjust some commansd input_output type (#11436)
# Description
1. Make table to be a subtype of `list<any>`, so some input_output_types
of filter commands are unnecessary
2. Change some commands which accept an input type, but generates
different output types. In this case, delete duplicate entry, and change
relative output type to `<any>`

Yeah it makes some commands more permissive, but I think it's better to
run into strange issue that why my script runs to failed during parse
time.

Fixes  #11193

# User-Facing Changes
NaN

# Tests + Formatting
NaN

# After Submitting
NaN
2024-01-15 16:58:26 +08:00
a109283118 Apply nightly clippy fixes (#11508)
# Description

Clippy fixes

# User-Facing Changes
N/A
2024-01-15 10:52:16 +08:00
42b03917fb Bump actions-rust-lang/setup-rust-toolchain from 1.6.0 to 1.8.0 (#11539)
Bumps
[actions-rust-lang/setup-rust-toolchain](https://github.com/actions-rust-lang/setup-rust-toolchain)
from 1.6.0 to 1.8.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions-rust-lang/setup-rust-toolchain/releases">actions-rust-lang/setup-rust-toolchain's
releases</a>.</em></p>
<blockquote>
<h2>v1.8.0</h2>
<ul>
<li>Allow specifying subdirectories for cache.</li>
<li>Fix toolchain file overriding.</li>
</ul>
<h2>v1.7.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Allow overriding the toolchain file by <a
href="https://github.com/Twey"><code>@​Twey</code></a> in <a
href="https://redirect.github.com/actions-rust-lang/setup-rust-toolchain/pull/26">actions-rust-lang/setup-rust-toolchain#26</a></li>
<li>ci: update checked rust-toolchain version by <a
href="https://github.com/robjtede"><code>@​robjtede</code></a> in <a
href="https://redirect.github.com/actions-rust-lang/setup-rust-toolchain/pull/29">actions-rust-lang/setup-rust-toolchain#29</a></li>
<li>Prepare 1.7.0 release by <a
href="https://github.com/robjtede"><code>@​robjtede</code></a> in <a
href="https://redirect.github.com/actions-rust-lang/setup-rust-toolchain/pull/30">actions-rust-lang/setup-rust-toolchain#30</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/Twey"><code>@​Twey</code></a> made their
first contribution in <a
href="https://redirect.github.com/actions-rust-lang/setup-rust-toolchain/pull/26">actions-rust-lang/setup-rust-toolchain#26</a></li>
<li><a href="https://github.com/robjtede"><code>@​robjtede</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions-rust-lang/setup-rust-toolchain/pull/29">actions-rust-lang/setup-rust-toolchain#29</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions-rust-lang/setup-rust-toolchain/compare/v1.6...v1.7.0">https://github.com/actions-rust-lang/setup-rust-toolchain/compare/v1.6...v1.7.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions-rust-lang/setup-rust-toolchain/blob/main/CHANGELOG.md">actions-rust-lang/setup-rust-toolchain's
changelog</a>.</em></p>
<blockquote>
<h2>[1.8.0] - 2024-01-13</h2>
<ul>
<li>Allow specifying subdirectories for cache.</li>
<li>Fix toolchain file overriding.</li>
</ul>
<h2>[1.7.0] - 2024-01-11</h2>
<ul>
<li>Allow overriding the toolchain file with explicit
<code>toolchain</code> input. (<a
href="https://redirect.github.com/actions-rust-lang/setup-rust-toolchain/issues/26">#26</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="b113a30d27"><code>b113a30</code></a>
Merge pull request <a
href="https://redirect.github.com/actions-rust-lang/setup-rust-toolchain/issues/34">#34</a>
from actions-rust-lang/rel-180</li>
<li><a
href="039765bd18"><code>039765b</code></a>
chore: prepare release 1.8.0</li>
<li><a
href="84e65ce315"><code>84e65ce</code></a>
Merge pull request <a
href="https://redirect.github.com/actions-rust-lang/setup-rust-toolchain/issues/32">#32</a>
from gruebel/add-workspaces</li>
<li><a
href="6f719a240e"><code>6f719a2</code></a>
Merge branch 'main' into add-workspaces</li>
<li><a
href="15d0afaad9"><code>15d0afa</code></a>
ci: fix cache test</li>
<li><a
href="922cc935eb"><code>922cc93</code></a>
ci: add cache-workspaces test</li>
<li><a
href="bcda41b18d"><code>bcda41b</code></a>
Merge pull request <a
href="https://redirect.github.com/actions-rust-lang/setup-rust-toolchain/issues/33">#33</a>
from fprasx/fprasx/fix-toolchain-overrides</li>
<li><a
href="ba41ca6f71"><code>ba41ca6</code></a>
ci: clearer test names</li>
<li><a
href="aa089182f2"><code>aa08918</code></a>
ci: fix conditional</li>
<li><a
href="c6086ae6e5"><code>c6086ae</code></a>
test: add toolchain file override test</li>
<li>Additional commits viewable in <a
href="https://github.com/actions-rust-lang/setup-rust-toolchain/compare/v1.6.0...v1.8.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions-rust-lang/setup-rust-toolchain&package-manager=github_actions&previous-version=1.6.0&new-version=1.8.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

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

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

---

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

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


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-15 10:27:41 +08:00
12a07052f9 Bump rust-embed from 8.1.0 to 8.2.0 (#11538)
Bumps [rust-embed](https://github.com/pyros2097/rust-embed) from 8.1.0
to 8.2.0.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/pyrossh/rust-embed/blob/master/changelog.md">rust-embed's
changelog</a>.</em></p>
<blockquote>
<h2>[8.2.0] - 2023-12-29</h2>
<ul>
<li>Fix naming collisions in macros <a
href="https://redirect.github.com/pyrossh/rust-embed/pull/230/files">#230</a>.
Thanks to <a href="https://github.com/hwittenborn">hwittenborn</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/pyros2097/rust-embed/commits">compare
view</a></li>
</ul>
</details>
<br />


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

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

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

---

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

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


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-15 10:27:09 +08:00
0cd927d634 Bump crate-ci/typos from 1.17.0 to 1.17.1 (#11540)
Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.17.0 to
1.17.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/releases">crate-ci/typos's
releases</a>.</em></p>
<blockquote>
<h2>v1.17.1</h2>
<h2>[1.17.1] - 2024-01-12</h2>
<h3>Features</h3>
<ul>
<li>First attempt at aarch64 for Mac</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/blob/master/CHANGELOG.md">crate-ci/typos's
changelog</a>.</em></p>
<blockquote>
<h2>[1.17.1] - 2024-01-12</h2>
<h3>Features</h3>
<ul>
<li>First attempt at aarch64 for Mac</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="a35b382b44"><code>a35b382</code></a>
chore: Release</li>
<li><a
href="4c32fc5ec4"><code>4c32fc5</code></a>
docs: Update changelog</li>
<li><a
href="b02f5895d3"><code>b02f589</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/908">#908</a>
from epage/ci</li>
<li><a
href="7b12730b18"><code>7b12730</code></a>
chore(ci): Build for aarch64</li>
<li><a
href="5adfdc2ade"><code>5adfdc2</code></a>
chore(ci): Show what gets bundled</li>
<li><a
href="657d1b1764"><code>657d1b1</code></a>
chore(ci): Remove use of undefined variable</li>
<li><a
href="a7762787d8"><code>a776278</code></a>
chore(ci): Ensure rustfmt is available</li>
<li>See full diff in <a
href="https://github.com/crate-ci/typos/compare/v1.17.0...v1.17.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=crate-ci/typos&package-manager=github_actions&previous-version=1.17.0&new-version=1.17.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

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

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

---

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

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


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-15 10:26:31 +08:00
e4c2c123ab Support for disabling automatic escaping in to xml (#11536)
# Description
This PR addresses #11525 by adding `--partial-escape` which makes `to
xml` only escape `<>&` in text and `<>&"` in comments. This PR also
fixes issue where comment and PI content was escaped even though [it
should not be](https://stackoverflow.com/a/46637835)

# User-Facing Changes
Correct comments and PIs
 `to xml --partial-escape` flag to emit less escaped characters

# Tests + Formatting
Added tests for specified issues
2024-01-14 07:36:53 -06:00
d25be66929 check existance w/o traversing symlinks (#10872)
# Description

Currently `path exists` checks the file/folder's existence by traversing
symlinks. I've added a `-n` switch/flag that disables symlink
traversing, similar to what `path expand -n` does.

## The Long Story (for those interested)

Hello! 👋 While working on one of my scripts, I discovered that the `path
exists` command was traversing symlinks. This meant that even if the
file existed, it would fail if the pointed location didn't exist. To
address this, I've introduced a new `-n` flag, which I borrowed from the
`path expand` command. This addition should make the behavior more
consistent within the *path commands universe*.

## But, is it any useful?
 
```nushell
let compat = /run/media/userX/DriveX/steam/steamapps/compatdata
if "symlink" == ($compat | path expand -n | path type) {}
# to this
if ($compat | path exists -n) {}
```

# User-Facing Changes

Users, will not efect. Unless they use the mentioned `-n` flag/switch.
2024-01-14 07:33:33 +08:00
6eb6086823 Show last command and running commands in title with shell_integration (#11532)
Closes #10260

I'm not 100% convinced about the star thing for running commands because
on short commands it makes the title jitter.

Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
2024-01-12 21:32:25 -06:00
e88a531945 Fix commandline --cursor-end (#11504)
<!--
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.
-->
In `commandline --cursor-end`, set `repl.cursor_pos` to the number of
bytes in the buffer, not the number of graphemes.

fixes: #11503

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-13 08:24:14 +08:00
a093e66822 update query web param --as-table from Table to List (#11531)
# Description

This is a small change that updates the `--as-table`/`-t` parameter to
`SyntaxShape::List` instead of `SyntaxShape::Table`. It was always
supposed to be a list of headers. Not sure where Table came from.

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-12 13:26:40 -06:00
387c5462e9 Add file attribute handling flag to cp (#11491)
# Description
This PR adds possibility to preserve/strip attributes from files when
using `cp` (via uu_cp::Attributes). To achieve this a single `--preserve
<list of attributes>` flag is added. This is different from how
coreutils and uutils cp function, but I believe this is better for
nushell.

Coreutils cp has three options `-p`, `--preserve` and `--no-presevce`.
The logic of these two options is not straightforward. As far as I
understand it is:
1. By default only mode attributes are preserved
2. `--preserve` option adds to default preserved attributes specified
ones (e.g. `--preserve=xattr,timestamps` will preserve mode, timestamps
and xattr)
3. `-p` is the same as `--preserve=mode,ownership,timestamps`
4. `--no-preserve` option rejects specified attributes (having priority
over `--preserve`)

However (in my opinion) the `--no-preserve` option is not needed,
because its only use seems to be rejecting attributes preserved by
default. But there is no need for this in nushell, because `--preserve`
can be specified with empty list as argument (whereas coreutils cp will
display a `cp: ambiguous argument ‘’ for ‘--preserve’` error if
`--preserve` is used with empty string as argument).

So to simplify this command is suggest (and implemented) only the
`--preserve` with the following logic:
1. By default mode attribute is preserved (as in coreutils cp)
2. `--preserve [ ... ]` will overwrite default with whatever is
specified in list (empty list meaning preserve nothing)

This way cp without `--preserve` behaves the same as coreutils `cp`, but
instead of using combinations of `--preserve` and `--no-preserve` one
needs to use `--preserve [ ... ]` with all attributes specified
explicitly. This seems more user-friendly to me as it does not require
remembering what the attributes preserved by default are and rejecting
them manually. However I see the possible problem with behavior
different from coreutils implementation, so some feedback is
apprecieated!

# User-Facing Changes
Users can now preserve or reject file attributes when using `cp`

# Tests + Formatting
Added tests manipulating mode and timestamps attributes.
2024-01-12 12:02:55 -06:00
724818030d add type check during eval time (#11475)
# Description
Fixes: #11438 

Take the following as example:
```nushell
def spam [foo: string] {
    $'foo: ($foo | describe)'
}
def outer [--foo: string] {
    spam $foo
}

outer
```
When we call `outer`, type checker only check the all for `outer`, but
doesn't check inside the body of `outer`. This pr is trying to introduce
a type checking process through `Type::is_subtype()` during eval time.

## NOTE
I'm not really sure if it's easy to make a check inside the body of
`outer`. Adding an eval time type checker seems like an easier solution.
As a result: `outer` will be caught by runtime, not parse time type
checker

cc @kubouch 

# User-Facing Changes
After this pr the following call will failed:
```nushell
> outer
Error: nu:🐚:cant_convert

  × Can't convert to string.
   ╭─[entry #27:1:1]
 1 │ def outer [--foo: any] {
 2 │     spam $foo
   ·          ──┬─
   ·            ╰── can't convert nothing to string
 3 │ }
   ╰────
```

# Tests + Formatting
Done

# After Submitting
NaN
2024-01-12 23:48:53 +08:00
8cad12a05c update nushell to latest reedline main after pr revert (#11528)
# Description

This PR updates nushell to the latest reedline main branch after a
reedline PR was reverted.

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-11 15:58:54 -06:00
41119d3f88 Fix "Char index out of bounds" Error (#11526)
# Description

The code that converts Nushell's span into LSP line and character
indices accidentally treated the span as character indices while they
are byte indices. Fixes #11522.

# User-Facing Changes

None, just a bugfix.
2024-01-11 15:24:49 -06:00
0ebbc8f71c Make only_buffer_difference: true work (#11488) 2024-01-11 11:58:14 -06:00
bd07f7b302 bump to reedline latest main (#11520)
# Description

Bump to latest reedline main in order to dogfood latest reedline
changes.

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-11 10:04:54 -06:00
1867bb1a88 Fix incorrect handling of boolean flags for builtin commands (#11492)
# Description
Possible fix of #11456
This PR fixes a bug where builtin commands did not respect the logic of
dynamically passed boolean flags. The reason is
[has_flag](6f59abaf43/crates/nu-protocol/src/ast/call.rs (L204C5-L212C6))
method did not evaluate and take into consideration expression used with
flag.

To address this issue a solution is proposed:
1. `has_flag` method is moved to `CallExt` and new logic to evaluate
expression and check if it is a boolean value is added
2. `has_flag_const` method is added to `CallExt` which is a constant
version of `has_flag`
3. `has_named` method is added to `Call` which is basically the old
logic of `has_flag`
4. All usages of `has_flag` in code are updated, mostly to pass
`engine_state` and `stack` to new `has_flag`. In `run_const` commands it
is replaced with `has_flag_const`. And in a few select places: parser,
`to nuon` and `into string` old logic via `has_named` is used.

# User-Facing Changes
Explicit values of boolean flags are now respected in builtin commands.
Before:

![image](https://github.com/nushell/nushell/assets/17511668/f9fbabb2-3cfd-43f9-ba9e-ece76d80043c)
After:

![image](https://github.com/nushell/nushell/assets/17511668/21867596-2075-437f-9c85-45563ac70083)

Another example:
Before:

![image](https://github.com/nushell/nushell/assets/17511668/efdbc5ca-5227-45a4-ac5b-532cdc2bbf5f)
After:

![image](https://github.com/nushell/nushell/assets/17511668/2907d5c5-aa93-404d-af1c-21cdc3d44646)


# Tests + Formatting
Added test reproducing some variants of original issue.
2024-01-11 17:19:48 +02:00
62272975f2 path exists: Empty path shouldn't be marked as exists (#11515)
<!--
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.
-->

Simply, `""` doesn't exist. 

It's easy to test the truthfulness of this:

```rust
fn main() {
    println!("{}", std::path::Path::new("").exists());
}
```
gives `false`

# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->
Technically this is a breaking change, so:
- **breaking:** `path exists` no longer considers an empty path (`""`)
as exists

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-11 07:19:34 +08:00
7bb9ee55c4 Bump to dev version 0.89.1 (#11513)
<!--
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` to
check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-11 00:19:21 +13:00
2c1560e281 Bump version for 0.89.0 release (#11511)
<!--
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!
-->

- [x] reedline
  - [x] released
  - [x] pinned
- [ ] git dependency check
- [ ] release notes


# 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` to
check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-09 22:16:29 +02:00
d5206cbd68 Pin reedline to 0.28 release (#11510)
<!--
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!
-->

See full release notes:
[nushell/reedline@v0.28.0
(release)](https://github.com/nushell/reedline/releases/tag/v0.28.0)

# 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` to
check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-09 21:42:44 +02:00
c74cff213e remove std clip (#11131)
follow up to
- https://github.com/nushell/nushell/pull/11097

related to
- https://github.com/nushell/nu_scripts/pull/674

> **Important**
> wait for in between Nushell 0.88.0 and 0.89.0

# Description
this PR removes the `std clip` command after it's been deprecated in
https://github.com/nushell/nushell/pull/11097 😋

# User-Facing Changes
`std clip` will no longer be available.

# Tests + Formatting

# After Submitting
2024-01-08 21:46:10 +02:00
2ea5819b02 Bump crate-ci/typos from 1.16.26 to 1.17.0
Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.16.26 to 1.17.0.
- [Release notes](https://github.com/crate-ci/typos/releases)
- [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crate-ci/typos/compare/v1.16.26...v1.17.0)

---
updated-dependencies:
- dependency-name: crate-ci/typos
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-08 01:17:04 +00:00
1115190a49 Bump shadow-rs from 0.25.0 to 0.26.0
Bumps [shadow-rs](https://github.com/baoyachi/shadow-rs) from 0.25.0 to 0.26.0.
- [Release notes](https://github.com/baoyachi/shadow-rs/releases)
- [Changelog](https://github.com/baoyachi/shadow-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/baoyachi/shadow-rs/compare/v0.25.0...v0.26.0)

---
updated-dependencies:
- dependency-name: shadow-rs
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-08 01:06:59 +00:00
7132c5ad02 add wheres 2024-01-07 19:04:04 -06:00
1920ece759 fix: closure captures can also be constants (#11493)
<!--
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.
-->
When evaluating a closure (in
`EvalRuntime::eval_row_condition_or_closure()`), we try to resolve the
closure's block's captures, but we only check if they're variables on
the stack. We need to also check if they are constants (see the logic in
`Stack::gather_captures()`).

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2024-01-07 12:51:39 +02:00
6f59abaf43 update reedline version to latest main (#11490)
# Description
Update reedline version to fix
https://github.com/nushell/nushell/issues/11399
2024-01-05 17:19:43 -06:00
5f7425a7b4 Xml errors fix (#11487)
# Description
Fixes #11264
This PR adds checks in `to xml` to output error for malformed xml
entries:
* With columns that are not one of `tag`, `attributes` or `content`
* With no `tag` when entry is not a string
* With `tag` that is not a string
This PR also replaces `attrs` with `attributes` in example and
extra_usage of `to xml` (column was originally named attrs and renamed
to attributes, but this was missed in docs)

# User-Facing Changes
`to xml` will produce error for conditions described above instead of
silently returning nothing

# Tests + Formatting
Added tests for `to xml` to check handling of malformed xml entries
2024-01-05 15:56:13 -06:00
1ab9ec3ebc Bump terminal_size to 0.3 (#11486)
# Description
Simplify the dependencies. There are two different versions of
`terminal_size` that nushell directly depends on.

Related: #8060
2024-01-05 10:19:46 -06:00
f2095ed0cc Fix cross building for target x86_64-pc-windows-gnu on linux (#11485)
# Description

Cross build for target `x86_64-pc-windows-gnu` fails on linux.

```console
nushell on  main [?] is 📦 v0.88.2 via 🦀 v1.77.0-nightly
❯ cargo build --target x86_64-pc-windows-gnu -p nu-system
   Compiling nu-system v0.88.2 (/data/source/nushell/crates/nu-system)
error[E0432]: unresolved import `chrono::Local`
   --> crates/nu-system/src/windows.rs:5:14
    |
5   | use chrono::{Local, NaiveDate};
    |              ^^^^^ no `Local` in the root
    |
note: found an item that was configured out
   --> /path/to/home/.cargo/registry/src/rsproxy.cn-0dccff568467c15b/chrono-0.4.31/src/lib.rs:537:17
    |
537 | pub use offset::Local;
    |                 ^^^^^
    = note: the item is gated behind the `clock` feature

error[E0412]: cannot find type `Local` in crate `chrono`
   --> crates/nu-system/src/windows.rs:68:46
    |
68  |     pub start_time: chrono::DateTime<chrono::Local>,
    |                                              ^^^^^ not found in `chrono`
    |
note: found an item that was configured out
   --> /path/to/home/.cargo/registry/src/rsproxy.cn-0dccff568467c15b/chrono-0.4.31/src/lib.rs:537:17
    |
537 | pub use offset::Local;
    |                 ^^^^^
    = note: the item is gated behind the `clock` feature

Some errors have detailed explanations: E0412, E0432.
For more information about an error, try `rustc --explain E0412`.
error: could not compile `nu-system` (lib) due to 2 previous errors
```
2024-01-05 07:31:38 -06:00
7e26b4fcc2 Bump sysinfo from 0.29 to 0.30 (#11484)
# Description
Bumps `sysinfo` to 0.30.

* Changelog
 https://github.com/GuillaumeGomez/sysinfo/blob/master/CHANGELOG.md#0304

# User-Facing Changes
N/A
2024-01-05 05:31:29 -06:00
ad95e4cc27 Refactor tests (using cococo instead of ^echo) (#11479)
- related PR: #11478 

# Description

Now we can use `nu --testbin cococo` instead of `^echo` to echo messages
to stdout in tests.

But `nu` treats parameters as its own flags when parameter starts with
`-`. So `^echo --foo='bar'` still use `^echo`.

# User-Facing Changes

(none)

# Tests + Formatting

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


# After Submitting

(none)
2024-01-05 11:40:56 +08:00
ee5a18167c Replace winapi with windows (#11481)
# Description
`winapi` is not actively maintained, use the Microsoft blessed `windows`
crate instead.

# User-Facing Changes
N/A
2024-01-04 11:17:19 -06:00
75c9e3e5df Try to fix riscv64 building by using unbuntu-latest (#11476)
Try to fix `riscv64gc-unknown-linux-gnu` building by using
`unbuntu-latest`
This PR should close https://github.com/nushell/nushell/issues/11452
The action should run without errors:
https://github.com/nushell/nightly/actions/runs/7394915358
2024-01-04 07:55:10 +08:00
77f10eb270 Fix the test which fails on windows (#11478)
- related PR: #11463

# Description

Currently, `commands::complete::basic` fails on Windows without git
bash.
This pr fixes it.

# User-Facing Changes

(none)

# Tests + Formatting

- [x] (on Windows) `cargo fmt --all -- --check` to check standard code
formatting (`cargo fmt --all` applies these changes)
- [x] (on Windows) `cargo clippy --workspace -- -D warnings -D
clippy::unwrap_used` to check that you're using the standard code style
- [x] (on Windows without git bash, Windows with git bash and Ubuntu)
`cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- on my Windows with Japanese lang pack: 1 test still fails. (see
#11463)
- [x] (on Windows and Ubuntu) `cargo run -- -c "use std testing; testing
run-tests --path crates/nu-std"` to run the tests for the standard
library

# After Submitting

(none)
2024-01-03 07:22:43 -06:00
42bb42a2e1 Fix rm for symlinks pointing to directory on windows (issue #11461) (#11463)
<!--
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 closes #11461

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

Using `std::fs::remove_dir` instead of `std::fs::remove_file` when try
remove symlinks pointing to a directory on Windows.

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

none

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

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

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

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

- [x] `cargo fmt --all -- --check` to check standard code formatting
(`cargo fmt --all` applies these changes)
- [x] `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used`
to check that you're using the standard code style
- [x] `cargo test --workspace` to check that all tests pass (on Windows
make sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- I got 2 test fails on my Windows devenv; these fails in main branch
too
- `commands::complete::basic` : passed on Ubuntu, failed on Windows (a
bug?)
- `commands::cp::copy_file_with_read_permission`: failed on Windows with
Japanese environment (This test refers error message, so that fails on
environments using a language except for english.)
- [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.
-->

This fix has no changes to user-facing interface.
2024-01-02 21:27:03 +08:00
f597380112 Bump lsp-types from 0.94.1 to 0.95.0 (#11457)
Bumps [lsp-types](https://github.com/gluon-lang/lsp-types) from 0.94.1
to 0.95.0.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/gluon-lang/lsp-types/blob/master/CHANGELOG.md">lsp-types's
changelog</a>.</em></p>
<blockquote>
<h2>v0.95.0 (2023-12-12)</h2>
<p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
<h3>v0.94.2 (2023-12-12)</h3>
<p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="ccf64e2fb6"><code>ccf64e2</code></a>
chore: Release lsp-types version 0.95.0</li>
<li><a
href="bccf50c1c6"><code>bccf50c</code></a>
Update changelog</li>
<li><a
href="75cea03884"><code>75cea03</code></a>
chore: Release lsp-types version 0.94.2</li>
<li><a
href="4084a00cd1"><code>4084a00</code></a>
Update changelog</li>
<li><a
href="b588e166be"><code>b588e16</code></a>
Merge pull request <a
href="https://redirect.github.com/gluon-lang/lsp-types/issues/274">#274</a>
from lapce/inline-completion</li>
<li><a
href="3031a76c44"><code>3031a76</code></a>
Add support for textDocument/inlineCompletion</li>
<li><a
href="038577b0b5"><code>038577b</code></a>
doc: Update readme to request links to the spec for PRs</li>
<li><a
href="f106ccb584"><code>f106ccb</code></a>
Merge pull request <a
href="https://redirect.github.com/gluon-lang/lsp-types/issues/257">#257</a>
from ahlinc/init-work-done-token</li>
<li><a
href="730924021a"><code>7309240</code></a>
Merge pull request <a
href="https://redirect.github.com/gluon-lang/lsp-types/issues/259">#259</a>
from ebkalderon/fix-telemetry-event-params</li>
<li><a
href="a15daede51"><code>a15daed</code></a>
Merge pull request <a
href="https://redirect.github.com/gluon-lang/lsp-types/issues/264">#264</a>
from tage64/master</li>
<li>Additional commits viewable in <a
href="https://github.com/gluon-lang/lsp-types/compare/v0.94.1...v0.95.0">compare
view</a></li>
</ul>
</details>
<br />


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

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

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

---

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

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


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-02 07:22:38 +08:00
b92b4120dc Bump crate-ci/typos from 1.16.25 to 1.16.26 (#11458)
Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.16.25
to 1.16.26.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/releases">crate-ci/typos's
releases</a>.</em></p>
<blockquote>
<h2>v1.16.26</h2>
<h2>[1.16.26] - 2023-12-27</h2>
<h3>Fixes</h3>
<ul>
<li>Apply <code>extend-ignore-re</code> to file names in addition to
file content</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/blob/master/CHANGELOG.md">crate-ci/typos's
changelog</a>.</em></p>
<blockquote>
<h2>[1.16.26] - 2023-12-27</h2>
<h3>Fixes</h3>
<ul>
<li>Apply <code>extend-ignore-re</code> to file names in addition to
file content</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="45a880d9f8"><code>45a880d</code></a>
chore: Release</li>
<li><a
href="1e55ede61c"><code>1e55ede</code></a>
docs: Update changelog</li>
<li><a
href="e32ec882ea"><code>e32ec88</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/886">#886</a>
from epage/olt</li>
<li><a
href="bf66cbd0b6"><code>bf66cbd</code></a>
fix(config): Apply extend-ignore-re to file names</li>
<li><a
href="a9afeef275"><code>a9afeef</code></a>
test(cli): Show extend-ignore on file names</li>
<li>See full diff in <a
href="https://github.com/crate-ci/typos/compare/v1.16.25...v1.16.26">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=crate-ci/typos&package-manager=github_actions&previous-version=1.16.25&new-version=1.16.26)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

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

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

---

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

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


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-02 07:22:19 +08:00
de5ad5de19 Revert "Return external file completions if not empty (#10898)" (#11446)
<!--
if this PR closes one or more issues, you can automatically link the PR
with
them by using one of the [*linking
keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword),
e.g.
- this PR should close #xxxx
- fixes #xxxx

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

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

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

This reverts #10898 which breaks external completion.
Not having file completion fallback on empty result is **intentional**
as this indicates that there is nothing to complete at this position.
To have nushell fallback to file completion the external completer can
simply return *nothing*.


`NO RECORDS FOUND`:
```nushell
let external_completer = {|spans|
    []
}
```

Fallback to file completion:
```nushell
let external_completer = {|spans|
}
```

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2023-12-31 08:45:05 -06:00
64695cd67c bump rust toolchain to 1.73.0 (#11445)
This PR bumps the nushell rust toolchain from 1.72.1 to 1.73.0 since
1.75.0 was released recently.

# 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` to
check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2023-12-30 10:41:27 -06:00
21b3eeed99 Allow spreading arguments to commands (#11289)
<!--
if this PR closes one or more issues, you can automatically link the PR
with
them by using one of the [*linking
keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword),
e.g.
- this PR should close #xxxx
- fixes #xxxx

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

Finishes implementing https://github.com/nushell/nushell/issues/10598,
which asks for a spread operator in lists, in records, and when calling
commands.

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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


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

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

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

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

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

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

# Examples

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

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

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

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

---

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

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

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

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

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

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

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

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

Running it:
```nushell
> search-pkgs-curated "git" "*vi*"
╭──────────────┬───────────────────────────────────────────────────────────────────╮
│ install      │ false                                                             │
│ log_level    │ 1                                                                 │
│ exclude      │ [emacs]                                                           │
│ repositories │ [example.com, foo.com]                                            │
│ pkgs         │ [vim, git, python, chrome, firefox, python, java, git, "python3"] │
╰──────────────┴───────────────────────────────────────────────────────────────────╯
```
2023-12-28 15:43:20 +08:00
a86a7e6c29 Allow http commands' automatic redirect-following to be disabled (#11329)
Intends to close #8920 

This PR suggests a new flag for the `http` commands, `--redirect-mode`,
which enables users to choose between different redirect handling modes.
The current behaviour of letting ureq silently follow redirects remains
the default, but two new options are introduced here, following the lead
of [JavaScript's `fetch`
API](https://developer.mozilla.org/en-US/docs/Web/API/fetch#redirect):
"manual", where any 3xx response to a request is simply returned as the
command's result, and "error", where any 3xx response causes a network
error like those caused by 4xx and 5xx responses.

This PR is a draft. Tests have not been added or run, the flag is
currently only implemented for the `http get` command, and design tweaks
are likely to be appropriate.

Most notably, it's not obvious to me whether a single flag which can
take one of three values is the nicest solution here.
We might instead consider two binary flags (like
`--no-following-redirects` and `--disallow-redirects`, although I'm bad
at naming things so I need help with that anyway), or completely drop
the "error" option if it's not deemed useful enough. (I personally think
it has some merit, especially since 4xx and 5xx responses are already
treated as errors by default; So this would allow users to treat only
immediate 2xx responses as success)

# User-facing changes
New options for the `http [method]` commands. Behaviour remains
unchanged when the command line flag introduced here is not used.


![image](https://github.com/nushell/nushell/assets/12228688/1eb89f14-7d48-4f41-8a3e-cc0f1bd0a4f8)
2023-12-28 15:26:34 +08:00
15421dc45e Fix the bug for "bytes remove --end" . (#11428)
This PR should close #11426 .

# Description
> ### Describe the bug
> When using the `--end` option of bytes remove, nushell panics if the
provided bytes don't exist. This doesn't seem to affect `bytes remove`
w/o flag or `bytes remove --all`.

# User-Facing Changes
Nushell doesn`t panic anymore.

# Tests + Formatting
Behavior before fixing the bug:
![nu-before
changes](https://github.com/UPB-CS-OpenSourceUpstream/nushell/assets/119429832/f9c26d88-8962-4f38-a373-ba436a26ca7c)
Behavior after fixing the bug:
![nu- after
changes](https://github.com/UPB-CS-OpenSourceUpstream/nushell/assets/119429832/0dd2b487-1696-45a6-9ea2-928cbd3a33a8)
2023-12-28 07:01:55 +08:00
9522052063 More specific errors for missing values in records (#11423)
# Description
Currently, when writing a record, if you don't give the value for a
field, the syntax error highlights the entire record instead of
pinpointing the issue. Here's some examples:

```nushell
> { a: 2, 3 } # Missing colon (and value)
Error: nu::parser::parse_mismatch

  × Parse mismatch during operation.
   ╭─[entry #2:1:1]
 1 │  { a: 2, 3 }
   ·  ─────┬─────
   ·       ╰── expected record
   ╰────

> { a: 2, 3: } # Missing value
Error: nu::parser::parse_mismatch

  × Parse mismatch during operation.
   ╭─[entry #3:1:1]
 1 │  { a: 2, 3: }
   ·  ──────┬─────
   ·        ╰── expected record
   ╰────

> { a: 2, 3 4 } # Missing colon
Error: nu::parser::parse_mismatch

  × Parse mismatch during operation.
   ╭─[entry #4:1:1]
 1 │  { a: 2, 3 4 }
   ·  ──────┬──────
   ·        ╰── expected record
   ╰────
```

In all of them, the entire record is highlighted red because an
`Expr::Garbage` is returned covering that whole span:


![image](https://github.com/nushell/nushell/assets/45539777/36660b50-23be-4353-b180-3f84eff3c220)

This PR is for highlighting only the part inside the record that could
not be parsed. If the record literal is big, an error message pointing
to the start of where the parser thinks things went wrong should help
people fix their code.

# User-Facing Changes
Below are screenshots of the new errors:

If there's a stray record key right before the record ends, it
highlights only that key and tells the user it expected a colon after
it:


![image](https://github.com/nushell/nushell/assets/45539777/94503256-8ea2-47dd-b69a-4b520c66f7b6)

If the record ends before the value for the last field was given, it
highlights the key and colon of that field and tells the user it
expected a value after the colon:


![image](https://github.com/nushell/nushell/assets/45539777/2f3837ec-3b35-4b81-8c57-706f8056ac04)

If there are two consecutive expressions without a colon between them,
it highlights everything from the second expression to the end of the
record and tells the user it expected a colon. I was tempted to add a
help message suggesting adding a colon in between, but that may not
always be the right thing to do.


![image](https://github.com/nushell/nushell/assets/45539777/1abaaaa8-1896-4909-bbb7-9a38cece5250)

# Tests + Formatting

# After Submitting
2023-12-27 10:15:12 +01:00
ba880277bf Remove unnecessary replace_in_variable (#11424)
# Description
`Expression::replace_in_variable` is only called in one place, and it is
called with `new_var_id` = `IN_VARIABLE_ID`. So, it ends up doing
nothing. E.g., adding `debug_assert_eq!(new_var_id, IN_VARIABLE_ID)` in
`replace_in_variable` does not trigger any panic.

# User-Facing Changes
Breaking change for `nu_protocol`.
2023-12-26 18:46:49 +01:00
40241e9be6 Revert "Bump reedline development version" (#11425)
Reverts nushell/nushell#11406

This PR https://github.com/nushell/reedline/pull/688 is causing clear
screens to happen at strange times. Documented here
https://github.com/nushell/nushell/pull/11406#issuecomment-1869591405
2023-12-26 09:08:32 -06:00
34f3da7150 Don't panic when http_client fails (#11422)
# Description

This PR makes `http_client` return `Result<ureq::Agent, ShellError>`, so
errors can be propagated to the caller.
2023-12-25 23:09:37 +08:00
534287ed65 Don't create a thread if stderr_stream is None (#11421)
# Description

There is no need to create a thread if `stderr_stream` is `None`.
2023-12-25 08:10:15 -06:00
913c2b8d1c Bump ical from 0.8.0 to 0.9.0 (#11419)
Bumps [ical](https://github.com/Peltoche/ical-rs) from 0.8.0 to 0.9.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/Peltoche/ical-rs/releases">ical's
releases</a>.</em></p>
<blockquote>
<h2>v0.9.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Add the github actions by <a
href="https://github.com/Peltoche"><code>@​Peltoche</code></a> in <a
href="https://redirect.github.com/Peltoche/ical-rs/pull/35">Peltoche/ical-rs#35</a></li>
<li>Use thiserror instead of failure by <a
href="https://github.com/Peltoche"><code>@​Peltoche</code></a> in <a
href="https://redirect.github.com/Peltoche/ical-rs/pull/36">Peltoche/ical-rs#36</a></li>
<li>Accept lowercase vCards by <a
href="https://github.com/link2xt"><code>@​link2xt</code></a> in <a
href="https://redirect.github.com/Peltoche/ical-rs/pull/37">Peltoche/ical-rs#37</a></li>
<li>Parse multiline attributes with tabs correctly by <a
href="https://github.com/FliegendeWurst"><code>@​FliegendeWurst</code></a>
in <a
href="https://redirect.github.com/Peltoche/ical-rs/pull/41">Peltoche/ical-rs#41</a></li>
<li>Ical serde by <a
href="https://github.com/daladim"><code>@​daladim</code></a> in <a
href="https://redirect.github.com/Peltoche/ical-rs/pull/44">Peltoche/ical-rs#44</a></li>
<li>Set the license to Apache 2 by <a
href="https://github.com/Peltoche"><code>@​Peltoche</code></a> in <a
href="https://redirect.github.com/Peltoche/ical-rs/pull/47">Peltoche/ical-rs#47</a></li>
<li>Update README.md by <a
href="https://github.com/Zearin"><code>@​Zearin</code></a> in <a
href="https://redirect.github.com/Peltoche/ical-rs/pull/51">Peltoche/ical-rs#51</a></li>
<li>Adding ical-output support by <a
href="https://github.com/migmedia"><code>@​migmedia</code></a> in <a
href="https://redirect.github.com/Peltoche/ical-rs/pull/49">Peltoche/ical-rs#49</a></li>
<li>Improve documentation of builders. by <a
href="https://github.com/migmedia"><code>@​migmedia</code></a> in <a
href="https://redirect.github.com/Peltoche/ical-rs/pull/52">Peltoche/ical-rs#52</a></li>
<li>Add access functions for properties by <a
href="https://github.com/reedts"><code>@​reedts</code></a> in <a
href="https://redirect.github.com/Peltoche/ical-rs/pull/53">Peltoche/ical-rs#53</a></li>
<li>Fix README by <a
href="https://github.com/westy92"><code>@​westy92</code></a> in <a
href="https://redirect.github.com/Peltoche/ical-rs/pull/55">Peltoche/ical-rs#55</a></li>
<li>Handle the case were a line contains non-utf8 characters by <a
href="https://github.com/Peltoche"><code>@​Peltoche</code></a> in <a
href="https://redirect.github.com/Peltoche/ical-rs/pull/57">Peltoche/ical-rs#57</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/link2xt"><code>@​link2xt</code></a> made
their first contribution in <a
href="https://redirect.github.com/Peltoche/ical-rs/pull/37">Peltoche/ical-rs#37</a></li>
<li><a
href="https://github.com/FliegendeWurst"><code>@​FliegendeWurst</code></a>
made their first contribution in <a
href="https://redirect.github.com/Peltoche/ical-rs/pull/41">Peltoche/ical-rs#41</a></li>
<li><a href="https://github.com/daladim"><code>@​daladim</code></a> made
their first contribution in <a
href="https://redirect.github.com/Peltoche/ical-rs/pull/44">Peltoche/ical-rs#44</a></li>
<li><a href="https://github.com/Zearin"><code>@​Zearin</code></a> made
their first contribution in <a
href="https://redirect.github.com/Peltoche/ical-rs/pull/51">Peltoche/ical-rs#51</a></li>
<li><a href="https://github.com/migmedia"><code>@​migmedia</code></a>
made their first contribution in <a
href="https://redirect.github.com/Peltoche/ical-rs/pull/49">Peltoche/ical-rs#49</a></li>
<li><a href="https://github.com/reedts"><code>@​reedts</code></a> made
their first contribution in <a
href="https://redirect.github.com/Peltoche/ical-rs/pull/53">Peltoche/ical-rs#53</a></li>
<li><a href="https://github.com/westy92"><code>@​westy92</code></a> made
their first contribution in <a
href="https://redirect.github.com/Peltoche/ical-rs/pull/55">Peltoche/ical-rs#55</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/Peltoche/ical-rs/compare/0.6.0...v0.9.0">https://github.com/Peltoche/ical-rs/compare/0.6.0...v0.9.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/Peltoche/ical-rs/commits/v0.9.0">compare
view</a></li>
</ul>
</details>
<br />


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

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

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

---

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

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


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-25 09:23:27 +08:00
aeffa188f0 Fix an infinite loop if the input stream and output stream are the same (#11384)
# Description

Fixes #11382 

# User-Facing Changes
* before

```console
nushell/test (109f629) [✘?]
❯ open hello.md
hello
nushell/test (109f629) [✘?]
❯ ls hello.md | get size
╭───┬─────╮
│ 0 │ 6 B │
╰───┴─────╯
nushell/test (109f629) [✘?]
❯ open --raw hello.md | prepend "world" | save --raw --force hello.md
^C
nushell/test (109f629) [✘?]
❯ ls hello.md | get size
╭───┬─────────╮
│ 0 │ 2.8 GiB │
╰───┴─────────╯
```

* after

```console
nushell/test on  fix_save [✘!?⇡]
❯ open hello.md | prepend "hello" | save --force hello.md
nushell/test on  fix_save [✘!?⇡]
❯ open --raw hello.md | prepend "hello" | save --raw --force ../test/hello.md
Error:   × pipeline input and output are same file
   ╭─[entry #4:1:1]
 1 │ open --raw hello.md | prepend "hello" | save --raw --force ../test/hello.md
   ·                                                           ────────┬───────
   ·                                                                   ╰── can't save output to '/data/source/nushell/test/hello.md' while it's being reading
   ╰────
  help: you should change output path


nushell/test on  fix_save [✘!?⇡]
❯ open hello | prepend "hello" | save --force hello
Error:   × pipeline input and output are same file
   ╭─[entry #5:1:1]
 1 │ open hello | prepend "hello" | save --force hello
   ·                                            ──┬──
   ·                                              ╰── can't save output to '/data/source/nushell/test/hello' while it's being reading
   ╰────
  help: you should change output path
```

# Tests + Formatting
Make sure you've run and fixed any issues with these commands:
- [x] add `commands::save::save_same_file_with_extension`
- [x] add `commands::save::save_same_file_without_extension`
- [x] `cargo fmt --all -- --check` to check standard code formatting
(`cargo fmt --all` applies these changes)
- [x] `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used`
to check that you're using the standard code style
- [x] `cargo test --workspace` to check that all tests pass (on Windows
make sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- [x] `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library

# After Submitting
2023-12-24 23:29:23 +08:00
543a25599c Simplify the feature gates for stor commands (#11416)
All of them depend on feature `sqlite` so just conditionally `use` the
parent module.
2023-12-24 13:31:46 +01:00
7ad0e5541e Make polars deps optional for cargo test --all (#11415)
As `--workspace/--all` pulls in all crates in the workspace for `cargo
test --workspace` let's make sure that the `polars` family of
dependencies are also feature gated so they only build for `--features
dataframe`. The test modules themselves also depend on the feature.

Should speed up a bare `cargo test --workspace`
2023-12-24 13:12:31 +01:00
c1cc1c82cc Lock out new direct construction of Record (#11414)
# Description
With #11386 we don't have any nushell-internal code directly accessing
the `vals` field of `Record`, so let's make it private so everyone in
the future uses the checked ways guaranteeing matching cols/vals.

The `cols` feel has to remain pub for now as `rename` still directly
mutates this field. See #11020 for challenges for this refactor.

# Plugin-Author-Facing Changes
This is a breaking change for outside plugins that relied on the `pub`
fields.
2023-12-24 13:12:16 +01:00
b0b4c3dffd Check for clean repo after tests (#11409)
Goal: detect problems like adressed by #11407 or missing `Cargo.lock`
update early

Try to fail when there is a non clear `git status` message
2023-12-23 20:28:07 +01:00
f3de373c59 Bump reedline development version (#11406)
Fix for #11399
Provided by nushell/reedline#688
2023-12-23 20:08:37 +01:00
df1fecd2cb Fix sandboxing of redirection tests (#11407)
When running `cargo test --workspace` a file `crates/nu-command/a.txt`
remained which we also saw as an accidential additions in some commits.

Searching for `a.txt` narrowed it down that
`redirection_keep_exit_codes` was not sandboxed in a temporary directory
and created this file.

Went through redirection tests and placed them in a `Playground` to get
sandboxing `dirs` for `nu!(cwd:`.
For those tests where redirection fails and no file should be created
now I added a check that no file is created on accident.


- Sandbox `redirection_keep_exit_codes` test
- Sandbox `no_duplicate_redirection` test
- Check that no redirect file is created on error
- Sandbox `redirection_should_have_a_target` test
2023-12-23 20:01:20 +01:00
9620e27e4f fix: prevent greedy matching of directory names (#11403)
Fixes #11396

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

If a directory name is an exact match, the completer stops greedily
matching directories with the same prefix.

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

Completions should work as described in #11396.

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2023-12-23 00:06:00 -06:00
072ecec8ca Bump unsafe-libyaml from 0.2.9 to 0.2.10 (#11391) 2023-12-21 18:49:12 +00:00
748d82cec1 Bump windows from 0.48.0 to 0.52.0 (#11325)
# Description
Bump `windows` to 0.52.0 and fix `is_admin`

https://github.com/microsoft/windows-rs/pull/2476

# User-Facing Changes
N/A

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-21 18:49:15 +01:00
5e5d1ea81b Bump fancy-regex to single 0.12.0 version (#11389)
Supersedes #11039 that was broken due to dependabot not correctly taking
the workspace into account (this bug has been worked around in #11387)
2023-12-21 17:10:33 +01:00
bb570e42be Bump lscolors from 0.15.0 to 0.16.0 (#11359) 2023-12-21 16:08:19 +00:00
3a050864df Simplify SIGQUIT handling (#11381)
# Description
Simplifies `SIGQUIT` protection to a single `signal` ignore system call.

# User-Facing Changes
`SIGQUIT` is no longer blocked if nushell is in non-interactive mode
(signals should not be blocked in non-interactive mode).
Also a breaking API change for `nu_protocol`.

# Tests + Formatting
Should come after #11178 for testing.
2023-12-21 17:00:38 +01:00
8cfa96b4c0 Construct Records only through checked helpers (#11386)
# Description

Constructing the internals of `Record` without checking the lengths is
bad. (also incompatible with changes to how we store records)

- Use `Record::from_raw_cols_vals` in dataframe code
- Use `record!` macro in dataframe test
- Use `record!` in `nu-color-config` tests
- Stop direct record construction in `nu-command`
- Refactor table construction in `from nuon`

# User-Facing Changes
None

# Tests + Formatting
No new tests, updated tests in equal fashion
2023-12-21 16:48:15 +01:00
6f384da57e Make Call::get_flag_expr return Expression by ref (#11388)
# Description
A small refactor that eliminates some `Expression` cloning.

# User-Facing Changes
Breaking change for `nu_protocol`.
2023-12-21 16:42:07 +01:00
f8e63328d8 Expand the workspace members in Cargo.toml (#11387)
While the `cargo` tools will include crates we depend on in the
directory into the workspace, I observed dependabot not taking all of
our crates into account in its version bump attempts leading to
duplication of outside dependencies.

e.g.
- https://github.com/nushell/nushell/pull/11039
2023-12-21 16:41:31 +01:00
5d98a727ca Deprecate --flag: bool in custom command (#11365)
# Description
While #11057 is merged, it's hard to tell the difference between
`--flag: bool` and `--flag`, and it makes user hard to read custom
commands' signature, and hard to use them correctly.

After discussion, I think we can deprecate `--flag: bool` usage, and
encourage using `--flag` instead.

# User-Facing Changes
The following code will raise warning message, but don't stop from
running.
```nushell
❯ def florb [--dry-run: bool, --another-flag] { "aaa" };  florb
Error:   × Deprecated: --flag: bool
   ╭─[entry #7:1:1]
 1 │ def florb [--dry-run: bool, --another-flag] { "aaa" };  florb
   ·                       ──┬─
   ·                         ╰── `--flag: bool` is deprecated. Please use `--flag` instead, more info: https://www.nushell.sh/book/custom_commands.html
   ╰────

aaa
```

cc @kubouch 

# Tests + Formatting
Done

# After Submitting
- [ ] Add more information under
https://www.nushell.sh/book/custom_commands.html to indicate `--dry-run:
bool` is not allowed,
- [ ] remove `: bool` from custom commands between 0.89 and 0.90

---------

Co-authored-by: Antoine Stevan <44101798+amtoine@users.noreply.github.com>
2023-12-21 10:07:08 +01:00
109f629cb6 📝 Update str trim CLI help doc (#11383)
# Description
Hi! I updated the samples of `str trim` because there were repeated and
clarified the explanations

# User-Facing Changes
Yes! I send the details here:


![image](https://github.com/nushell/nushell/assets/30557287/e30a5612-4214-4365-8b83-7aefbc0ee825)

(`old` is version `88.1` not the latest main)

# Tests + Formatting
~~I ran `toolkit check pr` successfully~~

There was a tiny problem, a test I never touched now it's failing

```nu
(^echo a | complete) == {stdout: "a\n", exit_code: 0}
```
should output `true` but outputs `false`, both in my running `nu`
version and in my PR version
This make the test `nu-command::main commands::complete::basic` fail
located in `crates\nu-command\tests\commands\complete.rs`

# After Submitting
I'm not sure if I need to update nushell.github.io, some of the help is
auto-generated, but maybe not all?
I can file a PR if needed
2023-12-20 14:23:41 -06:00
ff6a67d293 Remove Expr::MatchPattern (#11367)
# Description
Following from #11356, it looks like `Expr::MatchPattern` is no longer
used in any way. This PR removes `Expr::MatchPattern` alongside
`Type::MatchPattern` and `SyntaxShape::MatchPattern`.

# User-Facing Changes
Breaking API change for `nu_protocol`.
2023-12-20 18:52:28 +01:00
03ae01f11e Bump itertools from 0.11.0 to 0.12.0 (#11360)
Bumps [itertools](https://github.com/rust-itertools/itertools) from
0.11.0 to 0.12.0.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/rust-itertools/itertools/blob/master/CHANGELOG.md">itertools's
changelog</a>.</em></p>
<blockquote>
<h2>0.12.0</h2>
<h3>Breaking</h3>
<ul>
<li>Made <code>take_while_inclusive</code> consume iterator by value (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/709">#709</a>)</li>
<li>Added <code>Clone</code> bound to <code>Unique</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/777">#777</a>)</li>
</ul>
<h3>Added</h3>
<ul>
<li>Added <code>Itertools::try_len</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/723">#723</a>)</li>
<li>Added free function <code>sort_unstable</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/796">#796</a>)</li>
<li>Added <code>GroupMap::fold_with</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/778">#778</a>,
<a
href="https://redirect.github.com/rust-itertools/itertools/issues/785">#785</a>)</li>
<li>Added <code>PeekNth::{peek_mut, peek_nth_mut}</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/716">#716</a>)</li>
<li>Added <code>PeekNth::{next_if, next_if_eq}</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/734">#734</a>)</li>
<li>Added conversion into <code>(Option&lt;A&gt;,Option&lt;B&gt;)</code>
to <code>EitherOrBoth</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/713">#713</a>)</li>
<li>Added conversion from <code>Either&lt;A, B&gt;</code> to
<code>EitherOrBoth&lt;A, B&gt;</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/715">#715</a>)</li>
<li>Implemented <code>ExactSizeIterator</code> for <code>Tuples</code>
(<a
href="https://redirect.github.com/rust-itertools/itertools/issues/761">#761</a>)</li>
<li>Implemented <code>ExactSizeIterator</code> for
<code>(Circular)TupleWindows</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/752">#752</a>)</li>
<li>Made <code>EitherOrBoth&lt;T&gt;</code> a shorthand for
<code>EitherOrBoth&lt;T, T&gt;</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/719">#719</a>)</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Added missing <code>#[must_use]</code> annotations on iterator
adaptors (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/794">#794</a>)</li>
<li>Made <code>Combinations</code> lazy (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/795">#795</a>)</li>
<li>Made <code>Intersperse(With)</code> lazy (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/797">#797</a>)</li>
<li>Made <code>Permutations</code> lazy (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/793">#793</a>)</li>
<li>Made <code>Product</code> lazy (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/800">#800</a>)</li>
<li>Made <code>TupleWindows</code> lazy (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/602">#602</a>)</li>
<li>Specialized <code>Combinations::{count, size_hint}</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/729">#729</a>)</li>
<li>Specialized <code>CombinationsWithReplacement::{count,
size_hint}</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/737">#737</a>)</li>
<li>Specialized <code>Powerset::fold</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/765">#765</a>)</li>
<li>Specialized <code>Powerset::count</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/735">#735</a>)</li>
<li>Specialized <code>TupleCombinations::{count, size_hint}</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/763">#763</a>)</li>
<li>Specialized <code>TupleCombinations::fold</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/775">#775</a>)</li>
<li>Specialized <code>WhileSome::fold</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/780">#780</a>)</li>
<li>Specialized <code>WithPosition::fold</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/772">#772</a>)</li>
<li>Specialized <code>ZipLongest::fold</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/774">#774</a>)</li>
<li>Changed <code>{min, max}_set*</code> operations require
<code>alloc</code> feature, instead of <code>std</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/760">#760</a>)</li>
<li>Improved documentation of <code>tree_fold1</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/787">#787</a>)</li>
<li>Improved documentation of <code>permutations</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/724">#724</a>)</li>
<li>Fixed typo in documentation of <code>multiunzip</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/770">#770</a>)</li>
</ul>
<h3>Notable Internal Changes</h3>
<ul>
<li>Improved specialization tests (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/799">#799</a>,
<a
href="https://redirect.github.com/rust-itertools/itertools/issues/786">#786</a>,
<a
href="https://redirect.github.com/rust-itertools/itertools/issues/782">#782</a>)</li>
<li>Simplified implementation of <code>Permutations</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/739">#739</a>,
<a
href="https://redirect.github.com/rust-itertools/itertools/issues/748">#748</a>,
<a
href="https://redirect.github.com/rust-itertools/itertools/issues/790">#790</a>)</li>
<li>Combined
<code>Merge</code>/<code>MergeBy</code>/<code>MergeJoinBy</code>
implementations (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/736">#736</a>)</li>
<li>Simplified <code>Permutations::size_hint</code> (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/739">#739</a>)</li>
<li>Fix wrapping arithmetic in benchmarks (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/770">#770</a>)</li>
<li>Enforced <code>rustfmt</code> in CI (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/751">#751</a>)</li>
<li>Disallowed compile warnings in CI (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/720">#720</a>)</li>
<li>Used <code>cargo hack</code> to check MSRV (<a
href="https://redirect.github.com/rust-itertools/itertools/issues/754">#754</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="98ecabb47d"><code>98ecabb</code></a>
chore: Release itertools version 0.12.0</li>
<li><a
href="22fc427ac5"><code>22fc427</code></a>
prepare v0.12.0 release</li>
<li><a
href="6d291786a9"><code>6d29178</code></a>
Document the field <code>a_cur</code> of <code>Product</code></li>
<li><a
href="bf2b0129d1"><code>bf2b012</code></a>
Better <code>Product::size_hint</code></li>
<li><a
href="8d07f6b856"><code>8d07f6b</code></a>
Make <code>Product</code> lazy</li>
<li><a
href="d7e6bab9fd"><code>d7e6bab</code></a>
Document the field <code>peek</code> of
<code>IntersperseWith</code></li>
<li><a
href="9b01a11891"><code>9b01a11</code></a>
Make <code>IntersperseWith</code> lazy</li>
<li><a
href="4f22173b93"><code>4f22173</code></a>
Refactor <code>IntersperseWith::next</code></li>
<li><a
href="b76172b412"><code>b76172b</code></a>
chore: adjust docs to reflect discussion in the PR</li>
<li><a
href="955927f6c4"><code>955927f</code></a>
chore: fixup docs of tree_fold1</li>
<li>Additional commits viewable in <a
href="https://github.com/rust-itertools/itertools/compare/v0.11.0...v0.12.0">compare
view</a></li>
</ul>
</details>
<br />


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

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

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

---

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

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


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-20 22:58:07 +08:00
697f3c03f1 enable flag value type checking (#11311)
# Description
Fixes: #11310

# User-Facing Changes
After the change, the following code will go to error:
```nushell
> def a [--x: int = 3] { "aa" }
> let y = "aa"
> a --x=$y
Error: nu::parser::type_mismatch

  × Type mismatch.
   ╭─[entry #32:2:1]
 2 │ let y = "aa"
 3 │ a --x=$y
   ·       ─┬
   ·        ╰── expected int, found string
   ╰────
```
2023-12-20 11:07:19 +01:00
1cecb37628 Bump shadow-rs from 0.24.1 to 0.25.0 (#11282)
Bumps [shadow-rs](https://github.com/baoyachi/shadow-rs) from 0.24.1 to
0.25.0.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="f08828be45"><code>f08828b</code></a>
Update Cargo.toml</li>
<li><a
href="a3cc1a118f"><code>a3cc1a1</code></a>
Update README.md</li>
<li><a
href="96fdafc738"><code>96fdafc</code></a>
Merge pull request <a
href="https://redirect.github.com/baoyachi/shadow-rs/issues/144">#144</a>
from baoyachi/wasm_example</li>
<li><a
href="24d3bd82c0"><code>24d3bd8</code></a>
fix</li>
<li><a
href="aab9bf2d4d"><code>aab9bf2</code></a>
Update check.yml</li>
<li><a
href="1d4e455730"><code>1d4e455</code></a>
add wasm example</li>
<li>See full diff in <a
href="https://github.com/baoyachi/shadow-rs/compare/v0.24.1...v0.25.0">compare
view</a></li>
</ul>
</details>
<br />


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

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

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

---

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

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


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-20 17:49:03 +08:00
89436e978b add special emoji handling for debug --raw (#11368)
# Description

This PR add special handling in `debug -r` for emoji's so that it prints
the code points.

### Before
```nushell
❯ emoji --list | where name =~ farmer | reject utf8_bytes | get 0.emoji | debug -r
String {
    val: "🧑\u{200d}🌾",
    internal_span: Span {
        start: 0,
        end: 0,
    },
}
```

### After
```nushell
❯ emoji --list | where name =~ farmer | reject utf8_bytes | get 0.emoji | debug -r
String {
    val: "\\u{1f9d1}\\u{200d}\\u{1f33e}",
    internal_span: Span {
        start: 0,
        end: 0,
    },
}
```

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2023-12-19 13:09:31 -06:00
cd0a52cf00 Fix build for BSDs (#11372)
# Description
This PR fixes build for BSD variants (including FreeBSD and NetBSD). 

Currently, `procfs` only support linux, android and l4re, and
0cba269d80 only adds support for NetBSD,
this PR should work on all BSD variants.


b153b782a5/procfs/build.rs (L4-L8)

Fixes #11373 

# User-Facing Changes
* before

```console
nibon7@fbsd /d/s/nushell ((70f7db14))> cargo build
   Compiling tempfile v3.8.1
   Compiling procfs v0.16.0
   Compiling toml_edit v0.21.0
   Compiling native-tls v0.2.11
error: failed to run custom build command for `procfs v0.16.0`

Caused by:
  process didn't exit successfully: `/data/source/nushell/target/debug/build/procfs-d59599f40f32f0d5/build-script-build` (exit status: 1)
  --- stderr
  Building procfs on an for a unsupported platform. Currently only linux and android are supported
  (Your current target_os is freebsd)
warning: build failed, waiting for other jobs to finish...
```

* after

```console
nushell on  bsd [✘!?] is 📦 v0.88.2 via 🦀 v1.74.1
❯ version
╭────────────────────┬───────────────────────────────────────────╮
│ version            │ 0.88.2                                    │
│ branch             │ bsd                                       │
│ commit_hash        │ 151edef186  │
│ build_os           │ freebsd-x86_64                            │
│ build_target       │ x86_64-unknown-freebsd                    │
│ rust_version       │ rustc 1.74.1 (a28077b28 2023-12-04)       │
│ rust_channel       │ stable-x86_64-unknown-freebsd             │
│ cargo_version      │ cargo 1.74.1 (ecb9851af 2023-10-18)       │
│ build_time         │ 2023-12-19 10:12:15 +00:00                │
│ build_rust_channel │ debug                                     │
│ allocator          │ mimalloc                                  │
│ features           │ default, extra, sqlite, trash, which, zip │
│ installed_plugins  │                                           │
╰────────────────────┴───────────────────────────────────────────╯
nushell on  bsd [✘!?] is 📦 v0.88.2 via 🦀 v1.74.1
❯ cargo test --workspace commands::ulimit e>> /dev/null | rg ulimit
test commands::ulimit::limit_set_filesize2 ... ok
test commands::ulimit::limit_set_filesize1 ... ok
test commands::ulimit::limit_set_hard1 ... ok
test commands::ulimit::limit_set_hard2 ... ok
test commands::ulimit::limit_set_invalid1 ... ok
test commands::ulimit::limit_set_invalid3 ... ok
test commands::ulimit::limit_set_invalid4 ... ok
test commands::ulimit::limit_set_invalid5 ... ok
test commands::ulimit::limit_set_soft2 ... ok
test commands::ulimit::limit_set_soft1 ... ok
nushell on  bsd [✘!?] is 📦 v0.88.2 via 🦀 v1.74.1
```


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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2023-12-19 08:58:45 -06:00
c6043eb500 improve completions of use and overlay use (#11330)
# Description
this PR is two-fold
- make `use` and `overlay use` use the same completion algorithm in
48f29b633
- list directory modules in completions of both with 402acde5c

# User-Facing Changes
i currently have the following in my `NU_LIB_DIRS`
<details>
<summary>click to see the script</summary>

```nushell
for dir in $env.NU_LIB_DIRS {
    print $dir
    print (ls $dir --short-names | select name type)
}
```
</details>

```
/home/amtoine/.local/share/nupm/modules
#┬────────name────────┬type
0│nu-git-manager      │dir
1│nu-git-manager-sugar│dir
2│nu-hooks            │dir
3│nu-scripts          │dir
4│nu-themes           │dir
5│nupm                │dir
─┴────────────────────┴────

/home/amtoine/.config/nushell/overlays
#┬──name──┬type
0│ocaml.nu│file
─┴────────┴────
```

> **Note**
> all the samples below are run from the Nushell repo, i.e. a directory
with a `toolkit.nu` module

## before the changes
- `use` would give me `["ocaml.nu", "toolkit.nu"]` 
- `overlay use` would give me `[]` 

## after the changes
both commands give me
```nushell
[
    "nupm/",
    "ocaml.nu",
    "toolkit.nu",
    "nu-scripts/",
    "nu-git-manager/",
    "nu-git-manager-sugar/",
]
```

# Tests + Formatting
- adds a new `directory_completion/mod.nu` to the completion fixtures
- make sure `source-env`, `use` and `overlay-use` are all tested in the
_dotnu_ test
- fix all the other tests that use completions in the fixtures directory
for completions

# After Submitting
2023-12-19 17:14:34 +08:00
729373aba0 fix(cd): on android/termux fails to cd into /sdcard (#10329)
fix on android/termux fails to cd into /sdcard or any directory that
user has access via group

fixes #8095

I am not aware how this works on other platform so feel free to modify
this pr or even close it if it is not correct

# Description
on android or on linux to check if the user belongs to given directory
group, use `libc::getgroups` function

# User-Facing Changes
NA
2023-12-19 16:48:20 +08:00
f59a6990dc Refactor group-by with closure grouper (#11370)
# Description
Refactors `group_closure` in `group_by.rs` as suggested by the TODO
comment.
2023-12-19 15:48:37 +08:00
0f9094ead2 Bump crate-ci/typos from 1.16.24 to 1.16.25 (#11358)
Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.16.24
to 1.16.25.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/releases">crate-ci/typos's
releases</a>.</em></p>
<blockquote>
<h2>v1.16.25</h2>
<h2>[1.16.25] - 2023-12-13</h2>
<h3>Fixes</h3>
<ul>
<li>Have correction in <code>extend-words</code> match the original
word's case</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/blob/master/CHANGELOG.md">crate-ci/typos's
changelog</a>.</em></p>
<blockquote>
<h2>[1.16.25] - 2023-12-13</h2>
<h3>Fixes</h3>
<ul>
<li>Have correction in <code>extend-words</code> match the original
word's case</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="5bd389de71"><code>5bd389d</code></a>
chore: Release</li>
<li><a
href="8dbecf3e45"><code>8dbecf3</code></a>
docs: Update changelog</li>
<li><a
href="f8f8c6edf1"><code>f8f8c6e</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/884">#884</a>
from epage/custom</li>
<li><a
href="55d802d0ef"><code>55d802d</code></a>
fix(dict): Mirror original case for custom dict</li>
<li><a
href="86c4c9fb4a"><code>86c4c9f</code></a>
test(cli): Add reproduction case</li>
<li>See full diff in <a
href="https://github.com/crate-ci/typos/compare/v1.16.24...v1.16.25">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=crate-ci/typos&package-manager=github_actions&previous-version=1.16.24&new-version=1.16.25)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

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

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

---

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

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


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-19 15:17:10 +08:00
70f7db14d4 Only run $env.PROMPT_COMMAND once per prompt (copy of #10986) (#11366)
<!--
if this PR closes one or more issues, you can automatically link the PR
with
them by using one of the [*linking
keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword),
e.g.
- this PR should close #xxxx
- fixes #xxxx

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

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

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

This PR is basically a copy of #10986 by @CAD97, which made
`$env.PROMPT_COMMAND` only run once per prompt, but @fdncred found an
issue where hitting Enter would make the transient prompt appear and be
immediately overwritten by the regular prompt, so it was
[reverted](https://github.com/nushell/nushell/pull/11340).
https://github.com/nushell/nushell/pull/10788 was also made to do the
same thing as #10986 but that ended up having the same issue. For some
reason, this branch doesn't have that problem, although I haven't
figured out why yet.

@CAD97, if you have any inputs or want to make your own PR, let me know.

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

When hitting enter, the prompt shouldn't blink in place anymore.

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2023-12-18 09:33:04 -06:00
pin
0cba269d80 Fix build on NetBSD (#11364)
- this PR should close #11354

# Description
Allow building on NetBSD.

# User-Facing Changes
NA
2023-12-18 06:41:27 -06:00
ec2593efb8 nu-cli repl get_command_finished_marker() does not need to be pub (#11362)
```rust
fn get_command_finished_marker
```
does not need to be public so just doing a little code cleanup
2023-12-17 20:20:31 -08:00
c2283596ac Rename extra's format to format pattern (#11355)
This removes the naming conflict, introduced by `fd77114` (#11334), when
the `extra` feature is enabled.
2023-12-17 17:32:34 -06:00
c9399f5142 Downgrade openssl-src to fix riscv64 build target, close #11345 (#11353) 2023-12-18 05:57:20 +08:00
c9c93f5b4d Remove Value::MatchPattern (#11356)
# Description
`Value::MatchPattern` implies that `MatchPattern`s are first-class
values. This PR removes this case, and commands must now instead use
`Expr::MatchPattern` to extract `MatchPattern`s just like how the
`match` command does using `Expr::MatchBlock`.

# User-Facing Changes
Breaking API change for `nu_protocol` crate.
2023-12-18 07:25:34 +13:00
2264682443 fix shell integration markers (#11352)
<!--
if this PR closes one or more issues, you can automatically link the PR
with
them by using one of the [*linking
keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword),
e.g.
- this PR should close #xxxx
- fixes #xxxx

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

# 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.
-->
Note: my issue description was a bit wrong. Issue one can't be
reproduced without a config (`shell_integration` isn't on by default,
so..), however the issue itself is still valid

For issue 1, the default prompt needs to know about the
`shell_integration` config, and the markers are added around the default
prompt when that's on.

For issue 2, this is actually related to transient prompts. When
rendering, the markers weren't added like for normal prompts.

After the fix the output do now contain the proper markers:

Reproducing the minimum config here for convenience:

```nu
$env.config = {
    show_banner: false
    shell_integration: true
}
# $env.PROMPT_COMMAND = {|| "> " }
```

For issue 1, the output looks like: 
```
[2.3490236,"o","\u001b[?25l\u001b[21;1H\u001b[21;1H\u001b[J\u001b[38;5;10m\u001b]133;A\u001b\\/home/steven\u001b]133;B\u001b\\\u001b[38;5;14m\u001b[38;5;5m\u001b7\u001b[21;84H12/16/2023 03:31:58 PM\u001b8\u001b[0m\u001b[0m\u001b[1;36mecho\u001b[0m\u001b7\u001b8\u001b[?25h"]
[2.5676293,"o","\u001b[6n"]
[2.571353,"o","\u001b[?25l\u001b[21;1H\u001b[21;1H\u001b[J\u001b[38;5;10m\u001b]133;A\u001b\\\u001b]133;A\u001b\\/home/steven\u001b]133;B\u001b\\\u001b]133;B\u001b\\\u001b[38;5;14m\u001b[38;5;5m\u001b7\u001b[21;84H12/16/2023 03:31:59 PM\u001b8\u001b[0m\u001b[0m\u001b[1;36mecho\u001b[0m\u001b7\u001b8\u001b[?25h\u001b[21;1H\r\n\u001b[21;1H"]
[2.571436,"o","\u001b[?2004l"]
[2.5714657,"o","\u001b]133;C\u001b\\"]
```
in line 3, where enter is pressed, `133 A` and `B` are present.

Same for issue 2 (uncomment the `PROMPT_COMMAND` line in the config):
```
[1.9585224,"o","\u001b[?25l\u001b[21;1H\u001b[21;1H\u001b[J\u001b[38;5;10m\u001b]133;A\u001b\\> \u001b]133;B\u001b\\\u001b[38;5;14m\u001b[38;5;5m\u001b7\u001b[21;84H12/16/2023 03:32:15 PM\u001b8\u001b[0m\u001b[0m\u001b[1;36mecho\u001b[0m\u001b7\u001b8\u001b[?25h"]
[2.453972,"o","\u001b[6n"]
[2.4585786,"o","\u001b[?25l\u001b[21;1H\u001b[21;1H\u001b[J\u001b[38;5;10m\u001b]133;A\u001b\\\u001b]133;A\u001b\\> \u001b]133;B\u001b\\\u001b]133;B\u001b\\\u001b[38;5;14m\u001b[38;5;5m\u001b7\u001b[21;84H12/16/2023 03:32:15 PM\u001b8\u001b[0m\u001b[0m\u001b[1;36mecho\u001b[0m\u001b7\u001b8\u001b[?25h\u001b[21;1H\r\n\u001b[21;1H\u001b[?2004l\u001b]133;C\u001b\\\r\n\u001b]133;D;0\u001b\\\u001b]7;file://Aostro-5468/home/steven\u001b\\\u001b]2;~\u0007\u001b[?1l"]
[2.4669976,"o","\u001b[?2004h\u001b[6n"]
[2.4703515,"o","\u001b[6n"]
[2.4736586,"o","\u001b[?25l\u001b[21;1H\u001b[21;1H\u001b[J\u001b[38;5;10m\u001b]133;A\u001b\\> \u001b]133;B\u001b\\\u001b[38;5;14m\u001b[38;5;5m\u001b7\u001b[21;84H12/16/2023 03:32:15 PM\u001b8\u001b[0m\u001b[0m\u001b7\u001b8\u001b[?25h"]
```

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

None user facing changes other than that prompt markers are working

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2023-12-16 20:12:34 -06:00
247c33b6d6 Satisfy clippy lint in benchmark (#11350)
Fixes the two `clippy::let_and_return` lints in `benchmark.rs`.
2023-12-16 21:06:42 +01:00
a6da8ce769 Allow filesize type as a valid limit value (#11349)
# Description
This pr allow us to use `filesize` type as a valid limit value, which is
benefit for some file size based limits.

# User-Facing Changes
```console
/data/source/nushell> ulimit -f                                                                                                   
╭───┬─────────────────────────────────────────────────────┬───────────┬───────────╮
│ # │                     description                     │   soft    │   hard    │
├───┼─────────────────────────────────────────────────────┼───────────┼───────────┤
│ 0 │ Maximum size of files created by the shell (kB, -f) │ unlimited │ unlimited │
╰───┴─────────────────────────────────────────────────────┴───────────┴───────────╯
/data/source/nushell> ulimit -f 10Mib                                                                                           
/data/source/nushell> ulimit -f                                                                                                    
╭───┬─────────────────────────────────────────────────────┬───────┬───────╮
│ # │                     description                     │ soft  │ hard  │
├───┼─────────────────────────────────────────────────────┼───────┼───────┤
│ 0 │ Maximum size of files created by the shell (kB, -f) │ 10240 │ 10240 │
╰───┴─────────────────────────────────────────────────────┴───────┴───────╯
/data/source/nushell> ulimit -n                                                                                                 
╭───┬──────────────────────────────────────────────┬──────┬────────╮
│ # │                 description                  │ soft │  hard  │
├───┼──────────────────────────────────────────────┼──────┼────────┤
│ 0 │ Maximum number of open file descriptors (-n) │ 1024 │ 524288 │
╰───┴──────────────────────────────────────────────┴──────┴────────╯
/data/source/nushell> ulimit -n 10Mib                                                                                            
Error: nu:🐚:type_mismatch

  × Type mismatch.
   ╭─[entry #5:1:1]
 1 │ ulimit -n 10Mib
   ·             ─┬─
   ·              ╰── filesize is not compatible with resource RLIMIT_NOFILE
   ╰────
```

# Tests + Formatting
Make sure you've run and fixed any issues with these commands:

- [x] add `commands::ulimit::limit_set_filesize1`
- [x] add `commands::ulimit::limit_set_filesize2`
- [x] `cargo fmt --all -- --check` to check standard code formatting
(`cargo fmt --all` applies these changes)
- [x] `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used`
to check that you're using the standard code style
- [x] `cargo test --workspace` to check that all tests pass (on Windows
make sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- [x] `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library
2023-12-16 09:56:03 -06:00
020e121391 Bubble up errors passed to complete (#11313)
Errors passed in `PipelineData::Value` get thrown in `complete` now.

Also added two simple tests for the command.

Fix #11187
Fix #10204
2023-12-16 09:07:08 -06:00
7d5bd0d6be Allow int type as a valid limit value (#11346)
# Description
This PR allows `int` type as a valid limit value for `ulimit`, so there
is no need to use `into string` to convert limit values in the tests.

# User-Facing Changes
N/A

# Tests + Formatting
Make sure you've run and fixed any issues with these commands:
- [x] add `commands::ulimit::limit_set_invalid3`
- [x] add `commands::ulimit::limit_set_invalid4`
- [x] add `commands::ulimit::limit_set_invalid5`
- [x] `cargo fmt --all -- --check` to check standard code formatting
(`cargo fmt --all` applies these changes)
- [x] `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used`
to check that you're using the standard code style
- [x] `cargo test --workspace` to check that all tests pass (on Windows
make sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- [x] `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library
2023-12-16 08:55:44 -06:00
87717b9ddd Don't redraw prompt when transient prompt disabled (#10788)
# 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.
-->

moonlander pointed out in Discord that the transient prompt feature
added in release 0.86 (implemented in #10391) is causing the normal
prompt to be redrawn when the transient prompt variables are unset or
set to null. This PR is for fixing that, although it's more of a bandaid
fix. Maybe the transient prompt feature should be taken out entirely for
now so more thought can be given to its implementation.

Previously, I'd thought that when reedline redraws the prompt after a
command is entered, it's a whole new prompt, but apparently it's
actually the same prompt as the current line (?). So now, `nu_prompt` in
`repl.rs` is an `Arc<RwLock<NushellPrompt>>` (rather than just a
`NushellPrompt`), and this `Arc` is shared with the `TransientPrompt`
object so that if it can't find one of the `TRANSIENT_PROMPT_*`
variables, it uses a segment from `NushellPrompt` rather than
re-evaluate `PROMPT_COMMAND`, `PROMPT_COMMAND_RIGHT`, etc. Using an
`RwLock` means that there's a bunch of `.expect()`s all over the place,
which is not nice. It could perhaps be avoided with some changes on the
reedline side.

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

`$env.PROMPT_COMMAND` (and other such variables) should no longer be
executed twice if the corresponding `$env.TRANSIENT_PROMPT_*` variable
is not set.

<!--
Don't forget to add tests that cover your changes.

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

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

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

# Steps to reproduce

Described by moonlander in Discord
[here](https://discord.com/channels/601130461678272522/614593951969574961/1164928022126792844).

Adding this to `env.nu` will result in `11` being added to
`/tmp/run_count` every time any command is run. The expected behavior is
a single `1` being added to `/tmp/run_count` instead of two. The prompt
command should not be executed again when the prompt is redrawn after a
command is executed.

```nu
$env.PROMPT_COMMAND = {||
  touch /tmp/run_count
  '1' | save /tmp/run_count --append
  '>'
}

# $env.TRANSIENT_PROMPT_COMMAND not set
```

If the following is added to `env.nu`, then `12` will be added to
`/tmp/run_count` every time any command is run, which is expected
behavior because the normal prompt command must be displayed the first
time the prompt is shown, then the transient prompt command is run when
the prompt is redrawn.
```nu
$env.TRANSIENT_PROMPT_COMMAND = {||
  touch /tmp/run_count
  '2' | save /tmp/run_count --append
  '>'
}
```

Here's a screenshot of what adding that first snippet looks like (`cargo
run` in the `main` branch):

![image](https://github.com/nushell/nushell/assets/45539777/b27a5c07-55b4-43c7-8a2c-0deba2d9d53a)


Here's a screenshot of what it looks like with this PR (only one `1` is
added to `/tmp/run_count` each time):

![image](https://github.com/nushell/nushell/assets/45539777/2b5c0a3a-8566-4428-9fda-1ffcc1dd6ae3)
2023-12-15 13:41:44 -06:00
3c6fac059e Properly update to the reedline repo patch (#11342)
Follow up to #11339
2023-12-15 20:16:36 +01:00
9092fc1b12 Revert "Only run $env.PROMPT_COMMAND once per prompt" (#11340)
Reverts nushell/nushell#10986

@CAD97 This isn't working right. I have a 2 line prompt with a transient
prompt. on enter, you see the transient prompt drawn and then the normal
prompt overwrites it.
2023-12-15 11:58:32 -06:00
5b557a888e update reedline to latest + include PR 675 for testing (#11339)
# Description

This PR updates to the latest reedline main branch which includes
reedline 27.1 and reedline PR
https://github.com/nushell/reedline/pull/675 for better resize behavior.

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

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

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

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

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

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
2023-12-15 11:48:54 -06:00
398b756aee Make hover equal to help command (#11320)
# Description
Hi! A few days ago I changed the hover from `--ide-lsp` to match `help`
#11284, now this PR is doing the same but for the new `--lsp` server

I also did some tiny fixes to syntax, with some clippy `pedantic` lints

# User-Facing Changes

![image](https://github.com/nushell/nushell/assets/30557287/0e167dc8-777a-4961-8746-aa29f18eccfa)


# Tests + Formatting
 ran `toolkit check pr`
2023-12-15 11:39:19 -06:00
533c1a89af Only run $env.PROMPT_COMMAND once per prompt (#10986)
# Description

If `$env.TRANSIENT_PROMPT_COMMAND` is not set, use the prompt created by
`$env.PROMPT_COMMAND` instead of running the command a second time. As a
side effect, `$env.TRANSIENT_PROMPT_COMMAND` now runs after the hooks
`pre_prompt` and `env_change`, instead of before.

# User-Facing Changes

- `$env.PROMPT_COMMAND` gets run only once per prompt instead of twice
- `$env.TRANSIENT_PROMPT_COMMAND` now sees any environment set in a
`pre_prompt` or `env_change` hook, like `$env.PROMPT_COMMAND` does
2023-12-15 07:56:29 -06:00
84742275a1 Add ulimit command (#11324)
# Description
Add `ulimit` command to Nushell.

Closes #9563
Closes #3976

Related pr #11246

Reference:
https://github.com/fish-shell/fish-shell/blob/master/fish-rust/src/builtins/ulimit.rs
https://github.com/mirror/busybox/blob/master/shell/shell_common.c#L529

# User-Facing Changes
```
nushell on  ulimit is 📦 v0.88.2 via 🦀 v1.72.1                                                                                                [3/246]
❯ ulimit -a
╭────┬──────────────────────────────────────────────────────────────────────────┬───────────┬───────────╮
│  # │                               description                                │   soft    │   hard    │
├────┼──────────────────────────────────────────────────────────────────────────┼───────────┼───────────┤
│  0 │ Maximum size of core files created                              (kB, -c) │ unlimited │ unlimited │
│  1 │ Maximum size of a process's data segment                        (kB, -d) │ unlimited │ unlimited │
│  2 │ Controls of maximum nice priority                                   (-e) │         0 │         0 │
│  3 │ Maximum size of files created by the shell                      (kB, -f) │ unlimited │ unlimited │
│  4 │ Maximum number of pending signals                                   (-i) │     55273 │     55273 │
│  5 │ Maximum size that may be locked into memory                     (kB, -l) │      8192 │      8192 │
│  6 │ Maximum resident set size                                       (kB, -m) │ unlimited │ unlimited │
│  7 │ Maximum number of open file descriptors                             (-n) │      1024 │    524288 │
│  8 │ Maximum bytes in POSIX message queues                           (kB, -q) │       800 │       800 │
│  9 │ Maximum realtime scheduling priority                                (-r) │         0 │         0 │
│ 10 │ Maximum stack size                                              (kB, -s) │      8192 │ unlimited │
│ 11 │ Maximum amount of CPU time in seconds                      (seconds, -t) │ unlimited │ unlimited │
│ 12 │ Maximum number of processes available to the current user           (-u) │     55273 │     55273 │
│ 13 │ Maximum amount of virtual memory available to each process      (kB, -v) │ unlimited │ unlimited │
│ 14 │ Maximum number of file locks                                        (-x) │ unlimited │ unlimited │
│ 15 │ Maximum contiguous realtime CPU time                                (-y) │ unlimited │ unlimited │
╰────┴──────────────────────────────────────────────────────────────────────────┴───────────┴───────────╯
nushell on  ulimit is 📦 v0.88.2 via 🦀 v1.72.1
❯ ulimit -s
╭───┬─────────────────────────────┬──────┬───────────╮
│ # │         description         │ soft │   hard    │
├───┼─────────────────────────────┼──────┼───────────┤
│ 0 │ Maximum stack size (kB, -s) │ 8192 │ unlimited │
╰───┴─────────────────────────────┴──────┴───────────╯
nushell on  ulimit is 📦 v0.88.2 via 🦀 v1.72.1
❯ ulimit -s 100
nushell on  ulimit is 📦 v0.88.2 via 🦀 v1.72.1
❯ ulimit -s
╭───┬─────────────────────────────┬──────┬──────╮
│ # │         description         │ soft │ hard │
├───┼─────────────────────────────┼──────┼──────┤
│ 0 │ Maximum stack size (kB, -s) │  100 │  100 │
╰───┴─────────────────────────────┴──────┴──────╯
nushell on  ulimit is 📦 v0.88.2 via 🦀 v1.72.1
```

# Tests + Formatting
- [x] add commands::ulimit::limit_set_soft1
- [x] add commands::ulimit::limit_set_soft2
- [x] add commands::ulimit::limit_set_hard1
- [x] add commands::ulimit::limit_set_hard2
- [x] add commands::ulimit::limit_set_invalid1
- [x] add commands::ulimit::limit_set_invalid2
- [x] `cargo fmt --all -- --check` to check standard code formatting
(`cargo fmt --all` applies these changes)
- [x] `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used`
to check that you're using the standard code style
- [x] `cargo test --workspace` to check that all tests pass (on Windows
make sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- [x] `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library
2023-12-15 07:11:17 -06:00
92d968b8c8 ♻️ Match --ide-hover with help command (#11284)
# Description
Hi! @fdncred pointed that the `help` command doesn't give the same
result as hovering a command in the VS Code extension. I digged out that
this trace back from `src/ide.rs`, so I decided to change this: (look at
the window of VS Code when hovering help)

![image](https://github.com/nushell/nushell/assets/30557287/32e24090-9238-423e-88ba-7dd6eb53d885)

into this:

![image](https://github.com/nushell/nushell/assets/30557287/51457cf7-4baf-4220-b901-66a78f7ee817)


# User-Facing Changes
The `--ide-hover` change a lot, by matching the `help` command of the
terminal nushell

The only missing part is the `subcommands` part

# Tests + Formatting
All good!

# After Submitting
2023-12-15 07:00:08 -06:00
50102bf69b Move history into their own module (#11308)
# Description

Since there are plans to add more history commands, it seems sensible to
put them into their own module and category

https://github.com/nushell/nushell/pull/10440#issuecomment-1731408785

# User-Facing Changes

The history commands are in the category "History" rather than "Misc"
2023-12-15 13:17:12 +01:00
156232fe08 disable directory submodule auto export (#11157)
should
- close https://github.com/nushell/nushell/issues/11133

# Description
to allow more freedom when writing complex modules, we are disabling the
auto-export of director modules.

the change was as simple as removing the crawling of files and modules
next to any `mod.nu` and update the standard library.

# User-Facing Changes
users will have to explicitely use `export module <mod>` to define
submodules and `export use <mod> <cmd>` to re-export definitions, e.g.
```nushell
# my-module/mod.nu
export module foo.nu     # export a submodule
export use bar.nu bar-1  # re-export an internal command

export def top [] {
    print "`top` from `mod.nu`"
}
```
```nushell
# my-module/foo.nu
export def "foo-1" [] {
    print "`foo-1` from `lib/foo.nu`"
}

export def "foo-2" [] {
    print "`foo-2` from `lib/foo.nu`"
}
```
```nushell
# my-module/bar.nu
export def "bar-1" [] {
    print "`bar-1` from `lib/bar.nu`"
}
```

# Tests + Formatting
i had to add `export module` calls in the `tests/modules/samples/spam`
directory module and allow the `not_allowed` module to not give an
error, it is just empty, which is fine.

# After Submitting
- mention in the release note
- update the following repos
```
#┬─────name─────┬version┬─type─┬─────────repo─────────
0│nu-git-manager│0.4.0  │module│amtoine/nu-git-manager
1│nu-scripts    │0.1.0  │module│amtoine/scripts       
2│nu-zellij     │0.1.0  │module│amtoine/zellij-layouts
3│nu-scripts    │0.1.0  │module│nushell/nu_scripts    
4│nupm          │0.1.0  │module│nushell/nupm          
─┴──────────────┴───────┴──────┴──────────────────────
```
2023-12-15 12:37:55 +01:00
0a3761a594 Bump zerocopy from 0.7.29 to 0.7.31 (#11336) 2023-12-15 10:40:56 +00:00
44dc890124 Polars Struct support without unsafe blocks (#11229)
Second attempt at polars Struct support. This version avoid using unsafe
checks by cloning the StructArray and utilizing the into_static to
convert to a StructOwned.

---------

Co-authored-by: Jack Wright <jack.wright@disqo.com>
2023-12-15 11:21:30 +01:00
6ead98effb Bump actions/setup-python from 4 to 5 (#11279)
Bumps [actions/setup-python](https://github.com/actions/setup-python)
from 4 to 5.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/setup-python/releases">actions/setup-python's
releases</a>.</em></p>
<blockquote>
<h2>v5.0.0</h2>
<h2>What's Changed</h2>
<p>In scope of this release, we update node version runtime from node16
to node20 (<a
href="https://redirect.github.com/actions/setup-python/pull/772">actions/setup-python#772</a>).
Besides, we update dependencies to the latest versions.</p>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-python/compare/v4.8.0...v5.0.0">https://github.com/actions/setup-python/compare/v4.8.0...v5.0.0</a></p>
<h2>v4.8.0</h2>
<h2>What's Changed</h2>
<p>In scope of this release we added support for GraalPy (<a
href="https://redirect.github.com/actions/setup-python/pull/694">actions/setup-python#694</a>).
You can use this snippet to set up GraalPy:</p>
<pre lang="yaml"><code>steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4 
  with:
    python-version: 'graalpy-22.3' 
- run: python my_script.py
</code></pre>
<p>Besides, the release contains such changes as:</p>
<ul>
<li>Trim python version when reading from file by <a
href="https://github.com/FerranPares"><code>@​FerranPares</code></a> in
<a
href="https://redirect.github.com/actions/setup-python/pull/628">actions/setup-python#628</a></li>
<li>Use non-deprecated versions in examples by <a
href="https://github.com/jeffwidman"><code>@​jeffwidman</code></a> in <a
href="https://redirect.github.com/actions/setup-python/pull/724">actions/setup-python#724</a></li>
<li>Change deprecation comment to past tense by <a
href="https://github.com/jeffwidman"><code>@​jeffwidman</code></a> in <a
href="https://redirect.github.com/actions/setup-python/pull/723">actions/setup-python#723</a></li>
<li>Bump <code>@​babel/traverse</code> from 7.9.0 to 7.23.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/setup-python/pull/743">actions/setup-python#743</a></li>
<li>advanced-usage.md: Encourage the use actions/checkout@v4 by <a
href="https://github.com/cclauss"><code>@​cclauss</code></a> in <a
href="https://redirect.github.com/actions/setup-python/pull/729">actions/setup-python#729</a></li>
<li>Examples now use checkout@v4 by <a
href="https://github.com/simonw"><code>@​simonw</code></a> in <a
href="https://redirect.github.com/actions/setup-python/pull/738">actions/setup-python#738</a></li>
<li>Update actions/checkout to v4 by <a
href="https://github.com/dmitry-shibanov"><code>@​dmitry-shibanov</code></a>
in <a
href="https://redirect.github.com/actions/setup-python/pull/761">actions/setup-python#761</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/FerranPares"><code>@​FerranPares</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/setup-python/pull/628">actions/setup-python#628</a></li>
<li><a href="https://github.com/timfel"><code>@​timfel</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/setup-python/pull/694">actions/setup-python#694</a></li>
<li><a
href="https://github.com/jeffwidman"><code>@​jeffwidman</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/setup-python/pull/724">actions/setup-python#724</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-python/compare/v4...v4.8.0">https://github.com/actions/setup-python/compare/v4...v4.8.0</a></p>
<h2>v4.7.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Bump word-wrap from 1.2.3 to 1.2.4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/setup-python/pull/702">actions/setup-python#702</a></li>
<li>Add range validation for toml files by <a
href="https://github.com/dmitry-shibanov"><code>@​dmitry-shibanov</code></a>
in <a
href="https://redirect.github.com/actions/setup-python/pull/726">actions/setup-python#726</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-python/compare/v4...v4.7.1">https://github.com/actions/setup-python/compare/v4...v4.7.1</a></p>
<h2>v4.7.0</h2>
<p>In scope of this release, the support for reading python version from
pyproject.toml was added (<a
href="https://redirect.github.com/actions/setup-python/pull/669">actions/setup-python#669</a>).</p>
<pre lang="yaml"><code>      - name: Setup Python
        uses: actions/setup-python@v4
&lt;/tr&gt;&lt;/table&gt; 
</code></pre>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="0a5c615913"><code>0a5c615</code></a>
Update action to node20 (<a
href="https://redirect.github.com/actions/setup-python/issues/772">#772</a>)</li>
<li><a
href="0ae58361cd"><code>0ae5836</code></a>
Add example of GraalPy to docs (<a
href="https://redirect.github.com/actions/setup-python/issues/773">#773</a>)</li>
<li><a
href="b64ffcaf5b"><code>b64ffca</code></a>
update actions/checkout to v4 (<a
href="https://redirect.github.com/actions/setup-python/issues/761">#761</a>)</li>
<li><a
href="8d2896179a"><code>8d28961</code></a>
Examples now use checkout@v4 (<a
href="https://redirect.github.com/actions/setup-python/issues/738">#738</a>)</li>
<li><a
href="7bc6abb01e"><code>7bc6abb</code></a>
advanced-usage.md: Encourage the use actions/checkout@v4 (<a
href="https://redirect.github.com/actions/setup-python/issues/729">#729</a>)</li>
<li><a
href="e8111cec9d"><code>e8111ce</code></a>
Bump <code>@​babel/traverse</code> from 7.9.0 to 7.23.2 (<a
href="https://redirect.github.com/actions/setup-python/issues/743">#743</a>)</li>
<li><a
href="a00ea43da6"><code>a00ea43</code></a>
add fix for graalpy ci (<a
href="https://redirect.github.com/actions/setup-python/issues/741">#741</a>)</li>
<li><a
href="8635b1ccc5"><code>8635b1c</code></a>
Change deprecation comment to past tense (<a
href="https://redirect.github.com/actions/setup-python/issues/723">#723</a>)</li>
<li><a
href="f6cc428f53"><code>f6cc428</code></a>
Use non-deprecated versions in examples (<a
href="https://redirect.github.com/actions/setup-python/issues/724">#724</a>)</li>
<li><a
href="5f2af211d6"><code>5f2af21</code></a>
Add GraalPy support (<a
href="https://redirect.github.com/actions/setup-python/issues/694">#694</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/setup-python/compare/v4...v5">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/setup-python&package-manager=github_actions&previous-version=4&new-version=5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

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

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

---

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

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


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-15 15:31:18 +08:00
d5f76c02f0 Bump crate-ci/typos from 1.16.23 to 1.16.24 (#11280)
Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.16.23
to 1.16.24.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/releases">crate-ci/typos's
releases</a>.</em></p>
<blockquote>
<h2>v1.16.24</h2>
<h2>[1.16.24] - 2023-12-08</h2>
<h3>Fixes</h3>
<ul>
<li>Don't silently ignore config when there is an error in a field</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/blob/master/CHANGELOG.md">crate-ci/typos's
changelog</a>.</em></p>
<blockquote>
<h2>[1.16.24] - 2023-12-08</h2>
<h3>Fixes</h3>
<ul>
<li>Don't silently ignore config when there is an error in a field</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="548ac37a5d"><code>548ac37</code></a>
chore: Release</li>
<li><a
href="a838b1820f"><code>a838b18</code></a>
chore: Release</li>
<li><a
href="44e4455f33"><code>44e4455</code></a>
docs: Update changelog</li>
<li><a
href="4362a6e5e4"><code>4362a6e</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/882">#882</a>
from epage/regex</li>
<li><a
href="1b92c0182c"><code>1b92c01</code></a>
fix(config): Propagate validation errors</li>
<li><a
href="632b256901"><code>632b256</code></a>
test: Demonstrate bad config bug</li>
<li><a
href="8dec26e3c6"><code>8dec26e</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/879">#879</a>
from epage/update</li>
<li><a
href="69f4b1eaff"><code>69f4b1e</code></a>
chore: Move off deprecated</li>
<li><a
href="cb9b485bd3"><code>cb9b485</code></a>
chore: Update from '_rust/main'</li>
<li><a
href="8c836eaa9d"><code>8c836ea</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/10">#10</a> from
epage/renovate/migrate-config</li>
<li>Additional commits viewable in <a
href="https://github.com/crate-ci/typos/compare/v1.16.23...v1.16.24">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=crate-ci/typos&package-manager=github_actions&previous-version=1.16.23&new-version=1.16.24)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

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

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

---

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

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


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-15 15:31:04 +08:00
fd77114d82 Add format meta command (#11334) 2023-12-15 14:57:18 +08:00
78f52e8b66 Replace bash with POSIX sh in tests (#11293)
Just my small pet peeve. This allows to run tests without bash
installed.

There were only two minor tests which required a change.
2023-12-15 14:53:19 +08:00
5b01685fc3 Enforce required, optional, and rest positional arguments start with an uppercase and end with a period. (#11285)
# Description

This updates all the positional arguments (except with
`--features=dataframe` or `--features=extra`) to start with an uppercase
letter and end with a period.

Part of #5066, specifically [this
comment](/nushell/nushell/issues/5066#issuecomment-1421528910)

Some arguments had example data removed from them because it also
appears in the examples.

There are other inconsistencies in positional arguments I noticed while
making the tests pass which I will bring up in #5066.

# User-Facing Changes

Positional arguments are now consistent

# Tests + Formatting

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

# After Submitting

Automatic documentation updates
2023-12-15 14:32:37 +08:00
c2b684464f Bump version to 0.88.2 (#11333) 2023-12-14 13:55:48 -06:00
597 changed files with 15035 additions and 8569 deletions

1
.github/.typos.toml vendored
View File

@ -12,3 +12,4 @@ IIF = "IIF"
numer = "numer"
ratatui = "ratatui"
doas = "doas"
wheres = "wheres"

View File

@ -41,7 +41,7 @@ jobs:
- uses: actions/checkout@v4
- name: Setup Rust toolchain and cache
uses: actions-rust-lang/setup-rust-toolchain@v1.6.0
uses: actions-rust-lang/setup-rust-toolchain@v1.8.0
with:
rustflags: ""
@ -63,6 +63,10 @@ jobs:
platform: [windows-latest, macos-latest, ubuntu-20.04]
feature: [default, dataframe, extra]
include:
# linux CI cannot handle clipboard feature
- default-flags: ""
- platform: ubuntu-20.04
default-flags: "--no-default-features --features=default-no-clipboard"
- feature: default
flags: ""
- feature: dataframe
@ -85,12 +89,23 @@ jobs:
- uses: actions/checkout@v4
- name: Setup Rust toolchain and cache
uses: actions-rust-lang/setup-rust-toolchain@v1.6.0
uses: actions-rust-lang/setup-rust-toolchain@v1.8.0
with:
rustflags: ""
- name: Tests
run: cargo test --workspace --profile ci --exclude nu_plugin_* ${{ matrix.flags }}
run: cargo test --workspace --profile ci --exclude nu_plugin_* ${{ matrix.default-flags }} ${{ matrix.flags }}
- name: Check for clean repo
shell: bash
run: |
if [ -n "$(git status --porcelain)" ]; then
echo "there are changes";
git status --porcelain
exit 1
else
echo "no changes in working directory";
fi
std-lib-and-python-virtualenv:
strategy:
@ -106,7 +121,7 @@ jobs:
- uses: actions/checkout@v4
- name: Setup Rust toolchain and cache
uses: actions-rust-lang/setup-rust-toolchain@v1.6.0
uses: actions-rust-lang/setup-rust-toolchain@v1.8.0
with:
rustflags: ""
@ -114,10 +129,10 @@ jobs:
run: cargo install --path . --locked --no-default-features
- name: Standard library tests
run: nu -c 'use std testing; testing run-tests --path crates/nu-std'
run: nu -c 'use crates/nu-std/testing.nu; testing run-tests --path crates/nu-std'
- name: Setup Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: "3.10"
@ -129,6 +144,17 @@ jobs:
run: nu scripts/test_virtualenv.nu
shell: bash
- name: Check for clean repo
shell: bash
run: |
if [ -n "$(git status --porcelain)" ]; then
echo "there are changes";
git status --porcelain
exit 1
else
echo "no changes in working directory";
fi
plugins:
strategy:
fail-fast: true
@ -141,7 +167,7 @@ jobs:
- uses: actions/checkout@v4
- name: Setup Rust toolchain and cache
uses: actions-rust-lang/setup-rust-toolchain@v1.6.0
uses: actions-rust-lang/setup-rust-toolchain@v1.8.0
with:
rustflags: ""
@ -150,3 +176,14 @@ jobs:
- name: Tests
run: cargo test --profile ci --package nu_plugin_*
- name: Check for clean repo
shell: bash
run: |
if [ -n "$(git status --porcelain)" ]; then
echo "there are changes";
git status --porcelain
exit 1
else
echo "no changes in working directory";
fi

View File

@ -81,7 +81,7 @@ jobs:
- x86_64-unknown-linux-musl
- aarch64-unknown-linux-gnu
- armv7-unknown-linux-gnueabihf
- riscv64gc-unknown-linux-gnu
# - riscv64gc-unknown-linux-gnu
extra: ['bin']
include:
- target: aarch64-apple-darwin
@ -118,9 +118,9 @@ jobs:
- target: armv7-unknown-linux-gnueabihf
os: ubuntu-20.04
target_rustflags: ''
- target: riscv64gc-unknown-linux-gnu
os: ubuntu-20.04
target_rustflags: ''
# - target: riscv64gc-unknown-linux-gnu
# os: ubuntu-latest
# target_rustflags: ''
runs-on: ${{matrix.os}}
@ -135,7 +135,7 @@ jobs:
echo "targets = ['${{matrix.target}}']" >> rust-toolchain.toml
- name: Setup Rust toolchain and cache
uses: actions-rust-lang/setup-rust-toolchain@v1.6.0
uses: actions-rust-lang/setup-rust-toolchain@v1.8.0
# WARN: Keep the rustflags to prevent from the winget submission error: `CAQuietExec: Error 0xc0000135`
with:
rustflags: ''
@ -249,7 +249,7 @@ jobs:
echo "targets = ['${{matrix.target}}']" >> rust-toolchain.toml
- name: Setup Rust toolchain and cache
uses: actions-rust-lang/setup-rust-toolchain@v1.6.0
uses: actions-rust-lang/setup-rust-toolchain@v1.8.0
# WARN: Keep the rustflags to prevent from the winget submission error: `CAQuietExec: Error 0xc0000135`
with:
rustflags: ''

View File

@ -82,8 +82,8 @@ print $'Start building ($bin)...'; hr-line
# ----------------------------------------------------------------------------
# Build for Ubuntu and macOS
# ----------------------------------------------------------------------------
if $os in [$USE_UBUNTU, 'macos-latest'] {
if $os == $USE_UBUNTU {
if $os in [$USE_UBUNTU, 'macos-latest', 'ubuntu-latest'] {
if $os starts-with ubuntu {
sudo apt update
sudo apt-get install libxcb-composite0-dev -y
}
@ -106,7 +106,7 @@ if $os in [$USE_UBUNTU, 'macos-latest'] {
_ => {
# musl-tools to fix 'Failed to find tool. Is `musl-gcc` installed?'
# Actually just for x86_64-unknown-linux-musl target
if $os == $USE_UBUNTU { sudo apt install musl-tools -y }
if $os starts-with ubuntu { sudo apt install musl-tools -y }
cargo-build-nu $flags
}
}
@ -153,7 +153,7 @@ if ($ver | str trim | is-empty) {
# Create a release archive and send it to output for the following steps
# ----------------------------------------------------------------------------
cd $dist; print $'(char nl)Creating release archive...'; hr-line
if $os in [$USE_UBUNTU, 'macos-latest'] {
if $os in [$USE_UBUNTU, 'macos-latest', 'ubuntu-latest'] {
let files = (ls | get name)
let dest = if $env.RELEASE_TYPE == 'full' { $'($bin)-($version)-($FULL_NAME)' } else { $'($bin)-($version)-($target)' }

View File

@ -28,7 +28,7 @@ jobs:
- x86_64-unknown-linux-musl
- aarch64-unknown-linux-gnu
- armv7-unknown-linux-gnueabihf
- riscv64gc-unknown-linux-gnu
# - riscv64gc-unknown-linux-gnu
extra: ['bin']
include:
- target: aarch64-apple-darwin
@ -65,9 +65,9 @@ jobs:
- target: armv7-unknown-linux-gnueabihf
os: ubuntu-20.04
target_rustflags: ''
- target: riscv64gc-unknown-linux-gnu
os: ubuntu-20.04
target_rustflags: ''
# - target: riscv64gc-unknown-linux-gnu
# os: ubuntu-latest
# target_rustflags: ''
runs-on: ${{matrix.os}}
@ -79,7 +79,7 @@ jobs:
echo "targets = ['${{matrix.target}}']" >> rust-toolchain.toml
- name: Setup Rust toolchain and cache
uses: actions-rust-lang/setup-rust-toolchain@v1.6.0
uses: actions-rust-lang/setup-rust-toolchain@v1.8.0
# WARN: Keep the rustflags to prevent from the winget submission error: `CAQuietExec: Error 0xc0000135`
with:
rustflags: ''
@ -170,7 +170,7 @@ jobs:
echo "targets = ['${{matrix.target}}']" >> rust-toolchain.toml
- name: Setup Rust toolchain and cache
uses: actions-rust-lang/setup-rust-toolchain@v1.6.0
uses: actions-rust-lang/setup-rust-toolchain@v1.8.0
# WARN: Keep the rustflags to prevent from the winget submission error: `CAQuietExec: Error 0xc0000135`
with:
rustflags: ''

View File

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

1614
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@ license = "MIT"
name = "nu"
repository = "https://github.com/nushell/nushell"
rust-version = "1.72.1"
version = "0.88.1"
version = "0.90.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -33,7 +33,11 @@ members = [
"crates/nu-cmd-lang",
"crates/nu-cmd-dataframe",
"crates/nu-command",
"crates/nu-color-config",
"crates/nu-explore",
"crates/nu-json",
"crates/nu-lsp",
"crates/nu-pretty-hex",
"crates/nu-protocol",
"crates/nu-plugin",
"crates/nu_plugin_inc",
@ -43,33 +47,38 @@ members = [
"crates/nu_plugin_custom_values",
"crates/nu_plugin_formats",
"crates/nu-std",
"crates/nu-table",
"crates/nu-term-grid",
"crates/nu-utils",
]
[dependencies]
nu-cli = { path = "./crates/nu-cli", version = "0.88.1" }
nu-color-config = { path = "./crates/nu-color-config", version = "0.88.1" }
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.88.1" }
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.88.1" }
nu-cmd-dataframe = { path = "./crates/nu-cmd-dataframe", version = "0.88.1", features = ["dataframe"], optional = true }
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.88.1", optional = true }
nu-command = { path = "./crates/nu-command", version = "0.88.1" }
nu-engine = { path = "./crates/nu-engine", version = "0.88.1" }
nu-explore = { path = "./crates/nu-explore", version = "0.88.1" }
nu-json = { path = "./crates/nu-json", version = "0.88.1" }
nu-lsp = { path = "./crates/nu-lsp/", version = "0.88.1" }
nu-parser = { path = "./crates/nu-parser", version = "0.88.1" }
nu-path = { path = "./crates/nu-path", version = "0.88.1" }
nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.88.1" }
nu-pretty-hex = { path = "./crates/nu-pretty-hex", version = "0.88.1" }
nu-protocol = { path = "./crates/nu-protocol", version = "0.88.1" }
nu-system = { path = "./crates/nu-system", version = "0.88.1" }
nu-table = { path = "./crates/nu-table", version = "0.88.1" }
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.88.1" }
nu-std = { path = "./crates/nu-std", version = "0.88.1" }
nu-utils = { path = "./crates/nu-utils", version = "0.88.1" }
nu-ansi-term = "0.49.0"
reedline = { version = "0.27.0", features = ["bashisms", "sqlite"] }
nu-cli = { path = "./crates/nu-cli", version = "0.90.0" }
nu-color-config = { path = "./crates/nu-color-config", version = "0.90.0" }
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.90.0" }
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.90.0" }
nu-cmd-dataframe = { path = "./crates/nu-cmd-dataframe", version = "0.90.0", features = [
"dataframe",
], optional = true }
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.90.0", optional = true }
nu-command = { path = "./crates/nu-command", version = "0.90.0" }
nu-engine = { path = "./crates/nu-engine", version = "0.90.0" }
nu-explore = { path = "./crates/nu-explore", version = "0.90.0" }
nu-json = { path = "./crates/nu-json", version = "0.90.0" }
nu-lsp = { path = "./crates/nu-lsp/", version = "0.90.0" }
nu-parser = { path = "./crates/nu-parser", version = "0.90.0" }
nu-path = { path = "./crates/nu-path", version = "0.90.0" }
nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.90.0" }
nu-pretty-hex = { path = "./crates/nu-pretty-hex", version = "0.90.0" }
nu-protocol = { path = "./crates/nu-protocol", version = "0.90.0" }
nu-system = { path = "./crates/nu-system", version = "0.90.0" }
nu-table = { path = "./crates/nu-table", version = "0.90.0" }
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.90.0" }
nu-std = { path = "./crates/nu-std", version = "0.90.0" }
nu-utils = { path = "./crates/nu-utils", version = "0.90.0" }
nu-ansi-term = "0.50.0"
reedline = { version = "0.29.0", features = ["bashisms", "sqlite"] }
crossterm = "0.27"
ctrlc = "3.4"
@ -83,7 +92,6 @@ time = "0.3"
[target.'cfg(not(target_os = "windows"))'.dependencies]
# Our dependencies don't use OpenSSL on Windows
openssl = { version = "0.10", features = ["vendored"], optional = true }
signal-hook = { version = "0.3", default-features = false }
[target.'cfg(windows)'.build-dependencies]
winresource = "0.1"
@ -97,7 +105,7 @@ nix = { version = "0.27", default-features = false, features = [
] }
[dev-dependencies]
nu-test-support = { path = "./crates/nu-test-support", version = "0.88.1" }
nu-test-support = { path = "./crates/nu-test-support", version = "0.90.0" }
assert_cmd = "2.0"
criterion = "0.5"
pretty_assertions = "1.4"
@ -114,7 +122,16 @@ plugin = [
"nu-protocol/plugin",
"nu-engine/plugin",
]
default = ["plugin", "which-support", "trash-support", "sqlite", "mimalloc"]
default = ["default-no-clipboard", "system-clipboard"]
# Enables convenient omitting of the system-clipboard feature, as it leads to problems in ci on linux
# See https://github.com/nushell/nushell/pull/11535
default-no-clipboard = [
"plugin",
"which-support",
"trash-support",
"sqlite",
"mimalloc",
]
stable = ["default"]
wasi = ["nu-cmd-lang/wasi"]
# NOTE: individual features are also passed to `nu-cmd-lang` that uses them to generate the feature matrix in the `version` command
@ -124,6 +141,7 @@ wasi = ["nu-cmd-lang/wasi"]
static-link-openssl = ["dep:openssl", "nu-cmd-lang/static-link-openssl"]
mimalloc = ["nu-cmd-lang/mimalloc", "dep:mimalloc"]
system-clipboard = ["reedline/system_clipboard"]
# Stable (Default)
which-support = ["nu-command/which-support", "nu-cmd-lang/which-support"]
@ -165,8 +183,8 @@ bench = false
# To use a development version of a dependency please use a global override here
# changing versions in each sub-crate of the workspace is tedious
[patch.crates-io]
# reedline = { git = "https://github.com/nushell/reedline.git", branch = "main" }
#[patch.crates-io]
#reedline = { git = "https://github.com/nushell/reedline", branch = "main" }
# nu-ansi-term = {git = "https://github.com/nushell/nu-ansi-term.git", branch = "main"}
# uu_cp = { git = "https://github.com/uutils/coreutils.git", branch = "main" }

View File

@ -24,13 +24,9 @@ fn canonicalize_path(engine_state: &EngineState, path: &Path) -> PathBuf {
}
fn get_home_path(engine_state: &EngineState) -> PathBuf {
let home_path = if let Some(path) = nu_path::home_dir() {
let canon_home_path = canonicalize_path(engine_state, &path);
canon_home_path
} else {
std::path::PathBuf::new()
};
home_path
nu_path::home_dir()
.map(|path| canonicalize_path(engine_state, &path))
.unwrap_or_default()
}
// FIXME: All benchmarks live in this 1 file to speed up build times when benchmarking.

View File

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

View File

@ -71,7 +71,7 @@ impl Command for Commandline {
if let Some(cmd) = call.opt::<Value>(engine_state, stack, 0)? {
let mut repl = engine_state.repl_state.lock().expect("repl state mutex");
if call.has_flag("cursor") {
if call.has_flag(engine_state, stack, "cursor")? {
let cmd_str = cmd.as_string()?;
match cmd_str.parse::<i64>() {
Ok(n) => {
@ -96,9 +96,9 @@ impl Command for Commandline {
})
}
}
} else if call.has_flag("append") {
} else if call.has_flag(engine_state, stack, "append")? {
repl.buffer.push_str(&cmd.as_string()?);
} else if call.has_flag("insert") {
} else if call.has_flag(engine_state, stack, "insert")? {
let cmd_str = cmd.as_string()?;
let cursor_pos = repl.cursor_pos;
repl.buffer.insert_str(cursor_pos, &cmd_str);
@ -110,10 +110,10 @@ impl Command for Commandline {
Ok(Value::nothing(call.head).into_pipeline_data())
} else {
let mut repl = engine_state.repl_state.lock().expect("repl state mutex");
if call.has_flag("cursor-end") {
repl.cursor_pos = repl.buffer.graphemes(true).count();
if call.has_flag(engine_state, stack, "cursor-end")? {
repl.cursor_pos = repl.buffer.len();
Ok(Value::nothing(call.head).into_pipeline_data())
} else if call.has_flag("cursor") {
} else if call.has_flag(engine_state, stack, "cursor")? {
let char_pos = repl
.buffer
.grapheme_indices(true)

View File

@ -1,3 +1,4 @@
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
@ -23,10 +24,7 @@ impl Command for History {
fn signature(&self) -> nu_protocol::Signature {
Signature::build("history")
.input_output_types(vec![
(Type::Nothing, Type::Table(vec![])),
(Type::Nothing, Type::Nothing),
])
.input_output_types(vec![(Type::Nothing, Type::Any)])
.allow_variants_without_examples(true)
.switch("clear", "Clears out the history entries", Some('c'))
.switch(
@ -34,27 +32,31 @@ impl Command for History {
"Show long listing of entries for sqlite history",
Some('l'),
)
.category(Category::Misc)
.category(Category::History)
}
fn run(
&self,
engine_state: &EngineState,
_stack: &mut Stack,
stack: &mut Stack,
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let head = call.head;
let Some(history) = engine_state.history_config() else {
return Ok(PipelineData::empty());
};
// todo for sqlite history this command should be an alias to `open ~/.config/nushell/history.sqlite3 | get history`
if let Some(config_path) = nu_path::config_dir() {
let clear = call.has_flag("clear");
let long = call.has_flag("long");
let clear = call.has_flag(engine_state, stack, "clear")?;
let long = call.has_flag(engine_state, stack, "long")?;
let ctrlc = engine_state.ctrlc.clone();
let mut history_path = config_path;
history_path.push("nushell");
match engine_state.config.history_file_format {
match history.file_format {
HistoryFileFormat::Sqlite => {
history_path.push("history.sqlite3");
}
@ -68,29 +70,27 @@ impl Command for History {
// TODO: FIXME also clear the auxiliary files when using sqlite
Ok(PipelineData::empty())
} else {
let history_reader: Option<Box<dyn ReedlineHistory>> =
match engine_state.config.history_file_format {
HistoryFileFormat::Sqlite => {
SqliteBackedHistory::with_file(history_path, None, None)
.map(|inner| {
let boxed: Box<dyn ReedlineHistory> = Box::new(inner);
boxed
})
.ok()
}
let history_reader: Option<Box<dyn ReedlineHistory>> = match history.file_format {
HistoryFileFormat::Sqlite => {
SqliteBackedHistory::with_file(history_path, None, None)
.map(|inner| {
let boxed: Box<dyn ReedlineHistory> = Box::new(inner);
boxed
})
.ok()
}
HistoryFileFormat::PlainText => FileBackedHistory::with_file(
engine_state.config.max_history_size as usize,
history_path,
)
.map(|inner| {
let boxed: Box<dyn ReedlineHistory> = Box::new(inner);
boxed
})
.ok(),
};
HistoryFileFormat::PlainText => {
FileBackedHistory::with_file(history.max_size as usize, history_path)
.map(|inner| {
let boxed: Box<dyn ReedlineHistory> = Box::new(inner);
boxed
})
.ok()
}
};
match engine_state.config.history_file_format {
match history.file_format {
HistoryFileFormat::PlainText => Ok(history_reader
.and_then(|h| {
h.search(SearchQuery::everything(SearchDirection::Forward, None))

View File

@ -18,7 +18,7 @@ impl Command for HistorySession {
fn signature(&self) -> nu_protocol::Signature {
Signature::build("history session")
.category(Category::Misc)
.category(Category::History)
.input_output_types(vec![(Type::Nothing, Type::Int)])
}

View File

@ -0,0 +1,5 @@
mod history_;
mod history_session;
pub use history_::History;
pub use history_session::HistorySession;

View File

@ -1,15 +1,13 @@
mod commandline;
mod default_context;
mod history;
mod history_session;
mod keybindings;
mod keybindings_default;
mod keybindings_list;
mod keybindings_listen;
pub use commandline::Commandline;
pub use history::History;
pub use history_session::HistorySession;
pub use history::{History, HistorySession};
pub use keybindings::Keybindings;
pub use keybindings_default::KeybindingsDefault;
pub use keybindings_list::KeybindingsList;

View File

@ -94,6 +94,7 @@ impl CommandCompletion {
.map(move |x| Suggestion {
value: String::from_utf8_lossy(&x.0).to_string(),
description: x.1,
style: None,
extra: None,
span: reedline::Span::new(span.start - offset, span.end - offset),
append_whitespace: true,
@ -110,6 +111,7 @@ impl CommandCompletion {
.map(move |x| Suggestion {
value: x,
description: None,
style: None,
extra: None,
span: reedline::Span::new(span.start - offset, span.end - offset),
append_whitespace: true,
@ -123,6 +125,7 @@ impl CommandCompletion {
results.push(Suggestion {
value: format!("^{}", external.value),
description: None,
style: None,
extra: None,
span: external.span,
append_whitespace: true,

View File

@ -2,6 +2,7 @@ use crate::completions::{
CommandCompletion, Completer, CompletionOptions, CustomCompletion, DirectoryCompletion,
DotNuCompletion, FileCompletion, FlagCompletion, VariableCompletion,
};
use nu_color_config::{color_record_to_nustyle, lookup_ansi_color_style};
use nu_engine::eval_block;
use nu_parser::{flatten_expression, parse, FlatShape};
use nu_protocol::{
@ -110,10 +111,16 @@ impl NuCompleter {
fn completion_helper(&mut self, line: &str, pos: usize) -> Vec<Suggestion> {
let mut working_set = StateWorkingSet::new(&self.engine_state);
let offset = working_set.next_span_start();
// TODO: Callers should be trimming the line themselves
let line = if line.len() > pos { &line[..pos] } else { line };
// Adjust offset so that the spans of the suggestions will start at the right
// place even with `only_buffer_difference: true`
let fake_offset = offset + line.len() - pos;
let pos = offset + line.len();
let initial_line = line.to_string();
let mut line = line.to_string();
line.insert(pos, 'a');
let pos = offset + pos;
line.push('a');
let config = self.engine_state.get_config();
let output = parse(&mut working_set, Some("completer"), line.as_bytes(), false);
@ -186,7 +193,7 @@ impl NuCompleter {
&working_set,
prefix,
new_span,
offset,
fake_offset,
pos,
);
}
@ -200,7 +207,7 @@ impl NuCompleter {
&working_set,
prefix.clone(),
new_span,
offset,
fake_offset,
pos,
);
@ -211,9 +218,12 @@ impl NuCompleter {
// We got no results for internal completion
// now we can check if external completer is set and use it
if let Some(block_id) = config.external_completer {
if let Some(external_result) = self
.external_completion(block_id, &spans, offset, new_span)
{
if let Some(external_result) = self.external_completion(
block_id,
&spans,
fake_offset,
new_span,
) {
return external_result;
}
}
@ -237,7 +247,7 @@ impl NuCompleter {
&working_set,
prefix,
new_span,
offset,
fake_offset,
pos,
);
}
@ -250,7 +260,9 @@ impl NuCompleter {
working_set.get_span_contents(previous_expr.0).to_vec();
// Completion for .nu files
if prev_expr_str == b"use" || prev_expr_str == b"source-env"
if prev_expr_str == b"use"
|| prev_expr_str == b"overlay use"
|| prev_expr_str == b"source-env"
{
let mut completer =
DotNuCompletion::new(self.engine_state.clone());
@ -260,7 +272,7 @@ impl NuCompleter {
&working_set,
prefix,
new_span,
offset,
fake_offset,
pos,
);
} else if prev_expr_str == b"ls" {
@ -272,7 +284,7 @@ impl NuCompleter {
&working_set,
prefix,
new_span,
offset,
fake_offset,
pos,
);
}
@ -294,7 +306,7 @@ impl NuCompleter {
&working_set,
prefix,
new_span,
offset,
fake_offset,
pos,
);
}
@ -307,7 +319,7 @@ impl NuCompleter {
&working_set,
prefix,
new_span,
offset,
fake_offset,
pos,
);
}
@ -320,7 +332,7 @@ impl NuCompleter {
&working_set,
prefix,
new_span,
offset,
fake_offset,
pos,
);
}
@ -339,7 +351,7 @@ impl NuCompleter {
&working_set,
prefix.clone(),
new_span,
offset,
fake_offset,
pos,
);
@ -350,11 +362,12 @@ impl NuCompleter {
// Try to complete using an external completer (if set)
if let Some(block_id) = config.external_completer {
if let Some(external_result) = self.external_completion(
block_id, &spans, offset, new_span,
block_id,
&spans,
fake_offset,
new_span,
) {
if !external_result.is_empty() {
return external_result;
}
return external_result;
}
}
@ -366,7 +379,7 @@ impl NuCompleter {
&working_set,
prefix,
new_span,
offset,
fake_offset,
pos,
);
@ -453,6 +466,7 @@ pub fn map_value_completions<'a>(
return Some(Suggestion {
value: s,
description: None,
style: None,
extra: None,
span: reedline::Span {
start: span.start - offset,
@ -467,6 +481,7 @@ pub fn map_value_completions<'a>(
let mut suggestion = Suggestion {
value: String::from(""), // Initialize with empty string
description: None,
style: None,
extra: None,
span: reedline::Span {
start: span.start - offset,
@ -494,6 +509,16 @@ pub fn map_value_completions<'a>(
suggestion.description = Some(desc_str);
}
}
// Match `style` column
if it.0 == "style" {
// Convert the value to string
suggestion.style = match it.1 {
Value::String { val, .. } => Some(lookup_ansi_color_style(val)),
Value::Record { .. } => Some(color_record_to_nustyle(it.1)),
_ => None,
};
}
});
return Some(suggestion);

View File

@ -22,7 +22,10 @@ fn complete_rec(
Some(base) if matches(base, &entry_name, options) => {
let partial = &partial[1..];
if !partial.is_empty() || isdir {
completions.extend(complete_rec(partial, &path, options, dir, isdir))
completions.extend(complete_rec(partial, &path, options, dir, isdir));
if entry_name.eq(base) {
break;
}
} else {
completions.push(path)
}

View File

@ -44,6 +44,7 @@ impl Completer for DirectoryCompletion {
.map(move |x| Suggestion {
value: x.1,
description: None,
style: None,
extra: None,
span: reedline::Span {
start: x.0.start - offset,

View File

@ -5,7 +5,7 @@ use nu_protocol::{
};
use reedline::Suggestion;
use std::{
path::{is_separator, MAIN_SEPARATOR as SEP, MAIN_SEPARATOR_STR},
path::{is_separator, Path, MAIN_SEPARATOR as SEP, MAIN_SEPARATOR_STR},
sync::Arc,
};
@ -91,21 +91,27 @@ impl Completer for DotNuCompletion {
// and transform them into suggestions
let output: Vec<Suggestion> = search_dirs
.into_iter()
.flat_map(|it| {
file_path_completion(span, &partial, &it, options)
.flat_map(|search_dir| {
let completions = file_path_completion(span, &partial, &search_dir, options);
completions
.into_iter()
.filter(|it| {
.filter(move |it| {
// Different base dir, so we list the .nu files or folders
if !is_current_folder {
it.1.ends_with(".nu") || it.1.ends_with(SEP)
} else {
// Lib dirs, so we filter only the .nu files
it.1.ends_with(".nu")
// Lib dirs, so we filter only the .nu files or directory modules
if it.1.ends_with(SEP) {
Path::new(&search_dir).join(&it.1).join("mod.nu").exists()
} else {
it.1.ends_with(".nu")
}
}
})
.map(move |x| Suggestion {
value: x.1,
description: None,
style: None,
extra: None,
span: reedline::Span {
start: x.0.start - offset,

View File

@ -49,6 +49,7 @@ impl Completer for FileCompletion {
.map(move |x| Suggestion {
value: x.1,
description: None,
style: None,
extra: None,
span: reedline::Span {
start: x.0.start - offset,

View File

@ -46,6 +46,7 @@ impl Completer for FlagCompletion {
output.push(Suggestion {
value: String::from_utf8_lossy(&named).to_string(),
description: Some(flag_desc.to_string()),
style: None,
extra: None,
span: reedline::Span {
start: span.start - offset,
@ -68,6 +69,7 @@ impl Completer for FlagCompletion {
output.push(Suggestion {
value: String::from_utf8_lossy(&named).to_string(),
description: Some(flag_desc.to_string()),
style: None,
extra: None,
span: reedline::Span {
start: span.start - offset,

View File

@ -95,6 +95,7 @@ impl Completer for VariableCompletion {
output.push(Suggestion {
value: env_var.0,
description: None,
style: None,
extra: None,
span: current_span,
append_whitespace: false,
@ -165,6 +166,7 @@ impl Completer for VariableCompletion {
output.push(Suggestion {
value: builtin.to_string(),
description: None,
style: None,
extra: None,
span: current_span,
append_whitespace: false,
@ -187,6 +189,7 @@ impl Completer for VariableCompletion {
output.push(Suggestion {
value: String::from_utf8_lossy(v.0).to_string(),
description: None,
style: None,
extra: None,
span: current_span,
append_whitespace: false,
@ -208,6 +211,7 @@ impl Completer for VariableCompletion {
output.push(Suggestion {
value: String::from_utf8_lossy(v.0).to_string(),
description: None,
style: None,
extra: None,
span: current_span,
append_whitespace: false,
@ -239,6 +243,7 @@ fn nested_suggestions(
output.push(Suggestion {
value: col,
description: None,
style: None,
extra: None,
span: current_span,
append_whitespace: false,
@ -253,6 +258,7 @@ fn nested_suggestions(
output.push(Suggestion {
value: column_name.to_string(),
description: None,
style: None,
extra: None,
span: current_span,
append_whitespace: false,
@ -266,6 +272,7 @@ fn nested_suggestions(
output.push(Suggestion {
value: column_name,
description: None,
style: None,
extra: None,
span: current_span,
append_whitespace: false,

View File

@ -35,6 +35,10 @@ pub fn evaluate_commands(
let mut working_set = StateWorkingSet::new(engine_state);
let output = parse(&mut working_set, None, commands.item.as_bytes(), false);
if let Some(warning) = working_set.parse_warnings.first() {
report_error(&working_set, warning);
}
if let Some(err) = working_set.parse_errors.first() {
report_error(&working_set, err);

View File

@ -19,7 +19,7 @@ pub use completions::{FileCompletion, NuCompleter};
pub use config_files::eval_config_contents;
pub use eval_cmds::evaluate_commands;
pub use eval_file::evaluate_file;
pub use menus::{DescriptionMenu, NuHelpCompleter};
pub use menus::NuHelpCompleter;
pub use nu_cmd_base::util::get_init_cwd;
pub use nu_highlight::NuHighlight;
pub use print::Print;

View File

@ -1,730 +0,0 @@
use {
nu_ansi_term::{ansi::RESET, Style},
reedline::{
menu_functions::string_difference, Completer, Editor, Menu, MenuEvent, MenuTextStyle,
Painter, Suggestion, UndoBehavior,
},
};
/// Default values used as reference for the menu. These values are set during
/// the initial declaration of the menu and are always kept as reference for the
/// changeable [`WorkingDetails`]
struct DefaultMenuDetails {
/// Number of columns that the menu will have
pub columns: u16,
/// Column width
pub col_width: Option<usize>,
/// Column padding
pub col_padding: usize,
/// Number of rows for commands
pub selection_rows: u16,
/// Number of rows allowed to display the description
pub description_rows: usize,
}
impl Default for DefaultMenuDetails {
fn default() -> Self {
Self {
columns: 4,
col_width: None,
col_padding: 2,
selection_rows: 4,
description_rows: 10,
}
}
}
/// Represents the actual column conditions of the menu. These conditions change
/// since they need to accommodate possible different line sizes for the column values
#[derive(Default)]
struct WorkingDetails {
/// Number of columns that the menu will have
pub columns: u16,
/// Column width
pub col_width: usize,
/// Number of rows for description
pub description_rows: usize,
}
/// Completion menu definition
pub struct DescriptionMenu {
/// Menu name
name: String,
/// Menu status
active: bool,
/// Menu coloring
color: MenuTextStyle,
/// Default column details that are set when creating the menu
/// These values are the reference for the working details
default_details: DefaultMenuDetails,
/// Number of minimum rows that are displayed when
/// the required lines is larger than the available lines
min_rows: u16,
/// Working column details keep changing based on the collected values
working_details: WorkingDetails,
/// Menu cached values
values: Vec<Suggestion>,
/// column position of the cursor. Starts from 0
col_pos: u16,
/// row position in the menu. Starts from 0
row_pos: u16,
/// Menu marker when active
marker: String,
/// Event sent to the menu
event: Option<MenuEvent>,
/// String collected after the menu is activated
input: Option<String>,
/// Examples to select
examples: Vec<String>,
/// Example index
example_index: Option<usize>,
/// Examples may not be shown if there is not enough space in the screen
show_examples: bool,
/// Skipped description rows
skipped_rows: usize,
/// Calls the completer using only the line buffer difference difference
/// after the menu was activated
only_buffer_difference: bool,
}
impl Default for DescriptionMenu {
fn default() -> Self {
Self {
name: "description_menu".to_string(),
active: false,
color: MenuTextStyle::default(),
default_details: DefaultMenuDetails::default(),
min_rows: 3,
working_details: WorkingDetails::default(),
values: Vec::new(),
col_pos: 0,
row_pos: 0,
marker: "? ".to_string(),
event: None,
input: None,
examples: Vec::new(),
example_index: None,
show_examples: true,
skipped_rows: 0,
only_buffer_difference: true,
}
}
}
// Menu configuration
impl DescriptionMenu {
/// Menu builder with new name
pub fn with_name(mut self, name: &str) -> Self {
self.name = name.into();
self
}
/// Menu builder with new value for text style
pub fn with_text_style(mut self, text_style: Style) -> Self {
self.color.text_style = text_style;
self
}
/// Menu builder with new value for text style
pub fn with_selected_text_style(mut self, selected_text_style: Style) -> Self {
self.color.selected_text_style = selected_text_style;
self
}
/// Menu builder with new value for text style
pub fn with_description_text_style(mut self, description_text_style: Style) -> Self {
self.color.description_style = description_text_style;
self
}
/// Menu builder with new columns value
pub fn with_columns(mut self, columns: u16) -> Self {
self.default_details.columns = columns;
self
}
/// Menu builder with new column width value
pub fn with_column_width(mut self, col_width: Option<usize>) -> Self {
self.default_details.col_width = col_width;
self
}
/// Menu builder with new column width value
pub fn with_column_padding(mut self, col_padding: usize) -> Self {
self.default_details.col_padding = col_padding;
self
}
/// Menu builder with new selection rows value
pub fn with_selection_rows(mut self, selection_rows: u16) -> Self {
self.default_details.selection_rows = selection_rows;
self
}
/// Menu builder with new description rows value
pub fn with_description_rows(mut self, description_rows: usize) -> Self {
self.default_details.description_rows = description_rows;
self
}
/// Menu builder with marker
pub fn with_marker(mut self, marker: String) -> Self {
self.marker = marker;
self
}
/// Menu builder with new only buffer difference
pub fn with_only_buffer_difference(mut self, only_buffer_difference: bool) -> Self {
self.only_buffer_difference = only_buffer_difference;
self
}
}
// Menu functionality
impl DescriptionMenu {
/// Move menu cursor to the next element
fn move_next(&mut self) {
let mut new_col = self.col_pos + 1;
let mut new_row = self.row_pos;
if new_col >= self.get_cols() {
new_row += 1;
new_col = 0;
}
if new_row >= self.get_rows() {
new_row = 0;
new_col = 0;
}
let position = new_row * self.get_cols() + new_col;
if position >= self.get_values().len() as u16 {
self.reset_position();
} else {
self.col_pos = new_col;
self.row_pos = new_row;
}
}
/// Move menu cursor to the previous element
fn move_previous(&mut self) {
let new_col = self.col_pos.checked_sub(1);
let (new_col, new_row) = match new_col {
Some(col) => (col, self.row_pos),
None => match self.row_pos.checked_sub(1) {
Some(row) => (self.get_cols().saturating_sub(1), row),
None => (
self.get_cols().saturating_sub(1),
self.get_rows().saturating_sub(1),
),
},
};
let position = new_row * self.get_cols() + new_col;
if position >= self.get_values().len() as u16 {
self.col_pos = (self.get_values().len() as u16 % self.get_cols()).saturating_sub(1);
self.row_pos = self.get_rows().saturating_sub(1);
} else {
self.col_pos = new_col;
self.row_pos = new_row;
}
}
/// Menu index based on column and row position
fn index(&self) -> usize {
let index = self.row_pos * self.get_cols() + self.col_pos;
index as usize
}
/// Get selected value from the menu
fn get_value(&self) -> Option<Suggestion> {
self.get_values().get(self.index()).cloned()
}
/// Calculates how many rows the Menu will use
fn get_rows(&self) -> u16 {
let values = self.get_values().len() as u16;
if values == 0 {
// When the values are empty the no_records_msg is shown, taking 1 line
return 1;
}
let rows = values / self.get_cols();
if values % self.get_cols() != 0 {
rows + 1
} else {
rows
}
}
/// Returns working details col width
fn get_width(&self) -> usize {
self.working_details.col_width
}
/// Reset menu position
fn reset_position(&mut self) {
self.col_pos = 0;
self.row_pos = 0;
self.skipped_rows = 0;
}
fn no_records_msg(&self, use_ansi_coloring: bool) -> String {
let msg = "TYPE TO START SEARCH";
if use_ansi_coloring {
format!(
"{}{}{}",
self.color.selected_text_style.prefix(),
msg,
RESET
)
} else {
msg.to_string()
}
}
/// Returns working details columns
fn get_cols(&self) -> u16 {
self.working_details.columns.max(1)
}
/// End of line for menu
fn end_of_line(&self, column: u16, index: usize) -> &str {
let is_last = index == self.values.len().saturating_sub(1);
if column == self.get_cols().saturating_sub(1) || is_last {
"\r\n"
} else {
""
}
}
/// Update list of examples from the actual value
fn update_examples(&mut self) {
self.examples = self
.get_value()
.and_then(|suggestion| suggestion.extra)
.unwrap_or_default();
self.example_index = None;
}
/// Creates default string that represents one suggestion from the menu
fn create_entry_string(
&self,
suggestion: &Suggestion,
index: usize,
column: u16,
empty_space: usize,
use_ansi_coloring: bool,
) -> String {
if use_ansi_coloring {
if index == self.index() {
format!(
"{}{}{}{:>empty$}{}",
self.color.selected_text_style.prefix(),
&suggestion.value,
RESET,
"",
self.end_of_line(column, index),
empty = empty_space,
)
} else {
format!(
"{}{}{}{:>empty$}{}",
self.color.text_style.prefix(),
&suggestion.value,
RESET,
"",
self.end_of_line(column, index),
empty = empty_space,
)
}
} else {
// If no ansi coloring is found, then the selection word is
// the line in uppercase
let (marker, empty_space) = if index == self.index() {
(">", empty_space.saturating_sub(1))
} else {
("", empty_space)
};
let line = format!(
"{}{}{:>empty$}{}",
marker,
&suggestion.value,
"",
self.end_of_line(column, index),
empty = empty_space,
);
if index == self.index() {
line.to_uppercase()
} else {
line
}
}
}
/// Description string with color
fn create_description_string(&self, use_ansi_coloring: bool) -> String {
let description = self
.get_value()
.and_then(|suggestion| suggestion.description)
.unwrap_or_default()
.lines()
.skip(self.skipped_rows)
.take(self.working_details.description_rows)
.collect::<Vec<&str>>()
.join("\r\n");
if use_ansi_coloring && !description.is_empty() {
format!(
"{}{}{}",
self.color.description_style.prefix(),
description,
RESET,
)
} else {
description
}
}
/// Selectable list of examples from the actual value
fn create_example_string(&self, use_ansi_coloring: bool) -> String {
if !self.show_examples {
return "".into();
}
let examples: String = self
.examples
.iter()
.enumerate()
.map(|(index, example)| {
if let Some(example_index) = self.example_index {
if index == example_index {
format!(
" {}{}{}\r\n",
self.color.selected_text_style.prefix(),
example,
RESET
)
} else {
format!(" {example}\r\n")
}
} else {
format!(" {example}\r\n")
}
})
.collect();
if examples.is_empty() {
"".into()
} else if use_ansi_coloring {
format!(
"{}\r\n\r\nExamples:\r\n{}{}",
self.color.description_style.prefix(),
RESET,
examples,
)
} else {
format!("\r\n\r\nExamples:\r\n{examples}",)
}
}
}
impl Menu for DescriptionMenu {
/// Menu name
fn name(&self) -> &str {
self.name.as_str()
}
/// Menu indicator
fn indicator(&self) -> &str {
self.marker.as_str()
}
/// Deactivates context menu
fn is_active(&self) -> bool {
self.active
}
/// The menu stays active even with one record
fn can_quick_complete(&self) -> bool {
false
}
/// The menu does not need to partially complete
fn can_partially_complete(
&mut self,
_values_updated: bool,
_editor: &mut Editor,
_completer: &mut dyn Completer,
) -> bool {
false
}
/// Selects what type of event happened with the menu
fn menu_event(&mut self, event: MenuEvent) {
match &event {
MenuEvent::Activate(_) => self.active = true,
MenuEvent::Deactivate => {
self.active = false;
self.input = None;
self.values = Vec::new();
}
_ => {}
};
self.event = Some(event);
}
/// Updates menu values
fn update_values(&mut self, editor: &mut Editor, completer: &mut dyn Completer) {
if self.only_buffer_difference {
if let Some(old_string) = &self.input {
let (start, input) = string_difference(editor.get_buffer(), old_string);
if !input.is_empty() {
self.reset_position();
self.values = completer.complete(input, start);
}
}
} else {
let trimmed_buffer = editor.get_buffer().replace('\n', " ");
self.values = completer.complete(
trimmed_buffer.as_str(),
editor.line_buffer().insertion_point(),
);
self.reset_position();
}
}
/// The working details for the menu changes based on the size of the lines
/// collected from the completer
fn update_working_details(
&mut self,
editor: &mut Editor,
completer: &mut dyn Completer,
painter: &Painter,
) {
if let Some(event) = self.event.take() {
// Updating all working parameters from the menu before executing any of the
// possible event
let max_width = self.get_values().iter().fold(0, |acc, suggestion| {
let str_len = suggestion.value.len() + self.default_details.col_padding;
if str_len > acc {
str_len
} else {
acc
}
});
// If no default width is found, then the total screen width is used to estimate
// the column width based on the default number of columns
let default_width = if let Some(col_width) = self.default_details.col_width {
col_width
} else {
let col_width = painter.screen_width() / self.default_details.columns;
col_width as usize
};
// Adjusting the working width of the column based the max line width found
// in the menu values
if max_width > default_width {
self.working_details.col_width = max_width;
} else {
self.working_details.col_width = default_width;
};
// The working columns is adjusted based on possible number of columns
// that could be fitted in the screen with the calculated column width
let possible_cols = painter.screen_width() / self.working_details.col_width as u16;
if possible_cols > self.default_details.columns {
self.working_details.columns = self.default_details.columns.max(1);
} else {
self.working_details.columns = possible_cols;
}
// Updating the working rows to display the description
if self.menu_required_lines(painter.screen_width()) <= painter.remaining_lines() {
self.working_details.description_rows = self.default_details.description_rows;
self.show_examples = true;
} else {
self.working_details.description_rows = painter
.remaining_lines()
.saturating_sub(self.default_details.selection_rows + 1)
as usize;
self.show_examples = false;
}
match event {
MenuEvent::Activate(_) => {
self.reset_position();
self.input = Some(editor.get_buffer().to_string());
self.update_values(editor, completer);
}
MenuEvent::Deactivate => self.active = false,
MenuEvent::Edit(_) => {
self.reset_position();
self.update_values(editor, completer);
self.update_examples()
}
MenuEvent::NextElement => {
self.skipped_rows = 0;
self.move_next();
self.update_examples();
}
MenuEvent::PreviousElement => {
self.skipped_rows = 0;
self.move_previous();
self.update_examples();
}
MenuEvent::MoveUp => {
if let Some(example_index) = self.example_index {
if let Some(index) = example_index.checked_sub(1) {
self.example_index = Some(index);
} else {
self.example_index = Some(self.examples.len().saturating_sub(1));
}
} else if !self.examples.is_empty() {
self.example_index = Some(0);
}
}
MenuEvent::MoveDown => {
if let Some(example_index) = self.example_index {
let index = example_index + 1;
if index < self.examples.len() {
self.example_index = Some(index);
} else {
self.example_index = Some(0);
}
} else if !self.examples.is_empty() {
self.example_index = Some(0);
}
}
MenuEvent::MoveLeft => self.skipped_rows = self.skipped_rows.saturating_sub(1),
MenuEvent::MoveRight => {
let skipped = self.skipped_rows + 1;
let description_rows = self
.get_value()
.and_then(|suggestion| suggestion.description)
.unwrap_or_default()
.lines()
.count();
let allowed_skips =
description_rows.saturating_sub(self.working_details.description_rows);
if skipped < allowed_skips {
self.skipped_rows = skipped;
} else {
self.skipped_rows = allowed_skips;
}
}
MenuEvent::PreviousPage | MenuEvent::NextPage => {}
}
}
}
/// The buffer gets replaced in the Span location
fn replace_in_buffer(&self, editor: &mut Editor) {
if let Some(Suggestion { value, span, .. }) = self.get_value() {
let start = span.start.min(editor.line_buffer().len());
let end = span.end.min(editor.line_buffer().len());
let replacement = if let Some(example_index) = self.example_index {
self.examples
.get(example_index)
.expect("the example index is always checked")
} else {
&value
};
editor.edit_buffer(
|lb| {
lb.replace_range(start..end, replacement);
let mut offset = lb.insertion_point();
offset += lb
.len()
.saturating_sub(end.saturating_sub(start))
.saturating_sub(start);
lb.set_insertion_point(offset);
},
UndoBehavior::CreateUndoPoint,
);
}
}
/// Minimum rows that should be displayed by the menu
fn min_rows(&self) -> u16 {
self.get_rows().min(self.min_rows)
}
/// Gets values from filler that will be displayed in the menu
fn get_values(&self) -> &[Suggestion] {
&self.values
}
fn menu_required_lines(&self, _terminal_columns: u16) -> u16 {
let example_lines = self
.examples
.iter()
.fold(0, |acc, example| example.lines().count() + acc);
self.default_details.selection_rows
+ self.default_details.description_rows as u16
+ example_lines as u16
+ 3
}
fn menu_string(&self, _available_lines: u16, use_ansi_coloring: bool) -> String {
if self.get_values().is_empty() {
self.no_records_msg(use_ansi_coloring)
} else {
// The skip values represent the number of lines that should be skipped
// while printing the menu
let available_lines = self.default_details.selection_rows;
let skip_values = if self.row_pos >= available_lines {
let skip_lines = self.row_pos.saturating_sub(available_lines) + 1;
(skip_lines * self.get_cols()) as usize
} else {
0
};
// It seems that crossterm prefers to have a complete string ready to be printed
// rather than looping through the values and printing multiple things
// This reduces the flickering when printing the menu
let available_values = (available_lines * self.get_cols()) as usize;
let selection_values: String = self
.get_values()
.iter()
.skip(skip_values)
.take(available_values)
.enumerate()
.map(|(index, suggestion)| {
// Correcting the enumerate index based on the number of skipped values
let index = index + skip_values;
let column = index as u16 % self.get_cols();
let empty_space = self.get_width().saturating_sub(suggestion.value.len());
self.create_entry_string(
suggestion,
index,
column,
empty_space,
use_ansi_coloring,
)
})
.collect();
format!(
"{}{}{}",
selection_values,
self.create_description_string(use_ansi_coloring),
self.create_example_string(use_ansi_coloring)
)
}
}
}

View File

@ -102,10 +102,11 @@ impl NuHelpCompleter {
Suggestion {
value: sig.name.clone(),
description: Some(long_desc),
style: None,
extra: Some(extra),
span: reedline::Span {
start: pos,
end: pos + line.len(),
start: pos - line.len(),
end: pos,
},
append_whitespace: false,
}
@ -119,3 +120,42 @@ impl Completer for NuHelpCompleter {
self.completion_helper(line, pos)
}
}
#[cfg(test)]
mod test {
use super::*;
use rstest::rstest;
#[rstest]
#[case("who", 5, 8, &["whoami"])]
#[case("hash", 1, 5, &["hash", "hash md5", "hash sha256"])]
#[case("into f", 0, 6, &["into float", "into filesize"])]
#[case("into nonexistent", 0, 16, &[])]
fn test_help_completer(
#[case] line: &str,
#[case] start: usize,
#[case] end: usize,
#[case] expected: &[&str],
) {
let engine_state =
nu_command::add_shell_command_context(nu_cmd_lang::create_default_context());
let mut completer = NuHelpCompleter::new(engine_state.into());
let suggestions = completer.complete(line, end);
assert_eq!(
expected.len(),
suggestions.len(),
"expected {:?}, got {:?}",
expected,
suggestions
.iter()
.map(|s| s.value.clone())
.collect::<Vec<_>>()
);
for (exp, actual) in expected.iter().zip(suggestions) {
assert_eq!(exp, &actual.value);
assert_eq!(reedline::Span::new(start, end), actual.span);
}
}
}

View File

@ -101,9 +101,13 @@ fn convert_to_suggestions(
}
}
_ => reedline::Span {
start: if only_buffer_difference { pos } else { 0 },
start: if only_buffer_difference {
pos - line.len()
} else {
0
},
end: if only_buffer_difference {
pos + line.len()
pos
} else {
line.len()
},
@ -111,9 +115,13 @@ fn convert_to_suggestions(
}
}
_ => reedline::Span {
start: if only_buffer_difference { pos } else { 0 },
start: if only_buffer_difference {
pos - line.len()
} else {
0
},
end: if only_buffer_difference {
pos + line.len()
pos
} else {
line.len()
},
@ -138,6 +146,7 @@ fn convert_to_suggestions(
vec![Suggestion {
value: text,
description,
style: None,
extra,
span,
append_whitespace: false,
@ -150,10 +159,19 @@ fn convert_to_suggestions(
_ => vec![Suggestion {
value: format!("Not a record: {value:?}"),
description: None,
style: None,
extra: None,
span: reedline::Span {
start: 0,
end: line.len(),
start: if only_buffer_difference {
pos - line.len()
} else {
0
},
end: if only_buffer_difference {
pos
} else {
line.len()
},
},
append_whitespace: false,
}],

View File

@ -1,7 +1,5 @@
mod description_menu;
mod help_completions;
mod menu_completions;
pub use description_menu::DescriptionMenu;
pub use help_completions::NuHelpCompleter;
pub use menu_completions::NuMenuCompleter;

View File

@ -28,7 +28,7 @@ impl Command for NuHighlight {
fn run(
&self,
engine_state: &EngineState,
_stack: &mut Stack,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
@ -40,6 +40,7 @@ impl Command for NuHighlight {
let highlighter = crate::NuHighlighter {
engine_state,
stack: std::sync::Arc::new(stack.clone()),
config,
};

View File

@ -54,8 +54,8 @@ Since this command has no output, there is no point in piping it with other comm
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let args: Vec<Value> = call.rest(engine_state, stack, 0)?;
let no_newline = call.has_flag("no-newline");
let to_stderr = call.has_flag("stderr");
let no_newline = call.has_flag(engine_state, stack, "no-newline")?;
let to_stderr = call.has_flag(engine_state, stack, "stderr")?;
// This will allow for easy printing of pipelines as well
if !args.is_empty() {

View File

@ -1,3 +1,4 @@
use crate::prompt_update::{POST_PROMPT_MARKER, PRE_PROMPT_MARKER};
#[cfg(windows)]
use nu_utils::enable_vt_processing;
use reedline::DefaultPrompt;
@ -11,6 +12,7 @@ use {
/// Nushell prompt definition
#[derive(Clone)]
pub struct NushellPrompt {
shell_integration: bool,
left_prompt_string: Option<String>,
right_prompt_string: Option<String>,
default_prompt_indicator: Option<String>,
@ -20,15 +22,10 @@ pub struct NushellPrompt {
render_right_prompt_on_last_line: bool,
}
impl Default for NushellPrompt {
fn default() -> Self {
NushellPrompt::new()
}
}
impl NushellPrompt {
pub fn new() -> NushellPrompt {
pub fn new(shell_integration: bool) -> NushellPrompt {
NushellPrompt {
shell_integration,
left_prompt_string: None,
right_prompt_string: None,
default_prompt_indicator: None,
@ -111,7 +108,11 @@ impl Prompt for NushellPrompt {
.to_string()
.replace('\n', "\r\n");
prompt.into()
if self.shell_integration {
format!("{PRE_PROMPT_MARKER}{prompt}{POST_PROMPT_MARKER}").into()
} else {
prompt.into()
}
}
}

View File

@ -7,8 +7,6 @@ use nu_protocol::{
Config, PipelineData, Value,
};
use reedline::Prompt;
use std::borrow::Cow;
use std::sync::Arc;
// Name of environment variable where the prompt could be stored
pub(crate) const PROMPT_COMMAND: &str = "PROMPT_COMMAND";
@ -28,8 +26,8 @@ pub(crate) const TRANSIENT_PROMPT_MULTILINE_INDICATOR: &str =
"TRANSIENT_PROMPT_MULTILINE_INDICATOR";
// According to Daniel Imms @Tyriar, we need to do these this way:
// <133 A><prompt><133 B><command><133 C><command output>
const PRE_PROMPT_MARKER: &str = "\x1b]133;A\x1b\\";
const POST_PROMPT_MARKER: &str = "\x1b]133;B\x1b\\";
pub(crate) const PRE_PROMPT_MARKER: &str = "\x1b]133;A\x1b\\";
pub(crate) const POST_PROMPT_MARKER: &str = "\x1b]133;B\x1b\\";
fn get_prompt_string(
prompt: &str,
@ -98,12 +96,12 @@ fn get_prompt_string(
})
}
pub(crate) fn update_prompt<'prompt>(
pub(crate) fn update_prompt(
config: &Config,
engine_state: &EngineState,
stack: &Stack,
nu_prompt: &'prompt mut NushellPrompt,
) -> &'prompt dyn Prompt {
nu_prompt: &mut NushellPrompt,
) {
let mut stack = stack.clone();
let left_prompt_string = get_prompt_string(PROMPT_COMMAND, config, engine_state, &mut stack);
@ -146,125 +144,55 @@ pub(crate) fn update_prompt<'prompt>(
(prompt_vi_insert_string, prompt_vi_normal_string),
config.render_right_prompt_on_last_line,
);
let ret_val = nu_prompt as &dyn Prompt;
trace!("update_prompt {}:{}:{}", file!(), line!(), column!());
ret_val
}
struct TransientPrompt {
engine_state: Arc<EngineState>,
stack: Stack,
}
/// Try getting `$env.TRANSIENT_PROMPT_<X>`, and get `$env.PROMPT_<X>` if that fails
fn get_transient_prompt_string(
transient_prompt: &str,
prompt: &str,
/// Construct the transient prompt based on the normal nu_prompt
pub(crate) fn make_transient_prompt(
config: &Config,
engine_state: &EngineState,
stack: &mut Stack,
) -> Option<String> {
get_prompt_string(transient_prompt, config, engine_state, stack)
.or_else(|| get_prompt_string(prompt, config, engine_state, stack))
}
nu_prompt: &NushellPrompt,
) -> Box<dyn Prompt> {
let mut nu_prompt = nu_prompt.clone();
impl Prompt for TransientPrompt {
fn render_prompt_left(&self) -> Cow<str> {
let mut nu_prompt = NushellPrompt::new();
let config = &self.engine_state.get_config().clone();
let mut stack = self.stack.clone();
nu_prompt.update_prompt_left(get_transient_prompt_string(
TRANSIENT_PROMPT_COMMAND,
PROMPT_COMMAND,
config,
&self.engine_state,
&mut stack,
));
nu_prompt.render_prompt_left().to_string().into()
if let Some(s) = get_prompt_string(TRANSIENT_PROMPT_COMMAND, config, engine_state, stack) {
nu_prompt.update_prompt_left(Some(s))
}
fn render_prompt_right(&self) -> Cow<str> {
let mut nu_prompt = NushellPrompt::new();
let config = &self.engine_state.get_config().clone();
let mut stack = self.stack.clone();
nu_prompt.update_prompt_right(
get_transient_prompt_string(
TRANSIENT_PROMPT_COMMAND_RIGHT,
PROMPT_COMMAND_RIGHT,
config,
&self.engine_state,
&mut stack,
),
config.render_right_prompt_on_last_line,
);
nu_prompt.render_prompt_right().to_string().into()
if let Some(s) = get_prompt_string(TRANSIENT_PROMPT_COMMAND_RIGHT, config, engine_state, stack)
{
nu_prompt.update_prompt_right(Some(s), config.render_right_prompt_on_last_line)
}
fn render_prompt_indicator(&self, prompt_mode: reedline::PromptEditMode) -> Cow<str> {
let mut nu_prompt = NushellPrompt::new();
let config = &self.engine_state.get_config().clone();
let mut stack = self.stack.clone();
nu_prompt.update_prompt_indicator(get_transient_prompt_string(
TRANSIENT_PROMPT_INDICATOR,
PROMPT_INDICATOR,
config,
&self.engine_state,
&mut stack,
));
nu_prompt.update_prompt_vi_insert(get_transient_prompt_string(
TRANSIENT_PROMPT_INDICATOR_VI_INSERT,
PROMPT_INDICATOR_VI_INSERT,
config,
&self.engine_state,
&mut stack,
));
nu_prompt.update_prompt_vi_normal(get_transient_prompt_string(
TRANSIENT_PROMPT_INDICATOR_VI_NORMAL,
PROMPT_INDICATOR_VI_NORMAL,
config,
&self.engine_state,
&mut stack,
));
nu_prompt
.render_prompt_indicator(prompt_mode)
.to_string()
.into()
if let Some(s) = get_prompt_string(TRANSIENT_PROMPT_INDICATOR, config, engine_state, stack) {
nu_prompt.update_prompt_indicator(Some(s))
}
fn render_prompt_multiline_indicator(&self) -> Cow<str> {
let mut nu_prompt = NushellPrompt::new();
let config = &self.engine_state.get_config().clone();
let mut stack = self.stack.clone();
nu_prompt.update_prompt_multiline(get_transient_prompt_string(
TRANSIENT_PROMPT_MULTILINE_INDICATOR,
PROMPT_MULTILINE_INDICATOR,
config,
&self.engine_state,
&mut stack,
));
nu_prompt
.render_prompt_multiline_indicator()
.to_string()
.into()
}
fn render_prompt_history_search_indicator(
&self,
history_search: reedline::PromptHistorySearch,
) -> Cow<str> {
NushellPrompt::new()
.render_prompt_history_search_indicator(history_search)
.to_string()
.into()
}
}
/// Construct the transient prompt
pub(crate) fn transient_prompt(engine_state: Arc<EngineState>, stack: &Stack) -> Box<dyn Prompt> {
Box::new(TransientPrompt {
if let Some(s) = get_prompt_string(
TRANSIENT_PROMPT_INDICATOR_VI_INSERT,
config,
engine_state,
stack: stack.clone(),
})
stack,
) {
nu_prompt.update_prompt_vi_insert(Some(s))
}
if let Some(s) = get_prompt_string(
TRANSIENT_PROMPT_INDICATOR_VI_NORMAL,
config,
engine_state,
stack,
) {
nu_prompt.update_prompt_vi_normal(Some(s))
}
if let Some(s) = get_prompt_string(
TRANSIENT_PROMPT_MULTILINE_INDICATOR,
config,
engine_state,
stack,
) {
nu_prompt.update_prompt_multiline(Some(s))
}
Box::new(nu_prompt)
}

View File

@ -1,4 +1,3 @@
use super::DescriptionMenu;
use crate::{menus::NuMenuCompleter, NuHelpCompleter};
use crossterm::event::{KeyCode, KeyModifiers};
use nu_color_config::{color_record_to_nustyle, lookup_ansi_color_style};
@ -12,7 +11,8 @@ use nu_protocol::{
};
use reedline::{
default_emacs_keybindings, default_vi_insert_keybindings, default_vi_normal_keybindings,
ColumnarMenu, EditCommand, Keybindings, ListMenu, Reedline, ReedlineEvent, ReedlineMenu,
ColumnarMenu, DescriptionMenu, DescriptionMode, EditCommand, IdeMenu, Keybindings, ListMenu,
MenuBuilder, Reedline, ReedlineEvent, ReedlineMenu,
};
use std::sync::Arc;
@ -138,9 +138,10 @@ fn add_menu(
match layout.as_str() {
"columnar" => add_columnar_menu(line_editor, menu, engine_state, stack, config),
"list" => add_list_menu(line_editor, menu, engine_state, stack, config),
"ide" => add_ide_menu(line_editor, menu, engine_state, stack, config),
"description" => add_description_menu(line_editor, menu, engine_state, stack, config),
_ => Err(ShellError::UnsupportedConfigValue {
expected: "columnar, list or description".to_string(),
expected: "columnar, list, ide or description".to_string(),
value: menu.menu_type.into_abbreviated_string(config),
span: menu.menu_type.span(),
}),
@ -235,10 +236,26 @@ pub(crate) fn add_columnar_menu(
columnar_menu,
ColumnarMenu::with_description_text_style
);
add_style!(
"match_text",
val,
span,
config,
columnar_menu,
ColumnarMenu::with_match_text_style
);
add_style!(
"selected_match_text",
val,
span,
config,
columnar_menu,
ColumnarMenu::with_selected_match_text_style
);
}
let marker = menu.marker.into_string("", config);
columnar_menu = columnar_menu.with_marker(marker);
columnar_menu = columnar_menu.with_marker(&marker);
let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
columnar_menu = columnar_menu.with_only_buffer_difference(only_buffer_difference);
@ -320,7 +337,7 @@ pub(crate) fn add_list_menu(
}
let marker = menu.marker.into_string("", config);
list_menu = list_menu.with_marker(marker);
list_menu = list_menu.with_marker(&marker);
let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
list_menu = list_menu.with_only_buffer_difference(only_buffer_difference);
@ -351,6 +368,232 @@ pub(crate) fn add_list_menu(
}
}
// Adds an IDE menu to the line editor
pub(crate) fn add_ide_menu(
line_editor: Reedline,
menu: &ParsedMenu,
engine_state: Arc<EngineState>,
stack: &Stack,
config: &Config,
) -> Result<Reedline, ShellError> {
let span = menu.menu_type.span();
let name = menu.name.into_string("", config);
let mut ide_menu = IdeMenu::default().with_name(&name);
if let Value::Record { val, .. } = &menu.menu_type {
ide_menu = match extract_value("min_completion_width", val, span) {
Ok(min_completion_width) => {
let min_completion_width = min_completion_width.as_int()?;
ide_menu.with_min_completion_width(min_completion_width as u16)
}
Err(_) => ide_menu,
};
ide_menu = match extract_value("max_completion_width", val, span) {
Ok(max_completion_width) => {
let max_completion_width = max_completion_width.as_int()?;
ide_menu.with_max_completion_width(max_completion_width as u16)
}
Err(_) => ide_menu,
};
ide_menu = match extract_value("max_completion_height", val, span) {
Ok(max_completion_height) => {
let max_completion_height = max_completion_height.as_int()?;
ide_menu.with_max_completion_height(max_completion_height as u16)
}
Err(_) => ide_menu,
};
ide_menu = match extract_value("padding", val, span) {
Ok(padding) => {
let padding = padding.as_int()?;
ide_menu.with_padding(padding as u16)
}
Err(_) => ide_menu,
};
ide_menu = match extract_value("border", val, span) {
Ok(border) => {
if let Ok(border) = border.as_bool() {
if border {
ide_menu.with_default_border()
} else {
ide_menu
}
} else if let Ok(border_chars) = border.as_record() {
let top_right = extract_value("top_right", border_chars, span)?.as_char()?;
let top_left = extract_value("top_left", border_chars, span)?.as_char()?;
let bottom_right =
extract_value("bottom_right", border_chars, span)?.as_char()?;
let bottom_left =
extract_value("bottom_left", border_chars, span)?.as_char()?;
let horizontal = extract_value("horizontal", border_chars, span)?.as_char()?;
let vertical = extract_value("vertical", border_chars, span)?.as_char()?;
ide_menu.with_border(
top_right,
top_left,
bottom_right,
bottom_left,
horizontal,
vertical,
)
} else {
return Err(ShellError::UnsupportedConfigValue {
expected: "bool or record".to_string(),
value: border.into_abbreviated_string(config),
span: border.span(),
});
}
}
Err(_) => ide_menu,
};
ide_menu = match extract_value("cursor_offset", val, span) {
Ok(cursor_offset) => {
let cursor_offset = cursor_offset.as_int()?;
ide_menu.with_cursor_offset(cursor_offset as i16)
}
Err(_) => ide_menu,
};
ide_menu = match extract_value("description_mode", val, span) {
Ok(description_mode) => {
let description_mode_str = description_mode.as_string()?;
match description_mode_str.as_str() {
"left" => ide_menu.with_description_mode(DescriptionMode::Left),
"right" => ide_menu.with_description_mode(DescriptionMode::Right),
"prefer_right" => ide_menu.with_description_mode(DescriptionMode::PreferRight),
_ => {
return Err(ShellError::UnsupportedConfigValue {
expected: "\"left\", \"right\" or \"prefer_right\"".to_string(),
value: description_mode.into_abbreviated_string(config),
span: description_mode.span(),
});
}
}
}
Err(_) => ide_menu,
};
ide_menu = match extract_value("min_description_width", val, span) {
Ok(min_description_width) => {
let min_description_width = min_description_width.as_int()?;
ide_menu.with_min_description_width(min_description_width as u16)
}
Err(_) => ide_menu,
};
ide_menu = match extract_value("max_description_width", val, span) {
Ok(max_description_width) => {
let max_description_width = max_description_width.as_int()?;
ide_menu.with_max_description_width(max_description_width as u16)
}
Err(_) => ide_menu,
};
ide_menu = match extract_value("max_description_height", val, span) {
Ok(max_description_height) => {
let max_description_height = max_description_height.as_int()?;
ide_menu.with_max_description_height(max_description_height as u16)
}
Err(_) => ide_menu,
};
ide_menu = match extract_value("description_offset", val, span) {
Ok(description_padding) => {
let description_padding = description_padding.as_int()?;
ide_menu.with_description_offset(description_padding as u16)
}
Err(_) => ide_menu,
};
ide_menu = match extract_value("correct_cursor_pos", val, span) {
Ok(correct_cursor_pos) => {
let correct_cursor_pos = correct_cursor_pos.as_bool()?;
ide_menu.with_correct_cursor_pos(correct_cursor_pos)
}
Err(_) => ide_menu,
};
}
let span = menu.style.span();
if let Value::Record { val, .. } = &menu.style {
add_style!(
"text",
val,
span,
config,
ide_menu,
IdeMenu::with_text_style
);
add_style!(
"selected_text",
val,
span,
config,
ide_menu,
IdeMenu::with_selected_text_style
);
add_style!(
"description_text",
val,
span,
config,
ide_menu,
IdeMenu::with_description_text_style
);
add_style!(
"match_text",
val,
span,
config,
ide_menu,
IdeMenu::with_match_text_style
);
add_style!(
"selected_match_text",
val,
span,
config,
ide_menu,
IdeMenu::with_selected_match_text_style
);
}
let marker = menu.marker.into_string("", config);
ide_menu = ide_menu.with_marker(&marker);
let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
ide_menu = ide_menu.with_only_buffer_difference(only_buffer_difference);
let span = menu.source.span();
match &menu.source {
Value::Nothing { .. } => {
Ok(line_editor.with_menu(ReedlineMenu::EngineCompleter(Box::new(ide_menu))))
}
Value::Closure { val, .. } => {
let menu_completer = NuMenuCompleter::new(
val.block_id,
span,
stack.captures_to_stack(val.captures.clone()),
engine_state,
only_buffer_difference,
);
Ok(line_editor.with_menu(ReedlineMenu::WithCompleter {
menu: Box::new(ide_menu),
completer: Box::new(menu_completer),
}))
}
_ => Err(ShellError::UnsupportedConfigValue {
expected: "block or omitted value".to_string(),
value: menu.source.into_abbreviated_string(config),
span,
}),
}
}
// Adds a description menu to the line editor
pub(crate) fn add_description_menu(
line_editor: Reedline,
@ -434,7 +677,7 @@ pub(crate) fn add_description_menu(
}
let marker = menu.marker.into_string("", config);
description_menu = description_menu.with_marker(marker);
description_menu = description_menu.with_marker(&marker);
let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
description_menu = description_menu.with_only_buffer_difference(only_buffer_difference);
@ -861,22 +1104,82 @@ fn edit_from_record(
span: Span,
) -> Result<EditCommand, ShellError> {
let edit = match name {
"movetostart" => EditCommand::MoveToStart,
"movetolinestart" => EditCommand::MoveToLineStart,
"movetoend" => EditCommand::MoveToEnd,
"movetolineend" => EditCommand::MoveToLineEnd,
"moveleft" => EditCommand::MoveLeft,
"moveright" => EditCommand::MoveRight,
"movewordleft" => EditCommand::MoveWordLeft,
"movebigwordleft" => EditCommand::MoveBigWordLeft,
"movewordright" => EditCommand::MoveWordRight,
"movewordrightend" => EditCommand::MoveWordRightEnd,
"movebigwordrightend" => EditCommand::MoveBigWordRightEnd,
"movewordrightstart" => EditCommand::MoveWordRightStart,
"movebigwordrightstart" => EditCommand::MoveBigWordRightStart,
"movetostart" => EditCommand::MoveToStart {
select: extract_value("select", record, span)
.and_then(|value| value.as_bool())
.unwrap_or(false),
},
"movetolinestart" => EditCommand::MoveToLineStart {
select: extract_value("select", record, span)
.and_then(|value| value.as_bool())
.unwrap_or(false),
},
"movetoend" => EditCommand::MoveToEnd {
select: extract_value("select", record, span)
.and_then(|value| value.as_bool())
.unwrap_or(false),
},
"movetolineend" => EditCommand::MoveToLineEnd {
select: extract_value("select", record, span)
.and_then(|value| value.as_bool())
.unwrap_or(false),
},
"moveleft" => EditCommand::MoveLeft {
select: extract_value("select", record, span)
.and_then(|value| value.as_bool())
.unwrap_or(false),
},
"moveright" => EditCommand::MoveRight {
select: extract_value("select", record, span)
.and_then(|value| value.as_bool())
.unwrap_or(false),
},
"movewordleft" => EditCommand::MoveWordLeft {
select: extract_value("select", record, span)
.and_then(|value| value.as_bool())
.unwrap_or(false),
},
"movebigwordleft" => EditCommand::MoveBigWordLeft {
select: extract_value("select", record, span)
.and_then(|value| value.as_bool())
.unwrap_or(false),
},
"movewordright" => EditCommand::MoveWordRight {
select: extract_value("select", record, span)
.and_then(|value| value.as_bool())
.unwrap_or(false),
},
"movewordrightend" => EditCommand::MoveWordRightEnd {
select: extract_value("select", record, span)
.and_then(|value| value.as_bool())
.unwrap_or(false),
},
"movebigwordrightend" => EditCommand::MoveBigWordRightEnd {
select: extract_value("select", record, span)
.and_then(|value| value.as_bool())
.unwrap_or(false),
},
"movewordrightstart" => EditCommand::MoveWordRightStart {
select: extract_value("select", record, span)
.and_then(|value| value.as_bool())
.unwrap_or(false),
},
"movebigwordrightstart" => EditCommand::MoveBigWordRightStart {
select: extract_value("select", record, span)
.and_then(|value| value.as_bool())
.unwrap_or(false),
},
"movetoposition" => {
let value = extract_value("value", record, span)?;
EditCommand::MoveToPosition(value.as_int()? as usize)
let select = extract_value("select", record, span)
.and_then(|value| value.as_bool())
.unwrap_or(false);
EditCommand::MoveToPosition {
position: value.as_int()? as usize,
select,
}
}
"insertchar" => {
let value = extract_value("value", record, span)?;
@ -928,12 +1231,18 @@ fn edit_from_record(
"moverightuntil" => {
let value = extract_value("value", record, span)?;
let char = extract_char(value, config)?;
EditCommand::MoveRightUntil(char)
let select = extract_value("select", record, span)
.and_then(|value| value.as_bool())
.unwrap_or(false);
EditCommand::MoveRightUntil { c: char, select }
}
"moverightbefore" => {
let value = extract_value("value", record, span)?;
let char = extract_char(value, config)?;
EditCommand::MoveRightBefore(char)
let select = extract_value("select", record, span)
.and_then(|value| value.as_bool())
.unwrap_or(false);
EditCommand::MoveRightBefore { c: char, select }
}
"cutleftuntil" => {
let value = extract_value("value", record, span)?;
@ -948,14 +1257,23 @@ fn edit_from_record(
"moveleftuntil" => {
let value = extract_value("value", record, span)?;
let char = extract_char(value, config)?;
EditCommand::MoveLeftUntil(char)
let select = extract_value("select", record, span)
.and_then(|value| value.as_bool())
.unwrap_or(false);
EditCommand::MoveLeftUntil { c: char, select }
}
"moveleftbefore" => {
let value = extract_value("value", record, span)?;
let char = extract_char(value, config)?;
EditCommand::MoveLeftBefore(char)
let select = extract_value("select", record, span)
.and_then(|value| value.as_bool())
.unwrap_or(false);
EditCommand::MoveLeftBefore { c: char, select }
}
"complete" => EditCommand::Complete,
"cutselection" => EditCommand::CutSelection,
"copyselection" => EditCommand::CopySelection,
"selectall" => EditCommand::SelectAll,
e => {
return Err(ShellError::UnsupportedConfigValue {
expected: "reedline EditCommand".to_string(),
@ -1109,4 +1427,57 @@ mod test {
let b = EventType::try_from_record(&event, span);
assert!(matches!(b, Err(ShellError::MissingConfigValue { .. })));
}
#[test]
fn test_move_without_optional_select() {
let event = record! {
"edit" => Value::test_string("moveleft")
};
let event = Value::test_record(event);
let config = Config::default();
let parsed_event = parse_event(&event, &config).unwrap();
assert_eq!(
parsed_event,
Some(ReedlineEvent::Edit(vec![EditCommand::MoveLeft {
select: false
}]))
);
}
#[test]
fn test_move_with_select_false() {
let event = record! {
"edit" => Value::test_string("moveleft"),
"select" => Value::test_bool(false)
};
let event = Value::test_record(event);
let config = Config::default();
let parsed_event = parse_event(&event, &config).unwrap();
assert_eq!(
parsed_event,
Some(ReedlineEvent::Edit(vec![EditCommand::MoveLeft {
select: false
}]))
);
}
#[test]
fn test_move_with_select_true() {
let event = record! {
"edit" => Value::test_string("moveleft"),
"select" => Value::test_bool(true)
};
let event = Value::test_record(event);
let config = Config::default();
let parsed_event = parse_event(&event, &config).unwrap();
assert_eq!(
parsed_event,
Some(ReedlineEvent::Edit(vec![EditCommand::MoveLeft {
select: true
}]))
);
}
}

View File

@ -11,13 +11,13 @@ use miette::{ErrReport, IntoDiagnostic, Result};
use nu_cmd_base::util::get_guaranteed_cwd;
use nu_cmd_base::{hook::eval_hook, util::get_editor};
use nu_color_config::StyleComputer;
use nu_engine::convert_env_values;
use nu_engine::{convert_env_values, env_to_strings};
use nu_parser::{lex, parse, trim_quotes_str};
use nu_protocol::{
config::NuCursorShape,
engine::{EngineState, Stack, StateWorkingSet},
eval_const::create_nu_constant,
report_error, report_error_new, HistoryFileFormat, PipelineData, ShellError, Span, Spanned,
report_error_new, HistoryConfig, HistoryFileFormat, PipelineData, ShellError, Span, Spanned,
Value, NU_VARIABLE_ID,
};
use nu_utils::utils::perf;
@ -28,11 +28,11 @@ use reedline::{
use std::{
env::temp_dir,
io::{self, IsTerminal, Write},
path::Path,
path::PathBuf,
sync::atomic::Ordering,
time::Instant,
time::{Duration, Instant},
};
use sysinfo::SystemExt;
use sysinfo::System;
// According to Daniel Imms @Tyriar, we need to do these this way:
// <133 A><prompt><133 B><command><133 C><command output>
@ -44,6 +44,9 @@ const PRE_EXECUTE_MARKER: &str = "\x1b]133;C\x1b\\";
// const CMD_FINISHED_MARKER: &str = "\x1b]133;D;{}\x1b\\";
const RESET_APPLICATION_MODE: &str = "\x1b[?1l";
///
/// The main REPL loop, including spinning up the prompt itself.
///
pub fn evaluate_repl(
engine_state: &mut EngineState,
stack: &mut Stack,
@ -54,27 +57,19 @@ pub fn evaluate_repl(
) -> Result<()> {
use nu_cmd_base::hook;
use reedline::Signal;
let use_color = engine_state.get_config().use_ansi_coloring;
let config = engine_state.get_config();
let use_color = config.use_ansi_coloring;
// Guard against invocation without a connected terminal.
// reedline / crossterm event polling will fail without a connected tty
if !std::io::stdin().is_terminal() {
return Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
"Nushell launched as a REPL, but STDIN is not a TTY; either launch in a valid terminal or provide arguments to invoke a script!",
))
.into_diagnostic();
}
confirm_stdin_is_terminal()?;
let mut entry_num = 0;
let mut nu_prompt = NushellPrompt::new();
let mut nu_prompt = NushellPrompt::new(config.shell_integration);
let start_time = std::time::Instant::now();
// Translate environment variables from Strings to Values
if let Some(e) = convert_env_values(engine_state, stack) {
let working_set = StateWorkingSet::new(engine_state);
report_error(&working_set, &e);
report_error_new(engine_state, &e);
}
perf(
"translate env vars",
@ -108,42 +103,20 @@ pub fn evaluate_repl(
use_color,
);
// Setup history_isolation aka "history per session"
let history_isolation = engine_state.get_config().history_isolation;
let history_session_id = if history_isolation {
Reedline::create_history_session_id()
} else {
None
};
if let Some(history) = engine_state.history_config() {
start_time = std::time::Instant::now();
start_time = std::time::Instant::now();
let history_path = crate::config_files::get_history_path(
nushell_path,
engine_state.config.history_file_format,
);
if let Some(history_path) = history_path.as_deref() {
line_editor =
update_line_editor_history(engine_state, history_path, line_editor, history_session_id)?
};
perf(
"setup history",
start_time,
file!(),
line!(),
column!(),
use_color,
);
line_editor = setup_history(nushell_path, engine_state, line_editor, history)?;
start_time = std::time::Instant::now();
let sys = sysinfo::System::new();
perf(
"get sysinfo",
start_time,
file!(),
line!(),
column!(),
use_color,
);
perf(
"setup history",
start_time,
file!(),
line!(),
column!(),
use_color,
);
}
if let Some(s) = prerun_command {
eval_source(
@ -174,9 +147,7 @@ pub fn evaluate_repl(
);
}
if engine_state.get_config().use_kitty_protocol && !reedline::kitty_protocol_available() {
warn!("Terminal doesn't support use_kitty_protocol config");
}
kitty_protocol_healthcheck(engine_state);
loop {
let loop_start_time = std::time::Instant::now();
@ -212,20 +183,6 @@ pub fn evaluate_repl(
use_color,
);
start_time = std::time::Instant::now();
// Reset the SIGQUIT handler
if let Some(sig_quit) = engine_state.get_sig_quit() {
sig_quit.store(false, Ordering::SeqCst);
}
perf(
"reset sig_quit",
start_time,
file!(),
line!(),
column!(),
use_color,
);
start_time = std::time::Instant::now();
let config = engine_state.get_config();
@ -255,6 +212,7 @@ pub fn evaluate_repl(
.use_bracketed_paste(cfg!(not(target_os = "windows")) && config.bracketed_paste)
.with_highlighter(Box::new(NuHighlighter {
engine_state: engine_reference.clone(),
stack: std::sync::Arc::new(stack.clone()),
config: config.clone(),
}))
.with_validator(Box::new(NuValidator {
@ -267,11 +225,7 @@ pub fn evaluate_repl(
.with_quick_completions(config.quick_completions)
.with_partial_completions(config.partial_completions)
.with_ansi_colors(config.use_ansi_coloring)
.with_cursor_config(cursor_config)
.with_transient_prompt(prompt_update::transient_prompt(
engine_reference.clone(),
stack,
));
.with_cursor_config(cursor_config);
perf(
"reedline builder",
start_time,
@ -304,8 +258,7 @@ pub fn evaluate_repl(
start_time = std::time::Instant::now();
line_editor = add_menus(line_editor, engine_reference, stack, config).unwrap_or_else(|e| {
let working_set = StateWorkingSet::new(engine_state);
report_error(&working_set, &e);
report_error_new(engine_state, &e);
Reedline::create()
});
perf(
@ -322,12 +275,9 @@ pub fn evaluate_repl(
line_editor = if let Ok((cmd, args)) = buffer_editor {
let mut command = std::process::Command::new(&cmd);
command.args(args).envs(
engine_state
.render_env_vars()
.into_iter()
.filter_map(|(k, v)| v.as_string().ok().map(|v| (k, v))),
);
command
.args(args)
.envs(env_to_strings(engine_state, stack)?);
line_editor.with_buffer_editor(command, temp_file.clone())
} else {
line_editor
@ -341,43 +291,26 @@ pub fn evaluate_repl(
use_color,
);
start_time = std::time::Instant::now();
if config.sync_history_on_enter {
if let Err(e) = line_editor.sync_history() {
warn!("Failed to sync history: {}", e);
if let Some(history) = engine_state.history_config() {
start_time = std::time::Instant::now();
if history.sync_on_enter {
if let Err(e) = line_editor.sync_history() {
warn!("Failed to sync history: {}", e);
}
}
perf(
"sync_history",
start_time,
file!(),
line!(),
column!(),
use_color,
);
}
perf(
"sync_history",
start_time,
file!(),
line!(),
column!(),
use_color,
);
start_time = std::time::Instant::now();
// Changing the line editor based on the found keybindings
line_editor = match create_keybindings(config) {
Ok(keybindings) => match keybindings {
KeybindingsMode::Emacs(keybindings) => {
let edit_mode = Box::new(Emacs::new(keybindings));
line_editor.with_edit_mode(edit_mode)
}
KeybindingsMode::Vi {
insert_keybindings,
normal_keybindings,
} => {
let edit_mode = Box::new(Vi::new(insert_keybindings, normal_keybindings));
line_editor.with_edit_mode(edit_mode)
}
},
Err(e) => {
let working_set = StateWorkingSet::new(engine_state);
report_error(&working_set, &e);
line_editor
}
};
line_editor = setup_keybindings(engine_state, line_editor);
perf(
"keybindings",
start_time,
@ -424,7 +357,9 @@ pub fn evaluate_repl(
start_time = std::time::Instant::now();
let config = &engine_state.get_config().clone();
let prompt = prompt_update::update_prompt(config, engine_state, stack, &mut nu_prompt);
prompt_update::update_prompt(config, engine_state, stack, &mut nu_prompt);
let transient_prompt =
prompt_update::make_transient_prompt(config, engine_state, stack, &nu_prompt);
perf(
"update_prompt",
start_time,
@ -437,25 +372,20 @@ pub fn evaluate_repl(
entry_num += 1;
start_time = std::time::Instant::now();
let input = line_editor.read_line(prompt);
line_editor = line_editor.with_transient_prompt(transient_prompt);
let input = line_editor.read_line(&nu_prompt);
let shell_integration = config.shell_integration;
match input {
Ok(Signal::Success(s)) => {
let hostname = sys.host_name();
let history_supports_meta =
matches!(config.history_file_format, HistoryFileFormat::Sqlite);
if history_supports_meta && !s.is_empty() && line_editor.has_last_command_context()
{
line_editor
.update_last_command_context(&|mut c| {
c.start_timestamp = Some(chrono::Utc::now());
c.hostname = hostname.clone();
let hostname = System::host_name();
let history_supports_meta = matches!(
engine_state.history_config().map(|h| h.file_format),
Some(HistoryFileFormat::Sqlite)
);
c.cwd = Some(StateWorkingSet::new(engine_state).get_cwd());
c
})
.into_diagnostic()?; // todo: don't stop repl if error here?
if history_supports_meta {
prepare_history_metadata(&s, &hostname, engine_state, &mut line_editor)?;
}
// Right before we start running the code the user gave us, fire the `pre_execution`
@ -482,107 +412,27 @@ pub fn evaluate_repl(
run_ansi_sequence(PRE_EXECUTE_MARKER)?;
}
// Actual command execution logic starts from here
let start_time = Instant::now();
let tokens = lex(s.as_bytes(), 0, &[], &[], false);
// Check if this is a single call to a directory, if so auto-cd
let cwd = nu_engine::env::current_dir_str(engine_state, stack)?;
let mut orig = s.clone();
if orig.starts_with('`') {
orig = trim_quotes_str(&orig).to_string()
}
let path = nu_path::expand_path_with(&orig, &cwd);
if looks_like_path(&orig) && path.is_dir() && tokens.0.len() == 1 {
// We have an auto-cd
let (path, span) = {
if !path.exists() {
let working_set = StateWorkingSet::new(engine_state);
report_error(
&working_set,
&ShellError::DirectoryNotFound {
dir: path.to_string_lossy().to_string(),
span: tokens.0[0].span,
},
);
}
let path = nu_path::canonicalize_with(path, &cwd)
.expect("internal error: cannot canonicalize known path");
(path.to_string_lossy().to_string(), tokens.0[0].span)
};
stack.add_env_var("OLDPWD".into(), Value::string(cwd.clone(), Span::unknown()));
//FIXME: this only changes the current scope, but instead this environment variable
//should probably be a block that loads the information from the state in the overlay
stack.add_env_var("PWD".into(), Value::string(path.clone(), Span::unknown()));
let cwd = Value::string(cwd, span);
let shells = stack.get_env_var(engine_state, "NUSHELL_SHELLS");
let mut shells = if let Some(v) = shells {
v.as_list()
.map(|x| x.to_vec())
.unwrap_or_else(|_| vec![cwd])
} else {
vec![cwd]
};
let current_shell = stack.get_env_var(engine_state, "NUSHELL_CURRENT_SHELL");
let current_shell = if let Some(v) = current_shell {
v.as_int().unwrap_or_default() as usize
} else {
0
};
let last_shell = stack.get_env_var(engine_state, "NUSHELL_LAST_SHELL");
let last_shell = if let Some(v) = last_shell {
v.as_int().unwrap_or_default() as usize
} else {
0
};
shells[current_shell] = Value::string(path, span);
stack.add_env_var("NUSHELL_SHELLS".into(), Value::list(shells, span));
stack.add_env_var(
"NUSHELL_LAST_SHELL".into(),
Value::int(last_shell as i64, span),
);
} else if !s.trim().is_empty() {
trace!("eval source: {}", s);
let mut cmds = s.split_whitespace();
if let Some("exit") = cmds.next() {
let mut working_set = StateWorkingSet::new(engine_state);
let _ = parse(&mut working_set, None, s.as_bytes(), false);
if working_set.parse_errors.is_empty() {
match cmds.next() {
Some(s) => {
if let Ok(n) = s.parse::<i32>() {
drop(line_editor);
std::process::exit(n);
}
}
None => {
drop(line_editor);
std::process::exit(0);
}
}
}
match parse_operation(s.clone(), engine_state, stack)? {
ReplOperation::AutoCd { cwd, target, span } => {
do_auto_cd(target, cwd, stack, engine_state, span);
}
eval_source(
engine_state,
stack,
s.as_bytes(),
&format!("entry #{entry_num}"),
PipelineData::empty(),
false,
);
ReplOperation::RunCommand(cmd) => {
line_editor = do_run_cmd(
&cmd,
stack,
engine_state,
line_editor,
shell_integration,
entry_num,
)?;
}
// as the name implies, we do nothing in this case
ReplOperation::DoNothing => {}
}
let cmd_duration = start_time.elapsed();
stack.add_env_var(
@ -590,74 +440,21 @@ pub fn evaluate_repl(
Value::string(format!("{}", cmd_duration.as_millis()), Span::unknown()),
);
if history_supports_meta && !s.is_empty() && line_editor.has_last_command_context()
{
line_editor
.update_last_command_context(&|mut c| {
c.duration = Some(cmd_duration);
c.exit_status = stack
.get_env_var(engine_state, "LAST_EXIT_CODE")
.and_then(|e| e.as_i64().ok());
c
})
.into_diagnostic()?; // todo: don't stop repl if error here?
if history_supports_meta {
fill_in_result_related_history_metadata(
&s,
engine_state,
cmd_duration,
stack,
&mut line_editor,
)?;
}
if shell_integration {
run_ansi_sequence(&get_command_finished_marker(stack, engine_state))?;
if let Some(cwd) = stack.get_env_var(engine_state, "PWD") {
let path = cwd.as_string()?;
// Supported escape sequences of Microsoft's Visual Studio Code (vscode)
// https://code.visualstudio.com/docs/terminal/shell-integration#_supported-escape-sequences
if stack.get_env_var(engine_state, "TERM_PROGRAM")
== Some(Value::test_string("vscode"))
{
// If we're in vscode, run their specific ansi escape sequence.
// This is helpful for ctrl+g to change directories in the terminal.
run_ansi_sequence(&format!("\x1b]633;P;Cwd={}\x1b\\", path))?;
} else {
// Otherwise, communicate the path as OSC 7 (often used for spawning new tabs in the same dir)
run_ansi_sequence(&format!(
"\x1b]7;file://{}{}{}\x1b\\",
percent_encoding::utf8_percent_encode(
&hostname.unwrap_or_else(|| "localhost".to_string()),
percent_encoding::CONTROLS
),
if path.starts_with('/') { "" } else { "/" },
percent_encoding::utf8_percent_encode(
&path,
percent_encoding::CONTROLS
)
))?;
}
// Try to abbreviate string for windows title
let maybe_abbrev_path = if let Some(p) = nu_path::home_dir() {
path.replace(&p.as_path().display().to_string(), "~")
} else {
path
};
// Set window title too
// https://tldp.org/HOWTO/Xterm-Title-3.html
// ESC]0;stringBEL -- Set icon name and window title to string
// ESC]1;stringBEL -- Set icon name to string
// ESC]2;stringBEL -- Set window title to string
run_ansi_sequence(&format!("\x1b]2;{maybe_abbrev_path}\x07"))?;
}
run_ansi_sequence(RESET_APPLICATION_MODE)?;
do_shell_integration_finalize_command(hostname, engine_state, stack)?;
}
let mut repl = engine_state.repl_state.lock().expect("repl state mutex");
line_editor.run_edit_commands(&[
EditCommand::Clear,
EditCommand::InsertString(repl.buffer.to_string()),
EditCommand::MoveToPosition(repl.cursor_pos),
]);
repl.buffer = "".to_string();
repl.cursor_pos = 0;
drop(repl);
flush_engine_state_repl_buffer(engine_state, &mut line_editor);
}
Ok(Signal::CtrlC) => {
// `Reedline` clears the line content. New prompt is shown
@ -709,6 +506,364 @@ pub fn evaluate_repl(
Ok(())
}
///
/// Put in history metadata not related to the result of running the command
///
fn prepare_history_metadata(
s: &str,
hostname: &Option<String>,
engine_state: &EngineState,
line_editor: &mut Reedline,
) -> Result<()> {
if !s.is_empty() && line_editor.has_last_command_context() {
line_editor
.update_last_command_context(&|mut c| {
c.start_timestamp = Some(chrono::Utc::now());
c.hostname = hostname.clone();
c.cwd = Some(StateWorkingSet::new(engine_state).get_cwd());
c
})
.into_diagnostic()?; // todo: don't stop repl if error here?
}
Ok(())
}
///
/// Fills in history item metadata based on the execution result (notably duration and exit code)
///
fn fill_in_result_related_history_metadata(
s: &str,
engine_state: &EngineState,
cmd_duration: Duration,
stack: &mut Stack,
line_editor: &mut Reedline,
) -> Result<()> {
if !s.is_empty() && line_editor.has_last_command_context() {
line_editor
.update_last_command_context(&|mut c| {
c.duration = Some(cmd_duration);
c.exit_status = stack
.get_env_var(engine_state, "LAST_EXIT_CODE")
.and_then(|e| e.as_i64().ok());
c
})
.into_diagnostic()?; // todo: don't stop repl if error here?
}
Ok(())
}
/// The kinds of operations you can do in a single loop iteration of the REPL
enum ReplOperation {
/// "auto-cd": change directory by typing it in directly
AutoCd {
/// the current working directory
cwd: String,
/// the target
target: PathBuf,
/// span information for debugging
span: Span,
},
/// run a command
RunCommand(String),
/// do nothing (usually through an empty string)
DoNothing,
}
///
/// Parses one "REPL line" of input, to try and derive intent.
/// Notably, this is where we detect whether the user is attempting an
/// "auto-cd" (writing a relative path directly instead of `cd path`)
///
/// Returns the ReplOperation we believe the user wants to do
///
fn parse_operation(
s: String,
engine_state: &EngineState,
stack: &Stack,
) -> Result<ReplOperation, ErrReport> {
let tokens = lex(s.as_bytes(), 0, &[], &[], false);
// Check if this is a single call to a directory, if so auto-cd
let cwd = nu_engine::env::current_dir_str(engine_state, stack)?;
let mut orig = s.clone();
if orig.starts_with('`') {
orig = trim_quotes_str(&orig).to_string()
}
let path = nu_path::expand_path_with(&orig, &cwd);
if looks_like_path(&orig) && path.is_dir() && tokens.0.len() == 1 {
Ok(ReplOperation::AutoCd {
cwd,
target: path,
span: tokens.0[0].span,
})
} else if !s.trim().is_empty() {
Ok(ReplOperation::RunCommand(s))
} else {
Ok(ReplOperation::DoNothing)
}
}
///
/// Execute an "auto-cd" operation, changing the current working directory.
///
fn do_auto_cd(
path: PathBuf,
cwd: String,
stack: &mut Stack,
engine_state: &mut EngineState,
span: Span,
) {
let path = {
if !path.exists() {
report_error_new(
engine_state,
&ShellError::DirectoryNotFound {
dir: path.to_string_lossy().to_string(),
span,
},
);
}
let path = nu_path::canonicalize_with(path, &cwd)
.expect("internal error: cannot canonicalize known path");
path.to_string_lossy().to_string()
};
stack.add_env_var("OLDPWD".into(), Value::string(cwd.clone(), Span::unknown()));
//FIXME: this only changes the current scope, but instead this environment variable
//should probably be a block that loads the information from the state in the overlay
stack.add_env_var("PWD".into(), Value::string(path.clone(), Span::unknown()));
let cwd = Value::string(cwd, span);
let shells = stack.get_env_var(engine_state, "NUSHELL_SHELLS");
let mut shells = if let Some(v) = shells {
v.as_list()
.map(|x| x.to_vec())
.unwrap_or_else(|_| vec![cwd])
} else {
vec![cwd]
};
let current_shell = stack.get_env_var(engine_state, "NUSHELL_CURRENT_SHELL");
let current_shell = if let Some(v) = current_shell {
v.as_int().unwrap_or_default() as usize
} else {
0
};
let last_shell = stack.get_env_var(engine_state, "NUSHELL_LAST_SHELL");
let last_shell = if let Some(v) = last_shell {
v.as_int().unwrap_or_default() as usize
} else {
0
};
shells[current_shell] = Value::string(path, span);
stack.add_env_var("NUSHELL_SHELLS".into(), Value::list(shells, span));
stack.add_env_var(
"NUSHELL_LAST_SHELL".into(),
Value::int(last_shell as i64, span),
);
}
///
/// Run a command as received from reedline. This is where we are actually
/// running a thing!
///
fn do_run_cmd(
s: &str,
stack: &mut Stack,
engine_state: &mut EngineState,
// we pass in the line editor so it can be dropped in the case of a process exit
// (in the normal case we don't want to drop it so return it as-is otherwise)
line_editor: Reedline,
shell_integration: bool,
entry_num: usize,
) -> Result<Reedline> {
trace!("eval source: {}", s);
let mut cmds = s.split_whitespace();
if let Some("exit") = cmds.next() {
let mut working_set = StateWorkingSet::new(engine_state);
let _ = parse(&mut working_set, None, s.as_bytes(), false);
if working_set.parse_errors.is_empty() {
match cmds.next() {
Some(s) => {
if let Ok(n) = s.parse::<i32>() {
drop(line_editor);
std::process::exit(n);
}
}
None => {
drop(line_editor);
std::process::exit(0);
}
}
}
}
if shell_integration {
if let Some(cwd) = stack.get_env_var(engine_state, "PWD") {
let path = cwd.as_string()?;
// Try to abbreviate string for windows title
let maybe_abbrev_path = if let Some(p) = nu_path::home_dir() {
path.replace(&p.as_path().display().to_string(), "~")
} else {
path
};
let binary_name = s.split_whitespace().next();
if let Some(binary_name) = binary_name {
run_ansi_sequence(&format!("\x1b]2;{maybe_abbrev_path}> {binary_name}\x07"))?;
}
}
}
eval_source(
engine_state,
stack,
s.as_bytes(),
&format!("entry #{entry_num}"),
PipelineData::empty(),
false,
);
Ok(line_editor)
}
///
/// Output some things and set environment variables so shells with the right integration
/// can have more information about what is going on (after we have run a command)
///
fn do_shell_integration_finalize_command(
hostname: Option<String>,
engine_state: &EngineState,
stack: &mut Stack,
) -> Result<()> {
run_ansi_sequence(&get_command_finished_marker(stack, engine_state))?;
if let Some(cwd) = stack.get_env_var(engine_state, "PWD") {
let path = cwd.as_string()?;
// Supported escape sequences of Microsoft's Visual Studio Code (vscode)
// https://code.visualstudio.com/docs/terminal/shell-integration#_supported-escape-sequences
if stack.get_env_var(engine_state, "TERM_PROGRAM") == Some(Value::test_string("vscode")) {
// If we're in vscode, run their specific ansi escape sequence.
// This is helpful for ctrl+g to change directories in the terminal.
run_ansi_sequence(&format!("\x1b]633;P;Cwd={}\x1b\\", path))?;
} else {
// Otherwise, communicate the path as OSC 7 (often used for spawning new tabs in the same dir)
run_ansi_sequence(&format!(
"\x1b]7;file://{}{}{}\x1b\\",
percent_encoding::utf8_percent_encode(
&hostname.unwrap_or_else(|| "localhost".to_string()),
percent_encoding::CONTROLS
),
if path.starts_with('/') { "" } else { "/" },
percent_encoding::utf8_percent_encode(&path, percent_encoding::CONTROLS)
))?;
}
// Try to abbreviate string for windows title
let maybe_abbrev_path = if let Some(p) = nu_path::home_dir() {
path.replace(&p.as_path().display().to_string(), "~")
} else {
path
};
// Set window title too
// https://tldp.org/HOWTO/Xterm-Title-3.html
// ESC]0;stringBEL -- Set icon name and window title to string
// ESC]1;stringBEL -- Set icon name to string
// ESC]2;stringBEL -- Set window title to string
run_ansi_sequence(&format!("\x1b]2;{maybe_abbrev_path}\x07"))?;
}
run_ansi_sequence(RESET_APPLICATION_MODE)?;
Ok(())
}
///
/// Clear the screen and output anything remaining in the EngineState buffer.
///
fn flush_engine_state_repl_buffer(engine_state: &mut EngineState, line_editor: &mut Reedline) {
let mut repl = engine_state.repl_state.lock().expect("repl state mutex");
line_editor.run_edit_commands(&[
EditCommand::Clear,
EditCommand::InsertString(repl.buffer.to_string()),
EditCommand::MoveToPosition {
position: repl.cursor_pos,
select: false,
},
]);
repl.buffer = "".to_string();
repl.cursor_pos = 0;
}
///
/// Setup history management for Reedline
///
fn setup_history(
nushell_path: &str,
engine_state: &mut EngineState,
line_editor: Reedline,
history: HistoryConfig,
) -> Result<Reedline> {
// Setup history_isolation aka "history per session"
let history_session_id = if history.isolation {
Reedline::create_history_session_id()
} else {
None
};
if let Some(path) = crate::config_files::get_history_path(nushell_path, history.file_format) {
return update_line_editor_history(
engine_state,
path,
history,
line_editor,
history_session_id,
);
};
Ok(line_editor)
}
///
/// Setup Reedline keybindingds based on the provided config
///
fn setup_keybindings(engine_state: &EngineState, line_editor: Reedline) -> Reedline {
return match create_keybindings(engine_state.get_config()) {
Ok(keybindings) => match keybindings {
KeybindingsMode::Emacs(keybindings) => {
let edit_mode = Box::new(Emacs::new(keybindings));
line_editor.with_edit_mode(edit_mode)
}
KeybindingsMode::Vi {
insert_keybindings,
normal_keybindings,
} => {
let edit_mode = Box::new(Vi::new(insert_keybindings, normal_keybindings));
line_editor.with_edit_mode(edit_mode)
}
},
Err(e) => {
report_error_new(engine_state, &e);
line_editor
}
};
}
///
/// Make sure that the terminal supports the kitty protocol if the config is asking for it
///
fn kitty_protocol_healthcheck(engine_state: &EngineState) {
if engine_state.get_config().use_kitty_protocol && !reedline::kitty_protocol_available() {
warn!("Terminal doesn't support use_kitty_protocol config");
}
}
fn store_history_id_in_engine(engine_state: &mut EngineState, line_editor: &Reedline) {
let session_id = line_editor
.get_history_session_id()
@ -720,18 +875,15 @@ fn store_history_id_in_engine(engine_state: &mut EngineState, line_editor: &Reed
fn update_line_editor_history(
engine_state: &mut EngineState,
history_path: &Path,
history_path: PathBuf,
history: HistoryConfig,
line_editor: Reedline,
history_session_id: Option<HistorySessionId>,
) -> Result<Reedline, ErrReport> {
let config = engine_state.get_config();
let history: Box<dyn reedline::History> = match engine_state.config.history_file_format {
let history: Box<dyn reedline::History> = match history.file_format {
HistoryFileFormat::PlainText => Box::new(
FileBackedHistory::with_file(
config.max_history_size as usize,
history_path.to_path_buf(),
)
.into_diagnostic()?,
FileBackedHistory::with_file(history.max_size as usize, history_path)
.into_diagnostic()?,
),
HistoryFileFormat::Sqlite => Box::new(
SqliteBackedHistory::with_file(
@ -752,6 +904,18 @@ fn update_line_editor_history(
Ok(line_editor)
}
fn confirm_stdin_is_terminal() -> Result<()> {
// Guard against invocation without a connected terminal.
// reedline / crossterm event polling will fail without a connected tty
if !std::io::stdin().is_terminal() {
return Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
"Nushell launched as a REPL, but STDIN is not a TTY; either launch in a valid terminal or provide arguments to invoke a script!",
))
.into_diagnostic();
}
Ok(())
}
fn map_nucursorshape_to_cursorshape(shape: NuCursorShape) -> Option<SetCursorStyle> {
match shape {
NuCursorShape::Block => Some(SetCursorStyle::SteadyBlock),
@ -764,7 +928,7 @@ fn map_nucursorshape_to_cursorshape(shape: NuCursorShape) -> Option<SetCursorSty
}
}
pub fn get_command_finished_marker(stack: &Stack, engine_state: &EngineState) -> String {
fn get_command_finished_marker(stack: &Stack, engine_state: &EngineState) -> String {
let exit_code = stack
.get_env_var(engine_state, "LAST_EXIT_CODE")
.and_then(|e| e.as_i64().ok());
@ -839,14 +1003,18 @@ fn trailing_slash_looks_like_path() {
#[test]
fn are_session_ids_in_sync() {
let engine_state = &mut EngineState::new();
let history_path_o =
crate::config_files::get_history_path("nushell", engine_state.config.history_file_format);
assert!(history_path_o.is_some());
let history_path = history_path_o.as_deref().unwrap();
let history = engine_state.history_config().unwrap();
let history_path =
crate::config_files::get_history_path("nushell", history.file_format).unwrap();
let line_editor = reedline::Reedline::create();
let history_session_id = reedline::Reedline::create_history_session_id();
let line_editor =
update_line_editor_history(engine_state, history_path, line_editor, history_session_id);
let line_editor = update_line_editor_history(
engine_state,
history_path,
history,
line_editor,
history_session_id,
);
assert_eq!(
i64::from(line_editor.unwrap().get_history_session_id().unwrap()),
engine_state.history_session_id

View File

@ -1,15 +1,17 @@
use log::trace;
use nu_ansi_term::Style;
use nu_color_config::{get_matching_brackets_style, get_shape_color};
use nu_engine::env;
use nu_parser::{flatten_block, parse, FlatShape};
use nu_protocol::ast::{Argument, Block, Expr, Expression, PipelineElement, RecordItem};
use nu_protocol::engine::{EngineState, StateWorkingSet};
use nu_protocol::engine::{EngineState, Stack, StateWorkingSet};
use nu_protocol::{Config, Span};
use reedline::{Highlighter, StyledText};
use std::sync::Arc;
pub struct NuHighlighter {
pub engine_state: Arc<EngineState>,
pub stack: Arc<Stack>,
pub config: Config,
}
@ -32,7 +34,17 @@ impl Highlighter for NuHighlighter {
working_set.get_span_contents(Span::new(span.start, span.end));
let str_word = String::from_utf8_lossy(str_contents).to_string();
if which::which(str_word).ok().is_some() {
let paths = env::path_str(&self.engine_state, &self.stack, *span).ok();
let res = if let Ok(cwd) =
env::current_dir_str(&self.engine_state, &self.stack)
{
which::which_in(str_word, paths.as_ref(), cwd).ok()
} else {
which::which_in_global(str_word, paths.as_ref())
.ok()
.and_then(|mut i| i.next())
};
if res.is_some() {
*shape = FlatShape::ExternalResolved;
}
}
@ -321,15 +333,14 @@ fn find_matching_block_end_in_expr(
Expr::Keyword(..) => None,
Expr::ValueWithUnit(..) => None,
Expr::DateTime(_) => None,
Expr::Filepath(_) => None,
Expr::Directory(_) => None,
Expr::GlobPattern(_) => None,
Expr::Filepath(_, _) => None,
Expr::Directory(_, _) => None,
Expr::GlobPattern(_, _) => None,
Expr::String(_) => None,
Expr::CellPath(_) => None,
Expr::ImportPattern(_) => None,
Expr::Overlay(_) => None,
Expr::Signature(_) => None,
Expr::MatchPattern(_) => None,
Expr::MatchBlock(_) => None,
Expr::Nothing => None,
Expr::Garbage => None,
@ -386,6 +397,7 @@ fn find_matching_block_end_in_expr(
Argument::Named((_, _, opt_expr)) => opt_expr.as_ref(),
Argument::Positional(inner_expr) => Some(inner_expr),
Argument::Unknown(inner_expr) => Some(inner_expr),
Argument::Spread(inner_expr) => Some(inner_expr),
};
if let Some(inner_expr) = opt_expr {

View File

@ -220,6 +220,10 @@ pub fn eval_source(
source,
false,
);
if let Some(warning) = working_set.parse_warnings.first() {
report_error(&working_set, warning);
}
if let Some(err) = working_set.parse_errors.first() {
set_last_exit_code(stack, 1);
report_error(&working_set, err);

View File

@ -91,7 +91,7 @@ fn variables_dollar_sign_with_varialblecompletion() {
let target_dir = "$ ";
let suggestions = completer.complete(target_dir, target_dir.len());
assert_eq!(7, suggestions.len());
assert_eq!(8, suggestions.len());
}
#[rstest]
@ -144,15 +144,34 @@ fn dotnu_completions() {
let completion_str = "source-env ".to_string();
let suggestions = completer.complete(&completion_str, completion_str.len());
assert_eq!(1, suggestions.len());
assert_eq!(2, suggestions.len());
assert_eq!("custom_completion.nu", suggestions.first().unwrap().value);
#[cfg(windows)]
assert_eq!("directory_completion\\", suggestions.get(1).unwrap().value);
#[cfg(not(windows))]
assert_eq!("directory_completion/", suggestions.get(1).unwrap().value);
// Test use completion
let completion_str = "use ".to_string();
let suggestions = completer.complete(&completion_str, completion_str.len());
assert_eq!(1, suggestions.len());
assert_eq!(2, suggestions.len());
assert_eq!("custom_completion.nu", suggestions.first().unwrap().value);
#[cfg(windows)]
assert_eq!("directory_completion\\", suggestions.get(1).unwrap().value);
#[cfg(not(windows))]
assert_eq!("directory_completion/", suggestions.get(1).unwrap().value);
// Test overlay use completion
let completion_str = "overlay use ".to_string();
let suggestions = completer.complete(&completion_str, completion_str.len());
assert_eq!(2, suggestions.len());
assert_eq!("custom_completion.nu", suggestions.first().unwrap().value);
#[cfg(windows)]
assert_eq!("directory_completion\\", suggestions.get(1).unwrap().value);
#[cfg(not(windows))]
assert_eq!("directory_completion/", suggestions.get(1).unwrap().value);
}
#[test]
@ -208,6 +227,7 @@ fn file_completions() {
let expected_paths: Vec<String> = vec![
folder(dir.join("another")),
file(dir.join("custom_completion.nu")),
folder(dir.join("directory_completion")),
file(dir.join("nushell")),
folder(dir.join("test_a")),
folder(dir.join("test_b")),
@ -323,6 +343,7 @@ fn command_ls_with_filecompletion() {
let expected_paths: Vec<String> = vec![
"another\\".to_string(),
"custom_completion.nu".to_string(),
"directory_completion\\".to_string(),
"nushell".to_string(),
"test_a\\".to_string(),
"test_b\\".to_string(),
@ -333,6 +354,7 @@ fn command_ls_with_filecompletion() {
let expected_paths: Vec<String> = vec![
"another/".to_string(),
"custom_completion.nu".to_string(),
"directory_completion/".to_string(),
"nushell".to_string(),
"test_a/".to_string(),
"test_b/".to_string(),
@ -355,6 +377,7 @@ fn command_open_with_filecompletion() {
let expected_paths: Vec<String> = vec![
"another\\".to_string(),
"custom_completion.nu".to_string(),
"directory_completion\\".to_string(),
"nushell".to_string(),
"test_a\\".to_string(),
"test_b\\".to_string(),
@ -365,6 +388,7 @@ fn command_open_with_filecompletion() {
let expected_paths: Vec<String> = vec![
"another/".to_string(),
"custom_completion.nu".to_string(),
"directory_completion/".to_string(),
"nushell".to_string(),
"test_a/".to_string(),
"test_b/".to_string(),
@ -388,6 +412,7 @@ fn command_rm_with_globcompletion() {
let expected_paths: Vec<String> = vec![
"another\\".to_string(),
"custom_completion.nu".to_string(),
"directory_completion\\".to_string(),
"nushell".to_string(),
"test_a\\".to_string(),
"test_b\\".to_string(),
@ -398,6 +423,7 @@ fn command_rm_with_globcompletion() {
let expected_paths: Vec<String> = vec![
"another/".to_string(),
"custom_completion.nu".to_string(),
"directory_completion/".to_string(),
"nushell".to_string(),
"test_a/".to_string(),
"test_b/".to_string(),
@ -421,6 +447,7 @@ fn command_cp_with_globcompletion() {
let expected_paths: Vec<String> = vec![
"another\\".to_string(),
"custom_completion.nu".to_string(),
"directory_completion\\".to_string(),
"nushell".to_string(),
"test_a\\".to_string(),
"test_b\\".to_string(),
@ -431,6 +458,7 @@ fn command_cp_with_globcompletion() {
let expected_paths: Vec<String> = vec![
"another/".to_string(),
"custom_completion.nu".to_string(),
"directory_completion/".to_string(),
"nushell".to_string(),
"test_a/".to_string(),
"test_b/".to_string(),
@ -454,6 +482,7 @@ fn command_save_with_filecompletion() {
let expected_paths: Vec<String> = vec![
"another\\".to_string(),
"custom_completion.nu".to_string(),
"directory_completion\\".to_string(),
"nushell".to_string(),
"test_a\\".to_string(),
"test_b\\".to_string(),
@ -464,6 +493,7 @@ fn command_save_with_filecompletion() {
let expected_paths: Vec<String> = vec![
"another/".to_string(),
"custom_completion.nu".to_string(),
"directory_completion/".to_string(),
"nushell".to_string(),
"test_a/".to_string(),
"test_b/".to_string(),
@ -487,6 +517,7 @@ fn command_touch_with_filecompletion() {
let expected_paths: Vec<String> = vec![
"another\\".to_string(),
"custom_completion.nu".to_string(),
"directory_completion\\".to_string(),
"nushell".to_string(),
"test_a\\".to_string(),
"test_b\\".to_string(),
@ -497,6 +528,7 @@ fn command_touch_with_filecompletion() {
let expected_paths: Vec<String> = vec![
"another/".to_string(),
"custom_completion.nu".to_string(),
"directory_completion/".to_string(),
"nushell".to_string(),
"test_a/".to_string(),
"test_b/".to_string(),
@ -520,6 +552,7 @@ fn command_watch_with_filecompletion() {
let expected_paths: Vec<String> = vec![
"another\\".to_string(),
"custom_completion.nu".to_string(),
"directory_completion\\".to_string(),
"nushell".to_string(),
"test_a\\".to_string(),
"test_b\\".to_string(),
@ -530,6 +563,7 @@ fn command_watch_with_filecompletion() {
let expected_paths: Vec<String> = vec![
"another/".to_string(),
"custom_completion.nu".to_string(),
"directory_completion/".to_string(),
"nushell".to_string(),
"test_a/".to_string(),
"test_b/".to_string(),
@ -625,6 +659,7 @@ fn folder_with_directorycompletions() {
// Create the expected values
let expected_paths: Vec<String> = vec![
folder(dir.join("another")),
folder(dir.join("directory_completion")),
folder(dir.join("test_a")),
folder(dir.join("test_b")),
folder(dir.join(".hidden_folder")),
@ -649,13 +684,14 @@ fn variables_completions() {
// Test completions for $nu
let suggestions = completer.complete("$nu.", 4);
assert_eq!(14, suggestions.len());
assert_eq!(15, suggestions.len());
let expected: Vec<String> = vec![
"config-path".into(),
"current-exe".into(),
"default-config-dir".into(),
"env-path".into(),
"history-enabled".into(),
"history-path".into(),
"home-path".into(),
"is-interactive".into(),
@ -674,9 +710,13 @@ fn variables_completions() {
// Test completions for $nu.h (filter)
let suggestions = completer.complete("$nu.h", 5);
assert_eq!(2, suggestions.len());
assert_eq!(3, suggestions.len());
let expected: Vec<String> = vec!["history-path".into(), "home-path".into()];
let expected: Vec<String> = vec![
"history-enabled".into(),
"history-path".into(),
"home-path".into(),
];
// Match results
match_suggestions(expected, suggestions);
@ -839,6 +879,7 @@ fn unknown_command_completion() {
let expected_paths: Vec<String> = vec![
"another\\".to_string(),
"custom_completion.nu".to_string(),
"directory_completion\\".to_string(),
"nushell".to_string(),
"test_a\\".to_string(),
"test_b\\".to_string(),
@ -849,6 +890,7 @@ fn unknown_command_completion() {
let expected_paths: Vec<String> = vec![
"another/".to_string(),
"custom_completion.nu".to_string(),
"directory_completion/".to_string(),
"nushell".to_string(),
"test_a/".to_string(),
"test_b/".to_string(),
@ -899,6 +941,7 @@ fn filecompletions_triggers_after_cursor() {
let expected_paths: Vec<String> = vec![
"another\\".to_string(),
"custom_completion.nu".to_string(),
"directory_completion\\".to_string(),
"nushell".to_string(),
"test_a\\".to_string(),
"test_b\\".to_string(),
@ -909,6 +952,7 @@ fn filecompletions_triggers_after_cursor() {
let expected_paths: Vec<String> = vec![
"another/".to_string(),
"custom_completion.nu".to_string(),
"directory_completion/".to_string(),
"nushell".to_string(),
"test_a/".to_string(),
"test_b/".to_string(),

View File

@ -5,21 +5,21 @@ edition = "2021"
license = "MIT"
name = "nu-cmd-base"
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-base"
version = "0.88.1"
version = "0.90.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.88.1" }
nu-glob = { path = "../nu-glob", version = "0.88.1" }
nu-parser = { path = "../nu-parser", version = "0.88.1" }
nu-path = { path = "../nu-path", version = "0.88.1" }
nu-protocol = { path = "../nu-protocol", version = "0.88.1" }
nu-utils = { path = "../nu-utils", version = "0.88.1" }
nu-engine = { path = "../nu-engine", version = "0.90.0" }
nu-glob = { path = "../nu-glob", version = "0.90.0" }
nu-parser = { path = "../nu-parser", version = "0.90.0" }
nu-path = { path = "../nu-path", version = "0.90.0" }
nu-protocol = { path = "../nu-protocol", version = "0.90.0" }
nu-utils = { path = "../nu-utils", version = "0.90.0" }
indexmap = "2.1"
miette = "5.10.0"
[dev-dependencies]
nu-test-support = { path = "../nu-test-support", version = "0.88.1" }
nu-test-support = { path = "../nu-test-support", version = "0.90.0" }
rstest = "0.18.2"

View File

@ -1,205 +0,0 @@
// utilities for expanding globs in command arguments
use nu_glob::{glob_with_parent, MatchOptions, Paths};
use nu_protocol::{ShellError, Spanned};
use std::fs;
use std::path::{Path, PathBuf};
// standard glob options to use for filesystem command arguments
const GLOB_PARAMS: MatchOptions = MatchOptions {
case_sensitive: true,
require_literal_separator: false,
require_literal_leading_dot: false,
recursive_match_hidden_dir: true,
};
// handle an argument that could be a literal path or a glob.
// if literal path, return just that (whether user can access it or not).
// if glob, expand into matching paths, using GLOB_PARAMS options.
pub fn arg_glob(
pattern: &Spanned<String>, // alleged path or glob
cwd: &Path, // current working directory
) -> Result<Paths, ShellError> {
arg_glob_opt(pattern, cwd, GLOB_PARAMS)
}
// variant of [arg_glob] that requires literal dot prefix in pattern to match dot-prefixed path.
pub fn arg_glob_leading_dot(pattern: &Spanned<String>, cwd: &Path) -> Result<Paths, ShellError> {
arg_glob_opt(
pattern,
cwd,
MatchOptions {
require_literal_leading_dot: true,
..GLOB_PARAMS
},
)
}
fn arg_glob_opt(
pattern: &Spanned<String>,
cwd: &Path,
options: MatchOptions,
) -> Result<Paths, ShellError> {
// remove ansi coloring (?)
let pattern = {
Spanned {
item: nu_utils::strip_ansi_string_unlikely(pattern.item.clone()),
span: pattern.span,
}
};
// if there's a file with same path as the pattern, just return that.
let pp = cwd.join(&pattern.item);
let md = fs::metadata(pp);
#[allow(clippy::single_match)]
match md {
Ok(_metadata) => {
return Ok(Paths::single(&PathBuf::from(pattern.item), cwd));
}
// file not found, but also "invalid chars in file" (e.g * on Windows). Fall through and glob
Err(_) => {}
}
// user wasn't referring to a specific thing in filesystem, try to glob it.
match glob_with_parent(&pattern.item, options, cwd) {
Ok(p) => Ok(p),
Err(pat_err) => Err(ShellError::InvalidGlobPattern {
msg: pat_err.msg.into(),
span: pattern.span,
}),
}
}
#[cfg(test)]
mod test {
use super::*;
use nu_glob::GlobResult;
use nu_protocol::{Span, Spanned};
use nu_test_support::fs::Stub::EmptyFile;
use nu_test_support::playground::Playground;
use rstest::rstest;
fn spanned_string(str: &str) -> Spanned<String> {
Spanned {
item: str.to_string(),
span: Span::test_data(),
}
}
#[test]
fn does_something() {
let act = arg_glob(&spanned_string("*"), &PathBuf::from("."));
assert!(act.is_ok());
for f in act.expect("checked ok") {
match f {
Ok(p) => {
assert!(!p.to_str().unwrap().is_empty());
}
Err(e) => panic!("unexpected error {:?}", e),
};
}
}
#[test]
fn glob_format_error() {
let act = arg_glob(&spanned_string(r#"ab]c[def"#), &PathBuf::from("."));
assert!(act.is_err());
}
#[rstest]
#[case("*", 4, "no dirs")]
#[case("**/*", 7, "incl dirs")]
fn glob_subdirs(#[case] pat: &str, #[case] exp_count: usize, #[case] case: &str) {
Playground::setup("glob_subdirs", |dirs, sandbox| {
sandbox.with_files(vec![
EmptyFile("yehuda.txt"),
EmptyFile("jttxt"),
EmptyFile("andres.txt"),
]);
sandbox.mkdir(".children");
sandbox.within(".children").with_files(vec![
EmptyFile("timothy.txt"),
EmptyFile("tiffany.txt"),
EmptyFile("trish.txt"),
]);
let p: Vec<GlobResult> = arg_glob(&spanned_string(pat), &dirs.test)
.expect("no error")
.collect();
assert_eq!(
exp_count,
p.iter().filter(|i| i.is_ok()).count(),
" case: {case} ",
);
// expected behavior -- that directories are included in results (if name matches pattern)
let t = p
.iter()
.any(|i| i.as_ref().unwrap().to_string_lossy().contains(".children"));
assert!(t, "check for dir, case {case}");
})
}
#[rstest]
#[case("yehuda.txt", true, 1, "matches literal path")]
#[case("*", false, 3, "matches glob")]
#[case(r#"bad[glob.foo"#, true, 1, "matches literal, would be bad glob pat")]
fn exact_vs_glob(
#[case] pat: &str,
#[case] exp_matches_input: bool,
#[case] exp_count: usize,
#[case] case: &str,
) {
Playground::setup("exact_vs_glob", |dirs, sandbox| {
sandbox.with_files(vec![
EmptyFile("yehuda.txt"),
EmptyFile("jttxt"),
EmptyFile("bad[glob.foo"),
]);
let res = arg_glob(&spanned_string(pat), &dirs.test)
.expect("no error")
.collect::<Vec<GlobResult>>();
eprintln!("res: {:?}", res);
if exp_matches_input {
assert_eq!(
exp_count,
res.len(),
" case {case}: matches input, but count not 1? "
);
assert_eq!(
&res[0].as_ref().unwrap().to_string_lossy(),
pat, // todo: is it OK for glob to return relative paths (not to current cwd, but to arg cwd of arg_glob)?
);
} else {
assert_eq!(exp_count, res.len(), " case: {}: matched glob", case);
}
})
}
#[rstest]
#[case(r#"realbad[glob.foo"#, true, 1, "error, bad glob")]
fn exact_vs_bad_glob(
// if path doesn't exist but pattern is not valid glob, should get error.
#[case] pat: &str,
#[case] _exp_matches_input: bool,
#[case] _exp_count: usize,
#[case] _tag: &str,
) {
Playground::setup("exact_vs_bad_glob", |dirs, sandbox| {
sandbox.with_files(vec![
EmptyFile("yehuda.txt"),
EmptyFile("jttxt"),
EmptyFile("bad[glob.foo"),
]);
let res = arg_glob(&spanned_string(pat), &dirs.test);
assert!(res
.expect_err("expected error")
.to_string()
.contains("Invalid glob pattern"));
})
}
}

View File

@ -1,7 +1,4 @@
mod arg_glob;
pub mod formats;
pub mod hook;
pub mod input_handler;
pub mod util;
pub use arg_glob::arg_glob;
pub use arg_glob::arg_glob_leading_dot;

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.88.1"
version = "0.90.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -13,9 +13,9 @@ version = "0.88.1"
bench = false
[dependencies]
nu-engine = { path = "../nu-engine", version = "0.88.1" }
nu-parser = { path = "../nu-parser", version = "0.88.1" }
nu-protocol = { path = "../nu-protocol", version = "0.88.1" }
nu-engine = { path = "../nu-engine", version = "0.90.0" }
nu-parser = { path = "../nu-parser", version = "0.90.0" }
nu-protocol = { path = "../nu-protocol", version = "0.90.0" }
# Potential dependencies for extras
chrono = { version = "0.4", features = ["std", "unstable-locales"], default-features = false }
@ -24,11 +24,12 @@ fancy-regex = "0.12"
indexmap = { version = "2.1" }
num = { version = "0.4", optional = true }
serde = { version = "1.0", features = ["derive"] }
sqlparser = { version = "0.39", optional = true }
polars-io = { version = "0.35", features = ["avro"], optional = true }
polars-arrow = "0.35"
polars-ops = "0.35"
polars-plan = "0.35"
sqlparser = { version = "0.43", optional = true }
polars-io = { version = "0.36", features = ["avro"], optional = true }
polars-arrow = { version = "0.36", optional = true }
polars-ops = { version = "0.36", optional = true }
polars-plan = { version = "0.36", optional = true }
polars-utils = { version = "0.36", optional = true }
[dependencies.polars]
features = [
@ -62,12 +63,12 @@ features = [
"to_dummies",
]
optional = true
version = "0.35"
version = "0.36"
[features]
dataframe = ["num", "polars", "polars-io", "sqlparser"]
dataframe = ["num", "polars", "polars-io", "polars-arrow", "polars-ops", "polars-plan", "polars-utils", "sqlparser"]
default = []
[dev-dependencies]
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.88.1" }
nu-test-support = { path = "../nu-test-support", version = "0.88.1" }
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.90.0" }
nu-test-support = { path = "../nu-test-support", version = "0.90.0" }

View File

@ -37,24 +37,27 @@ impl Command for AppendDF {
example: r#"let a = ([[a b]; [1 2] [3 4]] | dfr into-df);
$a | dfr append $a"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
Column::new(
"a_x".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
),
Column::new(
"b_x".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
Column::new(
"a_x".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
),
Column::new(
"b_x".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -64,26 +67,29 @@ impl Command for AppendDF {
example: r#"let a = ([[a b]; [1 2] [3 4]] | dfr into-df);
$a | dfr append $a --col"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![
Value::test_int(1),
Value::test_int(3),
Value::test_int(1),
Value::test_int(3),
],
),
Column::new(
"b".to_string(),
vec![
Value::test_int(2),
Value::test_int(4),
Value::test_int(2),
Value::test_int(4),
],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![
Value::test_int(1),
Value::test_int(3),
Value::test_int(1),
Value::test_int(3),
],
),
Column::new(
"b".to_string(),
vec![
Value::test_int(2),
Value::test_int(4),
Value::test_int(2),
Value::test_int(4),
],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -110,7 +116,7 @@ fn command(
) -> Result<PipelineData, ShellError> {
let other: Value = call.req(engine_state, stack, 0)?;
let axis = if call.has_flag("col") {
let axis = if call.has_flag(engine_state, stack, "col")? {
Axis::Column
} else {
Axis::Row

View File

@ -35,10 +35,13 @@ impl Command for DropDF {
description: "drop column a",
example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr drop a",
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
)])
NuDataFrame::try_from_columns(
vec![Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -46,16 +46,19 @@ impl Command for DropDuplicates {
description: "drop duplicates",
example: "[[a b]; [1 2] [3 4] [1 2]] | dfr into-df | dfr drop-duplicates",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_int(3), Value::test_int(1)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(4), Value::test_int(2)],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![Value::test_int(3), Value::test_int(1)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(4), Value::test_int(2)],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -92,7 +95,7 @@ fn command(
let subset_slice = subset.as_ref().map(|cols| &cols[..]);
let keep_strategy = if call.has_flag("last") {
let keep_strategy = if call.has_flag(engine_state, stack, "last")? {
UniqueKeepStrategy::Last
} else {
UniqueKeepStrategy::First

View File

@ -43,20 +43,23 @@ impl Command for DropNulls {
let a = ($df | dfr with-column $res --name res);
$a | dfr drop-nulls"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(1)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(2)],
),
Column::new(
"res".to_string(),
vec![Value::test_int(1), Value::test_int(1)],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(1)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(2)],
),
Column::new(
"res".to_string(),
vec![Value::test_int(1), Value::test_int(1)],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -66,15 +69,18 @@ impl Command for DropNulls {
example: r#"let s = ([1 2 0 0 3 4] | dfr into-df);
($s / $s) | dfr drop-nulls"#,
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"div_0_0".to_string(),
vec![
Value::test_int(1),
Value::test_int(1),
Value::test_int(1),
Value::test_int(1),
],
)])
NuDataFrame::try_from_columns(
vec![Column::new(
"div_0_0".to_string(),
vec![
Value::test_int(1),
Value::test_int(1),
Value::test_int(1),
Value::test_int(1),
],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -31,16 +31,19 @@ impl Command for DataTypes {
description: "Dataframe dtypes",
example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr dtypes",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"column".to_string(),
vec![Value::test_string("a"), Value::test_string("b")],
),
Column::new(
"dtype".to_string(),
vec![Value::test_string("i64"), Value::test_string("i64")],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"column".to_string(),
vec![Value::test_string("a"), Value::test_string("b")],
),
Column::new(
"dtype".to_string(),
vec![Value::test_string("i64"), Value::test_string("i64")],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -79,6 +82,7 @@ fn command(
.dtype();
let dtype_str = dtype.to_string();
dtypes.push(Value::string(dtype_str, call.head));
Value::string(*v, call.head)
@ -88,7 +92,7 @@ fn command(
let names_col = Column::new("column".to_string(), names);
let dtypes_col = Column::new("dtype".to_string(), dtypes);
NuDataFrame::try_from_columns(vec![names_col, dtypes_col])
NuDataFrame::try_from_columns(vec![names_col, dtypes_col], None)
.map(|df| PipelineData::Value(df.into_value(call.head), None))
}

View File

@ -1,4 +1,5 @@
use super::super::values::NuDataFrame;
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
@ -78,12 +79,12 @@ impl Command for Dummies {
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let drop_first: bool = call.has_flag("drop-first");
let drop_first: bool = call.has_flag(engine_state, stack, "drop-first")?;
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
df.as_ref()

View File

@ -43,10 +43,13 @@ impl Command for FilterWith {
example: r#"let mask = ([true false] | dfr into-df);
[[a b]; [1 2] [3 4]] | dfr into-df | dfr filter-with $mask"#,
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(2)]),
])
NuDataFrame::try_from_columns(
vec![
Column::new("a".to_string(), vec![Value::test_int(1)]),
Column::new("b".to_string(), vec![Value::test_int(2)]),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -55,10 +58,13 @@ impl Command for FilterWith {
description: "Filter dataframe using an expression",
example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr filter-with ((dfr col a) > 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)]),
])
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)]),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -44,10 +44,13 @@ impl Command for FirstDF {
description: "Return the first row of a dataframe",
example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr first",
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(2)]),
])
NuDataFrame::try_from_columns(
vec![
Column::new("a".to_string(), vec![Value::test_int(1)]),
Column::new("b".to_string(), vec![Value::test_int(2)]),
],
None,
)
.expect("should not fail")
.into_value(Span::test_data()),
),
@ -56,16 +59,19 @@ impl Command for FirstDF {
description: "Return the first two rows of a dataframe",
example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr first 2",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
],
None,
)
.expect("should not fail")
.into_value(Span::test_data()),
),

View File

@ -36,10 +36,13 @@ impl Command for GetDF {
description: "Returns the selected column",
example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr get a",
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
)])
NuDataFrame::try_from_columns(
vec![Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -40,10 +40,13 @@ impl Command for LastDF {
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)]),
])
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)]),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -106,7 +106,7 @@ impl Command for MeltDF {
Value::test_string("c"),
],
),
])
], None)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -15,6 +15,7 @@ mod open;
mod query_df;
mod rename;
mod sample;
mod schema;
mod shape;
mod slice;
mod sql_context;
@ -49,10 +50,10 @@ pub use melt::MeltDF;
pub use query_df::QueryDf;
pub use rename::RenameDF;
pub use sample::SampleDF;
pub use schema::SchemaDF;
pub use shape::ShapeDF;
pub use slice::SliceDF;
pub use sql_context::SQLContext;
pub use sql_expr::parse_sql_expr;
pub use summary::Summary;
pub use take::TakeDF;
pub use to_arrow::ToArrow;
@ -94,6 +95,7 @@ pub fn add_eager_decls(working_set: &mut StateWorkingSet) {
QueryDf,
RenameDF,
SampleDF,
SchemaDF,
ShapeDF,
SliceDF,
TakeDF,

View File

@ -1,3 +1,5 @@
use crate::dataframe::values::NuSchema;
use super::super::values::{NuDataFrame, NuLazyFrame};
use nu_engine::CallExt;
use nu_protocol::{
@ -70,6 +72,12 @@ impl Command for OpenDataFrame {
"Columns to be selected from csv file. CSV and Parquet file",
None,
)
.named(
"schema",
SyntaxShape::Record(vec![]),
r#"Polars Schema in format [{name: str}]. CSV, JSON, and JSONL files"#,
Some('s')
)
.input_output_type(Type::Any, Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
@ -139,7 +147,7 @@ fn from_parquet(
stack: &mut Stack,
call: &Call,
) -> Result<Value, ShellError> {
if call.has_flag("lazy") {
if call.has_flag(engine_state, stack, "lazy")? {
let file: String = call.req(engine_state, stack, 0)?;
let args = ScanArgsParquet {
n_rows: None,
@ -238,7 +246,7 @@ fn from_ipc(
stack: &mut Stack,
call: &Call,
) -> Result<Value, ShellError> {
if call.has_flag("lazy") {
if call.has_flag(engine_state, stack, "lazy")? {
let file: String = call.req(engine_state, stack, 0)?;
let args = ScanArgsIpc {
n_rows: None,
@ -305,10 +313,19 @@ fn from_json(
help: None,
inner: vec![],
})?;
let maybe_schema = call
.get_flag(engine_state, stack, "schema")?
.map(|schema| NuSchema::try_from(&schema))
.transpose()?;
let buf_reader = BufReader::new(file);
let reader = JsonReader::new(buf_reader);
let reader = match maybe_schema {
Some(schema) => reader.with_schema(schema.into()),
None => reader,
};
let df: NuDataFrame = reader
.finish()
.map_err(|e| ShellError::GenericError {
@ -329,6 +346,10 @@ fn from_jsonl(
call: &Call,
) -> Result<Value, ShellError> {
let infer_schema: Option<usize> = call.get_flag(engine_state, stack, "infer-schema")?;
let maybe_schema = call
.get_flag(engine_state, stack, "schema")?
.map(|schema| NuSchema::try_from(&schema))
.transpose()?;
let file: Spanned<PathBuf> = call.req(engine_state, stack, 0)?;
let file = File::open(&file.item).map_err(|e| ShellError::GenericError {
error: "Error opening file".into(),
@ -343,6 +364,11 @@ fn from_jsonl(
.with_json_format(JsonFormat::JsonLines)
.infer_schema_len(infer_schema);
let reader = match maybe_schema {
Some(schema) => reader.with_schema(schema.into()),
None => reader,
};
let df: NuDataFrame = reader
.finish()
.map_err(|e| ShellError::GenericError {
@ -363,12 +389,17 @@ fn from_csv(
call: &Call,
) -> Result<Value, ShellError> {
let delimiter: Option<Spanned<String>> = call.get_flag(engine_state, stack, "delimiter")?;
let no_header: bool = call.has_flag("no-header");
let no_header: bool = call.has_flag(engine_state, stack, "no-header")?;
let infer_schema: Option<usize> = call.get_flag(engine_state, stack, "infer-schema")?;
let skip_rows: Option<usize> = call.get_flag(engine_state, stack, "skip-rows")?;
let columns: Option<Vec<String>> = call.get_flag(engine_state, stack, "columns")?;
if call.has_flag("lazy") {
let maybe_schema = call
.get_flag(engine_state, stack, "schema")?
.map(|schema| NuSchema::try_from(&schema))
.transpose()?;
if call.has_flag(engine_state, stack, "lazy")? {
let file: String = call.req(engine_state, stack, 0)?;
let csv_reader = LazyCsvReader::new(file);
@ -395,6 +426,11 @@ fn from_csv(
let csv_reader = csv_reader.has_header(!no_header);
let csv_reader = match maybe_schema {
Some(schema) => csv_reader.with_schema(Some(schema.into())),
None => csv_reader,
};
let csv_reader = match infer_schema {
None => csv_reader,
Some(r) => csv_reader.with_infer_schema_length(Some(r)),
@ -452,6 +488,11 @@ fn from_csv(
let csv_reader = csv_reader.has_header(!no_header);
let csv_reader = match maybe_schema {
Some(schema) => csv_reader.with_schema(Some(schema.into())),
None => csv_reader,
};
let csv_reader = match infer_schema {
None => csv_reader,
Some(r) => csv_reader.infer_schema(Some(r)),

View File

@ -44,10 +44,13 @@ impl Command for QueryDf {
description: "Query dataframe using SQL",
example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr query 'select a from df'",
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
)])
NuDataFrame::try_from_columns(
vec![Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -46,15 +46,18 @@ impl Command for RenameDF {
description: "Renames a series",
example: "[5 6 7 8] | dfr into-df | dfr rename '0' new_name",
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"new_name".to_string(),
vec![
Value::test_int(5),
Value::test_int(6),
Value::test_int(7),
Value::test_int(8),
],
)])
NuDataFrame::try_from_columns(
vec![Column::new(
"new_name".to_string(),
vec![
Value::test_int(5),
Value::test_int(6),
Value::test_int(7),
Value::test_int(8),
],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -63,16 +66,19 @@ impl Command for RenameDF {
description: "Renames a dataframe column",
example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr rename a a_new",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a_new".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a_new".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -81,16 +87,19 @@ impl Command for RenameDF {
description: "Renames two dataframe columns",
example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr rename [a b] [a_new b_new]",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a_new".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
),
Column::new(
"b_new".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a_new".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
),
Column::new(
"b_new".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -88,8 +88,8 @@ fn command(
let seed: Option<u64> = call
.get_flag::<i64>(engine_state, stack, "seed")?
.map(|val| val as u64);
let replace: bool = call.has_flag("replace");
let shuffle: bool = call.has_flag("shuffle");
let replace: bool = call.has_flag(engine_state, stack, "replace")?;
let shuffle: bool = call.has_flag(engine_state, stack, "shuffle")?;
let df = NuDataFrame::try_from_pipeline(input, call.head)?;

View File

@ -0,0 +1,119 @@
use super::super::values::NuDataFrame;
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, Record, ShellError, Signature, Span, Type, Value,
};
#[derive(Clone)]
pub struct SchemaDF;
impl Command for SchemaDF {
fn name(&self) -> &str {
"dfr schema"
}
fn usage(&self) -> &str {
"Show schema for a dataframe."
}
fn signature(&self) -> Signature {
Signature::build(self.name())
.switch("datatype-list", "creates a lazy dataframe", Some('l'))
.input_output_type(
Type::Custom("dataframe".into()),
Type::Custom("dataframe".into()),
)
.category(Category::Custom("dataframe".into()))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Dataframe schema",
example: r#"[[a b]; [1 "foo"] [3 "bar"]] | dfr into-df | dfr schema"#,
result: Some(Value::record(
Record::from_raw_cols_vals_unchecked(
vec!["a".to_string(), "b".to_string()],
vec![
Value::string("i64", Span::test_data()),
Value::string("str", Span::test_data()),
],
),
Span::test_data(),
)),
}]
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
if call.has_flag(engine_state, stack, "datatype-list")? {
Ok(PipelineData::Value(datatype_list(Span::unknown()), None))
} else {
command(engine_state, stack, call, input)
}
}
}
fn command(
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let schema = df.schema();
let value: Value = schema.into();
Ok(PipelineData::Value(value, None))
}
fn datatype_list(span: Span) -> Value {
let types: Vec<Value> = [
("null", ""),
("bool", ""),
("u8", ""),
("u16", ""),
("u32", ""),
("u64", ""),
("i8", ""),
("i16", ""),
("i32", ""),
("i64", ""),
("f32", ""),
("f64", ""),
("str", ""),
("binary", ""),
("date", ""),
("datetime<time_unit: (ms, us, ns) timezone (optional)>", "Time Unit can be: milliseconds: ms, microseconds: us, nanoseconds: ns. Timezone wildcard is *. Other Timezone examples: UTC, America/Los_Angeles."),
("duration<time_unit: (ms, us, ns)>", "Time Unit can be: milliseconds: ms, microseconds: us, nanoseconds: ns."),
("time", ""),
("object", ""),
("unknown", ""),
("list<dtype>", ""),
]
.iter()
.map(|(dtype, note)| {
Value::record(Record::from_raw_cols_vals_unchecked(
vec!["dtype".to_string(), "note".to_string()],
vec![Value::string(*dtype, span), Value::string(*note, span)],
),span)
})
.collect();
Value::list(types, span)
}
#[cfg(test)]
mod test {
use super::super::super::test_dataframe::test_dataframe;
use super::*;
#[test]
fn test_examples() {
test_dataframe(vec![Box::new(SchemaDF {})])
}
}

View File

@ -34,10 +34,13 @@ impl Command for ShapeDF {
description: "Shows row and column shape",
example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr shape",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new("rows".to_string(), vec![Value::test_int(2)]),
Column::new("columns".to_string(), vec![Value::test_int(2)]),
])
NuDataFrame::try_from_columns(
vec![
Column::new("rows".to_string(), vec![Value::test_int(2)]),
Column::new("columns".to_string(), vec![Value::test_int(2)]),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -70,7 +73,7 @@ fn command(
let rows_col = Column::new("rows".to_string(), vec![rows]);
let cols_col = Column::new("columns".to_string(), vec![cols]);
NuDataFrame::try_from_columns(vec![rows_col, cols_col])
NuDataFrame::try_from_columns(vec![rows_col, cols_col], None)
.map(|df| PipelineData::Value(df.into_value(call.head), None))
}

View File

@ -37,10 +37,13 @@ impl Command for SliceDF {
description: "Create new dataframe from a slice of the rows",
example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr slice 0 1",
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(2)]),
])
NuDataFrame::try_from_columns(
vec![
Column::new("a".to_string(), vec![Value::test_int(1)]),
Column::new("b".to_string(), vec![Value::test_int(2)]),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -13,7 +13,7 @@ fn map_sql_polars_datatype(data_type: &SQLDataType) -> Result<DataType> {
| SQLDataType::Uuid
| SQLDataType::Clob(_)
| SQLDataType::Text
| SQLDataType::String(_) => DataType::Utf8,
| SQLDataType::String(_) => DataType::String,
SQLDataType::Float(_) => DataType::Float32,
SQLDataType::Real => DataType::Float32,
SQLDataType::Double => DataType::Float64,
@ -62,7 +62,9 @@ fn binary_op_(left: Expr, right: Expr, op: &SQLBinaryOperator) -> Result<Expr> {
SQLBinaryOperator::Multiply => left * right,
SQLBinaryOperator::Divide => left / right,
SQLBinaryOperator::Modulo => left % right,
SQLBinaryOperator::StringConcat => left.cast(DataType::Utf8) + right.cast(DataType::Utf8),
SQLBinaryOperator::StringConcat => {
left.cast(DataType::String) + right.cast(DataType::String)
}
SQLBinaryOperator::Gt => left.gt(right),
SQLBinaryOperator::Lt => left.lt(right),
SQLBinaryOperator::GtEq => left.gt_eq(right),

View File

@ -10,7 +10,7 @@ use polars::{
chunked_array::ChunkedArray,
prelude::{
AnyValue, DataFrame, DataType, Float64Type, IntoSeries, NewChunkedArray,
QuantileInterpolOptions, Series, Utf8Type,
QuantileInterpolOptions, Series, StringType,
},
};
@ -46,53 +46,56 @@ impl Command for Summary {
description: "list dataframe descriptives",
example: "[[a b]; [1 1] [1 1]] | dfr into-df | dfr summary",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"descriptor".to_string(),
vec![
Value::test_string("count"),
Value::test_string("sum"),
Value::test_string("mean"),
Value::test_string("median"),
Value::test_string("std"),
Value::test_string("min"),
Value::test_string("25%"),
Value::test_string("50%"),
Value::test_string("75%"),
Value::test_string("max"),
],
),
Column::new(
"a (i64)".to_string(),
vec![
Value::test_float(2.0),
Value::test_float(2.0),
Value::test_float(1.0),
Value::test_float(1.0),
Value::test_float(0.0),
Value::test_float(1.0),
Value::test_float(1.0),
Value::test_float(1.0),
Value::test_float(1.0),
Value::test_float(1.0),
],
),
Column::new(
"b (i64)".to_string(),
vec![
Value::test_float(2.0),
Value::test_float(2.0),
Value::test_float(1.0),
Value::test_float(1.0),
Value::test_float(0.0),
Value::test_float(1.0),
Value::test_float(1.0),
Value::test_float(1.0),
Value::test_float(1.0),
Value::test_float(1.0),
],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"descriptor".to_string(),
vec![
Value::test_string("count"),
Value::test_string("sum"),
Value::test_string("mean"),
Value::test_string("median"),
Value::test_string("std"),
Value::test_string("min"),
Value::test_string("25%"),
Value::test_string("50%"),
Value::test_string("75%"),
Value::test_string("max"),
],
),
Column::new(
"a (i64)".to_string(),
vec![
Value::test_float(2.0),
Value::test_float(2.0),
Value::test_float(1.0),
Value::test_float(1.0),
Value::test_float(0.0),
Value::test_float(1.0),
Value::test_float(1.0),
Value::test_float(1.0),
Value::test_float(1.0),
Value::test_float(1.0),
],
),
Column::new(
"b (i64)".to_string(),
vec![
Value::test_float(2.0),
Value::test_float(2.0),
Value::test_float(1.0),
Value::test_float(1.0),
Value::test_float(0.0),
Value::test_float(1.0),
Value::test_float(1.0),
Value::test_float(1.0),
Value::test_float(1.0),
Value::test_float(1.0),
],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -171,7 +174,7 @@ fn command(
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let names = ChunkedArray::<Utf8Type>::from_slice_options("descriptor", &labels).into_series();
let names = ChunkedArray::<StringType>::from_slice_options("descriptor", &labels).into_series();
let head = std::iter::once(names);
@ -179,42 +182,50 @@ fn command(
.as_ref()
.get_columns()
.iter()
.filter(|col| col.dtype() != &DataType::Object("object"))
.filter(|col| !matches!(col.dtype(), &DataType::Object("object", _)))
.map(|col| {
let count = col.len() as f64;
let sum = col
.sum_as_series()
.cast(&DataType::Float64)
.ok()
.and_then(|ca| match ca.get(0) {
Ok(AnyValue::Float64(v)) => Some(v),
_ => None,
});
let sum = col.sum_as_series().ok().and_then(|series| {
series
.cast(&DataType::Float64)
.ok()
.and_then(|ca| match ca.get(0) {
Ok(AnyValue::Float64(v)) => Some(v),
_ => None,
})
});
let mean = match col.mean_as_series().get(0) {
Ok(AnyValue::Float64(v)) => Some(v),
_ => None,
};
let median = match col.median_as_series().get(0) {
Ok(AnyValue::Float64(v)) => Some(v),
_ => None,
};
let std = match col.std_as_series(0).get(0) {
Ok(AnyValue::Float64(v)) => Some(v),
_ => None,
};
let min = col
.min_as_series()
.cast(&DataType::Float64)
.ok()
.and_then(|ca| match ca.get(0) {
let median = match col.median_as_series() {
Ok(v) => match v.get(0) {
Ok(AnyValue::Float64(v)) => Some(v),
_ => None,
});
},
_ => None,
};
let std = match col.std_as_series(0) {
Ok(v) => match v.get(0) {
Ok(AnyValue::Float64(v)) => Some(v),
_ => None,
},
_ => None,
};
let min = col.min_as_series().ok().and_then(|series| {
series
.cast(&DataType::Float64)
.ok()
.and_then(|ca| match ca.get(0) {
Ok(AnyValue::Float64(v)) => Some(v),
_ => None,
})
});
let mut quantiles = quantiles
.clone()
@ -230,14 +241,15 @@ fn command(
})
.collect::<Vec<Option<f64>>>();
let max = col
.max_as_series()
.cast(&DataType::Float64)
.ok()
.and_then(|ca| match ca.get(0) {
Ok(AnyValue::Float64(v)) => Some(v),
_ => None,
});
let max = col.max_as_series().ok().and_then(|series| {
series
.cast(&DataType::Float64)
.ok()
.and_then(|ca| match ca.get(0) {
Ok(AnyValue::Float64(v)) => Some(v),
_ => None,
})
});
let mut descriptors = vec![Some(count), sum, mean, median, std, min];
descriptors.append(&mut quantiles);

View File

@ -44,16 +44,19 @@ impl Command for TakeDF {
let indices = ([0 2] | dfr into-df);
$df | dfr take $indices"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_int(4), Value::test_int(4)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![Value::test_int(4), Value::test_int(4)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -64,10 +67,13 @@ impl Command for TakeDF {
let indices = ([0 2] | dfr into-df);
$series | dfr take $indices"#,
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"0".to_string(),
vec![Value::test_int(4), Value::test_int(5)],
)])
NuDataFrame::try_from_columns(
vec![Column::new(
"0".to_string(),
vec![Value::test_int(4), Value::test_int(5)],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -70,7 +70,7 @@ fn command(
) -> Result<PipelineData, ShellError> {
let file_name: Spanned<PathBuf> = call.req(engine_state, stack, 0)?;
let delimiter: Option<Spanned<String>> = call.get_flag(engine_state, stack, "delimiter")?;
let no_header: bool = call.has_flag("no-header");
let no_header: bool = call.has_flag(engine_state, stack, "no-header")?;
let mut df = NuDataFrame::try_from_pipeline(input, call.head)?;

View File

@ -1,10 +1,14 @@
use crate::dataframe::values::NuSchema;
use super::super::values::{Column, NuDataFrame};
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use polars::prelude::*;
#[derive(Clone)]
pub struct ToDataFrame;
@ -20,6 +24,12 @@ impl Command for ToDataFrame {
fn signature(&self) -> Signature {
Signature::build(self.name())
.named(
"schema",
SyntaxShape::Record(vec![]),
r#"Polars Schema in format [{name: str}]. CSV, JSON, and JSONL files"#,
Some('s'),
)
.input_output_type(Type::Any, Type::Custom("dataframe".into()))
.category(Category::Custom("dataframe".into()))
}
@ -30,16 +40,19 @@ impl Command for ToDataFrame {
description: "Takes a dictionary and creates a dataframe",
example: "[[a b];[1 2] [3 4]] | dfr into-df",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -48,24 +61,27 @@ impl Command for ToDataFrame {
description: "Takes a list of tables and creates a dataframe",
example: "[[1 2 a] [3 4 b] [5 6 c]] | dfr into-df",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"0".to_string(),
vec![Value::test_int(1), Value::test_int(3), Value::test_int(5)],
),
Column::new(
"1".to_string(),
vec![Value::test_int(2), Value::test_int(4), Value::test_int(6)],
),
Column::new(
"2".to_string(),
vec![
Value::test_string("a"),
Value::test_string("b"),
Value::test_string("c"),
],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"0".to_string(),
vec![Value::test_int(1), Value::test_int(3), Value::test_int(5)],
),
Column::new(
"1".to_string(),
vec![Value::test_int(2), Value::test_int(4), Value::test_int(6)],
),
Column::new(
"2".to_string(),
vec![
Value::test_string("a"),
Value::test_string("b"),
Value::test_string("c"),
],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -74,14 +90,17 @@ impl Command for ToDataFrame {
description: "Takes a list and creates a dataframe",
example: "[a b c] | dfr into-df",
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"0".to_string(),
vec![
Value::test_string("a"),
Value::test_string("b"),
Value::test_string("c"),
],
)])
NuDataFrame::try_from_columns(
vec![Column::new(
"0".to_string(),
vec![
Value::test_string("a"),
Value::test_string("b"),
Value::test_string("c"),
],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -90,14 +109,41 @@ impl Command for ToDataFrame {
description: "Takes a list of booleans and creates a dataframe",
example: "[true true false] | dfr into-df",
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"0".to_string(),
vec![
Value::test_bool(true),
Value::test_bool(true),
Value::test_bool(false),
],
)])
NuDataFrame::try_from_columns(
vec![Column::new(
"0".to_string(),
vec![
Value::test_bool(true),
Value::test_bool(true),
Value::test_bool(false),
],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},
Example {
description: "Convert to a dataframe and provide a schema",
example: "{a: 1, b: {a: [1 2 3]}, c: [a b c]}| dfr into-df -s {a: u8, b: {a: list<u64>}, c: list<str>}",
result: Some(
NuDataFrame::try_from_series(vec![
Series::new("a", &[1u8]),
{
let dtype = DataType::Struct(vec![Field::new("a", DataType::List(Box::new(DataType::UInt64)))]);
let vals = vec![AnyValue::StructOwned(
Box::new((vec![AnyValue::List(Series::new("a", &[1u64, 2, 3]))], vec![Field::new("a", DataType::String)]))); 1];
Series::from_any_values_and_dtype("b", &vals, &dtype, false)
.expect("Struct series should not fail")
},
{
let dtype = DataType::List(Box::new(DataType::String));
let vals = vec![AnyValue::List(Series::new("c", &["a", "b", "c"]))];
Series::from_any_values_and_dtype("c", &vals, &dtype, false)
.expect("List series should not fail")
}
], Span::test_data())
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -107,12 +153,17 @@ impl Command for ToDataFrame {
fn run(
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
NuDataFrame::try_from_iter(input.into_iter())
let maybe_schema = call
.get_flag(engine_state, stack, "schema")?
.map(|schema| NuSchema::try_from(&schema))
.transpose()?;
NuDataFrame::try_from_iter(input.into_iter(), maybe_schema)
.map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None))
}
}

View File

@ -100,7 +100,7 @@ fn dataframe_command(
input: Value,
) -> Result<PipelineData, ShellError> {
let rows: Option<usize> = call.get_flag(engine_state, stack, "rows")?;
let tail: bool = call.has_flag("tail");
let tail: bool = call.has_flag(engine_state, stack, "tail")?;
let df = NuDataFrame::try_from_value(input)?;

View File

@ -42,20 +42,23 @@ impl Command for WithColumn {
| dfr into-df
| dfr with-column ([5 6] | dfr into-df) --name c"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
Column::new(
"c".to_string(),
vec![Value::test_int(5), Value::test_int(6)],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
Column::new(
"c".to_string(),
vec![Value::test_int(5), Value::test_int(6)],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -70,24 +73,27 @@ impl Command for WithColumn {
]
| dfr collect"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
Column::new(
"c".to_string(),
vec![Value::test_int(2), Value::test_int(6)],
),
Column::new(
"d".to_string(),
vec![Value::test_int(3), Value::test_int(9)],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
Column::new(
"c".to_string(),
vec![Value::test_int(2), Value::test_int(6)],
),
Column::new(
"d".to_string(),
vec![Value::test_int(3), Value::test_int(9)],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -32,10 +32,13 @@ impl Command for ExprArgWhere {
example: "let df = ([[a b]; [one 1] [two 2] [three 3]] | dfr into-df);
$df | dfr select (dfr arg-where ((dfr col b) >= 2) | dfr as b_arg)",
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"b_arg".to_string(),
vec![Value::test_int(1), Value::test_int(2)],
)])
NuDataFrame::try_from_columns(
vec![Column::new(
"b_arg".to_string(),
vec![Value::test_int(1), Value::test_int(2)],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -41,27 +41,30 @@ impl Command for ExprConcatStr {
example: r#"let df = ([[a b c]; [one two 1] [three four 2]] | dfr into-df);
$df | dfr with-column ((dfr concat-str "-" [(dfr col a) (dfr col b) ((dfr col c) * 2)]) | dfr as concat)"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_string("one"), Value::test_string("three")],
),
Column::new(
"b".to_string(),
vec![Value::test_string("two"), Value::test_string("four")],
),
Column::new(
"c".to_string(),
vec![Value::test_int(1), Value::test_int(2)],
),
Column::new(
"concat".to_string(),
vec![
Value::test_string("one-two-2"),
Value::test_string("three-four-4"),
],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![Value::test_string("one"), Value::test_string("three")],
),
Column::new(
"b".to_string(),
vec![Value::test_string("two"), Value::test_string("four")],
),
Column::new(
"c".to_string(),
vec![Value::test_int(1), Value::test_int(2)],
),
Column::new(
"concat".to_string(),
vec![
Value::test_string("one-two-2"),
Value::test_string("three-four-4"),
],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -9,6 +9,11 @@ use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type,
Value,
};
use polars::{
datatypes::{DataType, TimeUnit},
prelude::NamedFrom,
series::Series,
};
#[derive(Clone)]
pub struct ExprDatePart;
@ -47,10 +52,13 @@ impl Command for ExprDatePart {
description: "Creates an expression to capture the year date part",
example: r#"[["2021-12-30T01:02:03.123456789"]] | dfr into-df | dfr as-datetime "%Y-%m-%dT%H:%M:%S.%9f" | dfr with-column [(dfr col datetime | dfr datepart year | dfr as datetime_year )]"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new("datetime".to_string(), vec![Value::test_date(dt)]),
Column::new("datetime_year".to_string(), vec![Value::test_int(2021)]),
])
NuDataFrame::try_from_columns(
vec![
Column::new("datetime".to_string(), vec![Value::test_date(dt)]),
Column::new("datetime_year".to_string(), vec![Value::test_int(2021)]),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -66,16 +74,21 @@ impl Command for ExprDatePart {
(dfr col datetime | dfr datepart second | dfr as datetime_second ),
(dfr col datetime | dfr datepart nanosecond | dfr as datetime_ns ) ]"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new("datetime".to_string(), vec![Value::test_date(dt)]),
Column::new("datetime_year".to_string(), vec![Value::test_int(2021)]),
Column::new("datetime_month".to_string(), vec![Value::test_int(12)]),
Column::new("datetime_day".to_string(), vec![Value::test_int(30)]),
Column::new("datetime_hour".to_string(), vec![Value::test_int(1)]),
Column::new("datetime_minute".to_string(), vec![Value::test_int(2)]),
Column::new("datetime_second".to_string(), vec![Value::test_int(3)]),
Column::new("datetime_ns".to_string(), vec![Value::test_int(123456789)]),
])
NuDataFrame::try_from_series(
vec![
Series::new("datetime", &[dt.timestamp_nanos_opt()])
.cast(&DataType::Datetime(TimeUnit::Nanoseconds, None))
.expect("Error casting to datetime type"),
Series::new("datetime_year", &[2021_i64]), // i32 was coerced to i64
Series::new("datetime_month", &[12_i8]),
Series::new("datetime_day", &[30_i8]),
Series::new("datetime_hour", &[1_i8]),
Series::new("datetime_minute", &[2_i8]),
Series::new("datetime_second", &[3_i8]),
Series::new("datetime_ns", &[123456789_i64]), // i32 was coerced to i64
],
Span::test_data(),
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -179,7 +179,18 @@ macro_rules! lazy_expr_command {
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());
let lazy = NuLazyFrame::new(
lazy.from_eager,
lazy.into_polars()
.$func()
.map_err(|e| ShellError::GenericError {
error: "Dataframe Error".into(),
msg: e.to_string(),
help: None,
span: None,
inner: vec![],
})?,
);
Ok(PipelineData::Value(lazy.into_value(call.head)?, None))
} else {
@ -267,7 +278,18 @@ macro_rules! lazy_expr_command {
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));
let lazy = NuLazyFrame::new(
lazy.from_eager,
lazy.into_polars()
.$func($ddof)
.map_err(|e| ShellError::GenericError {
error: "Dataframe Error".into(),
msg: e.to_string(),
help: None,
span: None,
inner: vec![],
})?,
);
Ok(PipelineData::Value(lazy.into_value(call.head)?, None))
} else {
@ -385,10 +407,13 @@ lazy_expr_command!(
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)],),
])
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)],),
],
None
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -400,16 +425,19 @@ lazy_expr_command!(
| 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)],
),
])
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)],
),
],
None
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -430,10 +458,13 @@ lazy_expr_command!(
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)],),
])
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)],),
],
None
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -445,16 +476,19 @@ lazy_expr_command!(
| 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)],
),
])
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)],
),
],
None
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -475,10 +509,13 @@ lazy_expr_command!(
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)],),
])
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)],),
],
None
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -490,16 +527,19 @@ lazy_expr_command!(
| 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)],
),
])
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)],
),
],
None
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -520,10 +560,13 @@ lazy_expr_command!(
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)],),
])
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)],),
],
None
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -535,16 +578,19 @@ lazy_expr_command!(
| 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)],
),
])
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)],
),
],
None
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -567,16 +613,19 @@ expr_command!(
| dfr group-by a
| dfr agg (dfr col b | dfr median)"#,
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)],
),
])
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)],
),
],
None
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -596,10 +645,13 @@ lazy_expr_command!(
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)],),
])
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)],),
],
None
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -611,16 +663,19 @@ lazy_expr_command!(
| 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)],
),
])
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)],
),
],
None
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -643,10 +698,13 @@ lazy_expr_command!(
"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)],),
])
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)],),
],
None
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -658,16 +716,19 @@ lazy_expr_command!(
| 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)],
),
])
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)],
),
],
None
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -39,28 +39,31 @@ impl Command for ExprIsIn {
example: r#"let df = ([[a b]; [one 1] [two 2] [three 3]] | dfr into-df);
$df | dfr with-column (dfr col a | dfr is-in [one two] | dfr as a_in)"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![
Value::test_string("one"),
Value::test_string("two"),
Value::test_string("three"),
],
),
Column::new(
"b".to_string(),
vec![Value::test_int(1), Value::test_int(2), Value::test_int(3)],
),
Column::new(
"a_in".to_string(),
vec![
Value::test_bool(true),
Value::test_bool(true),
Value::test_bool(false),
],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![
Value::test_string("one"),
Value::test_string("two"),
Value::test_string("three"),
],
),
Column::new(
"b".to_string(),
vec![Value::test_int(1), Value::test_int(2), Value::test_int(3)],
),
Column::new(
"a_in".to_string(),
vec![
Value::test_bool(true),
Value::test_bool(true),
Value::test_bool(false),
],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -81,7 +84,8 @@ impl Command for ExprIsIn {
let list: Vec<Value> = call.req(engine_state, stack, 0)?;
let expr = NuExpression::try_from_pipeline(input, call.head)?;
let values = NuDataFrame::try_from_columns(vec![Column::new("list".to_string(), list)])?;
let values =
NuDataFrame::try_from_columns(vec![Column::new("list".to_string(), list)], None)?;
let list = values.as_series(call.head)?;
if matches!(list.dtype(), DataType::Object(..)) {

View File

@ -54,24 +54,27 @@ impl Command for ExprOtherwise {
)
| dfr collect"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_int(6), Value::test_int(1), Value::test_int(4)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(4), Value::test_int(1)],
),
Column::new(
"c".to_string(),
vec![Value::test_int(4), Value::test_int(5), Value::test_int(4)],
),
Column::new(
"d".to_string(),
vec![Value::test_int(10), Value::test_int(6), Value::test_int(0)],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![Value::test_int(6), Value::test_int(1), Value::test_int(4)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(4), Value::test_int(1)],
),
Column::new(
"c".to_string(),
vec![Value::test_int(4), Value::test_int(5), Value::test_int(4)],
),
Column::new(
"d".to_string(),
vec![Value::test_int(10), Value::test_int(6), Value::test_int(0)],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -41,16 +41,19 @@ impl Command for ExprQuantile {
| dfr group-by a
| dfr agg (dfr col b | dfr quantile 0.5)"#,
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(4.0), Value::test_float(1.0)],
),
])
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(4.0), Value::test_float(1.0)],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -62,24 +62,27 @@ impl Command for ExprWhen {
)
| dfr collect"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_int(6), Value::test_int(1), Value::test_int(4)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(4), Value::test_int(1)],
),
Column::new(
"c".to_string(),
vec![Value::test_int(4), Value::test_int(5), Value::test_int(4)],
),
Column::new(
"d".to_string(),
vec![Value::test_int(10), Value::test_int(6), Value::test_int(0)],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![Value::test_int(6), Value::test_int(1), Value::test_int(4)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(4), Value::test_int(1)],
),
Column::new(
"c".to_string(),
vec![Value::test_int(4), Value::test_int(5), Value::test_int(4)],
),
Column::new(
"d".to_string(),
vec![Value::test_int(10), Value::test_int(6), Value::test_int(0)],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -47,24 +47,27 @@ impl Command for LazyAggregate {
(dfr col b | dfr sum | dfr as "b_sum")
]"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(2)],
),
Column::new(
"b_min".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
Column::new(
"b_max".to_string(),
vec![Value::test_int(4), Value::test_int(6)],
),
Column::new(
"b_sum".to_string(),
vec![Value::test_int(6), Value::test_int(10)],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(2)],
),
Column::new(
"b_min".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
Column::new(
"b_max".to_string(),
vec![Value::test_int(4), Value::test_int(6)],
),
Column::new(
"b_sum".to_string(),
vec![Value::test_int(6), Value::test_int(10)],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -81,24 +84,27 @@ impl Command for LazyAggregate {
]
| dfr collect"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(2)],
),
Column::new(
"b_min".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
Column::new(
"b_max".to_string(),
vec![Value::test_int(4), Value::test_int(6)],
),
Column::new(
"b_sum".to_string(),
vec![Value::test_int(6), Value::test_int(10)],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(2)],
),
Column::new(
"b_min".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
Column::new(
"b_max".to_string(),
vec![Value::test_int(4), Value::test_int(6)],
),
Column::new(
"b_sum".to_string(),
vec![Value::test_int(6), Value::test_int(10)],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -160,7 +166,7 @@ fn get_col_name(expr: &Expr) -> Option<String> {
| polars::prelude::AggExpr::Last(e)
| polars::prelude::AggExpr::Mean(e)
| polars::prelude::AggExpr::Implode(e)
| polars::prelude::AggExpr::Count(e)
| polars::prelude::AggExpr::Count(e, _)
| polars::prelude::AggExpr::Sum(e)
| polars::prelude::AggExpr::AggGroups(e)
| polars::prelude::AggExpr::Std(e, _)

View File

@ -33,16 +33,19 @@ impl Command for LazyCollect {
description: "drop duplicates",
example: "[[a b]; [1 2] [3 4]] | dfr into-lazy | dfr collect",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(3)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -69,7 +69,7 @@ impl Command for LazyExplode {
Value::test_string("Skiing"),
Value::test_string("Football"),
]),
]).expect("simple df for test should not fail")
], None).expect("simple df for test should not fail")
.into_value(Span::test_data()),
)
},
@ -86,7 +86,7 @@ impl Command for LazyExplode {
Value::test_string("Skiing"),
Value::test_string("Football"),
]),
]).expect("simple df for test should not fail")
], None).expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},

View File

@ -38,16 +38,19 @@ impl Command for LazyFetch {
description: "Fetch a rows from the dataframe",
example: "[[a b]; [6 2] [4 2] [2 2]] | dfr into-df | dfr fetch 2",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_int(6), Value::test_int(4)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(2)],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![Value::test_int(6), Value::test_int(4)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(2)],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -38,16 +38,19 @@ impl Command for LazyFillNA {
description: "Fills the NaN values with 0",
example: "[1 2 NaN 3 NaN] | dfr into-df | dfr fill-nan 0",
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"0".to_string(),
vec![
Value::test_int(1),
Value::test_int(2),
Value::test_int(0),
Value::test_int(3),
Value::test_int(0),
],
)])
NuDataFrame::try_from_columns(
vec![Column::new(
"0".to_string(),
vec![
Value::test_int(1),
Value::test_int(2),
Value::test_int(0),
Value::test_int(3),
Value::test_int(0),
],
)],
None,
)
.expect("Df for test should not fail")
.into_value(Span::test_data()),
),
@ -56,16 +59,19 @@ impl Command for LazyFillNA {
description: "Fills the NaN values of a whole dataframe",
example: "[[a b]; [0.2 1] [0.1 NaN]] | dfr into-df | dfr fill-nan 0",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_float(0.2), Value::test_float(0.1)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(1), Value::test_int(0)],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![Value::test_float(0.2), Value::test_float(0.1)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(1), Value::test_int(0)],
),
],
None,
)
.expect("Df for test should not fail")
.into_value(Span::test_data()),
),
@ -123,7 +129,7 @@ impl Command for LazyFillNA {
})
.collect::<Vec<Column>>();
Ok(PipelineData::Value(
NuDataFrame::try_from_columns(dataframe)?.into_value(call.head),
NuDataFrame::try_from_columns(dataframe, None)?.into_value(call.head),
None,
))
}

View File

@ -37,16 +37,19 @@ impl Command for LazyFillNull {
description: "Fills the null values by 0",
example: "[1 2 2 3 3] | dfr into-df | dfr shift 2 | dfr fill-null 0",
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"0".to_string(),
vec![
Value::test_int(0),
Value::test_int(0),
Value::test_int(1),
Value::test_int(2),
Value::test_int(2),
],
)])
NuDataFrame::try_from_columns(
vec![Column::new(
"0".to_string(),
vec![
Value::test_int(0),
Value::test_int(0),
Value::test_int(1),
Value::test_int(2),
Value::test_int(2),
],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -38,16 +38,19 @@ impl Command for LazyFilter {
description: "Filter dataframe using an expression",
example: "[[a b]; [6 2] [4 2] [2 2]] | dfr into-df | dfr filter ((dfr col a) >= 4)",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_int(6), Value::test_int(4)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(2)],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![Value::test_int(6), Value::test_int(4)],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(2)],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -71,7 +71,7 @@ Example {
Value::test_string("Skiing"),
Value::test_string("Football"),
]),
]).expect("simple df for test should not fail")
], None).expect("simple df for test should not fail")
.into_value(Span::test_data()),
)
},
@ -88,7 +88,7 @@ Example {
Value::test_string("Skiing"),
Value::test_string("Football"),
]),
]).expect("simple df for test should not fail")
], None).expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},

View File

@ -46,24 +46,27 @@ impl Command for ToLazyGroupBy {
(dfr col b | dfr sum | dfr as "b_sum")
]"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(2)],
),
Column::new(
"b_min".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
Column::new(
"b_max".to_string(),
vec![Value::test_int(4), Value::test_int(6)],
),
Column::new(
"b_sum".to_string(),
vec![Value::test_int(6), Value::test_int(10)],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(2)],
),
Column::new(
"b_min".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
Column::new(
"b_max".to_string(),
vec![Value::test_int(4), Value::test_int(6)],
),
Column::new(
"b_sum".to_string(),
vec![Value::test_int(6), Value::test_int(10)],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -80,24 +83,27 @@ impl Command for ToLazyGroupBy {
]
| dfr collect"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(2)],
),
Column::new(
"b_min".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
Column::new(
"b_max".to_string(),
vec![Value::test_int(4), Value::test_int(6)],
),
Column::new(
"b_sum".to_string(),
vec![Value::test_int(6), Value::test_int(10)],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![Value::test_int(1), Value::test_int(2)],
),
Column::new(
"b_min".to_string(),
vec![Value::test_int(2), Value::test_int(4)],
),
Column::new(
"b_max".to_string(),
vec![Value::test_int(4), Value::test_int(6)],
),
Column::new(
"b_sum".to_string(),
vec![Value::test_int(6), Value::test_int(10)],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -53,53 +53,56 @@ impl Command for LazyJoin {
let df_b = ([["foo" "bar" "ham"];[1 "a" "let"] [2 "c" "var"] [3 "c" "const"]] | dfr into-lazy);
$df_a | dfr join $df_b a foo | dfr collect"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![
Value::test_int(1),
Value::test_int(2),
Value::test_int(1),
Value::test_int(1),
],
),
Column::new(
"b".to_string(),
vec![
Value::test_string("a"),
Value::test_string("b"),
Value::test_string("c"),
Value::test_string("c"),
],
),
Column::new(
"c".to_string(),
vec![
Value::test_int(0),
Value::test_int(1),
Value::test_int(2),
Value::test_int(3),
],
),
Column::new(
"bar".to_string(),
vec![
Value::test_string("a"),
Value::test_string("c"),
Value::test_string("a"),
Value::test_string("a"),
],
),
Column::new(
"ham".to_string(),
vec![
Value::test_string("let"),
Value::test_string("var"),
Value::test_string("let"),
Value::test_string("let"),
],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![
Value::test_int(1),
Value::test_int(2),
Value::test_int(1),
Value::test_int(1),
],
),
Column::new(
"b".to_string(),
vec![
Value::test_string("a"),
Value::test_string("b"),
Value::test_string("c"),
Value::test_string("c"),
],
),
Column::new(
"c".to_string(),
vec![
Value::test_int(0),
Value::test_int(1),
Value::test_int(2),
Value::test_int(3),
],
),
Column::new(
"bar".to_string(),
vec![
Value::test_string("a"),
Value::test_string("c"),
Value::test_string("a"),
Value::test_string("a"),
],
),
Column::new(
"ham".to_string(),
vec![
Value::test_string("let"),
Value::test_string("var"),
Value::test_string("let"),
Value::test_string("let"),
],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -110,53 +113,56 @@ impl Command for LazyJoin {
let df_b = ([["foo" "bar" "ham"];[1 "a" "let"] [2 "c" "var"] [3 "c" "const"]] | dfr into-lazy);
$df_a | dfr join $df_b a foo"#,
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![
Value::test_int(1),
Value::test_int(2),
Value::test_int(1),
Value::test_int(1),
],
),
Column::new(
"b".to_string(),
vec![
Value::test_string("a"),
Value::test_string("b"),
Value::test_string("c"),
Value::test_string("c"),
],
),
Column::new(
"c".to_string(),
vec![
Value::test_int(0),
Value::test_int(1),
Value::test_int(2),
Value::test_int(3),
],
),
Column::new(
"bar".to_string(),
vec![
Value::test_string("a"),
Value::test_string("c"),
Value::test_string("a"),
Value::test_string("a"),
],
),
Column::new(
"ham".to_string(),
vec![
Value::test_string("let"),
Value::test_string("var"),
Value::test_string("let"),
Value::test_string("let"),
],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![
Value::test_int(1),
Value::test_int(2),
Value::test_int(1),
Value::test_int(1),
],
),
Column::new(
"b".to_string(),
vec![
Value::test_string("a"),
Value::test_string("b"),
Value::test_string("c"),
Value::test_string("c"),
],
),
Column::new(
"c".to_string(),
vec![
Value::test_int(0),
Value::test_int(1),
Value::test_int(2),
Value::test_int(3),
],
),
Column::new(
"bar".to_string(),
vec![
Value::test_string("a"),
Value::test_string("c"),
Value::test_string("a"),
Value::test_string("a"),
],
),
Column::new(
"ham".to_string(),
vec![
Value::test_string("let"),
Value::test_string("var"),
Value::test_string("let"),
Value::test_string("let"),
],
),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -171,14 +177,14 @@ impl Command for LazyJoin {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let left = call.has_flag("left");
let outer = call.has_flag("outer");
let cross = call.has_flag("cross");
let left = call.has_flag(engine_state, stack, "left")?;
let outer = call.has_flag(engine_state, stack, "outer")?;
let cross = call.has_flag(engine_state, stack, "cross")?;
let how = if left {
JoinType::Left
} else if outer {
JoinType::Outer
JoinType::Outer { coalesce: true }
} else if cross {
JoinType::Cross
} else {

View File

@ -112,6 +112,70 @@ macro_rules! lazy_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_type(
Type::Custom("dataframe".into()),
Type::Custom("dataframe".into()),
)
.category(Category::Custom("lazyframe".into()))
}
fn examples(&self) -> Vec<Example> {
$examples
}
fn run(
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?;
let lazy = NuLazyFrame::new(
lazy.from_eager,
lazy.into_polars()
.$func()
.map_err(|e| ShellError::GenericError {
error: "Dataframe Error".into(),
msg: e.to_string(),
help: None,
span: None,
inner: vec![],
})?,
);
Ok(PipelineData::Value(lazy.into_value(call.head)?, None))
}
}
#[cfg(test)]
mod $test {
use super::super::super::test_dataframe::test_dataframe;
use super::*;
#[test]
fn test_examples() {
test_dataframe(vec![Box::new($command {})])
}
}
};
}
// LazyReverse command
@ -124,16 +188,19 @@ lazy_command!(
description: "Reverses the dataframe.",
example: "[[a b]; [6 2] [4 2] [2 2]] | dfr into-df | dfr reverse",
result: Some(
NuDataFrame::try_from_columns(vec![
Column::new(
"a".to_string(),
vec![Value::test_int(2), Value::test_int(4), Value::test_int(6),],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(2), Value::test_int(2),],
),
])
NuDataFrame::try_from_columns(
vec![
Column::new(
"a".to_string(),
vec![Value::test_int(2), Value::test_int(4), Value::test_int(6),],
),
Column::new(
"b".to_string(),
vec![Value::test_int(2), Value::test_int(2), Value::test_int(2),],
),
],
None
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -167,14 +234,17 @@ lazy_command!(
description: "Median value from columns in a dataframe",
example: "[[a b]; [6 2] [4 2] [2 2]] | dfr into-df | dfr median",
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)],),
])
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)],),
],
None
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
},],
median,
median?,
test_median
);

View File

@ -38,10 +38,13 @@ impl Command for LazyQuantile {
description: "quantile value from columns in a dataframe",
example: "[[a b]; [6 2] [1 4] [4 1]] | dfr into-df | dfr quantile 0.5",
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)]),
])
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)]),
],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -62,7 +65,14 @@ impl Command for LazyQuantile {
let lazy = NuLazyFrame::new(
lazy.from_eager,
lazy.into_polars()
.quantile(lit(quantile), QuantileInterpolOptions::default()),
.quantile(lit(quantile), QuantileInterpolOptions::default())
.map_err(|e| ShellError::GenericError {
error: "Dataframe Error".into(),
msg: e.to_string(),
help: None,
span: None,
inner: vec![],
})?,
);
Ok(PipelineData::Value(lazy.into_value(call.head)?, None))

View File

@ -37,10 +37,13 @@ impl Command for LazySelect {
description: "Select a column from the dataframe",
example: "[[a b]; [6 2] [4 2] [2 2]] | dfr into-df | dfr select a",
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"a".to_string(),
vec![Value::test_int(6), Value::test_int(4), Value::test_int(2)],
)])
NuDataFrame::try_from_columns(
vec![Column::new(
"a".to_string(),
vec![Value::test_int(6), Value::test_int(4), Value::test_int(2)],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -60,7 +60,7 @@ impl Command for LazySortBy {
"b".to_string(),
vec![Value::test_int(4), Value::test_int(1), Value::test_int(2)],
),
])
], None)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -89,7 +89,7 @@ impl Command for LazySortBy {
Value::test_int(2),
],
),
])
], None)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -107,8 +107,8 @@ impl Command for LazySortBy {
let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
let value = Value::list(vals, call.head);
let expressions = NuExpression::extract_exprs(value)?;
let nulls_last = call.has_flag("nulls-last");
let maintain_order = call.has_flag("maintain-order");
let nulls_last = call.has_flag(engine_state, stack, "nulls-last")?;
let maintain_order = call.has_flag(engine_state, stack, "maintain-order")?;
let reverse: Option<Vec<bool>> = call.get_flag(engine_state, stack, "reverse")?;
let reverse = match reverse {

View File

@ -1,9 +1,12 @@
use crate::dataframe::values::NuSchema;
use super::super::values::{NuDataFrame, NuLazyFrame};
use nu_engine::CallExt;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Type, Value,
Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
};
#[derive(Clone)]
@ -20,6 +23,12 @@ impl Command for ToLazyFrame {
fn signature(&self) -> Signature {
Signature::build(self.name())
.named(
"schema",
SyntaxShape::Record(vec![]),
r#"Polars Schema in format [{name: str}]. CSV, JSON, and JSONL files"#,
Some('s'),
)
.input_output_type(Type::Any, Type::Custom("dataframe".into()))
.category(Category::Custom("lazyframe".into()))
}
@ -34,12 +43,17 @@ impl Command for ToLazyFrame {
fn run(
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let df = NuDataFrame::try_from_iter(input.into_iter())?;
let maybe_schema = call
.get_flag(engine_state, stack, "schema")?
.map(|schema| NuSchema::try_from(&schema))
.transpose()?;
let df = NuDataFrame::try_from_iter(input.into_iter(), maybe_schema)?;
let lazy = NuLazyFrame::from_dataframe(df);
let value = Value::custom_value(Box::new(lazy), call.head);

View File

@ -33,10 +33,13 @@ impl Command for AllFalse {
description: "Returns true if all values are false",
example: "[false false false] | dfr into-df | dfr all-false",
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"all_false".to_string(),
vec![Value::test_bool(true)],
)])
NuDataFrame::try_from_columns(
vec![Column::new(
"all_false".to_string(),
vec![Value::test_bool(true)],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -47,10 +50,13 @@ impl Command for AllFalse {
let res = ($s > 9);
$res | dfr all-false"#,
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"all_false".to_string(),
vec![Value::test_bool(false)],
)])
NuDataFrame::try_from_columns(
vec![Column::new(
"all_false".to_string(),
vec![Value::test_bool(false)],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -88,8 +94,11 @@ fn command(
let value = Value::bool(!bool.any(), call.head);
NuDataFrame::try_from_columns(vec![Column::new("all_false".to_string(), vec![value])])
.map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None))
NuDataFrame::try_from_columns(
vec![Column::new("all_false".to_string(), vec![value])],
None,
)
.map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None))
}
#[cfg(test)]

View File

@ -33,10 +33,13 @@ impl Command for AllTrue {
description: "Returns true if all values are true",
example: "[true true true] | dfr into-df | dfr all-true",
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"all_true".to_string(),
vec![Value::test_bool(true)],
)])
NuDataFrame::try_from_columns(
vec![Column::new(
"all_true".to_string(),
vec![Value::test_bool(true)],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -47,10 +50,13 @@ impl Command for AllTrue {
let res = ($s > 9);
$res | dfr all-true"#,
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"all_true".to_string(),
vec![Value::test_bool(false)],
)])
NuDataFrame::try_from_columns(
vec![Column::new(
"all_true".to_string(),
vec![Value::test_bool(false)],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -88,7 +94,7 @@ fn command(
let value = Value::bool(bool.all(), call.head);
NuDataFrame::try_from_columns(vec![Column::new("all_true".to_string(), vec![value])])
NuDataFrame::try_from_columns(vec![Column::new("all_true".to_string(), vec![value])], None)
.map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None))
}

View File

@ -37,10 +37,10 @@ impl Command for ArgMax {
description: "Returns index for max value",
example: "[1 3 2] | dfr into-df | dfr arg-max",
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"arg_max".to_string(),
vec![Value::test_int(1)],
)])
NuDataFrame::try_from_columns(
vec![Column::new("arg_max".to_string(), vec![Value::test_int(1)])],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -37,10 +37,10 @@ impl Command for ArgMin {
description: "Returns index for min value",
example: "[1 3 2] | dfr into-df | dfr arg-min",
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"arg_min".to_string(),
vec![Value::test_int(0)],
)])
NuDataFrame::try_from_columns(
vec![Column::new("arg_min".to_string(), vec![Value::test_int(0)])],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -69,16 +69,19 @@ impl Command for Cumulative {
description: "Cumulative sum for a series",
example: "[1 2 3 4 5] | dfr into-df | dfr cumulative sum",
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"0_cumulative_sum".to_string(),
vec![
Value::test_int(1),
Value::test_int(3),
Value::test_int(6),
Value::test_int(10),
Value::test_int(15),
],
)])
NuDataFrame::try_from_columns(
vec![Column::new(
"0_cumulative_sum".to_string(),
vec![
Value::test_int(1),
Value::test_int(3),
Value::test_int(6),
Value::test_int(10),
Value::test_int(15),
],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -103,12 +106,12 @@ fn command(
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let cum_type: Spanned<String> = call.req(engine_state, stack, 0)?;
let reverse = call.has_flag("reverse");
let reverse = call.has_flag(engine_state, stack, "reverse")?;
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let series = df.as_series(call.head)?;
if let DataType::Object(_) = series.dtype() {
if let DataType::Object(..) = series.dtype() {
return Err(ShellError::GenericError {
error: "Found object series".into(),
msg: "Series of type object cannot be used for cumulative operation".into(),

View File

@ -6,7 +6,7 @@ use nu_protocol::{
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type,
};
use polars::prelude::{IntoSeries, Utf8Methods};
use polars::prelude::{IntoSeries, StringMethods};
#[derive(Clone)]
pub struct AsDate;
@ -64,11 +64,11 @@ fn command(
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let format: String = call.req(engine_state, stack, 0)?;
let not_exact = call.has_flag("not-exact");
let not_exact = call.has_flag(engine_state, stack, "not-exact")?;
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let series = df.as_series(call.head)?;
let casted = series.utf8().map_err(|e| ShellError::GenericError {
let casted = series.str().map_err(|e| ShellError::GenericError {
error: "Error casting to string".into(),
msg: e.to_string(),
span: Some(call.head),

View File

@ -7,7 +7,7 @@ use nu_protocol::{
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use polars::prelude::{IntoSeries, TimeUnit, Utf8Methods};
use polars::prelude::{IntoSeries, StringMethods, TimeUnit};
#[derive(Clone)]
pub struct AsDateTime;
@ -53,27 +53,30 @@ impl Command for AsDateTime {
description: "Converts string to datetime",
example: r#"["2021-12-30 00:00:00" "2021-12-31 00:00:00"] | dfr into-df | dfr as-datetime "%Y-%m-%d %H:%M:%S""#,
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"datetime".to_string(),
vec![
Value::date(
DateTime::parse_from_str(
"2021-12-30 00:00:00 +0000",
"%Y-%m-%d %H:%M:%S %z",
)
.expect("date calculation should not fail in test"),
Span::test_data(),
),
Value::date(
DateTime::parse_from_str(
"2021-12-31 00:00:00 +0000",
"%Y-%m-%d %H:%M:%S %z",
)
.expect("date calculation should not fail in test"),
Span::test_data(),
),
],
)])
NuDataFrame::try_from_columns(
vec![Column::new(
"datetime".to_string(),
vec![
Value::date(
DateTime::parse_from_str(
"2021-12-30 00:00:00 +0000",
"%Y-%m-%d %H:%M:%S %z",
)
.expect("date calculation should not fail in test"),
Span::test_data(),
),
Value::date(
DateTime::parse_from_str(
"2021-12-31 00:00:00 +0000",
"%Y-%m-%d %H:%M:%S %z",
)
.expect("date calculation should not fail in test"),
Span::test_data(),
),
],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -82,27 +85,30 @@ impl Command for AsDateTime {
description: "Converts string to datetime with high resolutions",
example: r#"["2021-12-30 00:00:00.123456789" "2021-12-31 00:00:00.123456789"] | dfr into-df | dfr as-datetime "%Y-%m-%d %H:%M:%S.%9f""#,
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"datetime".to_string(),
vec![
Value::date(
DateTime::parse_from_str(
"2021-12-30 00:00:00.123456789 +0000",
"%Y-%m-%d %H:%M:%S.%9f %z",
)
.expect("date calculation should not fail in test"),
Span::test_data(),
),
Value::date(
DateTime::parse_from_str(
"2021-12-31 00:00:00.123456789 +0000",
"%Y-%m-%d %H:%M:%S.%9f %z",
)
.expect("date calculation should not fail in test"),
Span::test_data(),
),
],
)])
NuDataFrame::try_from_columns(
vec![Column::new(
"datetime".to_string(),
vec![
Value::date(
DateTime::parse_from_str(
"2021-12-30 00:00:00.123456789 +0000",
"%Y-%m-%d %H:%M:%S.%9f %z",
)
.expect("date calculation should not fail in test"),
Span::test_data(),
),
Value::date(
DateTime::parse_from_str(
"2021-12-31 00:00:00.123456789 +0000",
"%Y-%m-%d %H:%M:%S.%9f %z",
)
.expect("date calculation should not fail in test"),
Span::test_data(),
),
],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),
@ -128,11 +134,11 @@ fn command(
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let format: String = call.req(engine_state, stack, 0)?;
let not_exact = call.has_flag("not-exact");
let not_exact = call.has_flag(engine_state, stack, "not-exact")?;
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
let series = df.as_series(call.head)?;
let casted = series.utf8().map_err(|e| ShellError::GenericError {
let casted = series.str().map_err(|e| ShellError::GenericError {
error: "Error casting to string".into(),
msg: e.to_string(),
span: Some(call.head),

View File

@ -35,10 +35,13 @@ impl Command for GetDay {
let df = ([$dt $dt] | dfr into-df);
$df | dfr get-day"#,
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"0".to_string(),
vec![Value::test_int(4), Value::test_int(4)],
)])
NuDataFrame::try_from_columns(
vec![Column::new(
"0".to_string(),
vec![Value::test_int(4), Value::test_int(4)],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

View File

@ -35,10 +35,13 @@ impl Command for GetHour {
let df = ([$dt $dt] | dfr into-df);
$df | dfr get-hour"#,
result: Some(
NuDataFrame::try_from_columns(vec![Column::new(
"0".to_string(),
vec![Value::test_int(16), Value::test_int(16)],
)])
NuDataFrame::try_from_columns(
vec![Column::new(
"0".to_string(),
vec![Value::test_int(16), Value::test_int(16)],
)],
None,
)
.expect("simple df for test should not fail")
.into_value(Span::test_data()),
),

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