Compare commits

...

632 Commits

Author SHA1 Message Date
bc38a6a795 Bump version for 0.76.0 release (#8121)
Before landing:

- [x] `reedline 0.16.0` is out and pinned.
- [x] all fixes and features necessary are landed.

In the meantime:

- [ ] feed the release notes with relevant features and breaking changes
2023-02-21 20:46:29 +00:00
e89866bedb TEST: add the output to the new with-env example (#8148)
Related to #8119.
Should address the review comment by @sholderbach from #8119.


# Description

this PR adds the output to the new example for the `with-env` command
introduced by #8119.

```bash
with-env {X: "Y", W: "Z"} { [$env.X $env.W] }
```
should output
```bash
["Y", "Z"]
```
hence the proposition from @sholderbach, i.e.
```rust
Some(Value::list(
    vec![Value::test_string("Y"), Value::test_string("Z")],
    Span::test_data(),
))
```

# User-Facing Changes
_none_

# Tests + Formatting

not really a test, only the output value for the last `with-env` example

- ✔️ `cargo fmt --all`
- ✔️ `cargo clippy --workspace -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect`
- ✔️ `cargo test --workspace`

# After Submitting
_none_
2023-02-21 10:15:35 +00:00
ca09dbbbee Pin reedline to 0.16.0 (#8142)
# Description

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

# User-Facing Changes

Only internal

# Tests + Formatting

(-)
2023-02-20 21:44:04 +00:00
fa4531fd17 Bump actions-rust-lang/setup-rust-toolchain from 1.3.7 to 1.4.2 (#8133)
Bumps
[actions-rust-lang/setup-rust-toolchain](https://github.com/actions-rust-lang/setup-rust-toolchain)
from 1.3.7 to 1.4.2.
<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.4.2] - 2023-02-15</h2>
<h3>Fixed</h3>
<ul>
<li>Tweak sparse registry version regex to better work with 1.68 nightly
versions.</li>
<li>Fix command not found issue</li>
</ul>
<h2>[1.4.1] - 2023-02-13</h2>
<h3>Fixed</h3>
<ul>
<li>
<p>Fixed running on macOS <a
href="https://github-redirect.dependabot.com/actions-rust-lang/setup-rust-toolchain/issues/9">#9</a>
<a
href="https://github-redirect.dependabot.com/actions-rust-lang/setup-rust-toolchain/issues/10">#10</a>
The macOS images have an ancient version of bash, but the action relies
on &quot;newer&quot; features than 2014.
We install bash via brew (already pre-installed) to have a new enough
version.</p>
<p>The CI is extended to also run on Windows and macOS to catch such
issues earlier in the future.</p>
<p>Thanks to <a
href="https://github.com/GeorgeHahn"><code>@​GeorgeHahn</code></a> for
reporting the issue.</p>
</li>
</ul>
<h2>[1.4.0] - 2023-02-13</h2>
<h3>Changed</h3>
<ul>
<li>Only set environment variables, if they are not set before.
This allows setting environment variables before using this action and
keeping their values.</li>
<li>Enable stable sparse registry, except on versions 1.66 and 1.67
where this leads to errors.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="9fa7c33ef0"><code>9fa7c33</code></a>
Merge pull request <a
href="https://github-redirect.dependabot.com/actions-rust-lang/setup-rust-toolchain/issues/11">#11</a>
from actions-rust-lang/tweak-regex</li>
<li><a
href="5f4f30a995"><code>5f4f30a</code></a>
Maybe fix rustup warning</li>
<li><a
href="2d7b97c05c"><code>2d7b97c</code></a>
Tweak sparse registry version regex and command not found</li>
<li><a
href="c7c759a5c9"><code>c7c759a</code></a>
New version with macOS fix</li>
<li><a
href="ba68a52e42"><code>ba68a52</code></a>
Merge pull request <a
href="https://github-redirect.dependabot.com/actions-rust-lang/setup-rust-toolchain/issues/10">#10</a>
from actions-rust-lang/issue-9</li>
<li><a
href="40e33d4912"><code>40e33d4</code></a>
Install newer bash on macOS</li>
<li><a
href="8ba1b441e5"><code>8ba1b44</code></a>
Run CI on more platforms</li>
<li><a
href="51b4f8316a"><code>51b4f83</code></a>
Bump version to 1.4.0</li>
<li><a
href="4605df10a0"><code>4605df1</code></a>
Merge pull request <a
href="https://github-redirect.dependabot.com/actions-rust-lang/setup-rust-toolchain/issues/8">#8</a>
from actions-rust-lang/sparse-registry</li>
<li><a
href="eac5ebb2ae"><code>eac5ebb</code></a>
Fix: Use acceptable crate name (lowercase)</li>
<li>Additional commits viewable in <a
href="https://github.com/actions-rust-lang/setup-rust-toolchain/compare/v1.3.7...v1.4.2">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.3.7&new-version=1.4.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

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

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

---

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

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot 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-02-20 19:22:52 +00:00
d17c970f8c update code coversage script to work better with windows (#8141)
# Description

This PR updates the code coverage script to help it work better on
Windows. The main changes here are to give you some progress outputs and
to enable `cargo llvm-cov show-env | from toml` to work better since the
toml spec says these literal strings should be single quoted vs double
quoted.

Closed #8139

# User-Facing Changes



# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-20 19:21:41 +00:00
6ca62ef131 show more informaiton when there are toml errors (#8140)
# Description

While debugging #8139 I noticed that there was some error information
coming from the toml crate that we were not displaying. This would've
helped me to understand what was going on. So, this PR shows more
verbose errors when toml fails to parse.

### Before

```
cargo llvm-cov show-env | from toml 
Error: nu:🐚:cant_convert (link)

  × Can't convert to structured toml data.
   ╭─[entry #1:1:1]
 1 │ cargo llvm-cov show-env | from toml
   · ──┬──
   ·   ╰── can't convert string to structured toml data
   ╰────
```

### After

```
cargo llvm-cov show-env | from toml
Error: nu:🐚:cant_convert (link)

  × Can't convert to structured toml data.
   ╭─[entry #1:1:1]
 1 │ cargo llvm-cov show-env | from toml
   · ──┬──
   ·   ╰── can't convert string to structured toml data
   ╰────
  help: TOML parse error at line 2, column 24
          |
        2 | LLVM_PROFILE_FILE="C:\CarTar\nushell-%p-%m.profraw"
          |                        ^
        invalid escape sequence
        expected `b`, `f`, `n`, `r`, `t`, `u`, `U`, `\`, `"`
```

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-20 18:50:31 +00:00
8e84e33638 add usage for plugin commands (#8138)
# Description

As title

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-20 15:03:17 +00:00
b9be416937 Add colors in table --collapse (#8120)
close #8110 

cc: @amtoine

---------

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2023-02-20 12:59:33 +00:00
0a8c9b22b0 string | fill counts clusters, not graphemes; and doesn't count ANSI escape codes (#8134)
Enhancement of new `fill` command (#7846) to handle content including
ANSI escape codes for formatting or multi-code-point Unicode grapheme
clusters.
In both of these cases, the content is (many) bytes longer than its
visible length, and `fill` was counting the extra bytes so not adding
enough fill characters.

# Description

This script:
```rust
# the teacher emoji `\u{1F9D1}\u{200D}\u{1F3EB}` is 3 code points, but only 1 print position wide.
echo "This output should be 3 print positions wide, with leading and trailing `+`"
$"\u{1F9D1}\u{200D}\u{1F3EB}" | fill -c "+" -w 3 -a "c"

echo "This output should be 3 print positions wide, with leading and trailing `+`"
$"(ansi green)a(ansi reset)" | fill -c "+" -w 3 -a c
echo ""
```

Was producing this output:
```rust
This output should be 3 print positions wide, with leading and trailing `+`
🧑‍🏫

This output should be 3 print positions wide, with leading and trailing `+`
a
```

After this PR, it produces this output:
```rust
This output should be 3 print positions wide, with leading and trailing `+`
+🧑‍🏫+

This output should be 3 print positions wide, with leading and trailing `+`
+a+
```
# User-Facing Changes

Users may have to undo fixes they may have introduced to work around the
former behavior. I have one such in my prompt string that I can now
revert.

# Tests + Formatting

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

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

- [x] `cargo fmt --all -- --check` to check standard code formatting
(`cargo fmt --all` applies these changes)
- [x] `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- [x] `cargo test --workspace` to check that all tests pass

# After Submitting

`fill` command not documented in the book, and it still talks about `str
lpad/rpad`. I'll fix.

Note added dependency on a new library `print-positions`, which is an
iterator that yields a complete print position (cluster + Ansi sequence)
per call. Should this be vendored?
2023-02-20 06:32:20 -06:00
527c44ed84 Bump sysinfo from 0.27.7 to 0.28.0 (#8132)
Bumps [sysinfo](https://github.com/GuillaumeGomez/sysinfo) from 0.27.7
to 0.28.0.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/GuillaumeGomez/sysinfo/blob/master/CHANGELOG.md">sysinfo's
changelog</a>.</em></p>
<blockquote>
<h1>0.28.0</h1>
<ul>
<li>Linux: Fix name and CPU usage for processes tasks.</li>
<li>unix: Keep all users, even &quot;not real&quot; accounts.</li>
<li>Windows: Use SID for Users ID.</li>
<li>Fix C API.</li>
<li>Disable default cdylib compilation.</li>
<li>Add <code>serde</code> feature to enable serialization.</li>
<li>Linux: Handle <code>Idle</code> state in
<code>ProcessStatus</code>.</li>
<li>Linux: Add brand and name of ARM CPUs.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/GuillaumeGomez/sysinfo/commits">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=sysinfo&package-manager=cargo&previous-version=0.27.7&new-version=0.28.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 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-02-19 20:58:07 -06:00
8ee015a847 Bump winreg from 0.10.1 to 0.11.0 (#8128)
Bumps [winreg](https://github.com/gentoo90/winreg-rs) from 0.10.1 to
0.11.0.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/gentoo90/winreg-rs/blob/master/CHANGELOG.md">winreg's
changelog</a>.</em></p>
<blockquote>
<h2>0.11.0</h2>
<ul>
<li>Migrate to the 2018 edition of Rust</li>
<li>Move the code from <code>lib.rs</code> to separate files</li>
<li>Use <a
href="https://crates.io/crates/cfg-if"><code>cfg-if</code></a> instead
of <code>build.rs</code> to fail build on non-windows systems</li>
<li>Reimplement deserialization logic, implement [de]serialization for
byte arrays (<a
href="https://github-redirect.dependabot.com/gentoo90/winreg-rs/issues/49">#49</a>)</li>
<li>Fix some typos and <code>clippy</code> warnings</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="f34742d674"><code>f34742d</code></a>
Bump version to 0.11.0</li>
<li><a
href="75f2593f62"><code>75f2593</code></a>
Move the changelog to a separate file</li>
<li><a
href="1f6f877ed7"><code>1f6f877</code></a>
Fix some clippy warnings</li>
<li><a
href="7a32d642cd"><code>7a32d64</code></a>
Implement [de]serialization for byte arrays</li>
<li><a
href="8464557c2d"><code>8464557</code></a>
Reimplement deserialization logic</li>
<li><a
href="9e8dc28029"><code>9e8dc28</code></a>
Put serialization tests into a separate file</li>
<li><a
href="04f7d232c7"><code>04f7d23</code></a>
Use <code>cfg-if</code> to fail build on non-windows systems</li>
<li><a
href="c3ac5ba5ea"><code>c3ac5ba</code></a>
Move the code from <code>lib.rs</code> to separate files</li>
<li><a
href="17378a9ca4"><code>17378a9</code></a>
Migrate to the 2018 edition of Rust</li>
<li><a
href="f4d45923ab"><code>f4d4592</code></a>
Remove Appveyor. It's broken anyway</li>
<li>Additional commits viewable in <a
href="https://github.com/gentoo90/winreg-rs/compare/v0.10.1...v0.11.0">compare
view</a></li>
</ul>
</details>
<br />


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

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

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

---

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

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot 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-02-19 20:57:46 -06:00
e8cabd16d5 Add a script to generate coverage locally (#8125)
# Description

This can be triggered manually and inspected for example with:

-
https://marketplace.visualstudio.com/items?itemName=ryanluker.vscode-coverage-gutters
- https://github.com/umaumax/vim-lcov
- https://github.com/andythigpen/nvim-coverage (probably with some
effort)

Currently I try to use the `--profile=ci` as well as the CI coverage
action relies on it but the flags passed to build and test differ.
First locally I don't run into the out of disk space problems of the CI
runners when also allowing the plugin tests to run. Furthermore I am not
fully sure what is going on with the recompilation between `cargo build`
and `cargo test`. Chose the most simple config, people might use for
running the test suite locally.



# User-Facing Changes

> Developers, Developers, Developers

Steve Ballmer
2023-02-19 21:19:48 +00:00
88e07b5ea4 DOCUMENTATION: add a new "key-value" example to with-env (#8119)
hello there 👋 😋 

when messing around with `with-env`, looking at the examples, i did not
understand that we could directly run `with-env` with a record as the
argument and not from the input of a pipe 😮

even though the last example, i.e. 
```bash
  Set by row(e.g. `open x.json` or `from json`)
  > '{"X":"Y","W":"Z"}'|from json|with-env $in { [$env.X $env.W] }
```
, is equivalent, just the record comes from the pipe, i thought adding
that explicite new example could be helpful 😌
 
# Description
looking at the single real change of this PR, i.e. 86ef34e90, you can
see i've simply added
```bash
  Set by key-value record
  > with-env {X: "Y", W: "Z"} { [$env.X $env.W] }
```
just before the example above

> **Note**
> i've also added spaces around the '|' in the last examples, from
> ```bash
>   > '{"X":"Y","W":"Z"}'|from json|with-env $in { [$env.X $env.W] }
> ```
> to
> ```bash
>   > '{"X":"Y","W":"Z"}' | from json | with-env $in { [$env.X $env.W] }
> ```
> hopefully making the pipeline a bit easier to read 👍

### hope you like that 😏 

# User-Facing Changes
a new example has been added to `with-env`

# Tests + Formatting
no tests have been added

# After Submitting
the change should not affect the website, i think

=> if i need to generate the associated `HTML` file on
https://github.com/nushell/nushell.github.io, please tell me 😋
2023-02-19 18:28:49 +00:00
f3ee8b50e3 Revert #7779 (enables back subcommand completions) (#8102)
# Description

Reverts the PR #7779 which breaks subcommand completions. The issues
#7648 and #7754 thus still need fixing.

This reverts commit 8acced5.

# User-Facing Changes

Enables subcommand completions.

Unfortunately, also brings back the completion panic if alias is shorter
than the command name.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-18 17:38:29 +00:00
68ad854b0d update link to command reference (#8111)
# Description

Broken link

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-18 07:38:36 -06:00
789b2e603a update nu_plugin_python due to signature changes (#8107)
# Description

As title..

# 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 -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-18 13:27:24 +00:00
66398fbf77 Factorize HTTP commands code (#8088)
# Description

In order to work on https://github.com/nushell/nushell/issues/2741, I'm
preparing the code.

# User-Facing Changes

Both commands do support the timeout option.

**But the timeout argument `-t, --timeout` has been migrated to `-m,
--max-time`**. I had to make a choice since there is another option
using the short command `t` which is "content-type".

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-17 23:10:29 +00:00
daeb3e5187 nu-table/ table --collapse style fix (#8041)
close #8033

So as I said they suppose to be there;

I've basically added a change of style if --collapse is used.

PS: I guess it's worth to add tests so hold on if you'll plan to merge
it.

---------

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2023-02-16 19:32:07 +00:00
1fd1a3a456 Support URLs in start command (#7799)
# Description
Fixes issue #7792 Fix basically by @kubouch , "stolen" by me :). Edit:
Added "proper" fix rather than the one liner
```
start Cargo.toml
// Opens in default editor 
```

```
start https://www.google.com [alternative_browser]
// Opens page in default browser or another browser if specified
```

# 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 -A
clippy::needless_collect` to check that you're using the standard code
style
- [X] `cargo test --workspace` to check that all tests pass

# 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-02-16 13:33:25 +00:00
30ac2d220c update colors in dark theme (#8090)
# Description

I noticed a bug in the default_config.nu while debugging something else.
The colors in the dark_theme should be named colors and not rgb colors.
Rgb colors prevents the dark theme from working properly in terminals
that don't support 24-bit aka rgb colors.

# User-Facing Changes


# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-16 06:59:26 -06:00
JT
ade7bde813 Bare word improvements (#8066)
# Description

This does two fixes for bare words:

* It changes completions for paths to wrap a path with backticks if it
starts with a number. This helps bare words that start with numbers be
separate from unit values
* It allows bare words wrapped with backticks to be the name of a
command. Backtick values in command positions are no longer treated as
strings

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-16 02:30:56 +00:00
cba3e100a0 fix rename when it is passed an empty column list to rename (#8086)
# Description

This PR fixes a bug that occurs if you pass `rename --column` and empty
list like `ls | rename -c []`.

## Before

```
> ls | rename -c []
thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', crates\nu-command\src\filters\rename.rs:110:15
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```

## After

```
> ls | rename -c []
Error: nu:🐚:type_mismatch (link)

  × Type mismatch.
   ╭─[entry #1:1:1]
 1 │ ls | rename -c []
   ·                ─┬
   ·                 ╰── The list cannot be empty and must contain only two values: the column's name and its replacement value
   ╰────
```

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-15 21:47:27 +00:00
664d8d3573 allow date grouping in group-by (#8084)
# Description

This small change allows tables to be grouped by date. It was previously
failing because nushell didn't know how to represent the date as a
string. This change allows the date to be formatted in rfc3339 format
with subseconds represented as dot milliseconds. This formatted datetime
representation is already understood by nushell.

Now you can do things like 

### Grouping by the exact time
```
> ls | group-by modified | table
╭───────────────────────────────┬────────────────╮
│ 2022-01-07T07:53:44.658-06:00 │ [table 1 row]  │
│ 2022-11-29T08:08:09.411-06:00 │ [table 2 rows] │
│ 2023-02-15T08:23:16.044-06:00 │ [table 5 rows] │
│ 2023-01-04T14:45:08.940-06:00 │ [table 2 rows] │
│ 2022-04-08T08:12:50.295-05:00 │ [table 1 row]  │
│ 2022-09-15T10:11:21.177-05:00 │ [table 1 row]  │
│ 2022-06-22T14:26:56.409-05:00 │ [table 1 row]  │
│ 2023-02-08T09:24:32.774-06:00 │ [table 1 row]  │
│ 2022-05-25T11:57:00.866-05:00 │ [table 2 rows] │
│ 2023-02-15T08:23:16.054-06:00 │ [table 4 rows] │
│ 2023-01-04T14:45:08.970-06:00 │ [table 3 rows] │
│ 2022-08-05T07:14:06.265-05:00 │ [table 1 row]  │
│ 2022-01-07T07:53:44.728-06:00 │ [table 1 row]  │
│ 2023-01-27T09:39:34.351-06:00 │ [table 1 row]  │
│ 2023-02-08T09:24:32.794-06:00 │ [table 1 row]  │
│ 2023-02-15T08:36:26.524-06:00 │ [table 1 row]  │
│ 2023-01-19T12:53:22.033-06:00 │ [table 1 row]  │
╰───────────────────────────────┴────────────────╯
```
### Grouping by only the date (truncating the time componenet to 0)
```
> ls | default "" date | update date {|r| $r.modified | date format '%Y-%m-%d' | into datetime} | group-by date | table
╭───────────────────────────────┬─────────────────╮
│ 2022-01-07T00:00:00.000-06:00 │ [table 2 rows]  │
│ 2022-11-29T00:00:00.000-06:00 │ [table 2 rows]  │
│ 2023-02-15T00:00:00.000-06:00 │ [table 10 rows] │
│ 2023-01-04T00:00:00.000-06:00 │ [table 5 rows]  │
│ 2022-04-08T00:00:00.000-06:00 │ [table 1 row]   │
│ 2022-09-15T00:00:00.000-06:00 │ [table 1 row]   │
│ 2022-06-22T00:00:00.000-06:00 │ [table 1 row]   │
│ 2023-02-08T00:00:00.000-06:00 │ [table 2 rows]  │
│ 2022-05-25T00:00:00.000-06:00 │ [table 2 rows]  │
│ 2022-08-05T00:00:00.000-06:00 │ [table 1 row]   │
│ 2023-01-27T00:00:00.000-06:00 │ [table 1 row]   │
│ 2023-01-19T00:00:00.000-06:00 │ [table 1 row]   │
╰───────────────────────────────┴─────────────────╯
```
### Grouping and Displaying only the date (you could do this before this
PR too)
```
> ls | default "" date | update date {|r| $r.modified | date format '%Y-%m-%d'} | group-by date | table
╭────────────┬─────────────────╮
│ 2022-01-07 │ [table 2 rows]  │
│ 2022-11-29 │ [table 2 rows]  │
│ 2023-02-15 │ [table 10 rows] │
│ 2023-01-04 │ [table 5 rows]  │
│ 2022-04-08 │ [table 1 row]   │
│ 2022-09-15 │ [table 1 row]   │
│ 2022-06-22 │ [table 1 row]   │
│ 2023-02-08 │ [table 2 rows]  │
│ 2022-05-25 │ [table 2 rows]  │
│ 2022-08-05 │ [table 1 row]   │
│ 2023-01-27 │ [table 1 row]   │
│ 2023-01-19 │ [table 1 row]   │
╰────────────┴─────────────────╯
```
### Shows that nushell understands the rfc3339 format
```
> 2022-01-07T07:53:44.658-06:00 | describe 
date
> 2022-01-07T07:53:44.658-06:00 | date format '%Y-%m-%d'
2022-01-07
```
# User-Facing Changes

Related to #8036

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-15 19:10:55 +00:00
d5ce509e3a move ast command to the debug group (#8077)
# Description

This PR tweaks how `ast` works a tiny bit by outputting values in stead
of eprintln!'s. It also moves the `ast` command into the folder with the
rest of the debug commands and changes the category to debug.

I started adding some tests but couldn't figure out a good way to do it
since every `ast` command contains spans that will be different on each
invocation.

# User-Facing Changes



# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-14 18:47:34 +00:00
2f10d19c98 remove spurious use from default_context.rs (#8073)
For some reason this "Use" in default_context.rs was in the code,
but it is not being "used" --- pun intended...
2023-02-13 20:14:20 +00:00
4c787af26d relocate debug commands (#8071)
# Description

Now that we've landed the debug commands we were working on, let's
relocate them to an easier place to find all of them. That's what this
PR does.

The only actual code change was changing the `timeit` command to a
`Category::Debug` command. The rest is just moving things around and
hooking them up.

# User-Facing Changes



# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-13 16:39:07 +00:00
8136170431 support multiplication operation on string and list values (#8061)
# Description

As title, I found this feature is useful to me too :)

Closes: #8039

# User-Facing Changes

```
❯ 3 * "ab"
ababab

❯ 3 * [1 2 3]
╭───┬───╮
│ 0 │ 1 │
│ 1 │ 2 │
│ 2 │ 3 │
│ 3 │ 1 │
│ 4 │ 2 │
│ 5 │ 3 │
│ 6 │ 1 │
│ 7 │ 2 │
│ 8 │ 3 │
╰───┴───╯
```

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-13 16:35:53 +00:00
007916c2c1 Syntax errors for string and int (#7952)
# Description

Added a few syntax errors in ints and strings, changed parser to stop
and show that error rather than continue trying to parse those tokens as
some other shape. However, I don't see how to push this direction much
further, and most of the classic confusing errors can't be changed.

Flagged as WIP for the moment, but passes all checks and works better
than current release:
1. I have yet to figure out how to make these errors refer back to the
book, as I see some other errors do.
2. How to give syntax error when malformed int is first token in line?
Currently parsed as external command, user gets confusing error message.
3. Would like to be more strict with *decimal* int literals (lacking,
e.g, `0x' prefix). Need to tinker more with the order of parse shape
calls, currently, float is tried after int, so '1.4' has to be passed.

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

```bash

〉"\z"
Error: 
   ╭─[entry #3:1:1]
 1 │ "\z"
   ·  ─┬─
   ·   ╰── Syntax error in string, unrecognized character after escape '\'.
   ╰────
```
Canonic presentation of a syntax error.
```bash
〉"  \u{01ffbogus}"
Error: 
  × Invalid syntax
   ╭─[entry #2:1:1]
 1 │ "  \u{01ffbogus}"
   ·    ───────┬──────
   ·           ╰── Syntax error in string, expecting 1 to 6 hex digits in unicode escape '\u{X...}', max value 10FFFF.
   ╰────
```
Malformed unicode escape in string, flagged as error.  
String parse can be opinionated, it's the last shape tried.
```bash
〉0x22bogus
Error: nu:🐚:external_command (link)
  × External command failed
   ╭─[entry #4:1:1]
1 │ 0x22bogus
   · ────┬────
   ·     ╰── executable was not found
   ╰────
  help: No such file or directory (os error 2)
```
A *correct* number in first token would be evaluated, but an *incorrect*
one is treated as external command? Confusing to users.
```bash
〉0 + 0x22bogus
Error: 
  × Invalid syntax
   ╭─[entry #5:1:1]
1 │ 0 + 0x22bogus
   ·     ────┬────
   ·         ╰── Syntax error in int, invalid digits in radix 16 int.
   ╰────
```
Can give syntax error if token is unambiguously int literal. e.g has 0b
or 0x prefix, could not be a float.
```bash
〉0 + 098bogus
Error: nu::parser::unsupported_operation (link)

  × Types mismatched for operation.
   ╭─[entry #6:1:1]
 1 │ 0 + 098bogus
   · ┬ ┬ ────┬───
   · │ │     ╰── string
   · │ ╰── doesn't support these values.
   · ╰── int
   ╰────
  help: Change int or string to be the right types and try again.
```
But *decimal* literal (no prefix) can't be too strict. Parser is going
to try float later. So '1.4' must be passed.

# User-Facing Changes

First and foremost, more specific error messages for typos in string and
int literals. Probably improves interactive user experience.

But a script that was causing and then checking for specific error might
notice a different error message.

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

Added (positive and negative unit tests in `cargo test -p nu-parser`.
Didn't add integration tests.

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

- [x] `cargo fmt --all -- --check` to check standard code formatting
(`cargo fmt --all` applies these changes)
- [x] `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- [x] `cargo test --workspace` to check that all tests pass

# 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: Stefan Holderbach <sholderbach@users.noreply.github.com>
2023-02-13 16:09:50 +00:00
208ffdc1da Move some from xxx commands to plugin (#7942)
# Description

From nushell 0.8 philosophy:
https://github.com/nushell/nushell.github.io/blob/main/contributor-book/philosophy_0_80.md#core-categories

> The following categories should be moved to plugins:
Uncommon format support

So this pr is trying to move following commands to plugin:
- [X] from eml
- [x] from ics
- [x] from ini
- [x] from vcf

And we can have a new plugin handles for these formatting, currently
it's implemented here:

https://github.com/WindSoilder/nu_plugin_format

The command usage should be the same to original command.

If it's ok, the plugin can support more formats like
[parquet](https://github.com/fdncred/nu_plugin_from_parquet), or [EDN
format](https://github.com/nushell/nushell/issues/6415), or something
else.

Just create a draft pr to show what's the blueprint looks like, and is
it a good direction to move forward?

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-13 12:42:08 +00:00
4468dc835c Make patch coverage check informational only (#8069)
See:
https://docs.codecov.com/docs/common-recipe-list#set-non-blocking-status-checks
2023-02-13 10:30:24 +00:00
90a2352337 Bump roxmltree from 0.17.0 to 0.18.0 (#8065)
Bumps [roxmltree](https://github.com/RazrFalcon/roxmltree) from 0.17.0
to 0.18.0.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/RazrFalcon/roxmltree/blob/master/CHANGELOG.md">roxmltree's
changelog</a>.</em></p>
<blockquote>
<h2>[0.18.0] - 2023-02-04</h2>
<h3>Added</h3>
<ul>
<li><code>StringStorage</code> that exposes an internal string
storage.</li>
<li>Allocated strings are stored as <code>Arc&lt;str&gt;</code> and not
<code>String</code> now.</li>
<li><code>Node::text_storage</code></li>
<li><code>Node::tail_storage</code></li>
<li><code>Attribute::value_storage</code></li>
<li><code>Node::range</code></li>
</ul>
<h3>Removed</h3>
<ul>
<li><code>Node::position</code>. Use <code>Node::range</code>
instead.</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Some methods return longer lifetimes now.
Thanks to <a
href="https://github.com/adamreichold"><code>@​adamreichold</code></a></li>
<li>Overly verbose Debug implementations.
Thanks to <a
href="https://github.com/adamreichold"><code>@​adamreichold</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="8f6f14bbc7"><code>8f6f14b</code></a>
Version bump.</li>
<li><a
href="c4d622fccc"><code>c4d622f</code></a>
Store node's end position again.</li>
<li><a
href="3d33827a75"><code>3d33827</code></a>
Use ref-counted owned strings.</li>
<li><a
href="e81718610a"><code>e817186</code></a>
Expose 'input lifetime where it is the backing lifetime.</li>
<li><a
href="0b12673528"><code>0b12673</code></a>
Use consistent debug impls for the various iterators that avoid
formatting th...</li>
<li>See full diff in <a
href="https://github.com/RazrFalcon/roxmltree/compare/v0.17.0...v0.18.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=roxmltree&package-manager=cargo&previous-version=0.17.0&new-version=0.18.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 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-02-13 02:35:09 +00:00
0a9d14fcb3 Bump rstest from 0.15.0 to 0.16.0 (#8064)
[//]: # (dependabot-start)
⚠️  **Dependabot is rebasing this PR** ⚠️ 

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

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

---

[//]: # (dependabot-end)

Bumps [rstest](https://github.com/la10736/rstest) from 0.15.0 to 0.16.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/la10736/rstest/releases">rstest's
releases</a>.</em></p>
<blockquote>
<h2>0.16.0</h2>
<p>Use values expression to define test names.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/la10736/rstest/blob/master/CHANGELOG.md">rstest's
changelog</a>.</em></p>
<blockquote>
<h2>[0.16.0] 2022/11/27</h2>
<h3>Changed</h3>
<ul>
<li>Show <code>TEST START</code> banner only when trace some argument:
See <a
href="https://github-redirect.dependabot.com/la10736/rstest/issues/158">#158</a>
for details.</li>
<li>Add values to test name: See <a
href="https://github-redirect.dependabot.com/la10736/rstest/issues/160">#160</a>
for details.</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Updated test fixtures to 1.64.0 compiler's error messages.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="d7ff088126"><code>d7ff088</code></a>
Update checkout list</li>
<li><a
href="4386575950"><code>4386575</code></a>
Version 0.16.0 chengelog</li>
<li><a
href="41749a881e"><code>41749a8</code></a>
Fix clippy warning</li>
<li><a
href="daaddde1a0"><code>daaddde</code></a>
Bump to 0.16.0 version and upgrade dependency</li>
<li><a
href="576768e4b3"><code>576768e</code></a>
Fixed dev dependency in rstest_macros</li>
<li><a
href="a6eb3a96cb"><code>a6eb3a9</code></a>
Update rstest_test version</li>
<li><a
href="4a18dd0bd1"><code>4a18dd0</code></a>
Update version</li>
<li><a
href="29648832ce"><code>2964883</code></a>
Update dependency version</li>
<li><a
href="5ad7e3fd61"><code>5ad7e3f</code></a>
<a
href="https://github-redirect.dependabot.com/la10736/rstest/issues/160">#160</a>
Add test for module annotation</li>
<li><a
href="a302be019f"><code>a302be0</code></a>
<a
href="https://github-redirect.dependabot.com/la10736/rstest/issues/160">#160</a>
Tests fixed and add unit for allow</li>
<li>Additional commits viewable in <a
href="https://github.com/la10736/rstest/compare/0.15.0...0.16.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=rstest&package-manager=cargo&previous-version=0.15.0&new-version=0.16.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 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-02-13 02:34:09 +00:00
7863fb1087 Bump proptest from 1.0.0 to 1.1.0 (#8063)
Bumps [proptest](https://github.com/proptest-rs/proptest) from 1.0.0 to
1.1.0.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="75c749ee50"><code>75c749e</code></a>
bump version to 1.1.0</li>
<li><a
href="a7c75a1bcb"><code>a7c75a1</code></a>
Merge pull request <a
href="https://github-redirect.dependabot.com/proptest-rs/proptest/issues/295">#295</a>
from proptest-rs/replays-dont-count-cases</li>
<li><a
href="a854d2ed7a"><code>a854d2e</code></a>
[replays-dont-count-cases] persisted failures are not counted against
success...</li>
<li><a
href="f8eff50603"><code>f8eff50</code></a>
Merge pull request <a
href="https://github-redirect.dependabot.com/proptest-rs/proptest/issues/291">#291</a>
from schuelermine/fix/prop_assert_ne!</li>
<li><a
href="d38268304c"><code>d382683</code></a>
Merge pull request <a
href="https://github-redirect.dependabot.com/proptest-rs/proptest/issues/294">#294</a>
from proptest-rs/fix-ci</li>
<li><a
href="ad0a4d311c"><code>ad0a4d3</code></a>
[fix-ci] changed the line for where the error occurs</li>
<li><a
href="00f29af8e8"><code>00f29af</code></a>
Merge pull request <a
href="https://github-redirect.dependabot.com/proptest-rs/proptest/issues/288">#288</a>
from proptest-rs/const-generic-arbitrary</li>
<li><a
href="a16853f4fc"><code>a16853f</code></a>
Fix prop_assert_ne! requiring import of prop_assert!</li>
<li><a
href="b513a32c72"><code>b513a32</code></a>
Config : support disabling failure persistence via env var (<a
href="https://github-redirect.dependabot.com/proptest-rs/proptest/issues/287">#287</a>)</li>
<li><a
href="7a94e16589"><code>7a94e16</code></a>
note that PROPTEST_CASES and other env var requires the std feature (<a
href="https://github-redirect.dependabot.com/proptest-rs/proptest/issues/262">#262</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/proptest-rs/proptest/compare/1.0.0...v1.1.0">compare
view</a></li>
</ul>
</details>
<br />


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

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

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

---

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

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot 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-02-13 02:31:53 +00:00
072d2a919d #8027 Hide implementation details in invalid cd call (#8049)
# Description

[GH issue](https://github.com/nushell/nushell/issues/8027)

The current error message for a cd command includes a Debug output of
the `io::Error` being returned from `canonicalize_with`, so it's been
replaced with a more user friendly and readable depiction of the error.

# User-Facing Changes

As described in the issue, I've changed the error message for a cd into
a directory that does not exist from:
```
/home/rdevenney/projects/open_source/nushell〉cd asdfasdf                                                                               02/11/2023 08:59:59 PM
Error: nu:🐚:directory_not_found (link)

 × Directory not found
   ╭─[entry #2:1:1]
 1 │ cd asdfasdf
   ·    ────┬───
   ·        ╰── directory not found
   ╰────
  help: IO Error: Os { code: 2, kind: NotFound, message: "No such file or directory" }
```
To:
```
/home/rdevenney/projects/open_source/nushell〉cd asdfasdf                                                                               02/11/2023 08:58:38 PM
Error: nu:🐚:directory_not_found (link)

  × Directory not found
   ╭─[entry #1:1:1]
 1 │ cd asdfasdf
   ·    ────┬───
   ·        ╰── directory not found
   ╰────
  help: IO Error: DirectoryNotFound
```
# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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: Reilly Wood <reilly.wood@icloud.com>
2023-02-13 02:24:48 +00:00
ccbdc9f6d8 nu-table/ Fix table --expand issue when table with no header involved (#8045)
close #8029

---------

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2023-02-12 23:28:42 +00:00
0f5ea16605 Add a codecov.yml configuration (#8059)
Goal: avoid failing based on small coverage fluctuations.

See:

https://docs.codecov.com/docs/codecovyml-reference
2023-02-12 23:04:18 +00:00
1cd70d7505 Disable auto-benchmark harness for crates (#8057)
# Description

This disables automatic detection of `#[bench]` and other benchmarks
within the crates. Our benchmarks should all live in `benches`

This fixes a problem with criterion flags and should also reduce the
build requirements for `cargo bench` a bit

Taken from https://github.com/nushell/nushell/pull/7952

See:
https://bheisler.github.io/criterion.rs/book/faq.html#cargo-bench-gives-unrecognized-option-errors-for-valid-command-line-options


# User-Facing Changes

None
2023-02-12 22:22:00 +00:00
b0775b3f1e Fix hidden env vars not being hidden in closures (#8055)
# Description

This one fixes env not being hidden inside closure, reported in the
conversation under https://github.com/nushell/nushell/issues/6593

https://github.com/nushell/nushell/issues/6593
https://github.com/nushell/nushell/issues/7937 still persist. These
seems a bit more involved and might need hidden env tracking also in the
engine state... I'm not yet sure what's causing it.

Also re-enables some env-related tests and removes unused Value clone.

# User-Facing Changes

Just a bugfix

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-12 17:48:51 +00:00
2894668b3e Improve error when regex rejects pattern. Resolution of #8037 (#8050)
# Description

Improve error when `str replace <pattern>` detects a problem with
<pattern>.

# User-Facing Changes

New "Incorrect value" error:
```
〉 'C:\Users\kubouch' | str replace 'C:\Users' 'foo'
Error: nu:🐚:incorrect_value (link)

  × Incorrect value.
   ╭─[entry #1:1:1]
 1 │  'C:\Users\kubouch' | str replace 'C:\Users' 'foo'
   ·                                   ─────┬────
   ·                                        ╰── Regex error: Parsing error at position 4: Invalid hex escape
   ╰────
```

We could fruitfully replace some of the current uses of
`ShellError::UnsupportedInput` with this error. 'Incorrect value' is
different from 'wrong type'

# Tests + Formatting

Don't forget to add tests that cover your changes.
* none added / changed.

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

- [x] `cargo fmt --all -- --check` to check standard code formatting
(`cargo fmt --all` applies these changes)
- [x] `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- [x] `cargo test --workspace` to check that all tests pass

# 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-02-12 13:25:40 +00:00
1096e653b0 update cargo wix to 0.3.4 (#8048)
# Description

hopefully this will make the next winget release go smoother


# User-Facing Changes


# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-12 04:13:28 +00:00
9777d755d5 add benchmark to deprecated commands (#8046)
# Description

This PR adds a deprecated message to the `benchmark` command.
```
> benchmark
Error: nu:🐚:deprecated_command (link)

  × Deprecated command benchmark
   ╭─[entry #1:1:1]
 1 │ benchmark
   · ────┬────
   ·     ╰── 'benchmark' is deprecated. Please use 'timeit' instead.
   ╰────
```

# User-Facing Changes

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-11 21:39:55 +00:00
58529aa0b2 Benchmark each pipeline element (#7854)
# Description

Adds a `profile` command that profiles each pipeline element of a block
and can also recursively step into child blocks.

# Limitations
* It is implemented using pipeline metadata which currently get lost in
some circumstances (e.g.,
https://github.com/nushell/nushell/issues/4501). This means that the
profiler will lose data coming from subexpressions. This issue will
hopefully be solved in the future.
* It also does not step into individual loop iteration which I'm not
sure why but maybe that's a good thing.

# User-Facing Changes

Shouldn't change any existing behavior.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# After Submitting

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

---------

Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2023-02-11 21:35:48 +00:00
JT
64b6c02a22 Add codecov badge 2023-02-12 08:39:37 +13:00
0780300fb3 add a new inspect command for more debugging (#8028)
# Description

The purpose of this command is to help to debug pipelines. It works by
allowing you to inject the `inspect` command into a pipeline at any
point. Then it shows you what the input description is and what the
input values are that are passed into `inspect`. With each step it
prints this information out while also passing the value information on
to the next step in the pipeline.


![image](https://user-images.githubusercontent.com/343840/218154064-e107859b-d0da-41c6-8e34-2d717639b81c.png)

This command is kind of a "hack job" because it clones maybe too much
and I had to get creative in order to output two different tables. I'm
sure there are many ways this can be improved or combined into other
commands but I wanted to start here. Note that the `inspect` output is
written to stderr and the normal nushell output is written to stdout. If
we were to output both to stdout, nushell would get confused.

# User-Facing Changes



# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-11 18:59:11 +00:00
b9106b633b rename benchmark to time (#8018)
# Description

This PR renames the `benchmark` command to the `time` command.

# User-Facing Changes

new command name

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-11 18:57:48 +00:00
23dfaa2933 Another shot at trying to setup codecov (#7948)
Trying to setup using
https://github.com/taiki-e/cargo-llvm-cov#get-coverage-of-external-tests


https://docs.codecov.com/docs/github-2-getting-a-codecov-account-and-uploading-coverage

Closes #7944
2023-02-11 18:44:35 +00:00
cfd2cc4970 Minor clippy: inline format string (#8043)
# Description

Clippy from nightly being pedantic
2023-02-11 17:47:08 +00:00
710349768f remove the --encoding option from register in the examples (#8038)
# Description
As `register` does not have `--encoding` as an option now, the [*Git
stat plugin for
Nushell*](https://github.com/nushell/nushell/tree/main/crates/nu_plugin_gstat#git-stat-plugin-for-nushell)
is not correct anymore

```
> register ~/.local/share/cargo/bin/nu_plugin_gstat --encoding msgpack
Error: nu::parser::unknown_flag (link)

  × The `register` command doesn't have flag `encoding`.
   ╭─[entry #22:1:1]
 1 │ register ~/.local/share/cargo/bin/nu_plugin_gstat --encoding msgpack
   ·                                                   ─────┬────
   ·                                                        ╰── unknown flag
   ╰────
  help: Available flags: --help(-h), --shell(-s). Use `--help` for more information.
```

This PR then simply removes `--encoding msgpack` from the `register`
call in the documentation of the `gstat` plugin.

# User-Facing Changes
There is no user-facing change in this PR.

# Tests + Formatting
This PR does not change any source code.

# After Submitting
Same here, nothing to report 😉
2023-02-11 13:13:40 +00:00
f4bd78b86d Make metadata a Category::Debug command (#8019)
# Description

This PR changes the `metadata` command to a `Category::Debug` command
for better organization.

# User-Facing Changes

Just a different category.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-10 08:09:21 -06:00
ddb7e4e179 Check ctrl+c when collecting a RawStream (#8020)
I noticed that `open some_big_file | into binary` cannot be cancelled
with `ctrl+c`.

This small PR fixes that by checking `ctrl+c` in
`RawStream::into_bytes()`, and does the same in
`RawStream::into_string()` for good measure.
2023-02-10 20:23:46 +13:00
00601f1835 A fill command to replace str lpad and str rpad (#7846)
# Description

The point of this command is to allow you to be able to format ints,
floats, filesizes, and strings with an alignment, padding, and a fill
character, as strings. It's meant to take the place of `str lpad` and
`str rpad`.

```
> help fill
Fill and Align

Search terms: display, render, format, pad, align

Usage:
  > fill {flags}

Flags:
  -h, --help - Display the help message for this command
  -w, --width <Int> - The width of the output. Defaults to 1
  -a, --alignment <String> - The alignment of the output. Defaults to Left (Left(l), Right(r), Center(c/m), MiddleRight(cr/mr))
  -c, --character <String> - The character to fill with. Defaults to ' ' (space)

Signatures:
  <number> | fill -> <string>
  <string> | fill -> <string>

Examples:
  Fill a string on the left side to a width of 15 with the character '─'
  > 'nushell' | fill -a l -c '─' -w 15

  Fill a string on the right side to a width of 15 with the character '─'
  > 'nushell' | fill -a r -c '─' -w 15

  Fill a string on both sides to a width of 15 with the character '─'
  > 'nushell' | fill -a m -c '─' -w 15

  Fill a number on the left side to a width of 5 with the character '0'
  > 1 | fill --alignment right --character 0 --width 5

  Fill a filesize on the left side to a width of 5 with the character '0'
  > 1kib | fill --alignment middle --character 0 --width 10
```

![image](https://user-images.githubusercontent.com/343840/214133752-6fc93fa7-4003-4eb4-96ed-cd967312e244.png)

# User-Facing Changes

Deprecated `str lpad` and `str rpad`.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-09 14:56:52 -06:00
c31225fdcf explain command (#7957)
# Description

The purpose of this PR is to introduce the `inspect` command. A command
that is used to inspect, but not run, a pipeline to ensure everything
looks right. This is meant as a debugging tool. This is some hackery, so
don't laugh. :)

![image](https://user-images.githubusercontent.com/343840/217896776-99c6bece-172c-4d3d-8cec-dda85d37cada.png)
2023-02-09 13:59:38 -06:00
16b99ed0ba Make ++ operator work with strings and binary values (#8017)
This PR makes `++` (the append operator) work with strings and binary
values. Can now do things like:

```bash
〉"a" ++ "b"
ab
〉0x[01 02] ++ 0x[03]
Length: 3 (0x3) bytes | printable whitespace ascii_other non_ascii
00000000:   01 02 03                                             •••
```

Closes #8015.
2023-02-10 07:52:10 +13:00
3b6d340603 Bump ical from 0.7.0 to 0.8.0 (#7975)
Bumps [ical](https://github.com/Peltoche/ical-rs) from 0.7.0 to 0.8.0.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/Peltoche/ical-rs/commits">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.7.0&new-version=0.8.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

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

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

---

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

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot 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-02-10 07:37:51 +13:00
99aea0c71c Filesystem commands print --verbose to stderr (#8014)
# Description

Makes `mkdir`, `cp`, `mv` and `rm` return nothing and print info to
stderr:

![image](https://user-images.githubusercontent.com/17511668/217859228-feffa4bc-c22d-45d3-b330-1903f5a4d938.png)
See https://github.com/nushell/nushell/pull/7925#issuecomment-1420861638
and
[discord](https://discord.com/channels/601130461678272522/615329862395101194/1072523941865857055).

# User-Facing Changes

`mkdir`, `cp`, `mv` and `rm` will return nothing and print info to
stderr with `--verbose` flag.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-09 10:29:34 -08:00
023e244958 view span & view files commands (#7989)
# Description

This PR does the following:
1. Adds a new command called `view span` - which shows what is at the
location of the span parameters
2. Adds a new command called `view` - which just lists all the `view`
commands.
3. Renames `view-source` to `view source`.
4. Adds a new command called `view files` - which shows you what files
are loaded into nushell's EngineState memory.
5. Added a `Category::Debug` and put these commands (and others) into
it. (`inspect` needs to be added to it, but it's not landed yet)

Spans are important to nushell. One of their uses is to show where
errors are. For instance, in this example, the leader lines pointing to
parts of the command line are able to point to `10`, `/`, and `"bob"`
because each of those items have a span.
```
> 10 / "bob"
Error: nu::parser::unsupported_operation (link)

  × Types mismatched for operation.
   ╭─[entry #8:1:1]
 1 │ 10 / "bob"
   · ─┬ ┬ ──┬──
   ·  │ │   ╰── string
   ·  │ ╰── doesn't support these values.
   ·  ╰── int
   ╰────
  help: Change int or string to be the right types and try again.
```


# Examples

## view span
Example:
```
> $env.config | get keybindings | first | debug -r
... bunch of stuff
                    span: Span {
                        start: 68065,
                        end: 68090,
                    },
                },
            ],
            span: Span {
                start: 68050,
                end: 68101,
            },
        },
    ],
    span: Span {
        start: 67927,
        end: 68108,
    },
}
```
To view the last span:
```
> view span 67927 68108 
{
        name: clear_everything
        modifier: control
        keycode: char_l
        mode: emacs
        event: [
            { send: clearscrollback }
        ]
    }
```
> To view the 2nd to last span:
```
view span 68065 68090
{ send: clearscrollback }
```
> To view the 3rd to last span:
```
view span 68050 68101
[
            { send: clearscrollback }
        ]
```

## view files
```
> view files  
╭────┬───────────────────────────────────────────────────────┬────────┬────────┬───────╮
│  # │                       filename                        │ start  │  end   │ size  │
├────┼───────────────────────────────────────────────────────┼────────┼────────┼───────┤
│  0 │ source                                                │      0 │      2 │     2 │
│  1 │ Host Environment Variables                            │      2 │   6034 │  6032 │
│  2 │ C:\Users\a_username\AppData\Roaming\nushell\plugin.nu │   6034 │  31236 │ 25202 │
│  3 │ C:\Users\a_username\AppData\Roaming\nushell\env.nu    │  31236 │  44961 │ 13725 │
│  4 │ C:\Users\a_username\AppData\Roaming\nushell\config.nu │  44961 │  76134 │ 31173 │
│  5 │ defs.nu                                               │  76134 │  91944 │ 15810 │
│  6 │ prompt\oh-my.nu                                       │  91944 │ 111523 │ 19579 │
│  7 │ weather\get-weather.nu                                │ 111523 │ 125556 │ 14033 │
│  8 │ .zoxide.nu                                            │ 125556 │ 127504 │  1948 │
│  9 │ source                                                │ 127504 │ 127561 │    57 │
│ 10 │ entry #1                                              │ 127561 │ 127585 │    24 │
│ 11 │ entry #2                                              │ 127585 │ 127595 │    10 │
╰────┴───────────────────────────────────────────────────────┴────────┴────────┴───────╯
```
`entry #x` will be each command you type in the repl (i think). so, it
may be good to filter those out sometimes.
```
> view files | where filename !~ entry
╭───┬───────────────────────────────────────────────────────┬────────┬────────┬───────╮
│ # │                       filename                        │ start  │  end   │ size  │
├───┼───────────────────────────────────────────────────────┼────────┼────────┼───────┤
│ 0 │ source                                                │      0 │      2 │     2 │
│ 1 │ Host Environment Variables                            │      2 │   6034 │  6032 │
│ 2 │ C:\Users\a_username\AppData\Roaming\nushell\plugin.nu │   6034 │  31236 │ 25202 │
│ 3 │ C:\Users\a_username\AppData\Roaming\nushell\env.nu    │  31236 │  44961 │ 13725 │
│ 4 │ C:\Users\a_username\AppData\Roaming\nushell\config.nu │  44961 │  76134 │ 31173 │
│ 5 │ defs.nu                                               │  76134 │  91944 │ 15810 │
│ 6 │ prompt\oh-my.nu                                       │  91944 │ 111523 │ 19579 │
│ 7 │ weather\get-weather.nu                                │ 111523 │ 125556 │ 14033 │
│ 8 │ .zoxide.nu                                            │ 125556 │ 127504 │  1948 │
│ 9 │ source                                                │ 127504 │ 127561 │    57 │
╰───┴───────────────────────────────────────────────────────┴────────┴────────┴───────╯
```
# User-Facing Changes

I renamed `view-source` to `view source` just to make a group of
commands. No functionality has changed in `view source`.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-09 11:35:23 -06:00
659d890ecf Added fix for #7981 - Replaced crate serde_ini with rust-ini for package nu-command/from (#8009)
# Description

Added fix for #7981 - Replaced crate serde_ini with rust-ini for package
nu-command/from

# Tests + Formatting

Added a test to support addition of the rust-ini crate.

`cargo test --package nu-command --lib -- formats::from::ini::tests
--nocapture`

Executed all tests.

`cargo test --workspace`

---------

Co-authored-by: Nitin Londhe <nitin.londhe@genmills.com>
2023-02-09 12:47:45 +01:00
8e9ed14b89 allow parse to work better with streams (#7870)
# Description

Fixes #7864. Haven't removed redundant code yet; and there's also a
weird visual bug, but I'm not sure if that's the fault of this PR or
just a quirk of how tabling works:

```
/home/gabriel/CodingProjects/nushell〉ping 1.1.1.1 | parse -r '(?P<num>\d+) ttl'                                                                                        01/27/2023 11:28:31 AM
╭───┬─────╮
│ # │ num │
├───┼─────┤
│ 0 │ 1   │
│ 1 │ 2   │
╰───┴─────╯
╭───┬─────╮
│ # │ num │
├───┼─────┤
│ 2 │ 3   │
╰───┴─────╯
╭───┬─────╮
│ # │ num │
├───┼─────┤
│ 3 │ 4   │
│ 4 │ 5   │
╰───┴─────╯
╭───┬─────╮
│ # │ num │
├───┼─────┤
│ 5 │ 6   │
│ 6 │ 7   │
╰───┴─────╯
^C
/home/gabriel/CodingProjects/nushell〉                                                                                                                                  01/27/2023 11:28:59 AM

```

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-08 20:59:02 -06:00
f4bf7316fe fix completions PATH vs Path (#8003)
# Description

This PR attempts to fix the completions issue where, on Windows,
completions wouldn't get generated from items in your path environment
variable. This seemed to be down to `PATH` vs `Path`. So, I tried to add
a new function that we can use anywhere to avoid this problem.

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-08 20:53:46 -06:00
0527f9bf0d Bump openssl-src from 111.22.0+1.1.1q to 111.25.0+1.1.1t (#8011)
Bumps [openssl-src](https://github.com/alexcrichton/openssl-src-rs) from
111.22.0+1.1.1q to 111.25.0+1.1.1t.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/alexcrichton/openssl-src-rs/commits">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=openssl-src&package-manager=cargo&previous-version=111.22.0+1.1.1q&new-version=111.25.0+1.1.1t)](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 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>
2023-02-09 00:23:40 +01:00
055edd886d Make plugin commands support examples. (#7984)
# Description

As title, we can't provide examples for plugin commands, this pr would
make it possible


# User-Facing Changes

Take plugin `nu-example-1` as example:
```
❯ nu-example-1 -h
PluginSignature test 1 for plugin. Returns Value::Nothing

Usage:
  > nu-example-1 {flags} <a> <b> (opt) ...(rest)

Flags:
  -h, --help - Display the help message for this command
  -f, --flag - a flag for the signature
  -n, --named <String> - named string

Parameters:
  a <int>: required integer value
  b <string>: required string value
  (optional) opt <int>: Optional number
  ...rest <string>: rest value string

Examples:
  running example with an int value and string value
  > nu-example-1 3 bb
```

The examples session is newly added.

## Basic idea behind these changes
when nushell query plugin signatures, plugin just returns it's signature
without any examples, so nushell have no idea about the examples of
plugin commands.
To adding the feature, we just making plugin returns it's signature with
examples.

Before:
```
        1. get signature
         ----------------> 
Nushell ------------------  Plugin
        <-----------------
        2. returns Vec<Signature>
```

After:
```
        1. get signature
        ----------------> 
Nushell ------------------  Plugin
        <-----------------
        2. returns Vec<PluginSignature>
```
        
When writing plugin signature to $nu.plugin-path:
Serialize `<PluginSignature>` rather than `<Signature>`, which would
enable us to serialize examples to `$nu.plugin-path`

## Shortcoming
It's a breaking changes because `Plugin::signature` is changed, and it
requires plugin authors to change their code for new signatures.

Fortunally it should be easy to change, for rust based plugin, we just
need to make a global replace from word `Signature` to word
`PluginSignature` in their plugin project.

Our content of plugin-path is really large, if one plugin have many
examples, it'd results to larger body of $nu.plugin-path, which is not
really scale. A solution would be save register information in other
binary formats rather than `json`. But I think it'd be another story.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-08 16:14:18 -06:00
5e70d4121a Add dfr to dataframe cmds (#7998)
# Description

This PR tries to resolve the overloading issue by going back to our
original naming convention for dataframes. So, this PR renames all
dataframe commands with a prefix of `dfr`. Some commands like `open-df`
were renamed to `dfr open` and things like `into df` were renamed `dfr
into-df`. I'm sure we can optimize naming a bit, but it seems to compile
now.

# User-Facing Changes

All dataframe commands are prefixed with dfr.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-08 15:52:57 -06:00
f9b5d8bc5e Add comment explaining background thread usage for plugin calls (#7878)
~~I happened to be reviewing our uses of `thread::spawn()` and came to
the conclusion that we're spawning a thread unnecessarily for plugin
calls. We were basically doing this:~~

~~1. Spawn a background thread to send data to the plugin over stdin~~
~~2. Immediately do a blocking wait for the plugin's response~~

~~As far as I can tell, there's no point in spawning a thread for 1 (and
it may harm error handling) given that we're blocking right away for the
response.~~

**Update:** the logic is correct, as confirmed by @WindSoilder
[here](https://discord.com/channels/601130461678272522/855947301380947968/1072743414795350037).
I've added a comment explaining the thread usage.
2023-02-08 08:53:44 -08:00
2917c045fb Bump actions-rust-lang/setup-rust-toolchain from 1.3.5 to 1.3.7 (#7979) 2023-02-08 13:03:05 +00:00
6e6ef862c5 Address #7997 (#8000)
Hi there,

The case which was presented must be addressed.

But I did not test it properly...
I'd encourage you to do so.

Take care.

---------

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2023-02-07 20:01:31 -06:00
a7fdca05c6 http: add --insecure flag to http get, share common code (#7992)
# Description

I factorized the HTTP client from HTTP Post and HTTP Get into a common
file, in order to reduce the code duplication. This PR has to be looked
commit by commit.

# User-Facing Changes

A new option has been to HTTP Get: `--insecure`. This option was already
available for HTTP Post command.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-07 14:22:19 -08:00
ddc33dc74a Fix imported virtualenv testsuite (#8001)
# Description

Patch `pyproject.toml` to ignore the checking of coverage level as we
only run part of the test suite affecting nushell.
2023-02-07 23:14:17 +01:00
a562f492e3 Windows: handle illegal filenames a little better (#7999)
This PR is an incremental improvement to `ls` when it encounters
'illegal' file paths on Windows. Related:
https://github.com/nushell/nushell/issues/7869

## Context

We have trouble with filenames that Windows doesn't like, for example
[files with a `.` at the end of their
name](https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions).
To make a long story short, the Rust stdlib and several Win32 APIs will
choke if asked to do something with an illegal filepath. This is a
problem because files with illegal names can be created via other means
(like `touch foo.` in MINGW bash).

Previously `ls` would fail completely in a directory with a bad file,
which isn't great. After this PR, bad files get included in `ls` results
but without any metadata columns. This is not quite where we want to be
— eventually we want to be able to display file metadata for _all_ files
(even naughty ones) — but it's an improvement on the status quo.

### Before


![image](https://user-images.githubusercontent.com/26268125/217340906-26afd6d3-0ec3-454f-bed4-2bfcc9cf3a2f.png)

### After


![image](https://user-images.githubusercontent.com/26268125/217344373-6b81cc39-50b8-4390-8061-3e570502a784.png)

## Future work

Try the workarounds @ChrisDenton suggested:
https://github.com/nushell/nushell/issues/7869#issuecomment-1405977221

Some info on verbatim paths:
https://users.rust-lang.org/t/understanding-windows-paths/58583

## Testing

I tried to write a test for this, but it looks like our testing sandbox
can't create files with illegal filenames.😔 Here's the code in case it
proves useful someday:

```rust
/// Windows doesn't like certain file names, like file names ending with a period:
/// https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions
/// However, those files can still be created with tools like MINGW bash.
/// We may not be able to get full metadata for those files, but we should test that we can at least include them in ls results
#[test]
#[cfg(windows)]
fn can_list_illegal_files() {
    Playground::setup("ls_test_all_columns", |dirs, sandbox| {
        sandbox.with_files(vec![
            EmptyFile("foo"),
            EmptyFile("bar."),
            EmptyFile("baz"),
        ]);

        let actual = nu!(
            cwd: dirs.test(),
            "ls | length"
        );
        assert_eq!(actual.out, "3");

        let actual = nu!(
            cwd: dirs.test(),
            "ls"
        );
        assert_eq!(actual.out, "1");

        let actual = nu!(
            cwd: dirs.test(),
            "ls | where {|f| $f.name | str ends-with 'bar.'} | length"
        );
        assert_eq!(actual.out, "1");
    })
}
```
2023-02-07 12:30:37 -08:00
58f0d0b945 Fix $nu path separators on Windows (#7996)
I noticed that `$nu.loginshell-path` was using backward *and* forward
slashes on Windows.

#### Before
`C:\Users\reill\AppData\Roaming\nushell/login.nu`

#### After
`C:\Users\reill\AppData\Roaming\nushell\login.nu`

Fixed up 2 other similar issues while I was at it.
2023-02-07 11:50:39 -08:00
67d1249b2b Validate input range of du flags (#7962)
# Description
Fix #7953
Fix flags on `du` which should be positive and added some tests. 

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-06 21:34:32 +01:00
66e5e42fb1 report which datetime couldn't be converted (#7980)
# Description

This PR will help report a bad date that can't be converted where the
error message says `* Unable to parse datetime`. This is helpful when
you're converting a big table and it fails somewhere that you really
can't see. I put it in `[]` so that when it's null, you can see that
there should be something there.

Before:
```
> 'Tue 1 0' | into datetime 
Error: nu:🐚:datetime_parse_error (link)

  × Unable to parse datetime
   ╭─[entry #1:1:1]
 1 │ 'Tue 1 0' | into datetime
   · ────┬────
   ·     ╰── datetime parsing failed
   ╰────
  help: Examples of supported inputs:
         * "5 pm"
         * "2020/12/4"
         * "2020.12.04 22:10 +2"
         * "2020-04-12 22:10:57 +02:00"
         * "2020-04-12T22:10:57.213231+02:00"
         * "Tue, 1 Jul 2003 10:52:37 +0200"
```
After:
```
> 'Tue 1 0' | into datetime
Error: nu:🐚:datetime_parse_error (link)

  × Unable to parse datetime: [Tue 1 0].
   ╭─[entry #4:1:1]
 1 │ 'Tue 1 0' | into datetime
   · ────┬────
   ·     ╰── datetime parsing failed
   ╰────
  help: Examples of supported inputs:
         * "5 pm"
         * "2020/12/4"
         * "2020.12.04 22:10 +2"
         * "2020-04-12 22:10:57 +02:00"
         * "2020-04-12T22:10:57.213231+02:00"
         * "Tue, 1 Jul 2003 10:52:37 +0200"
```

# User-Facing Changes

New format for the error message.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-06 14:17:07 -06:00
1f01b6438f Added fix for #7970 - Upgraded toml crate version from version from 0.5.8 to 0.7.1 for package nu-command (#7990)
# Description

Added fix for #7970 - Upgraded toml crate version from version from
0.5.8 to 0.7.1 for package nu-command

# Tests + Formatting

Added two tests to support the toml upgrade.

- `cargo test --package nu-command --lib -- formats::from::toml::tests
--nocapture`

Executed all tests.

- `cargo test --workspace`

---------

Co-authored-by: Nitin Londhe <nitin.londhe@genmills.com>
2023-02-06 14:15:14 -06:00
bea7ec33c1 Update few examples of math commands (#7987)
# Description

I just updated a few examples linked to math commands.

I used the character of pi where possible, and I updated one example
since the example was misleading IMO (for the tau command).

# User-Facing Changes

Only examples have been updated, there is no real user changes.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-06 13:43:00 +01:00
b5561f35b9 Bump which from 4.3.0 to 4.4.0 (#7974) 2023-02-06 10:43:28 +00:00
b796cda060 Test return in reduce closure from #7961 (#7973)
# Description

Functionality added by @nabacg in #7961 already

h/t @YuriGeinishO for the example in #7933

Closes #7933


# User-Facing Changes

None

# Tests + Formatting

+1 end to end example
2023-02-06 11:01:08 +01:00
4c308b7f2f Fix def-env docs according to docs#761 (#7972)
See nushell/nushell.github.io#761

# User-Facing Changes

Docs reflect up-to-date reality

Co-authored-by: Canop <cano.petrole@gmail.com>
2023-02-06 11:00:44 +01:00
d50eb9b41b Bump fs_extra from 1.2.0 to 1.3.0 (#7976) 2023-02-06 09:59:58 +00:00
9168301369 Clarify two config fields (#7969)
In particular this makes the `show_banner` field more findable.

Users may search for "welcome" and "startup" which appear
in the banner.
2023-02-06 00:01:23 +01:00
e8d930f659 Reorder help <keyword> priority (#7929)
# Description

`help <keyword>` will now search for `<keyword>` in aliases first, then
commands. This matches the way the parser resolves aliases before
commands.

# User-Facing Changes

Not significant
2023-02-05 23:51:09 +01:00
aef88aa03e Load env pwd (#7963)
# Description

Fixes #7940
avoid `load-env` to change PWD 

# User-Facing Changes

`{"PWD": whatever} | load-env` now fails
2023-02-05 23:40:46 +01:00
ec4370069a Bump tokio from 1.24.1 to 1.25.0 (#7958) 2023-02-05 21:22:37 +00:00
c79ece2b21 Extract run blocks into functions (#7964)
As usual, Rust optimizes a bit less if more function boundaries are
introduced.
However, in my opinion, being able to comprehend the decision tree beats
a couple of string allocations.
2023-02-05 22:20:35 +01:00
99076af18b Use imported names in Command::run signatures (#7967)
# Description

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

I opened this PR to unify the run command method. It's mainly to improve
consistency across the tree.

# 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 -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-05 22:17:46 +01:00
a0e3ad2b70 return in reduce command closure (#7961)
# Description

Fix for #7933. I've read through code and found the obvious difference
between them, where `each` command calls eval_with_early_return
e89e734ca2/crates/nu-command/src/filters/each.rs (L158),
while `reduce` command uses eval_block
e89e734ca2/crates/nu-command/src/filters/reduce.rs (L143)

That simple change seems to resolve the problem. 

# User-Facing Changes

Allows the use of `return` in reduce closures, as per example in #7933
description. Arguably it's restoring consistency, than changing user
interface.

```
[1, 2] | reduce --fold null { |it, state|                                                           
::: if $it == 1 {
:::     return 10
::: }
::: return ($it * $state)
::: }
20
```

# Tests + Formatting

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

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

    

- [x] `cargo fmt --all -- --check` to check standard code formatting
(cargo fmt --all applies these changes)
- [x] `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- [x]  `cargo test --workspace` to check that all tests pass

# 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-02-04 16:41:54 -06:00
e89e734ca2 Only abbreviate to "[table x rows]" if every value is a record (#7922)
# Description

Closes #6768.

BEFORE:
```
〉{ foo: [{a:1, b:2},2,3,4,5] }
╭─────┬────────────────╮
│ foo │ [table 5 rows] │
╰─────┴────────────────╯
```
AFTER:
```
〉{ foo: [{a:1, b:2},2,3,4,5] }
╭─────┬────────────────╮
│ foo │ [list 5 items] │
╰─────┴────────────────╯
```

# User-Facing Changes

See above.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-02 17:03:36 -06:00
9945241b77 Remove deprecated --numbered flag from four commands (#7777)
# Description

Remove `--numbered` from ~~`for`~~, `each`, `par-each`, `reduce` and
`each while`. These all provide indexes (numbering) via the optional
second param to their closures.

EDIT: Closes #6986.

# User-Facing Changes

Every command that had `--numbered` listed as "deprecated" in their help
docs is affected.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# After Submitting

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

---------

Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2023-02-02 16:59:58 -06:00
215ed141e7 Fix code in benchmarks (#7949)
# Description

Broken after #7415

We currently don't try to build the benchmarks in the CI thus this
slipped through the cracks.


# User-Facing Changes

None

# Tests + Formatting

Compile check is currently missing, but working towards that
2023-02-02 23:07:35 +01:00
f189ee67a1 Fix copy paste error (#7945) 2023-02-02 12:50:27 -06:00
babc7d3baf clean up the registry query output (#7939)
# Description

This cleans up the `registry query` output so that it's more usable.

Before:

![image](https://user-images.githubusercontent.com/343840/216129871-7cadcb68-a289-4e29-8857-6fc20b6a57f7.png)

After:

![image](https://user-images.githubusercontent.com/343840/216129814-70021706-f58a-4647-b5f1-a0e30f5fae16.png)


# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-02 07:10:38 -06:00
8f4807020f make do -i works with liststream (#7889)
# Description

Fixes: #7874 

It's because `do -i` doesn't handles `Pipeline::ListStream`
data(especially there is Value::Error inside the stream)

To fix it, we need to iterate through `ListStream`, check if there is
`Value::Error`. If so, just returns `Pipeline::empty()`

# User-Facing Changes

```
help commands | find arg | get search_terms | do -i { ansi strip }
```

No longer raises error.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-02 00:04:53 +01:00
31e1410191 respect use_ansi_coloring configuration (#7912)
# Description

Use the `use_ansi_coloring` configuration point to decide whether the
output will have colors, where possible.

Related: https://github.com/nushell/nushell/issues/7676


![image](https://user-images.githubusercontent.com/749306/215435128-cbf5f4b8-aafa-4718-bf23-3f0fd19b63ba.png)

- [x] `grid -c`
- [x] `perf()`

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-02 00:03:05 +01:00
24d7227e27 ensure that when nu evaluates files, it allows early returns (#7415)
# Description

Fixes #7301.

# User-Facing Changes

`return` can now be used in scripts without explicit `def main`.

# Tests + Formatting

Don't forget to add tests that cover your changes. (I'm not sure how to
test this.)

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-02-02 00:02:27 +01:00
c130ca1bc6 Fix: dst error on cp command (#7895)
Fixes #7693 

On `cp` commands there were two error which pass error message with
invalid detail about source and destination files . there error were for
Not exist file and Permission denied .

Examples:
  Before :
Copy `source_file_valid` to `destination_invalid_dir` throw this error ;
`copy file "/source_file_valid" failed: No such file or directory (os
error 2) `

 After this PR it will throw this if destination will be invalid :
`copying to destination "/destination_invalid_dir" failed: No such file
or directory (os error 2) `

it was for Permission denied too .

---------

Co-authored-by: Stefan Holderbach <sholderbach@users.noreply.github.com>
2023-02-01 21:48:21 +01:00
4db960c0a6 use newer reedline (once available) (#7919)
# Description

Use newer reedline that fixes the code completion crash in
https://github.com/nushell/nushell/issues/7885 by subtracting from the
insertion point if the suggestion is shorter than the editor span.

Closes https://github.com/nushell/nushell/issues/7885

Depends on https://github.com/nushell/reedline/pull/534

# User-Facing Changes


# Tests + Formatting

Tested in reedline.

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# After Submitting

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

---------

Co-authored-by: sholderbach <sholderbach@users.noreply.github.com>
2023-02-01 21:46:47 +01:00
d13ce2aec9 add ability to view-source on closures (#7935)
closes https://github.com/nushell/nushell/issues/7934
2023-02-01 20:48:27 +02:00
5e957ecda6 Bump to 0.75.1 development version (#7930)
To demark development work or to be used with a point release in an
emergency
2023-01-31 23:55:29 +01:00
17a265b197 Version bump for 0.75 release (#7902)
- [x] Are we ready for the release
- [x] Upgrade to upcoming `reedline 0.15`
2023-01-31 21:00:59 +01:00
3fabc8e1e6 update type check so that ++ with lists works better (#7926)
closes https://github.com/nushell/nushell/issues/7913
2023-01-31 21:11:05 +02:00
517ef7cde7 Remove deprecated where -b parameter (#7927) 2023-01-31 21:05:28 +02:00
ad14b763f9 Pin reedline to new 0.15 for release (#7918)
# Description

See release notes:

https://github.com/nushell/reedline/releases/tag/v0.15.0
2023-01-30 22:59:15 +01:00
f74694d5a3 Let redirection keep exit code (#7848)
# Description

Fixes: #7828

We delegate to `save` command to finish redirection, then if it runs to
success, the relative exit code is set to 0. To fix it, in redirection
context, we take exit_code stream before sending it to `save` command,
than manually returns `PipelineData::ExternalStream` to make nushell set
relative code properly.

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-30 16:49:31 +01:00
1ea39abcff Apply more recent/nightly clippy lints (#7916)
# Description

- Use inline format strings in dataframe code
- Fix manual `.is_ascii_digit()` check
- Remove unnecessary `.into_iter()` calls
2023-01-30 14:06:36 +01:00
7402589775 Bump trash to 3.0.1 (#7914)
# Description

Avoids duplication of `windows` crate and friends as it updates to the
most recent `windows 0.44` version.

# User-Facing Changes

None intended
2023-01-30 11:58:56 +01:00
e0cd5a714a Bump serial_test from 0.10.0 to 1.0.0 (#7910) 2023-01-30 02:47:51 +00:00
c6eea5de6b Bump typetag from 0.1.8 to 0.2.5 (#7908) 2023-01-30 02:46:31 +00:00
809416e3f0 Bump roxmltree from 0.16.0 to 0.17.0 (#7909) 2023-01-30 02:43:11 +00:00
040d812343 Bump windows from 0.43.0 to 0.44.0 (#7911) 2023-01-30 02:17:18 +00:00
72465e6724 Bump chrono-tz from 0.6.3 to 0.8.1 (#7907) 2023-01-30 01:38:39 +00:00
ab480856a5 Use variable names directly in the format strings (#7906)
# Description

Lint: `clippy::uninlined_format_args`

More readable in most situations.
(May be slightly confusing for modifier format strings
https://doc.rust-lang.org/std/fmt/index.html#formatting-parameters)

Alternative to #7865

# User-Facing Changes

None intended

# Tests + Formatting

(Ran `cargo +stable clippy --fix --workspace -- -A clippy::all -D
clippy::uninlined_format_args` to achieve this. Depends on Rust `1.67`)
2023-01-29 19:37:54 -06:00
6ae497eedc Remove unused nu-test-support in nu-table (#7905)
Unused dev-dependency
2023-01-29 23:36:46 +01:00
JT
421bc828ef Use clippy-recommended simplification (#7904)
# Description

Just a couple clippy-recommended simplifications.

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-29 23:31:35 +01:00
ed65886ae5 Update reedline for pre-release testing (#7903)
# Description

Let's check before shipping `reedline 0.15`



# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-29 22:33:49 +01:00
8c7e2dbdf9 make parse -r columns return 0-indexed uncapitalised (#7897)
# Description

Fixes #7886.

```
/home/gabriel/CodingProjects/nushell〉'A|B|C' | parse -r '(\w)\|(\w)\|(\w)'                                                                                             01/29/2023 01:08:29 PM
╭───┬──────────┬──────────┬──────────╮
│ # │ capture0 │ capture1 │ capture2 │
├───┼──────────┼──────────┼──────────┤
│ 0 │ A        │ B        │ C        │
╰───┴──────────┴──────────┴──────────╯
```

# User-Facing Changes
Columns automatically named by `parse -r` are now 0-indexec and
uncapitalised.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-29 07:34:34 -06:00
afb4209f10 make help commands search term don't generate $nothing (#7896)
# Description

Relative:
`https://github.com/nushell/nushell/pull/7889#issuecomment-1407503567`

Make `search_terms` return empty string rather than nothing, so some
other command can handle it better

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-28 18:57:26 -06:00
1d8775d237 mention do in complete command's doc (#7884)
# Description

Closes: #7841

# User-Facing Changes

new complete doc:
```
Complete the external piped in, collecting outputs and exit code

To collect stderr messages and exit_code, external piped in need to wrapped with `do`

Usage:
  > complete

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

Signatures:
  <any> | complete -> <record>

Examples:
  Run the external completion
  > ^external arg1 | complete

  Run external completion, collects stderr and exit_code
  > do { ^external arg1 } | complete
```

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# After Submitting

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

---------

Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2023-01-28 16:42:05 -06:00
8787ec9fe8 Add Github Actions workflow to check for typos (#7892)
- Add Github Actions workflow to check typos
- Fix existing typos
2023-01-29 10:22:56 +13:00
1f810cd26a Re-enable some good tests, remove some bad tests (#7875)
I tackled some of the disabled `FIXME`/`#[ignore]` tests. Most were
straightforward to re-enable, and a few of them did not deserve to be
re-enabled.

---------

Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2023-01-28 14:56:47 -06:00
f4d7d19370 Name threads (#7879)
I noticed that [it's pretty easy to name threads in
Rust](https://doc.rust-lang.org/std/thread/#naming-threads). We might as
well do this; it's a nice quality of life improvement when you're
profiling something and the developers took the time to give threads
names.

Also added/cleaned up some comments while I was in the area.
2023-01-28 21:40:52 +01:00
e616b2e247 Support extended unicode escapes in strings: "\u{10fff}" (#7883)
# Description

Support extended unicode escapes in strings with same syntax as Rust:
`"\u{6e}"`.

# User-Facing Changes

New syntax in string literals, `\u{NNNNNN}`, to go along with the
existing `\uNNNN`.
New syntax accepts 1-6 hex digits and rejects values greater than
0x10FFFF (max Unicode char)..

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

Won't break existing scripts, since this is new syntax.  

We might consider deprecating `char -u`, since users can now embed
unicode chars > 0xFFFF with the new escape.

# Tests + Formatting

Several unit tests and one integration test added.

- [x] `cargo fmt --all -- --check` to check standard code formatting
(`cargo fmt --all` applies these changes)
Done
- [x] `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
Done
- [x] `cargo test --workspace` to check that all tests pass  
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.
2023-01-29 09:25:53 +13:00
2a39332d51 Fix panic when assigning value to $env (#7894) 2023-01-28 21:17:32 +02:00
3c6b10c6b2 Fix wrong VarId of $in variable (#7893)
Fixes https://github.com/nushell/nushell/issues/7872
2023-01-28 19:55:29 +02:00
2a9226a55c refactor: use input_handler::operate in ansi_strip command (#7888)
# Description

While investigating `do --ignore-errors` issue, just found that
`ansi_strip` command using a custom `operate` function(which is not
needed), this pr is just a refactor

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-28 08:11:21 -06:00
3d65fd7cc4 Expose filtering by file type in glob (#7834)
# Description

Add flags for filtering the output of `glob` by file type. I find myself
occasionally wanting to do this, and getting a file's
[file_type](https://docs.rs/wax/latest/wax/struct.WalkEntry.html#method.file_type)
is presumably fast to do as it doesn't have to go through the fallible
metadata method.

The design of the signature does concern me; it's not as readable as a
filter or "include" type list would be. They have to be filtered one by
one, which can be annoying if you only want files `-D -S`, or only want
folders `-F -S`, or only want symlinks `--butwhy?`. I considered
SyntaxShape::Keyword for this but I'll just defer to comments on this PR
if they pop up.

I'd also like to bring up performance since including these flags
technically incurs a `.filter` penalty on all glob calls, which could be
optimized out if we added a branch for the no-filters case. But in
reality I'd expect the file system to be the bottleneck and the flags to
be pretty branch predictor friendly, so eh

# User-Facing Changes
Three new flags when using `glob` and a slightly more cluttered help
page. No breaking changes, I hope.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-28 07:50:12 -06:00
JT
36ddbfdc85 Add 'number' command for enumeration (#7871)
# Description

This adds a `number` command that will enumerate the input, and add an
`index` and `item` record for each item. The `index` is the number of
the item in the input stream, and `item` is the original value of the
item.

```
> ls | number | get 14
╭───────┬────────────────────────────╮
│ index │ 14                         │
│       │ ╭──────────┬─────────────╮ │
│ item  │ │ name     │ crates      │ │
│       │ │ type     │ dir         │ │
│       │ │ size     │ 832 B       │ │
│       │ │ modified │ 2 weeks ago │ │
│       │ ╰──────────┴─────────────╯ │
╰───────┴────────────────────────────╯
```

# User-Facing Changes

This adds a `number` command.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-28 06:45:57 +13:00
76292ef10c Clean up cd.rs (#7876)
Some general cleanup of `cd.rs`; the permission checking code was a
little hard to follow. Reworded comments and variable names,
reorganized+renamed the module used for Unix file permissions.
2023-01-27 15:02:38 +01:00
9ae2e528c5 Remove 🆖 comments (#7877)
Noticed several instances of commented out code that should just be
deleted. Also a comment on `eval_external` that was incorrect. All gone
now.
2023-01-27 08:48:31 -05:00
2849e28c2b Extract gather_commandline_args (#7868)
- Extract gathering of command line arguments
- Simplify the function a bit
2023-01-26 17:56:55 -06:00
9d0e52b94d with the release of rust 1.67, let's bump to 1.66.1 (#7866)
# Description

This PR bumps the required rust version to 1.66.1.

# User-Facing Changes


# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-26 15:31:17 -06:00
731f5f8523 nu-commands/table (table -e) Recognize limited space better (#7861)
fix #7858

Once again we here 😞 

~~I am thinking is there some files with not flat structure we could use
to test table -e?
I mean it is clear it was a while ago were we had to create at least
some tests.
Do you have anything in mind (or maybe commands which is consistent
across systems)?~~

Take care

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2023-01-26 14:06:17 -06:00
9d6d43ee55 Fix do swallowing all output when ignoring errors (#7859)
https://github.com/nushell/nushell/pull/7204#issuecomment-1404363845
2023-01-26 13:00:48 +01:00
f9e99048c4 convert SyntaxShape::Table into the corresponding Type (#7781)
# Description

Small fix. Related: #7699.

# User-Facing Changes

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-25 16:17:41 -06:00
e1df8d14b4 improve doc about flatten (#7856)
# Description

Relative #7210 

Improve doc to clarify current behavior.

To flatten all nested levels, we can use the following custom
command(maybe making it into our lib):
```
def flatten_all_nested [input_table: any] {
    mut input = $input_table

    mut flattened = ($input | flatten --all)
    while $input != $flattened {
        $input = $flattened
        $flattened = ($input | flatten --all)
    }
    $flattened
}
```

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-25 10:10:30 -08:00
b9419e0f36 To csv fix (#7850)
# Description

Fixes #7800 . 
`to csv` and `to tsv` no longer:
- accept anything but records and tables as input,
- accept lists that are not tables,
- accept tables and records with values that are not primitives (other
lists, tables and records).

# User-Facing Changes

Using `to csv` and `to tsv` on any of inputs mentioned above will result
in `cant_convert` error.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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: Stefan Holderbach <sholderbach@users.noreply.github.com>
2023-01-25 08:42:53 -06:00
e03c354e89 add decimal to SyntaxShape (#7852)
# Description

This adds the `SyntaxShape::Decimal` so you can create custom commands
with `decimal` types such as:
```shell
def cmd [x:decimal] { echo $x }
```

/cc @kurokirasama

Internally this is a little messy since we have `Type::Float` and
`SyntaxShape::Decimal`. I originally named it `float` and
`SyntaxShape::Float` but since we have `into decimal` and `1.1 |
describe` reports `decimal`, I decided to change the SyntaxShape.

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-25 06:43:22 -06:00
2e44e4d33c Fix the build after #7204 (#7857)
Fix the build after merging
https://github.com/nushell/nushell/pull/7204. It sat for a bit too long
and I should have rerun CI before merging it, my bad.
2023-01-24 22:12:15 -08:00
5cbaabeeab Fix pipeline stall in do during capture and remove excessive redirections (#7204)
Currently, if you run `do -i { sudo apt upgrade }`, stdin gets swallowed
and doesn't let you respond yes/no to the upgrade question. This PR
fixes that, but runs into https://github.com/nushell/nushell/issues/7205
so the tests fail.

Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
2023-01-25 00:24:38 -05:00
d64e381085 add some startup performance metrics (#7851)
# Description

This PR changes the old performance logging with `Instant` timers. I'm
not sure if this is the best way to do it but it does help reveal where
time is being spent on startup. This is what it looks like when you
launch nushell with `cargo run -- --log-level info`. I'm using the
`info` log level exclusively for performance monitoring at this point.

![image](https://user-images.githubusercontent.com/343840/214372903-fdfa9c99-b846-47f3-8faf-bd6ed98df3a9.png)
## After Startup

Since you're in the repl, you can continue running commands. Here's the
output of `ls`, for instance.

![image](https://user-images.githubusercontent.com/343840/214373035-4d2f6e2d-5c1d-43d3-b997-51d79d496ba3.png)
Note that the above screenshots are in debug mode, so they're much
slower than release.

# User-Facing Changes



# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-24 14:28:59 -06:00
41306aa7e0 Reduce again the number of match calls (#7815)
- Reduce the number of match calls (see commit messages)
- A few miscellaneous improvements
2023-01-24 12:23:42 +01:00
0bb2e47c98 Incorrect parsing of unbalanced braces based on issue 6914 (#7621) 2023-01-24 10:05:46 +02:00
ef660be285 print nushell startup time (#7831)
# Description

This PR shows the startup time and decreases the banner. This startup
time output can be disabled with the `show_banner: false` setting in the
config. This is the startup in debug mode.

![image](https://user-images.githubusercontent.com/343840/213955410-f319f8d4-1f96-47ae-8366-1c564a08d3e4.png)

On my mac in release mode
```
Startup Time: 368ms 429µs 83ns
```
On my mac without a config as `nu --config foo --env-config foo`
```
Startup Time: 11ms 663µs 791ns
```

I could really go either way on this. If people don't like this change,
we don't have to merge it.

# User-Facing Changes

Startup Time

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-23 12:57:40 -06:00
4bac90a3b2 Bump rayon from 1.5.3 to 1.6.1 (#7836)
Bumps [rayon](https://github.com/rayon-rs/rayon) from 1.5.3 to 1.6.1.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/rayon-rs/rayon/blob/master/RELEASES.md">rayon's
changelog</a>.</em></p>
<blockquote>
<h1>Release rayon 1.6.1 (2022-12-09)</h1>
<ul>
<li>Simplified <code>par_bridge</code> to only pull one item at a time
from the iterator,
without batching. Threads that are waiting for iterator items will now
block
appropriately rather than spinning CPU. (Thanks <a
href="https://github.com/njaard"><code>@​njaard</code></a>!)</li>
<li>Added protection against recursion in <code>par_bridge</code>, so
iterators that also
invoke rayon will not cause mutex recursion deadlocks.</li>
</ul>
<h1>Release rayon-core 1.10.1 (2022-11-18)</h1>
<ul>
<li>Fixed a race condition with threads going to sleep while a broadcast
starts.</li>
</ul>
<h1>Release rayon 1.6.0 / rayon-core 1.10.0 (2022-11-18)</h1>
<ul>
<li>The minimum supported <code>rustc</code> is now 1.56.</li>
<li>The new <code>IndexedParallelIterator::fold_chunks</code> and
<code>fold_chunks_with</code> methods
work like <code>ParallelIterator::fold</code> and <code>fold_with</code>
with fixed-size chunks of
items. This may be useful for predictable batching performance, without
the
allocation overhead of
<code>IndexedParallelIterator::chunks</code>.</li>
<li>New &quot;broadcast&quot; methods run a given function on all
threads in the pool.
These run at a sort of reduced priority after each thread has exhausted
their
local work queue, but before they attempt work-stealing from other
threads.
<ul>
<li>The global <code>broadcast</code> function and
<code>ThreadPool::broadcast</code> method will
block until completion, returning a <code>Vec</code> of all return
values.</li>
<li>The global <code>spawn_broadcast</code> function and methods on
<code>ThreadPool</code>, <code>Scope</code>,
and <code>ScopeFifo</code> will run detached, without blocking the
current thread.</li>
</ul>
</li>
<li>Panicking methods now use <code>#[track_caller]</code> to report the
caller's location.</li>
<li>Fixed a truncated length in <code>vec::Drain</code> when given an
empty range.</li>
</ul>
<h2>Contributors</h2>
<p>Thanks to all of the contributors for this release!</p>
<ul>
<li><a href="https://github.com/cuviper"><code>@​cuviper</code></a></li>
<li><a
href="https://github.com/idanmuze"><code>@​idanmuze</code></a></li>
<li><a href="https://github.com/JoeyBF"><code>@​JoeyBF</code></a></li>
<li><a
href="https://github.com/JustForFun88"><code>@​JustForFun88</code></a></li>
<li><a
href="https://github.com/kianmeng"><code>@​kianmeng</code></a></li>
<li><a
href="https://github.com/kornelski"><code>@​kornelski</code></a></li>
<li><a
href="https://github.com/ritchie46"><code>@​ritchie46</code></a></li>
<li><a
href="https://github.com/ryanrussell"><code>@​ryanrussell</code></a></li>
<li><a
href="https://github.com/steffahn"><code>@​steffahn</code></a></li>
<li><a
href="https://github.com/TheIronBorn"><code>@​TheIronBorn</code></a></li>
<li><a
href="https://github.com/willcrozi"><code>@​willcrozi</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="401678ee55"><code>401678e</code></a>
Merge <a
href="https://github-redirect.dependabot.com/rayon-rs/rayon/issues/709">#709</a></li>
<li><a
href="33e9843413"><code>33e9843</code></a>
Release rayon 1.2.1 / rayon-core 1.6.1</li>
<li><a
href="dd874ac5d4"><code>dd874ac</code></a>
Bump crate versions and dependencies</li>
<li><a
href="0c6338d267"><code>0c6338d</code></a>
Reduce Option complexity in demo cpu_time</li>
<li><a
href="be99e500bf"><code>be99e50</code></a>
cargo fmt</li>
<li><a
href="9b4d9798de"><code>9b4d979</code></a>
Avoid mem::uninitialized in the demo cpu_time</li>
<li><a
href="5a466434ab"><code>5a46643</code></a>
Avoid mem::uninitialized in par_sort_unstable</li>
<li><a
href="73b1061a23"><code>73b1061</code></a>
Merge <a
href="https://github-redirect.dependabot.com/rayon-rs/rayon/issues/705">#705</a></li>
<li><a
href="54c0b0dc0c"><code>54c0b0d</code></a>
Make sure that compat-Cargo.lock is fresh</li>
<li><a
href="4fd13b0334"><code>4fd13b0</code></a>
Regenerate compat-Cargo.lock</li>
<li>Additional commits viewable in <a
href="https://github.com/rayon-rs/rayon/compare/v1.5.3...rayon-core-v1.6.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=rayon&package-manager=cargo&previous-version=1.5.3&new-version=1.6.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 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-01-22 23:52:37 -05:00
4182fc203e Bump actions-rust-lang/setup-rust-toolchain from 1.3.4 to 1.3.5 (#7840)
Bumps
[actions-rust-lang/setup-rust-toolchain](https://github.com/actions-rust-lang/setup-rust-toolchain)
from 1.3.4 to 1.3.5.
<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.3.5] - 2023-01-21</h2>
<h3>Changed</h3>
<ul>
<li>Use the newly stabilized setting to enable sparse registry access.
This speeds up access to the crate registry and is in addition to the
unstable nightly env var.
<a
href="https://github-redirect.dependabot.com/rust-lang/cargo/pull/11224">rust-lang/cargo#11224</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="bc88fd0b3e"><code>bc88fd0</code></a>
Enable sparse registry access after stabilization</li>
<li>See full diff in <a
href="https://github.com/actions-rust-lang/setup-rust-toolchain/compare/v1.3.4...v1.3.5">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.3.4&new-version=1.3.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 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-01-22 23:51:52 -05:00
10e36c4233 Bump sysinfo from 0.26.4 to 0.27.7 (#7839) 2023-01-23 03:09:15 +00:00
bef397228f Bump miette from 5.3.0 to 5.5.0 (#7838) 2023-01-23 01:56:28 +00:00
5cf47767d7 Bump shadow-rs from 0.16.3 to 0.20.0 (#7837) 2023-01-23 01:55:51 +00:00
8f2d2535dc Bump scraper from 0.13.0 to 0.14.0 (#7835) 2023-01-23 01:54:50 +00:00
2aae8e6382 Bump regex from 1.6.0 to 1.7.1 (#7833) 2023-01-23 01:44:10 +00:00
ba12b0de0d Fix command name lookup for known externals (#7830)
Fixes https://github.com/nushell/nushell/issues/7822
2023-01-22 21:40:18 +02:00
3552d03f6c Allow main command to define top-level module command (#7764) 2023-01-22 21:34:15 +02:00
8d5165c449 Feat/7725 url join (#7823)
# Description

Added command: `url join`.
Closes: #7725 

# User-Facing Changes

```
Converts a record to url

Search terms: scheme, username, password, hostname, port, path, query, fragment

Usage:
  > url join

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

Signatures:
  <record> | url join -> <string>

Examples:
  Outputs a url representing the contents of this record
  > {
          "scheme": "http",
          "username": "",
          "password": "",
          "host": "www.pixiv.net",
          "port": "",
          "path": "/member_illust.php",
          "query": "mode=medium&illust_id=99260204",
          "fragment": "",
          "params":
          {
            "mode": "medium",
            "illust_id": "99260204"
          }
        } | url join

  Outputs a url representing the contents of this record
  > {
        "scheme": "http",
        "username": "user",
        "password": "pwd",
        "host": "www.pixiv.net",
        "port": "1234",
        "query": "test=a",
        "fragment": ""
      } | url join

  Outputs a url representing the contents of this record
  > {
        "scheme": "http",
        "host": "www.pixiv.net",
        "port": "1234",
        "path": "user",
        "fragment": "frag"
      } | url join
```                  

# Questions
- Which parameters should be required? Currenlty are: `scheme` and
`host`.
2023-01-22 19:49:40 +01:00
d8027656b5 benchmark now pipes input into the closure (#7776)
# Description

Closes #7762. See issue for motivation.

# User-Facing Changes

Something like this is now possible without having to split this into 2
commands:
```
fetch "https://www.gutenberg.org/files/11/11-0.txt" | benchmark { str downcase | split words | uniq -c | sort-by count --reverse | first 10 }
```

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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: Stefan Holderbach <sholderbach@users.noreply.github.com>
2023-01-22 19:18:28 +01:00
4f57c5d56e Fix multi-line redirection inside a block (#7808)
# Description

Fixes: #7786

The issue is because the lite block is wrong while converting from lex
tokens

# What happened internally?
Take the following as example:
```
❯ def foobar [] { 
    'hello' out> /tmp/output.1
    'world' out> /tmp/output.2
}
```

## Before:
```
LiteBlock { block: [
    LitePipeline { commands: [
        Command(None, LiteCommand { comments: [], parts: [Span { start: 40900, end:40907 }] }),
        Redirection(Span { start: 40908, end: 40912 }, Stdout, LiteCommand { comments: [], parts: [Span { start: 40913, end: 40926 }] })]
    },
    LitePipeline { commands: [
        Redirection(Span { start: 40908, end: 40912 }, Stdout, LiteCommand { comments: [], parts: [Span { start: 40929, end: 40936 }] }),   // this is wrong, should be command.
        Redirection(Span { start: 40937, end: 40941 }, Stdout, LiteCommand { comments: [], parts: [Span { start: 40942, end: 40955 }] })]
    }] }
```

## After:
```
LiteBlock { block: [
    LitePipeline { commands: [
        Command(None, LiteCommand { comments: [], parts: [Span { start: 40824, end: 40831 }] }),
        Redirection(Span { start: 40832, end: 40836 }, Stdout, LiteCommand { comments: [], parts: [Span { start: 40837, end: 40850 }] })] 
    },
    LitePipeline { commands: [
        Command(None, LiteCommand { comments: [], parts: [Span { start: 40854, end: 40861 }] }), 
        Redirection(Span { start: 40862, end: 40866 }, Stdout, LiteCommand { comments: [], parts: [Span { start: 40867, end: 40880 }] })] 
    }
] }
```

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-23 06:32:56 +13:00
2c5c81815a Fix typos (#7811)
Some minor text fixes
2023-01-22 15:22:10 +01:00
b97bfe9297 [nu-test-support] Gate system locale tests (#7824)
# Description

`src/locale_override.rs` is gated with `#![cfg(debug_assertions)]` but
`tests/get_system_locale.rs` is not; this makes `cargo test --release`
fails:

```
error[E0432]: unresolved import `nu_test_support::locale_override`
 --> crates/nu-test-support/tests/get_system_locale.rs:1:22
  |
1 | use nu_test_support::locale_override::with_locale_override;
  |                      ^^^^^^^^^^^^^^^ could not find `locale_override` in `nu_test_support`

For more information about this error, try `rustc --explain E0432`.
error: could not compile `nu-test-support` due to previous error
warning: build failed, waiting for other jobs to finish...
```

With the change it now passes:

```
❯ cargo test --release
   Compiling nu-test-support v0.74.1 (/home/michel/src/github/nushell/nushell/crates/nu-test-support)
    Finished release [optimized] target(s) in 7.57s
     Running unittests src/lib.rs (/home/michel/src/github/nushell/nushell/target/release/deps/nu_test_support-750505b13c102d2c)

running 3 tests
test tests::constructs_a_pipeline ... ok
test playground::tests::current_working_directory_back_to_root_from_anywhere ... ok
test playground::tests::current_working_directory_in_sandbox_directory_created ... ok

test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running tests/get_system_locale.rs (/home/michel/src/github/nushell/nushell/target/release/deps/get_system_locale-e0ecabe312044fa8)

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
```

Signed-off-by: Michel Alexandre Salim <salimma@fedoraproject.org>

# User-Facing Changes

N/A

Signed-off-by: Michel Alexandre Salim <salimma@fedoraproject.org>
2023-01-21 20:05:29 -05:00
db07657e40 Reduce number of match calls (#7813) 2023-01-21 15:47:00 +02:00
2d98d0fcc2 Extract manual PWD extraction with method current_work_dir (#7812) 2023-01-21 15:44:17 +02:00
e6f6f17c6d Bump bumpalo from 3.11.0 to 3.12.0 (#7805) 2023-01-21 13:31:56 +00:00
166a927c20 Bump git2 from 0.16.0 to 0.16.1 (#7807) 2023-01-21 13:25:52 +00:00
625fe8866c Bump libgit2-sys from 0.14.1+1.5.0 to 0.14.2+1.5.1 (#7806) 2023-01-21 00:50:33 +00:00
69e7aa9fc9 nu-table: Wrap last column in table -e (#7778)
Hi  @rgwood thank you for report.

So this PR must fix it but I'd make a few runs.

close #7763

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2023-01-20 14:18:22 -08:00
a775cfe177 Clean up nu-cli/src/eval_file.rs (#7804)
- Replace `match` with `unwrap_or_else` or `if let`
- Remove unnecessary `mut`
- Check if file path has a parent
- Reduce visibility to `pub(crate)`
2023-01-20 13:45:34 -08:00
9e4a2ab824 Move all functions of main.rs into modules (#7803)
The affected modules are:
- `command.rs`
- `config_files.rs`
- `terminal.rs`
2023-01-20 13:20:38 -08:00
24aa1f312a Cleanup of src/main.rs (#7801)
While reading nushell's code, I've started to clean up `src/main.rs` a
bit.
The description of the changes can be found in the commit messages.
2023-01-20 10:44:49 -08:00
cde56741fb fetch -> http get and post -> http post (#7796)
# Updated description by @rgwood

This PR changes `fetch` to `http get` and `post` to `http post`. `fetch`
and `post` are now deprecated. [I surveyed people on
Discord](https://discord.com/channels/601130461678272522/601130461678272524/1065706282566307910)
and users strongly approved of this change.

# Original Description
This PR is related to #2741 and my first pull request in rust :)

Implemented a new http mod to better http support and alias `fetch` and
`post` commands to `http get` and `http post` respectively.

# User-Facing Changes

Users will be able to use HTTP method via http command, for example
``` shell
> http get "https://www.example.com"
<!doctype html>
<html>
...
```
2023-01-20 10:38:30 -08:00
bbe694a622 fix signature display in help commands (#7802)
# Description

This PR fixes the signature display when running `help commands`. Before
this PR, there were leading spaces in the signatures column. Now,
they're left aligned for a cleaner look.

Before:

![image](https://user-images.githubusercontent.com/343840/213711847-368fba0d-c902-47e6-b777-54de978b1ce3.png)

After:

![image](https://user-images.githubusercontent.com/343840/213711551-c5eb29c9-1d47-444b-86a1-8e14711e9771.png)


# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-20 07:58:54 -06:00
7e575a718b Do not list deprecated subcommands in help <cmd> (#7798)
# Description

BEFORE:
```
Subcommands:
  str camel-case - Convert a string to camelCase
  str capitalize - Capitalize first letter of text
  str collect - 'str collect' is deprecated. Please use 'str join' instead.
  str contains - Checks if string input contains a substring
  str distance - Compare two strings and return the edit distance/Levenshtein distance
  str downcase - Make text lowercase
  str ends-with - Check if an input ends with a string
  str find-replace - Deprecated command
  str index-of - Returns start index of first occurrence of string in input, or -1 if no match
  str join - Concatenate multiple strings into a single string, with an optional separator between each
  str kebab-case - Convert a string to kebab-case
  str length - Output the length of any strings in the pipeline
  str lpad - Left-pad a string to a specific length
  str pascal-case - Convert a string to PascalCase
  str replace - Find and replace text
  str reverse - Reverse every string in the pipeline
  str rpad - Right-pad a string to a specific length
  str screaming-snake-case - Convert a string to SCREAMING_SNAKE_CASE
  str snake-case - Convert a string to snake_case
  str starts-with - Check if an input starts with a string
  str substring - Get part of a string. Note that the start is included but the end is excluded, and that the first character of a string is index 0.
  str title-case - Convert a string to Title Case
  str to-datetime - Deprecated command
  str to-decimal - Deprecated command
  str to-int - Deprecated command
  str trim - Trim whitespace or specific character
  str upcase - Make text uppercase
```

AFTER:

```
Subcommands:
  str camel-case - Convert a string to camelCase
  str capitalize - Capitalize first letter of text
  str contains - Checks if string input contains a substring
  str distance - Compare two strings and return the edit distance/Levenshtein distance
  str downcase - Make text lowercase
  str ends-with - Check if an input ends with a string
  str index-of - Returns start index of first occurrence of string in input, or -1 if no match
  str join - Concatenate multiple strings into a single string, with an optional separator between each     
  str kebab-case - Convert a string to kebab-case
  str length - Output the length of any strings in the pipeline
  str lpad - Left-pad a string to a specific length
  str pascal-case - Convert a string to PascalCase
  str replace - Find and replace text
  str reverse - Reverse every string in the pipeline
  str rpad - Right-pad a string to a specific length
  str screaming-snake-case - Convert a string to SCREAMING_SNAKE_CASE
  str snake-case - Convert a string to snake_case
  str starts-with - Check if an input starts with a string
  str substring - Get part of a string. Note that the start is included but the end is excluded, and that the first character of a string is index 0.
  str title-case - Convert a string to Title Case
  str trim - Trim whitespace or specific character
  str upcase - Make text uppercase
```

The deprecated subcommands still exist, but are no longer listed in
`help` for the containing command.

# User-Facing Changes

See above.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-20 06:28:27 -06:00
ea9ca8b4ed str length, str substring, str index-of, split words and split chars now use graphemes instead of UTF-8 bytes (#7752)
Closes https://github.com/nushell/nushell/issues/7742
2023-01-20 09:16:18 +02:00
0fe2884397 add dedicated const in pipeline, const builtin var errors (#7784)
# Description

Currently `let` and `const` share error handling, and this might lead to
confusing error messages


![sJan17-51](https://user-images.githubusercontent.com/98623181/212981108-c80b3e55-cece-4ee5-ba8f-cb5dcfdf63e0.png)

This PR adds dedicated errors to `const`
2023-01-20 00:11:48 +01:00
2982a2c963 let find take linebreaks into account in Value::String (#7789)
# Description

Fixes #7774. The functionality should be the same as feeding all
`PipelineDate::Value(Value::String(_,_),_)` into `lines` before putting
it into `find`.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-20 00:07:34 +01:00
6a43e1a64d Add test for fix of issue #7754 (#7756)
Fix already landed with #7779
2023-01-19 11:19:27 +01:00
3b5172a8fa LazyRecord (#7619)
This is an attempt to implement a new `Value::LazyRecord` variant for
performance reasons.

`LazyRecord` is like a regular `Record`, but it's possible to access
individual columns without evaluating other columns. I've implemented
`LazyRecord` for the special `$nu` variable; accessing `$nu` is
relatively slow because of all the information in `scope`, and [`$nu`
accounts for about 2/3 of Nu's startup time on
Linux](https://github.com/nushell/nushell/issues/6677#issuecomment-1364618122).

### Benchmarks

I ran some benchmarks on my desktop (Linux, 12900K) and the results are
very pleasing.

Nu's time to start up and run a command (`cargo build --release;
hyperfine 'target/release/nu -c "echo \"Hello, world!\""' --shell=none
--warmup 10`) goes from **8.8ms to 3.2ms, about 2.8x faster**.

Tests are also much faster! Running `cargo nextest` (with our very slow
`proptest` tests disabled) goes from **7.2s to 4.4s (1.6x faster)**,
because most tests involve launching a new instance of Nu.

### Design (updated)

I've added a new `LazyRecord` trait and added a `Value` variant wrapping
those trait objects, much like `CustomValue`. `LazyRecord`
implementations must implement these 2 functions:

```rust
// All column names
fn column_names(&self) -> Vec<&'static str>;

// Get 1 specific column value
fn get_column_value(&self, column: &str) -> Result<Value, ShellError>;
 ```

### Serializability

`Value` variants must implement `Serializable` and `Deserializable`, which poses some problems because I want to use unserializable things like `EngineState` in `LazyRecord`s. To work around this, I basically lie to the type system:

1. Add `#[typetag::serde(tag = "type")]` to `LazyRecord` to make it serializable
2. Any unserializable fields in `LazyRecord` implementations get marked with `#[serde(skip)]`
3. At the point where a `LazyRecord` normally would get serialized and sent to a plugin, I instead collect it into a regular `Value::Record` (which can be serialized)
2023-01-18 19:27:26 -08:00
be32aeee70 add magenta to ansi command as synonym for purple (#7785)
# Description

Added `magenta` as a synonym for Purple in the ansi command. Previously,
ansi errored out on `ansi magenta` as the `AnsiCode` vec didn't have
magenta as a name as seen in #7747.


<img width="909" alt="image"
src="https://user-images.githubusercontent.com/101823296/213012495-10bb29e3-b6d3-4fdc-bc3c-cb8a891c2bc2.png">




# User-Facing Changes

Users can now use the ANSI standard name `magenta`.
2023-01-17 19:50:55 -06:00
adcc74ab8d Check all user groups. (#7775)
Previously the group check was only for the current users gid, now we
check against all the users groups.


# Description

Currently when using the `cd` command to enter a directory there was
only a check against the current user id, and exact current group id,
meaning if a directory had a group permission and that group wasn't the
users group it was effectively ignored.

The fix simply implements a check through all the users current groups.

Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2023-01-17 19:49:54 -06:00
8acced56b2 Fixes Issue 7648 which crashes nushell and happens when an alias name is shorter than the alias command and the alias command is an external command. (#7779) 2023-01-17 08:30:00 +02:00
f823c7cb5d fix some typos (#7773)
# Description

Nothing changed, just fix some typos

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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: Stefan Holderbach <sholderbach@users.noreply.github.com>
2023-01-16 12:43:46 +01:00
26e6516626 update sqlparser dependency (#7772)
# Description

This PR updates the `sqlparser` dependency and updates code to the
latest api changes.

# User-Facing Changes


# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-15 21:30:39 -06:00
5979e0cd0c update semver dep (#7771)
# Description

This PR updates the semver dependency and updates the `inc` plugin to
use the latest api.

# User-Facing Changes



# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-15 20:39:27 -06:00
3ba1bfc369 Bump quick-xml from 0.25.0 to 0.27.1 (#7768) 2023-01-16 02:06:31 +00:00
efa0e6eb62 Bump serial_test from 0.8.0 to 0.10.0 (#7769) 2023-01-16 02:06:03 +00:00
159b4bd7dc Bump actions/stale from 3 to 6 (#7770) 2023-01-16 02:05:35 +00:00
2611c9525e Bump dialoguer from 0.9.0 to 0.10.3 (#7765) 2023-01-16 02:04:47 +00:00
0353eb4a12 make save stream on list stream data (#7675)
# Description

Closes: #7590

# User-Facing Changes

So the following command
```
1..100 | each { |i| sleep 400ms; $i} | save --raw -f output.txt
```

Will stream data to `output.txt`

But I'm note sure how to make a proper test for it, so I leave with no
new test cases..

Also rename from `string_binary_list_value_to_bytes ` to
`value_to_bytes` to accepts more Value type.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-15 10:54:30 -08:00
92c4097f8d Rename to url command to url build-query (#7702)
# Description

Refactor command: "to url" in: "to url query". Changed usage sentence.
Closes: #7495

# User-Facing Changes

Now we get a query string from a record or table by using command: "to
url query".

```
> help to url query
Convert record or table into query string applying percent-encoding.

Usage:
  > to url query

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

Signatures:
  <record> | to url query -> <string>
  <table> | to url query -> <string>

Examples:
  Outputs a query string representing the contents of this record
  > { mode:normal userid:31415 } | to url query

  Outputs a query string representing the contents of this 1-row table
  > [[foo bar]; ["1" "2"]] | to url query

  Outputs a query string representing the contents of this record
  > {a:"AT&T", b: "AT T"} | to url query
```

# Tests + Formatting

Added this test:
```
Example {
    description: "Outputs a query string representing the contents of this record",
    example: r#"{a:"AT&T", b: "AT T"} | to url query"#,
    result: Some(Value::test_string("a=AT%26T&b=AT+T")),
},
```
to ensure percent-encoding. 

# After Submitting

If PR is accepted I'll open another PR on documentation to notify
changes on
[this.](https://github.com/nushell/nushell.github.io/blob/main/book/commands/to_url.md)
2023-01-15 10:16:29 -08:00
a909c60f05 Ansi link (#7751) 2023-01-15 17:23:37 +02:00
56a9eab7eb Allow underscores in integers and floats (#7759)
# Description

This PR makes changes that allow underscores in numbers.

Example:
```nu
# allows underscores to be placed arbitrarily to enhance readability.
let pi = 3.1415_9265_3589_793

# works with integers
let num = 1_000_000_000_000
let fav_color = 0x68_9d_6a
```
2023-01-15 09:03:57 -06:00
7221eb7f39 Fix typos and use more idiomatic assertions (#7755)
I have changed `assert!(a == b)` calls to `assert_eq!(a, b)`, which give
better error messages. Similarly for `assert!(a != b)` and
`assert_ne!(a, b)`. Basically all instances were comparing primitives
(string slices or integers), so there is no loss of generality from
special-case macros,

I have also fixed a number of typos in comments, variable names, and a
few user-facing messages.
2023-01-15 15:03:32 +13:00
b0b0482d71 Add cursor shape configuration for each edit mode (#7745)
# Description

This PR allows the configuration of cursor shapes in nushell for each
edit mode. This is the change that is in the default_config.nu file.
```
  cursor_shape: {
    emacs: line # block, underscore, line (line is the default)
    vi_insert: block # block, underscore, line (block is the default)
    vi_normal: underscore # block, underscore, line  (underscore is the default)
  }
```

# User-Facing Changes

See above. If you'd prefer a different default, please speak up and let
us know.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-13 14:37:39 -06:00
49ab559992 Trim quotes when shelling out to cmd.exe (#7740)
Closes #6337 and #5366. Prior to this PR, when "shelling out" to cmd.exe
on Windows we were not trimming quotes correctly:

```bash
〉^echo "foo"
\"foo\"
```
After this change, we do:
```bash
〉^echo "foo"
foo
```

### Breaking Change

I ended up removing `dir` from the list of supported cmd.exe internal
commands as part of this PR.

For this PR, I extracted the argument-cleaning-and-expanding code from
`spawn_simple_command()` for reuse in `spawn_cmd_command()`. This means
that we now expand globs, which broke some tests for the `dir` cmd.exe
internal command.

I probably could have kept the tests working, but... tbh, I don't think
it's worth it. I don't want to make the `cmd.exe` functionality any more
complicated than it already is, and calling `dir` from Nu is always
going to be weird+hacky compared to `ls`.
2023-01-13 11:00:30 -08:00
3dd21c635a dependency update: update polar to 0.26.1 (#7743)
# Description

As title

# User-Facing Changes

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-13 09:27:37 -06:00
835bbb2e44 update base64 implementation to newer crate (#7739)
# Description

This PR updates the base64 crate, which has changed significantly, so
all the base64 implementations had to be changed too. Tests pass. I hope
that's enough.

# User-Facing Changes

None, except added a new character encoding imap-mutf7 as mutf7.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-13 07:16:14 -06:00
2ee2370a71 Detailed message during core dumped (#7737)
# Description

In bash when a program crashes, it prints the reason for what happened:
```
$ ./division_by_zero
Floating point exception (core dumped)
$ ./segfault
Segmentation fault (core dumped)
```

Nushell always prints the same thing in this case:
```
> ./division_by_zero
nushell: oops, process './division_by_zero' core dumped
Error: nu:🐚:external_command (link)
# etc..
```

This PR adds more detailed error printing, like in bash:
```
> ./division_by_zero
Floating point exception: oops, process './division_by_zero' core dumped
Error: nu:🐚:external_command (link)
# etc..
```

I made this message format as an example:
```
Floating point exception: oops, process './division_by_zero' core dumped
```
Instead of `nushell:` it writes a meaningful message, but I can change
this format as per the suggestions.

I tested the change only on linux, but it should work on other unix
systems.

# User-Facing Changes

The error message only.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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: Stefan Holderbach <sholderbach@users.noreply.github.com>
2023-01-13 10:22:11 +01:00
54dd65cfe1 Disallow encode's silent conversion to HTML entities (and add -i/--ignore-errors flag to re-allow it) (#7738)
# Description

Closes #7514.

* For both `encode` and `decode`: add a special case allowing `utf16` as
a valid alias for `utf-16` (just as `utf-8` has `utf8`).
* For `encode` , make it an error when encodings_rs replaces characters
outside the given encoding with HTML entities
* For `encode` , add `-i`/`--ignore-errors` flag to bring back this
behaviour.

Note: `--ignore-errors` does NOT ignore the error for using a wrong
encoding label like `uft8`

# User-Facing Changes

See above.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# After Submitting

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

Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2023-01-12 15:00:17 -06:00
b004aacd69 Add search terms in random and expression categories (#7736)
# Description

Refers to: [5093](https://github.com/nushell/nushell/issues/5093)

# Tests

- [x] `cargo fmt --all -- --check` to check standard code formatting
(`cargo fmt --all` applies these changes)
- [x] `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- [x]  `cargo test --workspace` to check that all tests pass
2023-01-12 14:01:40 +01:00
48b7b415e2 spanned error on path exists command (#7717)
# Description

Closes: #7696 

# User-Facing Changes

Before:
```
❯ 'temp/aa' | path exists
Error: nu:🐚:io_error (link)

  × I/O error
  help: Os { code: 13, kind: PermissionDenied, message: "Permission denied" }
```

After:
```
❯ 'temp/aa' | path exists
Error: nu:🐚:io_error (link)

  × I/O error
   ╭─[entry #42:1:1]
 1 │ 'temp/aa' | path exists
   · ────┬────
   ·     ╰── Permission denied (os error 13)
   ╰────
```
# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-12 06:56:39 -06:00
544cea95e1 Bump uuid from 1.1.2 to 1.2.2 (#7734) 2023-01-12 12:48:49 +00:00
8aa2632661 Support redirect err and out to different streams (#7685)
# Description

Closes: #7364 

# User-Facing Changes

Given the following shell script:
```bash
x=$(printf '=%.0s' {1..100})
echo $x
echo $x 1>&2
```

It supports the following command:
```
bash test.sh out> out.txt err> err.txt
```

Then both `out.txt` and `err.txt` will contain `=`(100 times)

## About the change

The core idea is that when doing lite-parsing, introduce a new variant
`LiteElement::SeparateRedirection` if we meet two Redirection
token(which is generated by `lex` function),
During converting from lite block to block,
`LiteElement::SeparateRedirection` will be converted to
`PipelineElement::SeparateRedirection`.

Then in the block eval process, if we get
`PipelineElement::SeparateRedirection`, we invoke `save` command with
`--stderr` arguments to acthive our behavior.



## What happened internally?
Take the following command as example:
```
^ls out> out.txt err> err.txt
```

lex parsing result(`Tokens`) are not changed, but `LiteBlock` and
`Block` is changed after this pr.

### LiteBlock before
```rust
LiteBlock {
    block: [
        LitePipeline { commands: [
            Command(None, LiteCommand { comments: [], parts: [Span { start: 39041, end: 39044 }] }),
            // actually the span of first Redirection is wrong too..
            Redirection(Span { start: 39058, end: 39062 }, Stdout, LiteCommand { comments: [], parts: [Span { start: 39050, end: 39057 }] }),
            Redirection(Span { start: 39058, end: 39062 }, Stderr, LiteCommand { comments: [], parts: [Span { start: 39063, end: 39070 }] })
        ]
    }]
}
```
### LiteBlock after
```rust
LiteBlock {
    block: [
        LitePipeline { commands: [
            Command(
                None, 
                LiteCommand { comments: [], parts: [Span { start: 38525, end: 38528 }] }),
                // new one! two Redirection merged into one SeparateRedirection.
                SeparateRedirection { 
                    out: (Span { start: 38529, end: 38533 }, LiteCommand { comments: [], parts: [Span { start: 38534, end: 38541 }] }),
                    err: (Span { start: 38542, end: 38546 }, LiteCommand { comments: [], parts: [Span { start: 38547, end: 38554 }] })
                }
        ]
    }]
}
```

### Block before
```rust
Pipeline {
    elements: [
        Expression(None, Expression {
            expr: ExternalCall(Expression { expr: String("ls"), span: Span { start: 39042, end: 39044 }, ty: String, custom_completion: None }, [], false),
            span: Span { start: 39041, end: 39044 },
            ty: Any, custom_completion: None 
        }),
        Redirection(Span { start: 39058, end: 39062 }, Stdout, Expression { expr: String("out.txt"), span: Span { start: 39050, end: 39057 }, ty: String, custom_completion: None }),
        Redirection(Span { start: 39058, end: 39062 }, Stderr, Expression { expr: String("err.txt"), span: Span { start: 39063, end: 39070 }, ty: String, custom_completion: None })] }
```

### Block after
```rust
Pipeline {
    elements: [
        Expression(None, Expression {
            expr: ExternalCall(Expression { expr: String("ls"), span: Span { start: 38526, end: 38528 }, ty: String, custom_completion: None }, [], false),
            span: Span { start: 38525, end: 38528 },
            ty: Any,
            custom_completion: None 
        }),
        // new one! SeparateRedirection
        SeparateRedirection {
            out: (Span { start: 38529, end: 38533 }, Expression { expr: String("out.txt"), span: Span { start: 38534, end: 38541 }, ty: String, custom_completion: None }),
            err: (Span { start: 38542, end: 38546 }, Expression { expr: String("err.txt"), span: Span { start: 38547, end: 38554 }, ty: String, custom_completion: 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 -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-12 10:22:30 +01:00
5419e8ae9d don't expand tilde if we quote external arguments (#7711)
# Description

As title
Fixes: #7673
Fixes: #4205
Also possiblely fixes: https://github.com/nushell/nushell/issues/6993

# User-Facing Changes

Before:
```
> ^echo "~"
/Users/ttt
```

After:
```
> ^echo "~"
~
```
# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-11 19:14:19 -05:00
d4d28ab796 Bump once_cell from 1.16.0 to 1.17.0 (#7732) 2023-01-11 23:00:44 +00:00
b8db928c58 Bump git2 from 0.15.0 to 0.16.0 (#7731) 2023-01-11 22:56:02 +00:00
bf45a5860e experiment with dependabot and rust dependencies (#7716)
# Description

The PR is an experiment to see if we want to use dependabot to notify us
and automatically update rust dependencies.

# User-Facing Changes



# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-11 16:30:34 -06:00
ca543fc8af update release-pkg comments for manual runs (#7726)
# Description

After running this script manually again, I found more comments that
needed to be added.

# User-Facing Changes

N/A

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-11 16:28:30 -06:00
57cf805e12 Add const support for all overlay commands (#7720) 2023-01-12 00:18:06 +02:00
1ae9157985 Bump to 0.74.1 development version (#7721)
# Description

May be used for hotfix if needed
2023-01-11 22:30:41 +01:00
206a6ae6c9 Fix generated doc for explore commands (#7723)
# Description

Fix generated doc for `explore` commands, and resolve the static site
build error:
https://github.com/nushell/nushell.github.io/actions/runs/3889029668/jobs/6636921318

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-11 11:17:12 +08:00
82ac590412 Progress bar Implementation (#7661)
# Description

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

I implemented the status bar we talk about yesterday. The idea was
inspired by the progress bar of `wget`.
I decided to go for the second suggestion by `@Reilly`
> 2. add an Option<usize> or whatever to RawStream (and ListStream?) for
situations where you do know the length ahead of time

For now only works with the command `save` but after the approve of this
PR we can see how we can implement it on commands like `cp` and `mv`

When using `fetch` nushell will check if there is any `content-length`
attribute in the request header. If so, then `fetch` will send it
through the new `Option` variable in the `RawStream` to the `save`.
If we know the total size we show the progress bar 

![nu_pb01](https://user-images.githubusercontent.com/38369407/210298647-07ee55ea-e751-41b1-a84d-f72ec1f6e9e5.jpg)
but if we don't then we just show the stats like: data already saved,
bytes per second, and time lapse.

![nu_pb02](https://user-images.githubusercontent.com/38369407/210298698-1ef65f51-40cc-4481-83de-309cbd1049cb.jpg)

![nu_pb03](https://user-images.githubusercontent.com/38369407/210298701-eef2ef13-9206-4a98-8202-e4fe5531d79d.jpg)

Please let me know If I need to make any changes and I will be happy to
do it.

# User-Facing Changes

A new flag (`--progress` `-p`) was added to the `save` command 
Examples:
```nu
fetch https://github.com/torvalds/linux/archive/refs/heads/master.zip | save --progress -f main.zip
fetch https://releases.ubuntu.com/22.04.1/ubuntu-22.04.1-desktop-amd64.iso | save --progress -f main.zip
open main.zip --raw | save --progress main.copy
```

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
-
I am getting some errors and its weird because the errors are showing up
in files i haven't touch. Is this normal?

# 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: Reilly Wood <reilly.wood@icloud.com>
2023-01-10 20:57:48 -05:00
9a274128ce Combine benchmarks to speed up cargo bench build times (#7722)
I've been using the new Criterion benchmarks and I noticed that they
take a _long_ time to build before the benchmark can run. Turns out
`cargo build` was building 3 separate benchmarking binaries with most of
Nu's functionality in each one.

As a simple temporary fix, I've moved all the benchmarks into a single
file so that we only build 1 binary.

### Future work

Would be nice to split the unrelated benchmarks out into modules, but
when I did that a separate binary still got built for each one. I
suspect Criterion's macros are doing something funny with module or file
names. I've left a FIXME in the code to investigate this further.
2023-01-10 17:51:25 -08:00
5664ee7bda Remove engine_state clones in REPL eval (#7713)
A small but easy optimization for `evaluate_repl()`: clone
`engine_state` 1x instead of 3x.

This reduces time spent in a simple REPL eval (`enter` key pressed with
no command text) by about 10%, as measured in
[Superluminal](https://superluminal.eu/).
2023-01-10 17:22:32 -08:00
9a56665c6b Commit the lockfile for 0.74 (#7719)
Was missed in #7718
2023-01-10 21:12:41 +01:00
8044fb2db0 Bump version to 0.74.0 (#7718)
Preparing the release
2023-01-10 20:58:13 +01:00
3a59ab9f14 Improve wording of str replace help messages (#7708)
# Description

See title.

# User-Facing Changes

See title.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-10 20:46:50 +01:00
f609a4f26a Auto-Completion: put ` tildes around filenames with parentheses (#7712)
# Description

Fixes: #7706

# User-Facing Changes


![img](https://user-images.githubusercontent.com/22256154/211286663-3d07a650-5e2d-406e-99f6-cff90dba352b.png)


# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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: Stefan Holderbach <sholderbach@users.noreply.github.com>
2023-01-10 20:41:54 +01:00
80463d12fb Revert "Primitives now use color closures..." (#7710)
This temporarily reverts commit c5639cd9fa
(PR https://github.com/nushell/nushell/pull/7650). See
[here](https://github.com/nushell/nushell/pull/7650#issuecomment-1375036213)
for details; the PR is accidentally adding ANSI escape codes to strings
piped to externals.

I think we should revert the PR because we're only 1-2 days away from a
release; reverting it will give us more time to land+test a proper fix
in the next release cycle.
2023-01-08 21:53:52 -08:00
cef05d3553 Fix line-end trimming in subexpression (#7543)
# Description

Currently the implementation is different for Windows and Unix.

Thus certain operations will fail if the platform foreign line ending is
used:

example failing under windows

```
git show (git merge-base main HEAD)
```

Temporary cheat is to strip all `\r` and `\n` from the end. Proper
solution should trim them as correct patterns.

Also needed: test of behavior with both platform newline and
platform-foreign line endings

cc @WindSoilder 


# User-Facing Changes

Line endings should be trimmed no matter the source and no matter the
platform

# Tests + Formatting

Still missing
2023-01-08 22:51:51 +01:00
5879b0df99 clean up some extra logging code in the cli (#7709)
I have been recently going through some info logging in the cli and
noticed that there is too much info being printed to get a handle on
whats going on...

This is an attempt to do some minor logging clean up to print out "less
stuff",
in info logging mode mainly having to do with the prompt...

If someone really want to see what is going on they can very easily add
it
back in without too much trouble.
2023-01-08 15:05:46 -05:00
95cd9dd2b2 move BufferedReader out of nu-command (#7697)
src/main.rs has a dependency on BufferedReader
which is currently located in nu_command.

I am moving BufferedReader to a more relevant
location (crate) which will allow / eliminate main's dependency
on nu_command in a benchmark / testing environment...

now that @rgwood  has landed benches I want
to start experimenting with benchmarks related
to the parser.

For benchmark purposes when dealing with parsing
you need a very simple set of commands that show
how well the parser is doing, in other words
just the core commands... Not all of nu_command...

Having a smaller nu binary when running the benchmark CI
would enable building nushell quickly, yet still show us
how well the parser is performing...

Once this PR lands the only dependency main will have
on nu_command is create_default_context ---
meaning for benchmark purposes we can swap in a tiny
crate of commands instead of the gigantic nu_command
which has its "own" create_default_context...

It will also enable other crates going forward to
use BufferedReader.  Right now it is not accessible
to other lower level crates because it is located in a
"top of the stack crate".
2023-01-06 15:22:17 -08:00
424d5611a5 Bump tokio from 1.21.2 to 1.24.1 (#7701)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.21.2 to 1.24.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tokio-rs/tokio/releases">tokio's
releases</a>.</em></p>
<blockquote>
<h2>Tokio v1.24.1</h2>
<p>This release fixes a compilation failure on targets without
<code>AtomicU64</code> when using rustc older than 1.63. (<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5356">#5356</a>)</p>
<p><a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5356">#5356</a>:
<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/pull/5356">tokio-rs/tokio#5356</a></p>
<h2>Tokio v1.24.0</h2>
<p>The highlight of this release is the reduction of lock contention for
all I/O operations (<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5300">#5300</a>).
We have received reports of up to a 20% improvement in CPU utilization
and increased throughput for real-world I/O heavy applications.</p>
<h3>Fixed</h3>
<ul>
<li>rt: improve native <code>AtomicU64</code> support detection (<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5284">#5284</a>)</li>
</ul>
<h3>Added</h3>
<ul>
<li>rt: add configuration option for max number of I/O events polled
from the OS
per tick (<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5186">#5186</a>)</li>
<li>rt: add an environment variable for configuring the default number
of worker
threads per runtime instance (<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/4250">#4250</a>)</li>
</ul>
<h3>Changed</h3>
<ul>
<li>sync: reduce MPSC channel stack usage (<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5294">#5294</a>)</li>
<li>io: reduce lock contention in I/O operations (<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5300">#5300</a>)</li>
<li>fs: speed up <code>read_dir()</code> by chunking operations (<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5309">#5309</a>)</li>
<li>rt: use internal <code>ThreadId</code> implementation (<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5329">#5329</a>)</li>
<li>test: don't auto-advance time when a <code>spawn_blocking</code>
task is running (<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5115">#5115</a>)</li>
</ul>
<p><a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5186">#5186</a>:
<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/pull/5186">tokio-rs/tokio#5186</a>
<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5294">#5294</a>:
<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/pull/5294">tokio-rs/tokio#5294</a>
<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5284">#5284</a>:
<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/pull/5284">tokio-rs/tokio#5284</a>
<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/4250">#4250</a>:
<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/pull/4250">tokio-rs/tokio#4250</a>
<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5300">#5300</a>:
<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/pull/5300">tokio-rs/tokio#5300</a>
<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5329">#5329</a>:
<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/pull/5329">tokio-rs/tokio#5329</a>
<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5115">#5115</a>:
<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/pull/5115">tokio-rs/tokio#5115</a>
<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5309">#5309</a>:
<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/pull/5309">tokio-rs/tokio#5309</a></p>
<h2>Tokio v1.23.1</h2>
<p>This release forward ports changes from 1.18.4.</p>
<h3>Fixed</h3>
<ul>
<li>net: fix Windows named pipe server builder to maintain option when
toggling
pipe mode (<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5336">#5336</a>).</li>
</ul>
<p><a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5336">#5336</a>:
<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/pull/5336">tokio-rs/tokio#5336</a></p>
<h2>Tokio v1.23.0</h2>
<h3>Fixed</h3>
<ul>
<li>net: fix Windows named pipe connect (<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5208">#5208</a>)</li>
<li>io: support vectored writes for <code>ChildStdin</code> (<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5216">#5216</a>)</li>
<li>io: fix <code>async fn ready()</code> false positive for OS-specific
events (<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5231">#5231</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="31c7e82919"><code>31c7e82</code></a>
chore: prepare Tokio v1.24.1 (<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5357">#5357</a>)</li>
<li><a
href="8d8db27442"><code>8d8db27</code></a>
tokio: add load and compare_exchange_weak to loom StaticAtomicU64 (<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5356">#5356</a>)</li>
<li><a
href="dfe252d1fa"><code>dfe252d</code></a>
chore: prepare Tokio v1.24.0 release (<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5353">#5353</a>)</li>
<li><a
href="21b233fa9c"><code>21b233f</code></a>
test: bump version of async-stream (<a
href="https://github-redirect.dependabot.com/tokio-rs/tokio/issues/5347">#5347</a>)</li>
<li><a
href="72993044e6"><code>7299304</code></a>
Merge branch 'tokio-1.23.x' into master</li>
<li><a
href="1a997ffbd6"><code>1a997ff</code></a>
chore: prepare Tokio v1.23.1 release</li>
<li><a
href="a8fe333cc4"><code>a8fe333</code></a>
Merge branch 'tokio-1.20.x' into tokio-1.23.x</li>
<li><a
href="ba81945ffc"><code>ba81945</code></a>
chore: prepare Tokio 1.20.3 release</li>
<li><a
href="763bdc967e"><code>763bdc9</code></a>
ci: run WASI tasks using latest Rust</li>
<li><a
href="9f98535877"><code>9f98535</code></a>
Merge remote-tracking branch 'origin/tokio-1.18.x' into
fix-named-pipes-1.20</li>
<li>Additional commits viewable in <a
href="https://github.com/tokio-rs/tokio/compare/tokio-1.21.2...tokio-1.24.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=tokio&package-manager=cargo&previous-version=1.21.2&new-version=1.24.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 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)
- `@dependabot use these labels` will set the current labels as the
default for future PRs for this repo and language
- `@dependabot use these reviewers` will set the current reviewers as
the default for future PRs for this repo and language
- `@dependabot use these assignees` will set the current assignees as
the default for future PRs for this repo and language
- `@dependabot use this milestone` will set the current milestone as the
default for future PRs for this repo and language

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>
2023-01-06 16:37:37 -06:00
9bff68a4f6 align durations to the right (#7700)
# Description

This PR aligns durations to the right side versus the left.
Before this PR

![image](https://user-images.githubusercontent.com/343840/211092575-2199f4ce-7972-4726-a243-5499e656fb46.png)

After this PR

![image](https://user-images.githubusercontent.com/343840/211092601-ff63ecd2-9710-4e5f-8c32-85476f4b7110.png)


# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-06 16:36:59 -06:00
a9bdc655c1 Add benchmarks for evaluating default env+config (#7688)
A quick follow-up to https://github.com/nushell/nushell/pull/7686. This
adds benchmarks for evaluating `default_env.nu` and `default_config.nu`,
because evaluating config takes up the lion's share of Nushell's startup
time. The benchmarks will help us speed up Nu's startup and test
execution.

```
eval default_env.nu     time:   [4.2417 ms 4.2596 ms 4.2780 ms]
...
eval default_config.nu  time:   [1.9362 ms 1.9439 ms 1.9523 ms]
```
2023-01-05 14:14:58 -08:00
9b617de6f0 Continue and Break on Try/Catch (#7683)
Co-authored-by: sholderbach <sholderbach@users.noreply.github.com>
Fixes https://github.com/nushell/nushell/issues/7656
2023-01-05 21:41:51 +01:00
771270d526 Add Criterion benchmarks for parser (#7686)
This PR sets up [Criterion](https://github.com/bheisler/criterion.rs)
for benchmarking in the main `nu` crate, and adds some simple parser
benchmarks.

To run the benchmarks, just do `cargo bench` or `cargo bench -- <regex
matching benchmark names>` in the repo root:

```bash
〉cargo bench -- parse
...
     Running benches/parser_benchmark.rs (target/release/deps/parser_benchmark-75d224bac82d5b0b)
parse_default_env_file  time:   [221.17 µs 222.34 µs 223.61 µs]
Found 8 outliers among 100 measurements (8.00%)
  5 (5.00%) high mild
  3 (3.00%) high severe

parse_default_config_file
                        time:   [1.4935 ms 1.4993 ms 1.5059 ms]
Found 11 outliers among 100 measurements (11.00%)
  7 (7.00%) high mild
  4 (4.00%) high severe
```

Existing benchmarks from `nu-plugin` have been moved into the main `nu`
crate to keep all our benchmarks in one place.
2023-01-05 11:39:54 -08:00
26d1307476 Url encode to escape special characters (#7664)
Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
Co-authored-by: Stefan Holderbach <sholderbach@users.noreply.github.com>
2023-01-05 19:24:38 +01:00
86707b9972 Remove environment variable hiding from hide (#7687) 2023-01-05 20:08:43 +02:00
52cb865c5c Upgrade all remaining crates to Rust 2021 (#7681)
2 crates were still using Rust 2018, including the base `nu` crate. This
PR upgrades them to Rust 2021. If you're aware of any reason why this is
a bad idea, please speak now or forever hold your peace.

## Context

I was moving benchmarks from `nu-plugin` to the base crate and couldn't
figure out why they wouldn't compile. Turns out the benchmarks rely on
some Rust 2021 features. Would be nice to have everything on 2021.
2023-01-05 06:24:42 -06:00
3ea027a136 Make user parameter optional in fetch (#7680)
# Description

This commit makes the `user` parameter optional in the `fetch` command.
Previously when attempting to _only_ pass a `password`, the command
would ignore authentication. Now when a `user` is not supplied, but a
`password` is, an empty user is implied.

Before this PR, consider the following:
```nushell
fetch -password "mypassword" $url
```
This would result in the `password` parameter being ignored entirely.

Now, with changes made in this PR, consider the same code snippet as
above. The following HTTP header will be used:
```
Authentication: Basic <base64_encode(":{password}")>
```
Note that the `user` field is implied as empty if one is not supplied
when `password` is.

# User-Facing Changes

* `fetch` now supports `password`-only authentication, using an empty
`user` if one is not supplied.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-04 19:57:56 -08:00
00469de93e Limit recursion to avoid stack overflow (#7657)
Add recursion limit to `def` and `block`.
Summary of this PR , it will detect if `def` call itself or not .
Then execute by using `stack` which I think best choice to use with this
design and core as it is available in all crates and mutable and
calculate the recursion limit on calling `def`.
Set 50 as recursion limit on `Config`.
Add some tests too .

Fixes #5899

Co-authored-by: Reilly Wood <reilly.wood@icloud.com>
2023-01-04 18:38:50 -08:00
9bc4e6794d Remove math eval command (#7284)
Reasoning: 

Most missing math commands are implemented with #7258.
The `meval` crate itself declares that it doesn't strive to stringent
standards (https://docs.rs/meval/latest/meval/#related-projects).
For example no particular special casing or transformations are
performed to ensure numerical stability. It uses the same rust `std`
library functions we use or have access to (and `f64`).
While the command call syntax in nushell may be a bit more verbose,
having a single source of truth and common commands is beneficial.
Furthermore the `math` commands can themselves implement broadcasting
over lists (or table columns).

Closes #7073

Removed dependencies:
- `meval`
- `nom 1.2.4` (duplicate)

User-Facing Changes:

Scripts using `math eval` will break. 
We remove a further `eval` like behavior to get results through runtime evaluation (albeit limited in scope)

Tests:

- Updated tests that internally used `math eval`.
- Removed one test that primarily used `math eval` to obtain a result from `str join`
2023-01-04 23:50:18 +01:00
429127793f [Chore] cleanup in where implementation (#7679)
- Remove commented out example that is unnecessary after #7365
- remove unnecessary closure map
2023-01-04 22:50:02 +01:00
75cb3fcc5f uniq and uniq-by optimization (#7477) (#7534)
# Description

Refactored the quadratic complexity on `uniq` to use a HashMap, as key I
converted the Value to string.
I tried to use the HashableValue, but it looks it is not very developed
yet and it was getting more complex and difficult.

This improves performance on large data sets.

Fixes https://github.com/nushell/nushell/issues/7477


# Tests + Formatting
```
> let data = fetch "https://home.treasury.gov/system/files/276/yield-curve-rates-1990-2021.csv"
> $data | uniq
```

it keeps original attribute order in Records:
```
> [ {b:2, a:1} {a:1, b:2} ] | uniq 
╭───┬───┬───╮
│ # │ b │ a │
├───┼───┼───┤
│ 0 │ 2 │ 1 │
╰───┴───┴───╯
```
2023-01-04 11:35:49 -08:00
f0e87da830 fix register-plugins script (#7677)
# Description

The register-plugins.nu script was broken on Windows where it was trying
to register files that ended in .d. Hopefully this will fix it once and
for all.

# User-Facing Changes



# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-04 11:22:54 -06:00
c5639cd9fa Primitives now use color closures when printed on the command line (#7650)
# Description

Closes #7554


![image](https://user-images.githubusercontent.com/83939/210177700-4890fcf2-1be9-4da9-9974-58d4ed403430.png)

# User-Facing Changes

See above.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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: Reilly Wood <26268125+rgwood@users.noreply.github.com>
2023-01-03 23:59:10 -08:00
95d4922e44 Make stream info visible to users in describe (#7589)
Closes #7581.

After this PR, `describe` shows `(stream)` next to input that arrived at
`describe` as a `ListStream`:
```bash
〉ls | describe
table<name: string, type: string, size: filesize, modified: date> (stream)
〉[1 2 3] | each {|i| $i} | describe
list<int> (stream)
```

`describe` must collect all items of the stream to display type
information for lists and tables. If users need to avoid collecting
input, they can use the `-n`/`--no-collect` flag:

```bash
〉[1 2 3] | each {|i| $i} | describe --no-collect
stream
```
2023-01-03 21:08:05 -08:00
bdd52f0111 Fix build-all-windows.cmd (#7674)
# Description

Fixed a minor scripting error 😀

Change a command in `build-all-windows.cmd`
`cargo build cargo build --features=dataframe` → `cargo build
--features=dataframe`


# User-Facing Changes

No

# Tests + Formatting

Yes
2023-01-03 18:31:36 -08:00
7bd07cb351 Reorder flags in nu --help (#7672)
The ordering of flags in `nu --help` was a bit of a mess; I think it
grew organically over time. Related commands (like
`--config`/`--env-config`/`--plugin-config`) weren't grouped together,
common flags weren't near the top, and we weren't following alphabetical
ordering.

### Before

```bash
Flags:
  -h, --help - Display the help message for this command
  --stdin - redirect standard input to a command (with `-c`) or a script file
  -l, --login - start as a login shell
  -i, --interactive - start as an interactive shell
  -v, --version - print the version
  --testbin <String> - run internal test binary
  -c, --commands <String> - run the given commands and then exit
  --config <String> - start with an alternate config file
  --env-config <String> - start with an alternate environment config file
  --log-level <String> - log level for diagnostic logs (error, warn, info, debug, trace). Off by default
  --log-target <String> - set the target for the log to output. stdout, stderr(default), mixed or file
  -e, --execute <String> - run the given commands and then enter an interactive shell
  -t, --threads <Int> - threads to use for parallel commands
  -m, --table-mode <String> - the table mode to use. rounded is default.
  --plugin-config <String> - start with an alternate plugin signature file
```

### After

```bash
Flags:
  -h, --help - Display the help message for this command
  -c, --commands <String> - run the given commands and then exit
  -e, --execute <String> - run the given commands and then enter an interactive shell
  -i, --interactive - start as an interactive shell
  -l, --login - start as a login shell
  -m, --table-mode <String> - the table mode to use. rounded is default.
  -t, --threads <Int> - threads to use for parallel commands
  -v, --version - print the version
  --config <String> - start with an alternate config file
  --env-config <String> - start with an alternate environment config file
  --plugin-config <String> - start with an alternate plugin signature file
  --log-level <String> - log level for diagnostic logs (error, warn, info, debug, trace). Off by default
  --log-target <String> - set the target for the log to output. stdout, stderr(default), mixed or file
  --stdin - redirect standard input to a command (with `-c`) or a script file
  --testbin <String> - run internal test binary
```

The new ordering:

1. Groups commands with short flags together, sorted alphabetically by
short flag
1. Groups commands with only long flags together, sorted alphabetically
(with the exception of `--plugin-config` so we can keep related flags
together)

Conveniently, this puts the very commonly used `-c` at the top and the
very rarely used `--testbin` at the bottom.
2023-01-03 16:18:37 -08:00
249afc5df4 Clarify url base command (#7670)
I noticed that the help for the `url` command was confusing (it wasn't
clear that `url` is just a base command that does nothing itself) and
the input type was also wrong. Fixed.

Before:
```bash
〉help url
Apply url function.

Search terms: network, parse

Usage:
  > url 

Subcommands:
  url parse - Parses a url

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

Signatures:
  <string> | url -> <string>
```

After:
```bash
〉help url
Various commands for working with URLs

You must use one of the following subcommands. Using this command as-is will only produce this help message.

Search terms: network, parse

Usage:
  > url 

Subcommands:
  url parse - Parses a url

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

Signatures:
  <nothing> | url -> <string>
  ```
2023-01-03 15:49:43 -08:00
d7af461173 Delete unused files (#7668)
Just tidying up a bit, deleting the unused files in `crates/old`. The
files can still be accessed in source control history if anyone needs
them.
2023-01-03 13:03:05 -08:00
b17e9f4ed0 Extend config support from F1-F12 to F1-F20, #7666 (#7669)
Co-authored-by: Piotr Meyer <aniou@smutek.pl>
2023-01-03 22:00:21 +01:00
6862734580 let start open anything and everything (#7580)
# Description

Fixes #7546 's request. I'm unsure, so hopefully someone in charge of
design can chip in.

# User-Facing Changes

`open` now opens directories in the default file manager.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-03 10:47:37 -08:00
9e1f645428 Fix save error handling (#7608)
Closes #5178

Modularizes `save` implementation
2023-01-03 14:22:28 +01:00
c4818d79f3 adding link to list of nu-plugins (#7649)
Co-authored-by: Stefan Holderbach <sholderbach@users.noreply.github.com>
2023-01-03 13:50:21 +01:00
d1a78a58cd revert changes on prepend and append (#7660)
# Description

#7623 causes a break on PATH convertion, this pr is going to revert
`prepend` and `append` bahavior.

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-02 17:09:55 -08:00
65d0b5b9d9 Make get hole errors and cell path hole errors identical (improvement on #7002) (#7647)
# Description

This closes #7498, as well as fixes an issue reported in
https://github.com/nushell/nushell/pull/7002#issuecomment-1368340773

BEFORE:
```
〉[{foo: 'bar'} {}] | get foo
Error: nu:🐚:column_not_found (link)

  × Cannot find column
   ╭─[entry #5:1:1]
 1 │ [{foo: 'bar'} {}] | get foo
   · ────────┬────────   ─┬─
   ·         │            ╰── value originates here
   ·         ╰── cannot find column 'Empty cell'
   ╰────

〉[{foo: 'bar'} {}].foo
╭───┬─────╮
│ 0 │ bar │
│ 1 │     │
╰───┴─────╯
```
AFTER:
```
〉[{foo: 'bar'} {}] | get foo
Error: nu:🐚:column_not_found (link)

  × Cannot find column
   ╭─[entry #1:1:1]
 1 │ [{foo: 'bar'} {}] | get foo
   ·               ─┬        ─┬─
   ·                │         ╰── cannot find column 'foo'
   ·                ╰── value originates here
   ╰────

〉[{foo: 'bar'} {}].foo
Error: nu:🐚:column_not_found (link)

  × Cannot find column
   ╭─[entry #3:1:1]
 1 │ [{foo: 'bar'} {}].foo
   ·               ─┬  ─┬─
   ·                │   ╰── cannot find column 'foo'
   ·                ╰── value originates here       
   ╰────
```

EDIT: This also changes the semantics of `get`/`select` `-i` somewhat.
I've decided to leave it like this because it works more intuitively
with `default` and `compact`.
BEFORE:
```
〉[{a:1} {b:2} {a:3}] | select -i foo | to nuon
null
```
AFTER:
```
〉[{a:1} {b:2} {a:3}] | select -i foo | to nuon
[[foo]; [null], [null], [null]]
```

# User-Facing Changes

See above. EDIT: the issue with holes in cases like ` [{foo: 'bar'}
{}].foo.0` versus ` [{foo: 'bar'} {}].0.foo` has been resolved.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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-01-02 14:45:43 -08:00
614bc2a943 early return for parsing closure and block with interchanged shape (#7618) 2023-01-01 12:26:51 +02:00
27b06358ea Tweak new input type error message (#7646)
A tiny follow-up from https://github.com/nushell/nushell/pull/7623,
changes "Only supports for specific input types" to "Input type not
supported"

Before:

```
〉"asdf" | append "foo"
Error: nu:🐚:only_supports_this_input_type (link)

  × Only supports for specific input types.
   ╭─[entry #2:1:1]
 1 │ "asdf" | append "foo"
   · ───┬──   ───┬──
   ·    │        ╰── only list, binary, raw data or range input data is supported
   ·    ╰── input type: string
   ╰────
```
   
After:
```
〉"asdf" | append "foo"
Error: nu:🐚:only_supports_this_input_type (link)

  × Input type not supported.
   ╭─[entry #2:1:1]
 1 │ "asdf" | append "foo"
   · ───┬──   ───┬──
   ·    │        ╰── only list, binary, raw data or range input data is supported
   ·    ╰── input type: string
   ╰────
```
2022-12-31 21:56:59 -08:00
e56c01d0e2 Simplify register-plugins.nu (#7636) 2022-12-31 18:32:34 -06:00
ececca7ad2 fix: ci problem (#7643) 2022-12-31 14:00:35 +02:00
e9cc417fd5 last, skip, drop, take until, take while, skip until, skip while, where, reverse, shuffle, append, prepend and sort-by raise error when given non-lists (#7623)
Closes https://github.com/nushell/nushell/issues/6941
2022-12-31 13:35:12 +02:00
81a7d17b33 return Error if get meet nothing and without "i" (#7002) 2022-12-31 13:27:09 +02:00
9382dd6d55 fix: empty cell in select (#7639) 2022-12-31 13:19:10 +02:00
7aa2a57434 def: make various punctuation misuses into errors (#7624)
Closes https://github.com/nushell/nushell/issues/7604
2022-12-31 13:18:53 +02:00
9b88ea5b60 Try to use the latest tagged virtualenv (#7638) 2022-12-31 12:26:01 +02:00
8bfcea8054 Expand Nushell's help system (#7611) 2022-12-30 17:44:37 +02:00
f3d2be7a56 doc: correct some really tiny typos. (#7635) 2022-12-30 13:18:28 +01:00
be31182969 Fix quoting of empty string in to nuon (#7632)
Closes https://github.com/nushell/nushell/issues/7631
2022-12-30 09:49:35 +01:00
b543063749 Fix the syntax highlighting in help metadata (#7628) 2022-12-29 17:45:55 +01:00
ce0060e6b0 Update Cargo.lock to powierza-coefficient 1.0.2 (#7629)
Follow-up to #7625
2022-12-29 17:40:11 +01:00
35b12fe5ec Fix usage of deprecated C-style logical and (#7627)
n untested examples we still had `&&`
2022-12-29 16:47:33 +01:00
6ac26094da Slight edits to ls and zip's help text (#7626) 2022-12-29 16:24:08 +01:00
8c6a0f68d4 Update powierza-coefficient to 1.0.2 (#7625) 2022-12-29 15:55:00 +01:00
f5d6672ccf Disallow ^ in def command names (#7606)
# Description

Closes #7273.

Also slightly edits/tidies up parser.rs.

# User-Facing Changes

`^` is now forbidden in `def` and `def-env` command names. EDIT: also
`alias`.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-27 15:00:44 -08:00
db06edc5d3 add --mime-type(-m) to ls in the type column (#7616)
# Description

This PR adds the `mime-type` to the `type` column if you add the
`--mime-type(-m)` flag to `ls`.
<img width="853" alt="Screenshot 2022-12-27 at 11 43 20 AM"
src="https://user-images.githubusercontent.com/343840/209705499-27fe40fe-0356-4d9d-97f2-4b2dc52e0963.png">

<img width="781" alt="Screenshot 2022-12-27 at 11 45 53 AM"
src="https://user-images.githubusercontent.com/343840/209705509-4d677389-fd68-401e-a7af-3fc6052743b6.png">

# User-Facing Changes

If you specify the `-m` flag, you get the "guessed at" mime type. The
guess is based on the file name and uses this crate
https://docs.rs/mime_guess/latest/mime_guess/ for the guessing.

Part of issue #7612 and and #7524

There's some debate on if the `mime-type` should be added to the `type`
column or if there should be a separate `mime` column. I tend to lean on
the side of `type` since it's technically a type and it's only in that
column if you ask it to be there. Also, I'd prefer to reuse a column
rather than having a list of sprawling columns. Also, as @KodiCraft
suggested, there is precedence as with `ls -d` where the summed size is
in the size column.

I could go either way and if someone wants to create a `mime` column,
we'd probably accept it.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-27 12:46:23 -06:00
568927349d Fix and Allow Number and Boolean type to be key in from yaml (#7607)
Fix and Allow Number and Boolean type to be key in Yaml .

For example : 
`"200 : " | from yaml` not allowed because of Number key type.

PR allow , we can use Boolean and Number for key. 
For example :
`"true : false" | from yaml`
`"5050 : it is number" | from yaml`

Fixes #7222 .
2022-12-27 08:28:24 -08:00
4f812a7f34 Fix table expand wrap in case no header is there (#7605)
ref #7598

To be honest I was not able to obtain such results in basic mode as you
@rgwood.
But I've got it in `table -e`.

So this must fix the `table -e` wrapping.

Could you verify if it got fixed?

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2022-12-27 07:44:34 -06:00
38fc42d352 Fix const examples (#7610)
# Description

Fix const examples

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
2022-12-27 15:44:03 +08:00
b4c5693ac6 Fix an example of env command (#7603)
# Description

Fix an example of `env` command

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-26 16:40:34 +08:00
79000aa5e0 Fix typos by codespell (#7600)
# Description

Found via `codespell -S target -L
crate,ser,numer,falsy,ro,te,nd,bu,ndoes,statics,ons,fo,rouge,pard`

# User-Facing Changes

None.

# Tests + Formatting

None and done.

# After Submitting

None.
2022-12-26 02:31:26 -05:00
2415381682 fix python plugin example (#7599)
# Description

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

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

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-24 18:31:44 -06:00
b499e7c682 Fix some issues with table wrapping of lists (#7598)
close #7591 

I tend to think it must be addressed.
But I'd verify it @rgwood.

PS: I've noticed how `table -e` and `table` with the same width wraps a
bit differently sometimes. (I guess it also must be addressed......)

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2022-12-24 18:27:34 -06:00
d8cde2ae89 Include clippy check for dataframe in CI (#7596) 2022-12-24 22:44:52 +01:00
ddc00014be To toml fix (#7597)
# Description

Fixes #7510 .
Remove support for tables from `to toml` command and update description.
Previously, as indicated in #7510 , a table could be converted to toml
and would result in this invalid toml:


![image](https://user-images.githubusercontent.com/17511668/209443930-c3dd3a3f-5ffd-4273-9c10-acbb345c788e.png)

This commit removes functionality of serializing tables and now `to
toml` produces an error:


![image](https://user-images.githubusercontent.com/17511668/209443975-be119465-8946-4644-8994-489ca94f6006.png)

The `from toml` command already acknowledges the fact that toml can
contain only records as indicated in its signature


![image](https://user-images.githubusercontent.com/17511668/209443995-1590d044-a790-4be3-a967-b26292a6e70c.png)

Now help of `to toml` reflects this feature of format as well:


![image](https://user-images.githubusercontent.com/17511668/209444014-7cfe8f8e-ad8a-4845-a151-24df6b99a1a2.png)

Additionally new tests were created for `to toml` command. See
`crates\nu-command\tests\format_conversions\toml.rs`.

Also removed undocumented behavior that would accept and validate a
string as toml:


![image](https://user-images.githubusercontent.com/17511668/209449482-5d876074-fc5b-4b21-b8a5-64e643a50083.png)


# User-Facing Changes

- Serializing tables to toml now produces error instead of invalid toml
- Updated `to toml` help
- Remove undocumented "validation" (not really user-facing)

# Tests + Formatting

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

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

- [x] `cargo fmt --all -- --check` to check standard code formatting
(`cargo fmt --all` applies these changes)
- [x] `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- [x] `cargo test --workspace` to check that all tests pass

# 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.
2022-12-24 15:12:09 -06:00
9ffa3e55c2 Fix #6888 and rename fill-na to fill-nan (#7565)
Co-authored-by: sholderbach <sholderbach@users.noreply.github.com>
Fixes https://github.com/nushell/nushell/issues/6888
2022-12-24 16:04:46 +01:00
45fe3be83e Further cleanup of Span::test_data usage + span fixes (#7595)
# Description

Inspired by #7592

For brevity use `Value::test_{string,int,float,bool}`

Includes fixes to commands that were abusing `Span::test_data` in their
implementation. Now the call span is used where possible or the explicit
`Span::unknonw` is used.

## Command fixes
- Fix abuse of `Span::test_data()` in `query_xml`
- Fix abuse of `Span::test_data()` in `term size`
- Fix abuse of `Span::test_data()` in `seq date`
- Fix two abuses of `Span::test_data` in `nu-cli`
- Change `Span::test_data` to `Span::unknown` in `keybindings listen`
- Add proper call span to `registry query`
- Fix span use in `nu_plugin_query`
- Fix span assignment in `select`
- Use `Span::unknown` instead of `test_data` in more places

## Other
- Use `Value::test_int`/`test_float()` consistently
- More `test_string` and `test_bool`
- Fix unused imports


# User-Facing Changes

Some commands may now provide more helpful spans for downstream use in
errors
2022-12-24 07:41:57 -06:00
dd6fe6a04a Add extra_usage messages for subcommand-only commands (#7594)
# Description

The message reads "You must use one of the following subcommands. Using
this command as-is will only produce this help message." and is added to
commands like `into`, `bytes`, `str`, etc.

# User-Facing Changes

See above.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-24 07:16:29 -06:00
e76b38882c columns now errors when given a non-record non-table (#7593)
# Description

This is for consistency with the new `values` command. Previously it
would return a completely empty record (??!) when given an
incorrectly-typed value.

# User-Facing Changes

See title.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-24 07:08:25 -06:00
11bdab7e61 Change instances of Value::string("foo", Span::test_data()) to Value::test_string("foo") (#7592) 2022-12-24 10:25:38 +01:00
3d682fe957 Fix error message when interrupting table with ctrl+c (#7588)
`table` was displaying an incorrect "Couldn't fit table into X columns!"
error when streaming was interrupted by `ctrl+c`:

![image](https://user-images.githubusercontent.com/26268125/209415204-cc20964b-fc43-42a0-867f-1b01cefb3213.png)

This PR fixes that:

![image](https://user-images.githubusercontent.com/26268125/209415163-b3041357-7f16-4a17-b15a-170b4d50f5ee.png)
2022-12-23 16:38:38 -08:00
a43e66ef92 Add LRU regex cache (#7587)
Closes #7572 by adding a cache for compiled regexes of type
`Arc<Mutex<LruCache<String, Regex>>>` to `EngineState` .

The cache is limited to 100 entries (limit chosen arbitrarily) and
evicts least-recently-used items first.

This PR makes a noticeable difference when using regexes for
`color_config`, e.g.:
```bash
#first set string formatting in config.nu like:
string: { if $in =~ '^#\w{6}$' { $in } else { 'white' } }`

# then try displaying and exploring a table with many strings
# this is instant after the PR, but takes hundreds of milliseconds before
['#ff0033', '#0025ee', '#0087aa', 'string', '#4101ff', '#ff0033', '#0025ee', '#0087aa', 'string', '#6103ff', '#ff0033', '#0025ee', '#0087aa', 'string', '#6103ff', '#ff0033', '#0025ee', '#0087aa', 'string', '#6103ff', '#ff0033', '#0025ee', '#0087aa', 'string', '#6103ff','#ff0033', '#0025ee', '#0087aa', 'string', '#6103ff','#ff0033', '#0025ee', '#0087aa', 'string', '#6103ff','#ff0033', '#0025ee', '#0087aa', 'string', '#6103ff','#ff0033', '#0025ee', '#0087aa', 'string', '#6103ff','#ff0033', '#0025ee', '#0087aa', 'string', '#6103ff']
```

## New dependency (`lru`)
This uses [the popular `lru` crate](https://lib.rs/crates/lru). The new
dependency adds 19.8KB to a Linux release build of Nushell. I think this
is OK, especially since the crate can be useful elsewhere in Nu.
2022-12-23 14:30:04 -08:00
3be7996e79 add metadata to wrap (#7586)
# Description

This PR allows `wrap` to pass through metadata.

# User-Facing Changes

This change allows this:
<img width="789" alt="Screenshot 2022-12-23 at 3 12 37 PM"
src="https://user-images.githubusercontent.com/343840/209406010-1da9b814-1892-4961-bb01-9f88ddc83474.png">
Instead of this:
<img width="786" alt="Screenshot 2022-12-23 at 3 12 48 PM"
src="https://user-images.githubusercontent.com/343840/209406021-6e5eb860-0911-42c4-a39e-5fe76c61af03.png">

Strangely enough, this command doesn't result in LS_COLORS `(ls |
values).0 | wrap name`

/cc @webbedspace - we were talking about LS_COLORS in `values` earlier.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-23 15:56:28 -06:00
5041a4ffa3 Re-enable test_bits (#7585)
The tests in `src/tests/test_bits.rs` weren't being run because we were
missing a `mod test_bits;`. Fixed.
2022-12-23 11:19:10 -08:00
b16b3c0b7f Add values command (see #7166) (#7583) 2022-12-23 12:49:19 -06:00
852ec3f9a0 Fix signatures of commands which accept records also (#7582)
# Description

Certain commands that operate on tables also work on bare records, but
their type sig didn't reflect that. This corrects this.

I did not fix certain commands which, I feel, currently give unintended
behaviour when given plain records. These are `sort-by` and `uniq-by`.

Also corrected the wording of some stuff in headers.rs, and removed a
wrong comment in insert.rs.

# User-Facing Changes

See above.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-23 07:38:37 -06:00
dd7b7311b3 Standardise the use of ShellError::UnsupportedInput and ShellError::TypeMismatch and add spans to every instance of the former (#7217)
# Description

* I was dismayed to discover recently that UnsupportedInput and
TypeMismatch are used *extremely* inconsistently across the codebase.
UnsupportedInput is sometimes used for input type-checks (as per the
name!!), but *also* used for argument type-checks. TypeMismatch is also
used for both.
I thus devised the following standard: input type-checking *only* uses
UnsupportedInput, and argument type-checking *only* uses TypeMismatch.
Moreover, to differentiate them, UnsupportedInput now has *two* error
arrows (spans), one pointing at the command and the other at the input
origin, while TypeMismatch only has the one (because the command should
always be nearby)
* In order to apply that standard, a very large number of
UnsupportedInput uses were changed so that the input's span could be
retrieved and delivered to it.
* Additionally, I noticed many places where **errors are not propagated
correctly**: there are lots of `match` sites which take a Value::Error,
then throw it away and replace it with a new Value::Error with
less/misleading information (such as reporting the error as an
"incorrect type"). I believe that the earliest errors are the most
important, and should always be propagated where possible.
* Also, to standardise one broad subset of UnsupportedInput error
messages, who all used slightly different wordings of "expected
`<type>`, got `<type>`", I created OnlySupportsThisInputType as a
variant of it.
* Finally, a bunch of error sites that had "repeated spans" - i.e. where
an error expected two spans, but `call.head` was given for both - were
fixed to use different spans.

# Example
BEFORE
```
〉20b | str starts-with 'a'
Error: nu:🐚:unsupported_input (link)

  × Unsupported input
   ╭─[entry #31:1:1]
 1 │ 20b | str starts-with 'a'
   ·   ┬
   ·   ╰── Input's type is filesize. This command only works with strings.
   ╰────

〉'a' | math cos
Error: nu:🐚:unsupported_input (link)

  × Unsupported input
   ╭─[entry #33:1:1]
 1 │ 'a' | math cos
   · ─┬─
   ·  ╰── Only numerical values are supported, input type: String
   ╰────

〉0x[12] | encode utf8
Error: nu:🐚:unsupported_input (link)

  × Unsupported input
   ╭─[entry #38:1:1]
 1 │ 0x[12] | encode utf8
   ·          ───┬──
   ·             ╰── non-string input
   ╰────
```
AFTER
```
〉20b | str starts-with 'a'
Error: nu:🐚:pipeline_mismatch (link)

  × Pipeline mismatch.
   ╭─[entry #1:1:1]
 1 │ 20b | str starts-with 'a'
   ·   ┬   ───────┬───────
   ·   │          ╰── only string input data is supported
   ·   ╰── input type: filesize
   ╰────

〉'a' | math cos
Error: nu:🐚:pipeline_mismatch (link)

  × Pipeline mismatch.
   ╭─[entry #2:1:1]
 1 │ 'a' | math cos
   · ─┬─   ────┬───
   ·  │        ╰── only numeric input data is supported
   ·  ╰── input type: string
   ╰────

〉0x[12] | encode utf8
Error: nu:🐚:pipeline_mismatch (link)

  × Pipeline mismatch.
   ╭─[entry #3:1:1]
 1 │ 0x[12] | encode utf8
   · ───┬──   ───┬──
   ·    │        ╰── only string input data is supported
   ·    ╰── input type: binary
   ╰────
```

# User-Facing Changes

Various error messages suddenly make more sense (i.e. have two arrows
instead of one).

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-23 01:48:53 -05:00
9364bad625 Make to text stream ListStreams (#7577)
This PR changes `to text` so that when given a `ListStream`, it streams
the incoming values instead of collecting them all first.

The easiest way to observe/verify this PR is to convert a list to a very
slow `ListStream` with `each`:
```bash
ls | get name | each {|n| sleep 1sec; $n} | to text
```
The `to text` output will appear 1 item at a time.
2022-12-22 16:38:07 -08:00
6fc5244439 tighter restrictions on alias and def names (#7392)
# Description

Prevent a situation where a `def` can't be run due to a poor choice of
name. Related: #6335. Hashtags, numbers and filesizes are no longer
allowed. `alias` check has been moved because previously `alias 123`
would be caught but `alias "123"` would be permitted.

# User-Facing Changes

Some definitions can no longer be made, but because they couldn't be run
previously anyway, it doesn't really matter.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-22 12:31:34 -08:00
8e1112c1dd Change other instances of $nothing to null (#7569)
# Description

Purely for consistency, various remaining instances of `$nothing`
(almost all of which were in test code) have been changed to `null`.
Now, the only place that refers to `$nothing` is the parser code which
implements it.

# User-Facing Changes

The default config.nu now uses `null` in certain places where it used
`$nothing`.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-22 12:30:10 -08:00
9d1cb1bfaf Make $in work in catch closures (#7458)
# Description

This now works:
```
try { 'x' | math abs } catch { $in }
```

# User-Facing Changes

See above.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-22 09:35:41 -06:00
216d7d035f Add cross-rs config (#7559)
Cross-compiling Nu can be a little tricky due to dependencies. This PR
makes it easy to use [`cross-rs`](https://github.com/cross-rs/cross), a
popular tool for cross-compiling Rust code using Docker:
```bash
cross build --target aarch64-unknown-linux-musl --release
```

I find this useful for compiling ARM binaries from x64. Easy to add more
target triples later as needed.
2022-12-22 08:52:07 -06:00
ead6fbdf9c let case_insensitive option work for variable completion as well (#7539)
# Description

Fixes #7529.

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-22 08:50:59 -06:00
5b616770df Make config.filesize_format/config.filesize_metric conflict resolution consistent (#7410)
# Description

Currently, `filesize_format`/`filesize_metric` conflicts are resolved as
follows: if the `filesize_format` ends in "ib", then that overrides
`filesize_metric`, otherwise, `filesize_metric` overrides
`filesize_format`. This removes this difficult-to-predict asymmetric
behaviour, and makes it so that `filesize_metric` always overrides
`filesize_format`.

This also adds tests for `$env.config.filesize.format` and
`$env.config.filesize.metric` values.

REMINDER: `filesize_metric` means "increments of 1000", and refers to
KB-MB-GB-TB etc.

# User-Facing Changes

See above.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# After Submitting

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

Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2022-12-22 08:46:55 -06:00
23a5c5dc09 Remove shape-directed import pattern parsing (#7570) 2022-12-22 16:36:13 +02:00
74656bf976 Fix #7551 record support in color_config (#7567)
Closes https://github.com/nushell/nushell/issues/7551
2022-12-22 12:55:50 +01:00
d8a2e0e9a3 Small parser refactors (#7568) 2022-12-22 13:41:44 +02:00
046e46b962 avoid panic when using from nuon (#7533)
# Description

Fixes #5996 

Just found a relative easy way to fix the issue

# User-Facing Changes

```
❯ open $nu.plugin-path | from nuon
Error:
  × error when loading nuon text
   ╭─[entry #36:1:1]
 1 │ open $nu.plugin-path | from nuon
   ·                        ────┬────
   ·                            ╰── could not load nuon text
   ╰────

Error:
  × Error when loading


❯ open $nu.config-path | from nuon
Error:
  × error when loading nuon text
   ╭─[entry #37:1:1]
 1 │ open $nu.config-path | from nuon
   ·                        ────┬────
   ·                            ╰── could not load nuon text
   ╰────

Error:
  × error when loading
```

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-21 16:42:23 -08:00
ec08e4bc6d Fix && quotation in to nuon after proptest fail (#7564)
`proptest` caught a failing test condition for `&&` as a literal string. It requires a quotation to be parsed correctly by current `from nuon`
    
https://github.com/nushell/nushell/actions/runs/3753242377/jobs/6376308675

The change in the parser that now returns an error was introduced by https://github.com/nushell/nushell/pull/7241

This in theory doesn't have to be an error (it is a diagnostic for nushell code) but it is probably better safe than sorry to require quotation here.

- Add a test for `&&` in `to nuon` from proptest fail
- Fix `to nuon` generating invalid `&&` literal
- Add a test for `,` in `to nuon`/`from nuon` cycle
  - Bonus: should already be properly quoted
2022-12-22 00:36:07 +01:00
05e07ddf5c Add some cell path tests (#7563) 2022-12-21 23:54:39 +01:00
757d7479af Add "fall-through" signatures (#7527)
Fixes https://github.com/nushell/nushell/issues/4659
Fixes https://github.com/nushell/nushell/issues/5294
Fixes https://github.com/nushell/nushell/issues/6124
fix https://github.com/nushell/nushell/issues/5103
2022-12-22 00:33:26 +02:00
440feaf74a Clarify --stdin flag (#7541)
Just change the description of the `--stdin` flag as shown in `nu
--help`:

"redirect the stdin" -> "redirect standard input to a command (with
`-c`) or a script file"

The old description was a little too terse and I had to look in the code
to see what it was doing.
2022-12-21 14:30:53 -08:00
22c50185b5 table: Check stream timeout on every item (#7509)
`table` handles slow `ListStream`s in a special way: every 100 items, it
checks whether 1 second has elapsed since the last table page, and if so
it outputs a new page with all the items in its buffer.

**I would like to remove the "every 100 items" condition and always
output whatever we have if a second has elapsed.** I think this will be
a better user experience for very slow streams.

As a motivating example, imagine tailing a log file and doing some
string parsing/projection on each line. The user will be really annoyed
if they have to wait for 100 lines to be written to the log before
seeing new results!

I did some quick performance measurements with Criterion, and the
elapsed-time check takes about 16ns on my machine (Linux, 12900k). I
think the performance impact of checking that for every item will be
negligible.
2022-12-21 14:28:27 -08:00
3a2c7900d6 Initial support for parse-time constants (#7436) 2022-12-22 00:21:03 +02:00
fa8629300f chore: make the config setup messages consistent (#7560) 2022-12-21 23:16:08 +01:00
37dc226996 Remove preview.rs (#7555)
Leftover from `explore` development

Closes https://github.com/nushell/nushell/issues/7553
2022-12-21 21:51:30 +01:00
4e1f94026c Add more input/output type annotations (#7532) 2022-12-21 20:20:46 +01:00
d27263af97 Bump to new development version 0.73.1 (#7544) 2022-12-21 12:35:50 -06:00
215f1af1da fix the wix file to overwrite with save -f (#7545) 2022-12-21 12:34:49 -06:00
JT
1291b647ae bump to 0.73 (#7542)
# Description

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

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

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-20 21:58:48 +13:00
91df6c236f Remove unused deps or move to devdeps (#7537)
# Description

General tree shaking through `cargo +nightly udeps` and moving mentions
of `nu-test-support` to the dev deps.

Also since #7488 no separate import of `nu-path` necessary

cc @webbedspace
2022-12-20 12:53:17 +13:00
JT
58cea7e8b4 Turn off cd abbreviations by default (#7536)
# Description

This turns off `cd` abbreviations by default

# User-Facing Changes

`cd` goes back to requiring a name with the default configuration

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-19 13:32:24 -08:00
b01f50bd70 nu-explore/ Fix configuration issues (#7520)
close #7518

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2022-12-19 11:34:21 -06:00
5f48452e3b some filesystem command signatures (#7464)
# Description

Signature for the following commands:

- `cd` 
- `cp` 
- `glob` 
- `ls` 
- `mkdir` 
- `mv` 
- `open`
- `rm`
- `save`
- `touch`

Related to https://github.com/nushell/nushell/issues/7320

Co-authored-by: sholderbach <sholderbach@users.noreply.github.com>
2022-12-19 13:40:57 +01:00
dae1b9a996 prevent panic with format command (#7522)
Related: #7211.

Prevents numeric underflow in span.

Co-authored-by: sholderbach <sholderbach@users.noreply.github.com>
2022-12-19 13:10:02 +01:00
a21af0ade4 Revert "into cellpath command (#7417)" (#7523)
This reverts commit f0e93c2fa9 (PR #7417).

I'm currently [working on improving cell
paths](https://github.com/nushell/nushell/issues/7498#issuecomment-1356834798),
and I realized that I would need to make several improvements to `into
cellpath` along the lines of Jakub's comment here:
https://github.com/nushell/nushell/pull/7417#issuecomment-1345264955

I don't think `into cellpath` is quite ready for prime-time, and I'd
like to remove it before the upcoming release.
2022-12-18 23:02:18 -08:00
28123841ba Patch explore 4 (#7517)
ref #7339 - This PR updates explore to take some of the colors from
nushell, namely the line colors and the ls_colors.

note: Not sure why this regression appeared maybe it's a feature or it's
no longer supposed to be supported?

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2022-12-18 08:43:15 -06:00
183be911d0 Patch after fix after fix 7380 (#7501)
> I'm not sure how i feel about that. I mean if there are a lot of
columns, it should probably have a max width so 1 column doesn't take
the entire width of your screen. Ideally it would work closely like
table worked before we migrated to tabled, as far as how column widths
were allocated.

I believe it still not completely matched.
*To be honest I am not against the #7446 approach.

The PR makes a switch between logics on a premise of `termwidth`.
So if `termwidth > 120` we start prioritizing amount of columns we can
show (We try to show as many columns as we can).
Otherwise we do what I've described in #7446 (We show the least columns
but with least truncation involvement).

In case it's OK,
I guess we could make the value configurable.

cc @fdncred 
ref #7446

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2022-12-17 16:16:32 -06:00
1966809502 explore tweaks Round 1 (#7511)
A few small tweaks to the new `explore` command:

1. Rewrote the help text a bit.
    1. I think it's important to mention `:try` up front.
2. Removed the info about `:help foo` because it's currently supported
by very few subcommands
2. Make `exit_esc` default to true. I want to avoid people getting stuck
in `explore` like they get stuck in Vim
3. ~~Always show the help message ("For help type :help") on startup~~
1. The message is small+unobtrusive and I don't this is worth a
configuration item
4. Exit the information view when Escape is pressed
5. General typo+grammar cleanup
    
cc: @zhiburt @fdncred
2022-12-17 12:05:41 -08:00
c3c41a61b0 replace lazy_static with once_cell (#7502)
replacing the dependence on `lazy_static` with `once_cell`, this will
ensure that variables are initialized when needed instead of startup
time.
2022-12-17 10:30:04 -08:00
90849a067f Fix encode base64 type signature and examples (#7515)
# Description

See title.

# User-Facing Changes

See title.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-17 11:57:16 -06:00
705f12c1d9 Fix cell path when getting columns of non-records (#7508)
A follow-up to #7497. That change made it so that `get foo` would
eliminate non-record rows; I think that was an unintentional and
undesirable side-effect.

Before #7497:
```bash
〉[$nothing, { item: "foo" }] | get item
╭───┬─────╮
│ 0 │     │
│ 1 │ foo │
╰───┴─────╯
```
After #7497:
```bash
〉[$nothing, {item: "foo"}] | get item
╭───┬─────╮
│ 0 │ foo │
╰───┴─────╯
```

After this PR:
```bash
〉[$nothing, { item: "foo" }] | get item
╭───┬─────╮
│ 0 │     │
│ 1 │ foo │
╰───┴─────╯
```

cc: @merelymyself
2022-12-17 09:14:12 -08:00
0826e66fe0 add xterm color names to ansi --list (#7513)
# Description

Follow up to #7141 to map @webbedspace's rgb colors to xterm 256 color
indexes. Also added the xterm 256 named colors to `ansi --list` in the
process.

The few dozen or so names that were duplicate in the xterm 256 names
from [here](https://www.ditig.com/256-colors-cheat-sheet) were renamed
by appending a,b,c,d. So, instead of two blue3's there will be blue3a
and blue3b.

# User-Facing Changes

More colors.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-17 11:10:14 -06:00
774769a7ad color_config now accepts closures as color values (#7141)
# Description

Closes #6909. You can now add closures to your `color_config` themes.
Whenever a value would be printed with `table`, the closure is run with
the value piped-in. The closure must return either a {fg,bg,attr} record
or a color name (`'light_red'` etc.). This returned style is used to
colour the value.

This is entirely backwards-compatible with existing config.nu files.

Example code excerpt:
```
let my_theme = {
    header: green_bold
    bool: { if $in { 'light_cyan' } else { 'light_red' } }
    int: purple_bold
    filesize: { |e| if $e == 0b { 'gray' } else if $e < 1mb { 'purple_bold' } else { 'cyan_bold' } }
    duration: purple_bold
    date: { (date now) - $in | if $in > 1wk { 'cyan_bold' } else if $in > 1day { 'green_bold' } else { 'yellow_bold' } }
    range: yellow_bold
    string: { if $in =~ '^#\w{6}$' { $in } else { 'white' } }
    nothing: white
```
Example output with this in effect:
![2022-11-16 12 47 23 AM - style_computer
rs_-_nushell_-_VSCodium](https://user-images.githubusercontent.com/83939/201952558-482de05d-69c7-4bf2-91fc-d0964bf71264.png)
![2022-11-16 12 39 41 AM - style_computer
rs_-_nushell_-_VSCodium](https://user-images.githubusercontent.com/83939/201952580-2384bb86-b680-40fe-8192-71bae396c738.png)
![2022-11-15 09 21 54 PM - run_external
rs_-_nushell_-_VSCodium](https://user-images.githubusercontent.com/83939/201952601-343fc15d-e4a8-4a92-ad89-9a7d17d42748.png)

Slightly important notes:

* Some color_config names, namely "separator", "empty" and "hints", pipe
in `null` instead of a value.
* Currently, doing anything non-trivial inside a closure has an
understandably big perf hit. I currently do not actually recommend
something like `string: { if $in =~ '^#\w{6}$' { $in } else { 'white' }
}` for serious work, mainly because of the abundance of string-type data
in the world. Nevertheless, lesser-used types like "date" and "duration"
work well with this.
* I had to do some reorganisation in order to make it possible to call
`eval_block()` that late in table rendering. I invented a new struct
called "StyleComputer" which holds the engine_state and stack of the
initial `table` command (implicit or explicit).
* StyleComputer has a `compute()` method which takes a color_config name
and a nu value, and always returns the correct Style, so you don't have
to worry about A) the color_config value was set at all, B) whether it
was set to a closure or not, or C) which default style to use in those
cases.
* Currently, errors encountered during execution of the closures are
thrown in the garbage. Any other ideas are welcome. (Nonetheless, errors
result in a huge perf hit when they are encountered. I think what should
be done is to assume something terrible happened to the user's config
and invalidate the StyleComputer for that `table` run, thus causing
subsequent output to just be Style::default().)
* More thorough tests are forthcoming - ran into some difficulty using
`nu!` to take an alternative config, and for some reason `let-env config
=` statements don't seem to work inside `nu!` pipelines(???)
* The default config.nu has not been updated to make use of this yet. Do
tell if you think I should incorporate that into this.

# User-Facing Changes

See above.

# 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 --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass

# 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.
2022-12-17 07:07:56 -06:00
e72cecf457 Remove unnecessary echo uses from examples (#7500)
`echo` tends to confuse new Nu users; they expect it to work like
`print` when it just passes a value to the next stage of the pipeline.

We haven't quite figured out what to do about `echo` in the long run,
but I think a good start is to remove `echo` from command examples where
it would be unnecessary and arguably unidiomatic.
2022-12-16 11:51:00 -05:00
9c1a3aa244 nu-explore/ A few things (#7339)
ref #7332

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2022-12-16 09:47:07 -06:00
2d07c6eedb ensure get doesn't delve too deep in nested lists (#7497)
# Description

Fixes #7494.

```
/home/gabriel/CodingProjects/nushell〉[[{foo: bar}]] | get foo          12/16/2022 12:31:17 PM
Error: nu::parser::not_found (link)

  × Not found.
   ╭─[entry #1:1:1]
 1 │ [[{foo: bar}]] | get foo
   · ───────┬──────
   ·        ╰── did not find anything under this name
   ╰────

```

# User-Facing Changes

cell paths no longer drill into nested tables.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-15 22:03:38 -08:00
JT
fdd92b2dda Update README.md 2022-12-16 18:50:37 +13:00
8c70189422 (nu_plugin_python): Send back the signature required fields. (#7489)
# Description

The `Signature` data structure has changed. We need to add the required
fields for the nu plugin in python to work well when registering it.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
2022-12-15 14:37:12 -06:00
075c83b3a1 add new plugins to script (#7493)
# Description

This PR adds more plugins to the match statement and documents the
plugin repos as comments.

# User-Facing Changes



# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-15 14:36:14 -06:00
d3a19c5ac7 (register-plugins.nu): Filter out files ending with .d on systems other than windows. (#7492) 2022-12-15 14:00:48 -06:00
080874df10 Fix #7486 (#7487)
close #7486

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2022-12-15 09:55:15 -08:00
24848a1e35 Use nu-path correctly in nu! test macro to make dev-dependency transitive (#7488)
## Fix `nu-path` usage in `nu!` testing macro

The `nu-path` crate needs to be properly re-exported so the generated
code is valid if `nu-path` is not present among the dependencies of the
using crate.

Usage of crates in `macro_rules!` macros has to follow the
`$crate::symbol_in_crate` path pattern (With an absolute path-spec also
for macros defined in submodules)

## Move `nu-test-support` to devdeps in `nu-protocol`

Also remove the now unnecessary direct dependency on `nu-path`.
`nu!` macro had to be changed to make it a proper transitive dependency.
2022-12-15 18:53:26 +01:00
e215fbbd08 Add helper method to check whether ctrl+c was pressed, adopt it (#7482)
I've been working on streaming and pipeline interruption lately. It was
bothering me that checking ctrl+c (something we want to do often) always
requires a bunch of boilerplate like:
```rust
use std::sync::atomic::Ordering;

if let Some(ctrlc) = &engine_state.ctrlc {
     if ctrlc.load(Ordering::SeqCst) {
          ...
```
I added a helper method to cut that down to:

```rust
if nu_utils::ctrl_c::was_pressed(&engine_state.ctrlc) {
    ...
```
2022-12-15 09:39:24 -08:00
33aea56ccd Try to fix #7380 (#7446)
fix https://github.com/nushell/nushell/issues/7380
2022-12-15 08:47:04 -06:00
b6683a3010 add --long flag to history command for sqlite history (#7480) 2022-12-15 08:46:32 -06:00
578ef04988 remove output, append, bin flag from fetch command (#7468)
Closes https://github.com/nushell/nushell/issues/7439
2022-12-14 16:44:04 -06:00
735a7a21bd Add example showing first class closure to do (#7473)
# Description

Demonstrates that you can use `do` to execute stored closures and
evaluate their captures properly.

# Tests + Formatting

As an example test increases coverage of the usage to execute first
class closures.
Additional tests using that found in
`tests/shell/pipeline/commands/internal.rs`
2022-12-14 20:55:00 +01:00
80a69224f7 Handle ctrl-c in uniq and uniq-by (#7478)
A partial fix for #7477. `uniq` can be slow sometimes, so we should
check `ctrl-c` when it's running.

Tested on [this
file](https://home.treasury.gov/system/files/276/yield-curve-rates-1990-2021.csv),
I ran `open yield-curve-rates-1990-2021.csv | uniq` and confirmed that I
can now cancel the operation.

Future work is needed to figure out why `uniq` is so slow.
2022-12-14 11:31:54 -08:00
e0bf17930b refactor: introduce is_external_failed to PipelineData, and simplify try logic (#7476)
# Description

Just spot that there are some duplicate code about checking external
runs to failed, is pr is trying to refactor it and reduce lines of code

# User-Facing Changes

NaN

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-14 10:25:32 -08:00
db3177a5aa break for, loop, while execution when external command runs to failed (#7475)
Fixes: #7467

# User-Facing Changes

## for
```
❯ for i in 1..2 { echo 1;  ^false }
1
```

## loop
```
❯ loop { echo bb; ^false }
bb
```

## while
```
❯ mut x = 1; while $x < 3 { $x = $x + 1; echo bb; ^false }
bb
```
2022-12-14 16:20:18 +01:00
98b9839e3d Fix for escaping backslashes in interpolated strings (fixes #6737) (#7119)
Co-authored-by: Gavin Foley <gavinmfoley@gmail.com>
2022-12-14 07:54:13 -06:00
0db4d89838 add missing shapes to default_config (#7472)
# Description

We've added some shapes recently. This PR adds them to the
default_config and sorts them in order to make finding missing ones
easier.

# User-Facing Changes


# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-14 07:11:17 -06:00
52278f8562 Help messages: edit various instances of "block" to "closure" (#7470) 2022-12-14 14:02:41 +01:00
c19d9597fd Add riscv64 binary release target (#7469)
# Description

Add `riscv64gc-unknown-linux-gnu` release target

TEST release workflow:
https://github.com/hustcer/nu-release/actions/runs/3693191329
TEST release: https://github.com/hustcer/nu-release/releases/tag/v0.73.0

# User-Facing Changes

New `nu-*-riscv64gc-unknown-linux-gnu.tar.gz` package will be added to
the following release

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-14 23:09:39 +13:00
d9d9916ccc Fix streaming page missing newline (#7466)
Fixes #7342. `0..1000 | table` before this change:


![image](https://user-images.githubusercontent.com/26268125/207474492-dead4267-d828-4840-8da0-4edfda3e3916.png)

`0..1000 | table` after this change:


![image](https://user-images.githubusercontent.com/26268125/207474583-26633db0-46c5-4c30-8681-654855e7042b.png)

When piping data to `table`, pages were not getting a newline at the
end[^1]. This problem was uncovered and exacerbated by the new
`display_output` hook which implicitly piped _everything_ to `table`.

## The Fix

`PagingTableCreator` now adds a newline to each page instead of relying
on later code to do it.

## Tests

I spent a while trying to write a regression test for this behaviour but
I couldn't get the test to fail before my fix! I think the test
infrastructure does something special with newlines when it's checking
command output. I eventually ran out of steam trying to investigate
that, sorry.

[^1]: unless the pipe to table was the implicit one that's done when
there is no `display_output` hook set. That situation was still working
OK.
2022-12-14 16:45:37 +13:00
26759c4af2 mkdir change flag -s to -v (#7462)
Change in `mkdir` `-s` flag to `-v` to be similar to other commands


# Description

Other commands like `rm`, `mv`, `cp` have a `-v` (`--verbose`) flag.
`mkdir` has a `-s` (`--show-created-paths`), but should be consistent
with other commands.

# User-Facing Changes

- flag `-s` replaced by `-v` in `mkdir` command.


# Tests + Formatting
```
> mkdir -v new_dir
╭───┬───────────────────────────────────╮
│ 0 │ C:\Users\ricardo.monteiro\new_dir │
╰───┴───────────────────────────────────╯
```
2022-12-13 11:56:44 -05:00
e529746294 sort enums add missing items to parse_shape_name (#7450)
# Description

This PR adds missing items in `parse_shape_name`, sorts the
`SyntaxShape` enum and the `Type` enum. It's a pain to hunt around for
particular items in an enum when they're unsorted.

# User-Facing Changes


# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-13 10:46:22 -06:00
0c4d4632ef let UnknownFlag error list out available flags (#7443)
# Description
Fixes #6773.

```
/home/gabriel/CodingProjects/nushell〉ls -r                                                                                                                             12/12/2022 02:57:35 PM
Error: nu::parser::unknown_flag (link)

  × The `ls` command doesn't have flag `-r`.
   ╭─[entry #1:1:1]
 1 │ ls -r
   ·     ┬
   ·     ╰── unknown flag
   ╰────
  help: Available flags: --help(-h), --all(-a), --long(-l), --short-names(-s), --full-paths(-f), --du(-d), --directory(-D). Use `--help` for more information.
```

# User-Facing Changes

Different error for unknown flag.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-13 06:45:33 -06:00
e2c1216c1b Fix du error message (#7460)
BEFORE:
```
〉du *.***
Error:
  × wildcards are either regular `*` or recursive `**`
   ╭─[entry #6:1:1]
 1 │ du *.***
   · ─┬
   ·  ╰── glob error
   ╰────
```
AFTER:
```
〉du *.***
Error:
  × glob error
   ╭─[entry #8:1:1]
 1 │ du *.***
   ·    ──┬──
   ·      ╰── wildcards are either regular `*` or recursive `**`
   ╰────

```
2022-12-13 13:11:55 +01:00
d83dbc3670 add input_output_types() to benchmark,cd and config reset (#7455)
# Description

add input_output_types() to benchmark, cd and config reset commands
It's an update to https://github.com/nushell/nushell/issues/7320


# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-13 06:10:55 -06:00
JT
0242b30027 Revert "Add pipeline operators to help" (#7454)
Reverts nushell/nushell#7449
2022-12-13 16:49:00 +13:00
JT
0c656fd276 Revert "Pipeline operators: && and ||" (#7452)
Reverts nushell/nushell#7448

Some surprising behavior in how we do this. For example:

```
〉if (true || false) { print "yes!" } else { print "no!" }
no!
〉if (true or false) { print "yes!" } else { print "no!" }
yes!
```

This means for folks who are using the old `||`, they possibly get the
wrong answer once they upgrade. I don't think we can ship with that as
it will catch too many people by surprise and just make it easier to
write buggy code.
2022-12-13 16:36:13 +13:00
b7a3e5989d Make hook execution stream instead of collecting (#7440)
Closes #7431. In a nutshell:
- `run_hook_block()` in repl.rs was collecting all input into a `Value`
instead of handling streaming input properly
- this was a problem because now we have a default `display_output` hook
that _everything_ gets piped to
- this PR fixes the problem by tweaking `run_hook_block()` to return a
`PipelineData` instead of a `Value`

After this change, individual pages are rendered as they finish. This is
a little easier to see if I tweak `STREAM_PAGE_SIZE` in table.rs to 10:

![image](https://user-images.githubusercontent.com/26268125/206935370-412b2ee9-9401-4222-bc93-5bd5a9adc13b.png)

## Future work

This does _not_ fix https://github.com/nushell/nushell/issues/7342.
2022-12-12 15:23:04 -08:00
JT
5b5f1d1b92 Add pipeline operators to help (#7449)
# Description

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

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

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-13 11:31:03 +13:00
JT
35bea5e044 Pipeline operators: && and || (#7448)
# Description

We got some feedback from folks used to other shells that `try/catch`
isn't quite as convenient as things like `||`. This PR adds `&&` as a
synonym for `;` and `||` as equivalent to what `try/catch` would do.

# User-Facing Changes

Adds `&&` and `||` pipeline operators.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-13 09:53:46 +13:00
7917cf9f00 Add config mutation tests (#7437)
# Description

Env config can be mutated by `=`, this pr is to add a few tests 

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-12 12:46:25 -06:00
5036672a58 add interact-once switch to rm (#7432)
# Description

Fixes: #7216 

Adds `interact-once` switch which numbers out the number of files to
delete and asks the user for confirmation.

```
/home/gabriel/test〉ls                                                                                                                                                  12/11/2022 11:25:42 AM
╭───┬───────┬──────┬──────┬──────────╮
│ # │ name  │ type │ size │ modified │
├───┼───────┼──────┼──────┼──────────┤
│ 0 │ a.txt │ file │  0 B │ now      │
│ 1 │ b.txt │ file │  0 B │ now      │
│ 2 │ c.txt │ file │  0 B │ now      │
╰───┴───────┴──────┴──────┴──────────╯
/home/gabriel/test〉rm *.txt -I                                                                                                                                         12/11/2022 11:25:42 AM
rm: remove 3 files? : y

/home/gabriel/test〉ls                                                                                                                                                  12/11/2022 11:25:51 AM
/home/gabriel/test〉                                                                                                                                                    12/11/2022 11:25:54 AM
```

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-11 13:22:27 -08:00
585ab56ea4 in for, loop, while, auto print final value in each iteration (#7433)
# Description

Fixes: #7404 
Fixes: #7402 

## About change
In `eval_block`, all pipelines(or called statements?) result will be
printed except the last one, the last one is returned by `eval_block`
function.

So if we want to print the last statement in eval block, we just need to
print that value.

# User-Facing Changes

### for
```
❯ for _ in 1..2 { echo "a" }
a
a
```

### while
```
❯ mut x = 1; while $x < 3 { $x = $x + 1; echo bb; }
bb
bb
```

### loop
```
❯ mut total = 0; loop {
∙     if $total > 1 {
∙         break
∙     } else {
∙         $total += 1
∙     }
∙     echo 3
∙ }
3
3
```

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
  - `cargo test --workspace` to check that all tests pass

# 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.
2022-12-12 05:46:03 +13:00
9009f68e09 Tweak "Cannot convert {x} to a string argument" error in run_external (#7434)
# Description

The message arrow is altered to show the external command name in case
it wasn't obvious. (See example for an occasion where it is
non-obvious).

BEFORE:
```
〉else if (2mb) > 4mb
Error: nu:🐚:external_command (link)

  × External command failed
   ╭─[entry #35:1:1]
 1 │ else if (2mb) > 4mb
   ·           ─┬
   ·            ╰── Cannot convert filesize to a string
   ╰────
  help: All arguments to an external command need to be string-compatible
```
AFTER:
```
〉else if (2mb) > 4mb
Error: nu:🐚:external_command (link)

  × External command failed
   ╭─[entry #3:1:1]
 1 │ else if (2mb) > 4mb
   ·           ─┬
   ·            ╰── Cannot convert filesize to a string argument for 'else'
   ╰────
  help: All arguments to an external command need to be string-compatible

```
# User-Facing Changes

See above.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-11 08:39:51 -08:00
2bacc29d30 Replace row conditions with closures in commands (#7428)
# Description

This PR changes some commands that previously accepted row conditions
(like `$it > 5`) as parameter to accept closures instead. The reasons
are:
a) The commands would need to move into parser keywords in the future
while they feel more like commands to be implemented in Nushell code as
a part of standard library.
b) In scripts, it is useful to store the predicate condition in a
variable which you can't do with row conditions.
c) These commands are not used that often to benefit enough from the
shorter row condition syntax

# User-Facing Changes

The following commands now accept **closure** instead of a **row
condition**:
- `take until`
- `take while`
- `skip until`
- `skip while`
- `any`
- `all`

This is a part of an effort to move away from shape-directed parsing.
Related PR: https://github.com/nushell/nushell/pull/7365

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-10 19:24:06 +02:00
4d7d97e0e6 Simplify FILE_PWD setting in 'overlay use' (#7425)
# Description

Changes the `FILE_PWD` setting mechanism to match the one used in the
`use` command.

Fixes https://github.com/nushell/nushell/pull/7424

# 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 -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-10 19:23:55 +02:00
f1000a17b4 Add FILE_PWD environment variable when running 'nu script.nu' (#7424)
# Description

When running `nu script.nu`, the `$env.FILE_PWD` will be set to the
directory where the script is.

Also makes the error message a bit nicer:
```
> target/debug/nu asdihga
Error: nu:🐚:file_not_found (link)

  × File not found
   ╭─[source:1:1]
 1 │ nu
   · ▲
   · ╰── Could not access file 'asdihga': "No such file or directory (os error 2)"
   ╰────

```

# User-Facing Changes

`FILE_PWD` environment variable is available when running a script as
`nu script.nu`.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-10 19:23:44 +02:00
f43edbccdc Make env-related tests more resilient (#7423)
# Description

Fixes https://github.com/nushell/nushell/issues/6708

The error message of environment variable not found could change
depending on the `$env` content which can produce random failures on
different systems. This PR hopefully makes the tests more resilient.

# 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 -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-10 19:23:34 +02:00
6b4282eadf Move 'where' to parser keywords; Add 'filter' command (#7365)
# Description

This PR moves the `where` command to a parser keyword. While it still
uses the shape-directed parsing dictated by the signature, we're free to
change the parsing code now to a custom one once we remove the syntax
shapes.

As a side effect, the `where -b` flag was removed and its functionality
has moved to the new `filter` command.

Just FYI, other commands that take row conditions:
- `take until`
- `take while`
- `skip until`
- `skip while`
- `any`
- `all`

We can either move these to the parser as well or make them accept a
closure instead of row condition.

# User-Facing Changes

New `filter` command which replaces `where -b` functionality.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-10 19:23:24 +02:00
7e2781a2af fix docker build (#7422)
# Description

Docker build fails with the latest release 0.72.1
```bash
Sending build context to Docker daemon  3.072kB
Step 1/6 : FROM alpine
 ---> 49176f190c7e
Step 2/6 : LABEL maintainer=nushell
 ---> Using cache
 ---> 7afa6864f008
Step 3/6 : RUN echo '/usr/bin/nu' >> /etc/shells     && adduser -D -s /usr/bin/nu nushell     && mkdir -p /home/nushell/.config/nushell/     && wget -q https://raw.githubusercontent.com/nushell/nushell/main/crates/nu-utils/src/sample_config/default_config.nu -O /home/nushell/.config/nushell/config.nu     && wget -q https://raw.githubusercontent.com/nushell/nushell/main/crates/nu-utils/src/sample_config/default_env.nu -O /home/nushell/.config/nushell/env.nu     && cd /tmp     && wget -qO - https://api.github.com/repos/nushell/nushell/releases/latest     |grep browser_download_url     |grep musl     |cut -f4 -d '"'     |xargs -I{} wget {}     && tar -xzf nu*     && chmod +x nu     && mv nu /usr/bin/nu     && chown -R nushell:nushell /home/nushell/.config/nushell     && rm -rf /tmp/*
 ---> Running in fa544239a3ea
Connecting to github.com (140.82.121.4:443)
Connecting to objects.githubusercontent.com (185.199.108.133:443)
saving to 'nu-0.72.1-x86_64-unknown-linux-musl.tar.gz'
nu-0.72.1-x86_64-unk   3% |*                               |  552k  0:00:29 ETA
nu-0.72.1-x86_64-unk  93% |*****************************   | 15.2M  0:00:00 ETA
nu-0.72.1-x86_64-unk 100% |********************************| 16.2M  0:00:00 ETA
'nu-0.72.1-x86_64-unknown-linux-musl.tar.gz' saved
chmod: nu: No such file or directory
```
2022-12-10 09:22:23 -06:00
32a53450a6 make split row works like python and rust ways (#7413)
# Description

Fixes: #7389 

Make split row works more like python or rust, especially, when the
input string stars/ends with separator, append a empty string to result.
Here are examples:

python:
```python
In [6]: "\nasdf\nghi\n".split("\n")
Out[6]: ['', 'asdf', 'ghi', '']
```
rust:
```rust
fn main() {
    let x = "\nabc\ndef\n";
    let y = x.split("\n").collect::<Vec<&str>>();
    println!("{:?}", y);   // outputs: ["", "abc", "def", ""]
}
```
# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-10 09:21:53 -06:00
ce78817f41 $env.config now always holds a record with only valid values (#7309)
# Description
Closes #7059. Rather than generate a new Record each time $env.config is
accessed (as described in that issue), instead `$env.config = ` now A)
parses the input record, then B) un-parses it into a clean Record with
only the valid values, and stores that as an env-var. The reasoning for
this is that I believe `config_to_nu_record()` (the method that performs
step B) will be useful in later PRs. (See below)

As a result, this also "fixes" the following "bug":
```
〉$env.config = 'butts'
$env.config is not a record
〉$env.config
butts
```
~~Instead, `$env.config = 'butts'` now turns `$env.config` into the
default (not the default config.nu, but `Config::default()`, which
notably has empty keybindings, color_config, menus and hooks vecs).~~

This doesn't attempt to fix #7110. cc @Kangaxx-0

# Example of new behaviour

OLD:
```
〉$env.config = ($env.config | merge { foo: 1 })
$env.config.foo is an unknown config setting
〉$env.config.foo
1
```
NEW:
```
〉$env.config = ($env.config | merge { foo: 1 })
Error:
  × Config record contains invalid values or unknown settings

Error:
  × Error while applying config changes
   ╭─[entry #1:1:1]
 1 │ $env.config = ($env.config | merge { foo: 1 })
   ·                                           ┬
   ·                                           ╰── $env.config.foo is an unknown config setting
   ╰────
  help: This value has been removed from your $env.config record.

〉$env.config.foo
Error: nu:🐚:column_not_found (link)

  × Cannot find column
   ╭─[entry #1:1:1]
 1 │ $env.config = ($env.config | merge { foo: 1 })
   ·                              ──┬──
   ·                                ╰── value originates here
   ╰────
   ╭─[entry #2:1:1]
 1 │ $env.config.foo
   ·             ─┬─
   ·              ╰── cannot find column 'foo'
   ╰────
```
# Example of new errors

OLD:
```
$env.config.cd.baz is an unknown config setting
$env.config.foo is an unknown config setting
$env.config.bar is an unknown config setting
$env.config.table.qux is an unknown config setting
$env.config.history.qux is an unknown config setting
```
NEW:
```
Error: 
  × Config record contains invalid values or unknown settings

Error:
  × Error while applying config changes
     ╭─[C:\Users\Leon\AppData\Roaming\nushell\config.nu:267:1]
 267 │     abbreviations: true # allows `cd s/o/f` to expand to `cd some/other/folder`
 268 │     baz: 3,
     ·          ┬
     ·          ╰── $env.config.cd.baz is an unknown config setting
 269 │   }
     ╰────
  help: This value has been removed from your $env.config record.

Error:
  × Error while applying config changes
     ╭─[C:\Users\Leon\AppData\Roaming\nushell\config.nu:269:1]
 269 │   }
 270 │   foo: 1,
     ·        ┬
     ·        ╰── $env.config.foo is an unknown config setting
 271 │   bar: 2,
     ╰────
  help: This value has been removed from your $env.config record.

Error:
  × Error while applying config changes
     ╭─[C:\Users\Leon\AppData\Roaming\nushell\config.nu:270:1]
 270 │   foo: 1,
 271 │   bar: 2,
     ·        ┬
     ·        ╰── $env.config.bar is an unknown config setting
     ╰────
  help: This value has been removed from your $env.config record.

Error:
  × Error while applying config changes
     ╭─[C:\Users\Leon\AppData\Roaming\nushell\config.nu:279:1]
 279 │     }
 280 │     qux: 4,
     ·          ┬
     ·          ╰── $env.config.table.qux is an unknown config setting
 281 │   }
     ╰────
  help: This value has been removed from your $env.config record.

Error:
  × Error while applying config changes
     ╭─[C:\Users\Leon\AppData\Roaming\nushell\config.nu:285:1]
 285 │     file_format: "plaintext" # "sqlite" or "plaintext"
 286 │  qux: 2
     ·       ┬
     ·       ╰── $env.config.history.qux is an unknown config setting
 287 │   }
     ╰────
  help: This value has been removed from your $env.config record.


```

# User-Facing Changes

See above.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-10 15:34:46 +02:00
f0e93c2fa9 into cellpath command (#7417)
# Description

Address part of feature request #7337, add a small command `into
cellpath` to allow string -> cellpath auto-conversion, with this change,
we could run

```
let p = 'ls.use_ls_colors'
$env.config | upsert ($p | nito cellpath) false
```

<img width="710" alt="image"
src="https://user-images.githubusercontent.com/85712372/206782818-3024b34f-150b-482d-aebc-9426ef6a1cf9.png">

Note - This pr only covers `String` -> `CellPath`, any other conversions
should be considered 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:

- [x] `cargo fmt --all -- --check` to check standard code formatting
(`cargo fmt --all` applies these changes)
- [x] `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- [x] `cargo test --workspace` to check that all tests pass

# 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.
2022-12-10 15:26:42 +02:00
fa6bb147ea remove example missed from an earlier refactor (#7419)
# Description

When `seq date` was changed to remove the `-s` param, the example was
missed. This PR removes that example.

# User-Facing Changes


# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-09 20:04:14 -06:00
220b105efb Reduced LOC by replacing several instances of Value::Int {}, Value::Float{}, Value::Bool {}, and Value::String {} with Value::int(), Value::float(), Value::boolean() and Value::string() (#7412)
# Description

While perusing Value.rs, I noticed the `Value::int()`, `Value::float()`,
`Value::boolean()` and `Value::string()` constructors, which seem
designed to make it easier to construct various Values, but which aren't
used often at all in the codebase. So, using a few find-replaces
regexes, I increased their usage. This reduces overall LOC because
structures like this:
```
Value::Int {
  val: a,
  span: head
}
```
are changed into
```
Value::int(a, head)
```
and are respected as such by the project's formatter.
There are little readability concerns because the second argument to all
of these is `span`, and it's almost always extremely obvious which is
the span at every callsite.

# 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 -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-09 11:37:51 -05:00
b56ad92e25 ++= appendAssign operator (#7346) (#7354)
# Description

Closes  https://github.com/nushell/nushell/issues/7346



# Tests + Formatting
```
> mut a = [1 2 3]
> $a ++= [4 5 6]
> $a
[1 2 3 4 5 6]
```
2022-12-09 11:20:58 -05:00
fc5fe4b445 ensure error in else is forwarded appropriately (#7411)
# Description

Fixes #7407. 

```
/home/gabriel/CodingProjects/nushell〉if false { 'a' } else { $foo }    12/09/2022 08:14:48 PM
Error: nu::parser::variable_not_found (link)

  × Variable not found.
   ╭─[entry #1:1:1]
 1 │ if false { 'a' } else { $foo }
   ·                         ──┬─
   ·                           ╰── variable not found
   ╰────
```

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-09 15:48:12 +02:00
c01d44e37d Add arbitrary base math log (#7409)
Adds new command `math log` that takes as a required positional argument
a base.

Specialized for `math log 2` and `math log 10` for better performance
and precision that matches the expectations there. This leads to
discontinuities in numerical error but should make a better trade-off
for common usecases.


Example testing of the happy path
2022-12-09 11:20:42 +01:00
5a0e86aa70 fix external completions; add a caret when there is overlap (#7405)
# Description

Fixes #5424. Checking the code, apparently this was always supposed to
work; however, because it compared the `Suggestion`s directly, and
internal commands had descriptions while external commands did not, it
never did function properly.

# User-Facing Changes

Completing to external commands (with overlap) adds a caret so the
external command is actually run.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-09 22:27:50 +13:00
b4529a20e8 Add math tau (#7408)
# Description

Prompted by
https://discord.com/channels/601130461678272522/615329862395101194/1050693116501426216

# User-Facing Changes

New command `math tau` and endless agony whether to use `math pi` or
`math tau`

# Tests + Formatting

Example test
2022-12-09 22:27:19 +13:00
b938adefaa Fix math e usage text (#7406)
Closes #7401

# Tests + Formatting

Doesn't apply, doc fix
2022-12-09 09:56:12 +01:00
b39d797c1f Add quotes to hash file autocomplete (#7398)
# Description

Fixes #6741. Autocompleting a dir/file named something like foo#bar will
now complete to \`foo#bar\`
2022-12-08 21:37:10 +01:00
4240bfb7b1 Fix tab not working in vi editor mode (#7396)
# Description

The "tab" key now cycles completions in all editor modes, not just
emacs.

# User-Facing Changes

Updated default config

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-08 11:07:40 +02:00
JT
b7572f107f Remove and/or from 'help operators' (#7388)
# Description

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

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

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-07 18:05:51 -06:00
JT
379e3d70ca Better errors when bash-like operators are used (#7241)
# Description

Adds improved errors for when a user uses a bashism that nu doesn't
support.

fixes #7237 

Examples:

```
Error: nu::parser::shell_andand (link)

  × The '&&' operator is not supported in Nushell
   ╭─[entry #1:1:1]
 1 │ ls && ls
   ·    ─┬
   ·     ╰── instead of '&&', use ';' or 'and'
   ╰────
  help: use ';' instead of the shell '&&', or 'and' instead of the boolean '&&'
```

```
Error: nu::parser::shell_oror (link)

  × The '||' operator is not supported in Nushell
   ╭─[entry #8:1:1]
 1 │ ls || ls
   ·    ─┬
   ·     ╰── instead of '||', use 'try' or 'or'
   ╰────
  help: use 'try' instead of the shell '||', or 'or' instead of the boolean '||'
```

```
Error: nu::parser::shell_err (link)

  × The '2>' shell operation is 'err>' in Nushell.
   ╭─[entry #9:1:1]
 1 │ foo 2> bar.txt
   ·     ─┬
   ·      ╰── use 'err>' instead of '2>' in Nushell
   ╰────
```

```
Error: nu::parser::shell_outerr (link)

  × The '2>&1' shell operation is 'out+err>' in Nushell.
   ╭─[entry #10:1:1]
 1 │ foo 2>&1 bar.txt
   ·     ──┬─
   ·       ╰── use 'out+err>' instead of '2>&1' in Nushell
   ╰────
  help: Nushell redirection will write all of stdout before stderr.
```


# User-Facing Changes

**BREAKING CHANGES**

This removes the `&&` and `||` operators. We previously supported by
`&&`/`and` and `||`/`or`. With this change, only `and` and `or` are
valid boolean operators.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-08 12:02:11 +13:00
JT
6fc87fad72 Fix input redirect for externals (#7387)
# Description

Ooops, fix the input redirection logic so we don't break vim.

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-08 11:33:42 +13:00
JT
fa15a2856a Add OneOf shape to fix else (#7385)
# Description

fixes #7384 

This is a stop-gap fix until we remove type-directed parsing. With this,
you can create a `OneOf` shape that can be one of a list of syntax
shapes. This gives you a little more control than you get with `Any`,
allowing you to add `Block` without breaking other parsing rules.

# User-Facing Changes

`else` block will no longer capture variables as it will now use a block
instead of a closure.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-08 08:58:54 +13:00
JT
eaec480f42 Improve empty pipelines (#7383)
# Description

This fix changes pipelines to allow them to actually be empty. Mapping
over empty pipelines gives empty pipelines. Empty pipelines immediately
return `None` when iterated.

This removes a some of where `Span::new(0, 0)` was coming from, though
there are other cases where we still use it.

# 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 -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-08 07:31:57 +13:00
d18587330a fix semicolon doesn't work for some commands (#7373)
# Description

Fix semicolon working for the following commands which runs to failed:

1. into record (example: `into record; echo 'aa'`) -- the final aa
shouldn't be printed
2. save ( example: `touch a; chmod a-w a; echo 'aa' | save a; echo asdf`
) -- the final asdf shouldn't be printed
3. fetch ( example: `touch a; chmod a-w a; fetch https://www.google.com
-o a; echo asdf` ) -- the final asdf shouldn't be printed
4. registry_query (I don't have window machine, sorry for that I can't
demo for it)

I've reviewed most of built-in commands, and it seems that other
commands works fine.

# User-Facing Changes

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-06 19:48:39 -08:00
5114dfca7d Remove use of deprecated actions-rs/cargo GH action (#7375)
Our CI actions have a lot of warnings like this:

>  nu-fmt-clippy (ubuntu-20.04, stable)
> Node.js 12 actions are deprecated. For more information see:
https://github.blog/changelog/2022-09-22-github-actions-all-actions-will-begin-running-on-node16-instead-of-node12/.
Please update the following actions to use Node.js 16:
actions-rs/cargo@v1.0.1

[It looks like `actions-rs/cargo` is
abandoned](https://github.com/actions-rs/toolchain/issues/216). But the
good news is we don't actually need it, we can just run `cargo`
subcommands without a special action because we've already installed
`cargo` with `actions-rust-lang/setup-rust-toolchain`.
2022-12-06 18:57:07 -08:00
3395beaa56 Make seq return a ListStream where possible (#7367)
# Description

Title.

# User-Facing Changes

Faster seq that works better with functions that take in `ListStream`s.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-06 18:48:03 -08:00
df66d9fcdf Fix watch for block+closure split (#7374)
The block+closure split broke `watch` for some use cases. Fixed.

We should eventually add some tests for `watch` but it's a little tricky
since it's an interactive command.

Closes #7362.
2022-12-06 18:20:20 -08:00
1af1e0b5a3 fix upsert index of zero (#7350)
# Description

Try to fix #7347, this pr does not fix the error message to `upserting
beyond 1 + the list's length doesn't work,`, I feel this is still not
explicit or general engouh, if we want to change, what would be the best
message to be printed out ?

Add tests too

# 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 -A
clippy::needless_collect` to check that you're using the standard code
style
- [x] `cargo test --workspace` to check that all tests pass

# 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.
2022-12-06 15:26:27 -05:00
9b41f9ecb8 Allow $env and mutable records to be mutated by = (closes #7110) (#7318)
# Description

Closes #7110. ~~Note that unlike "real" `mut` vars, $env can be deeply
mutated via stuff like `$env.PYTHON_IO_ENCODING = utf8` or
`$env.config.history.max_size = 2000`. So, it's a slightly awkward
special case, arguably justifiable because of what $env represents (the
environment variables of your system, which is essentially "outside"
normal Nushell regulations).~~
EDIT: Now allows all `mut` vars to be deeply mutated using `=`, on
request.

# User-Facing Changes

See above.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-06 19:51:55 +02:00
48ade4993d remove redundant code mentioning ToCsv (#7370)
# Description

```rust
ToCsv
```

ToCsv was in there twice so I removed the 2nd reference...

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

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

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-06 09:42:12 -08:00
4ecc807dbb fix split list when separater is the first element of list (#7355)
# Description

Fixes: #7278

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-06 08:51:38 -06:00
86b69cc5d1 add input_output_types() to ansi gradient (#7357)
# Description

Add the input_output_types() to the ansi gradient command in support of
#7320

# User-Facing Changes


# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-06 08:51:18 -06:00
017a13fa3f bump to dev build v0.72.2 (#7360)
# Description

After the 0.72.1 hotfix, let's bump our dev builds to 0.72.2.

# User-Facing Changes



# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-05 14:18:06 -06:00
ca12b2e30e Pin CI jobs to Ubuntu 20.04 (#7359)
The release job was pinned to Ubuntu 20.04 to avoid glibc breakage in
https://github.com/nushell/nushell/pull/7290. This PR updates the CI
jobs to keep things consistent (it would sure be unpleasant if things
worked in CI but not at release time).
2022-12-05 10:12:36 -08:00
db6c804b17 fix menus in default config (#7352)
Simply fixes menus commands_with_description, commands_menu
2022-12-04 19:23:58 -08:00
57ff668d2e Make SQLite queries cancellable (#7351)
This change makes SQLite queries (`open foo.db`, `open foo.db | query db
"select ..."`) cancellable using `ctrl+c`. Previously they were not
cancellable, which made it unpleasant to accidentally open a very large
database or run an unexpectedly slow query!

UX-wise there's not too much to show:


![image](https://user-images.githubusercontent.com/26268125/205519205-e1f2ab58-c92d-4b96-9f80-eb123f678ec3.png)

## Notes

I was hoping to make SQLite queries streamable as part of this work, but
I ran into 2 problems:
1. `rusqlite` lifetimes are nightmarishly complex and they make it hard
to create a `ListStream` iterator
2. The functions on Nu's `CustomValue` trait return `Value` not
`PipelineData` and so `CustomValue` implementations can't stream data
AFAICT.
2022-12-04 16:49:47 -08:00
9fb9b16b38 kill: don't show signal example on windows (#7353)
# Description

Windows doesn't support the --signal(-s) option, so don't show the
example in help.

# User-Facing Changes

N/A

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-04 16:39:54 -08:00
41178dff90 Try to fix #7338 (#7343)
Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2022-12-04 17:47:46 -06:00
12deff5d1b Add comments for nu syntax shape (#7349)
# Description

FIx the typo of `List` and also add more comments to other variants


# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-04 11:20:47 -08:00
21a645b1a9 Improve error message for illegal filenames on Windows (#7348)
`ls` can fail when a directory contains a file that violates [the
Windows file naming
conventions](https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions).
This PR tweaks the error message so we tell the user _which_ file caused
the problem.

Closes #7345.

### Before:

![image](https://user-images.githubusercontent.com/26268125/205508355-2875f851-6b61-4897-97b8-9094b24ea197.png)

### After:


![image](https://user-images.githubusercontent.com/26268125/205508325-0b4efd25-b454-4d1b-b8e9-cb26803fbcff.png)


## Future Work

Like Chris said in the linked issue, it would be even better if Nu could
just handle these naughty files like cmd.exe and pwsh do. If someone has
the time to dive into how PowerShell does this, that would be much
appreciated.
2022-12-04 10:33:30 -08:00
e8a55aa647 Overhaul schema command, remove database name (#7344)
This PR changes the `schema` command for viewing the schema of a SQLite
database file. It removes 1 level of nesting (intended to handle
multiple databases in the same connection) that I believe is
unnecessary.

### Before

![image](https://user-images.githubusercontent.com/26268125/205467643-05df0f64-bc8f-4135-9ff1-f978cc7a12bd.png)

### After

![image](https://user-images.githubusercontent.com/26268125/205467655-c4783184-9bde-46e2-9316-0f06acd1abe1.png)

## Rationale

A SQLite database connection can technically be associated with multiple
non-temporary databases using [the ATTACH DATABASE
command](https://www.sqlite.org/lang_attach.html). But it's not possible
to do that _in the context of Nushell_, and so I believe that there is
no benefit to displaying the schema as if there could be multiple
databases.

I initially raised this concern back in April, but we decided to keep
the database nesting because at the time we were still looking into more
generalized database functionality (i.e. not just SQLite). I believe
that rationale no longer applies.

Also, the existing code would not have worked correctly even if a
connection had multiple databases; for every database, it was looking up
tables without filtering them by database:

6295b20545/crates/nu-command/src/database/values/sqlite.rs (L104-L118)

## Future Work

I'd like to add information on views+triggers to the `schema` output.
I'm also working on making it possible to `ctrl+c` reading from a
database (which is turning into a massive yak shave).
2022-12-03 18:16:57 -08:00
6295b20545 add background colors to the ansi command (#7312)
# Description

This PR adds the ability to easily specific background colors using the
ansi command. It also allows you to use attributes.

![image](https://user-images.githubusercontent.com/343840/205151594-968cc7a6-f1d8-406e-aa8b-cb67e8487563.png)

I also updated the grid output to be clear that the output includes an
escape character, represented here by `\e`.

![image](https://user-images.githubusercontent.com/343840/205151066-09966f90-6341-4eeb-83c1-df3d169cfbf6.png)

# User-Facing Changes

You can see a list of these new items with `ansi --list` with their long
and short names.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-03 13:08:51 -06:00
850ecf648a Protocol: debug_assert!() Span to reflect a valid slice (#6806)
Also enforce this by #[non_exhaustive] span such that going forward we
cannot, in debug builds (1), construct invalid spans.

The motivation for this stems from #6431 where I've seen crashes due to
invalid slice indexing.

My hope is this will mitigate such senarios

1. https://github.com/nushell/nushell/pull/6431#issuecomment-1278147241

# Description

(description of your pull request here)

# Tests

Make sure you've done the following:

- [ ] Add tests that cover your changes, either in the command examples,
the crate/tests folder, or in the /tests folder.
- [ ] Try to think about corner cases and various ways how your changes
could break. Cover them with tests.
- [ ] If adding tests is not possible, please document in the PR body a
minimal example with steps on how to reproduce so one can verify your
change works.

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)
- [ ] `cargo clippy --workspace --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- [ ] `cargo test --workspace --features=extra` to check that all the
tests pass

# Documentation

- [ ] If your PR touches a user-facing nushell feature then make sure
that there is an entry in the documentation
(https://github.com/nushell/nushell.github.io) for the feature, and
update it if necessary.
2022-12-03 11:44:12 +02:00
e6cf18ea43 nu-explore/ A few fixes. (#7334)
close #7322
close #7323

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2022-12-03 00:12:33 +02:00
d28624796c make histogram sorted (#7267)
# Description

Closes:  #7208

After this pr, histogram will output by count descending

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-02 09:29:19 -08:00
380c216d77 Fix documentation for merge (#7329)
# Description

`merge` no longer accepts blocks as arguments.
2022-12-02 11:35:28 -05:00
ee5a387300 Handle mixed LF+CRLF in lines (#7316)
This closes #4989. Previously `lines` was unable to handle text input
with CRLF line breaks _and_ LF line breaks.

### Before:

![image](https://user-images.githubusercontent.com/26268125/205207685-b25da9e1-19fa-4abb-8ab2-0dd216c63fc0.png)

### After:


![image](https://user-images.githubusercontent.com/26268125/205207808-9f687242-a8c2-4b79-a12c-38b0583d8d52.png)
2022-12-02 11:30:26 -05:00
3ac36879e0 Handle ctrl-c in RawStream iterator (#7314)
Fixes #7246 and #1898.

Darren noticed that `open /dev/random` could not be interrupted by
`ctrl+c`. Thankfully the solution was very simple; it looks like we just
forgot to check `ctrlc` in the `impl Iterator for RawStream`!

To reproduce this, just run `open /dev/random` and then cancel it with
`ctrl+c`.
2022-12-02 08:00:56 -08:00
bc0c9ab698 add :q! alias to explore command (#7326)
# Description

This simply adds an alias to the explore quit command in order to quit
out of explore. `:q` and `:q!` work now.

# User-Facing Changes

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-02 08:13:19 -06:00
5762489070 Edited help text and examples in explore for readability (#7324)
# Description

* Various help messages were edited for clarity/grammar/etc.
* Some examples were made more interesting or relevant

# User-Facing Changes

See above.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-02 08:01:02 -06:00
fcdc474731 uniq-by command (#7295)
New command `uniq-by` to get uniq results by column.

Closes https://github.com/nushell/nushell/issues/7109
2022-12-02 11:36:01 +01:00
f491d3e1e1 Rename $env.config.explore_config to $env.config.explore (for consistency with $env.config.ls, $env.config.table etc.) (#7317)
# Description

* `$env.config.explore_config` renamed to `$env.config.explore`. This
follows the principle that config subrecords relating to single commands
(as this relates to `explore`) should be exactly named after the command
(see `ls`, `rm`, `table` etc.)
* In `into_config()`, moved the match arm relating to
`$env.config.explore` out of the "legacy options" section (which is
slated for removal in a later version).

# User-Facing Changes

`explore` is not in any public releases yet, so this has no end-user
impact.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-02 01:42:18 -05:00
94c89eb623 Use setup-rust-toolchain for release workflow (#7315)
# Description

Use setup-rust-toolchain for release workflow to inline with the CI
workflow

Test workflow:
https://github.com/hustcer/nu-release/actions/runs/3598316520
Demo Release: https://github.com/hustcer/nu-release/releases/tag/v0.72.8
2022-12-01 19:23:29 -08:00
cf0a18be51 Fix where -b flag (#7313)
# Description

The `where -b` flag was broken. The following now works:
```
let cond = {|x| $x.name !~ 'foo'}; ls | where -b $cond
```

This is just a quick fix. Ultimately, the `where` command shouldn't need
the flag and `where $cond` should work. The first step, however, is to
move `where` away from shape-directed parsing and make it a parser
keyword.

# User-Facing Changes

`where -b` is not broken

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-01 15:11:03 -08:00
JT
0621ab6652 couple minor updates to xml deps (#7311)
# Description

Just some minor updates to xml deps

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-02 08:25:13 +13:00
64a028cc76 Deliver a few fixes for explore command (#7310)
ref #6984

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2022-12-01 12:14:56 -06:00
f71a45235a fix try for external command runs to failed (#7300)
# Description

Fixes: #7298

So `try .. catch` works better on external command failed.

# User-Facing Changes

```
try {nu --testbin fail} catch {print "fail"}
```

After this pr, it will output "fail"

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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: JT <547158+jntrnr@users.noreply.github.com>
2022-12-02 05:58:32 +13:00
718ee3d545 [MVP][WIP] less like pager (#6984)
Run it as `explore`.

#### example

```nu
ls | explore
```

Configuration points in `config.nu` file.
```
  # A 'explore' utility config
   explore_config: {
     highlight: { bg: 'yellow', fg: 'black' }
     status_bar: { bg: '#C4C9C6', fg: '#1D1F21' }
     command_bar: { fg: '#C4C9C6' }
     split_line: '#404040'
     cursor: true
     # selected_column: 'blue'
     # selected_row: { fg: 'yellow', bg: '#C1C2A3' }
     # selected_cell: { fg: 'white', bg: '#777777' }
     # line_shift: false,
     # line_index: false,
     # line_head_top: false,
     # line_head_bottom: false,
   }
```

You can start without a pipeline and type `explore` and it'll give you a
few tips.

![image](https://user-images.githubusercontent.com/343840/205088971-a8c0262f-f222-4641-b13a-027fbd4f5e1a.png)

If you type `:help` you an see the help screen with some information on
what tui keybindings are available.

![image](https://user-images.githubusercontent.com/343840/205089461-c4c54217-7ec4-4fa0-96c0-643d68dc0062.png)

From the `:help` screen you can now hit `i` and that puts you in
`cursor` aka `inspection` mode and you can move the cursor left right up
down and it you put it on an area such as `[table 5 rows]` and hit the
enter key, you'll see something like this, which shows all the `:`
commands. If you hit `esc` it will take you to the previous screen.

![image](https://user-images.githubusercontent.com/343840/205090155-3558a14b-87b7-4072-8dfb-dc8cc2ef4943.png)

If you then type `:try` you'll get this type of window where you can
type in the top portion and see results in the bottom.

![image](https://user-images.githubusercontent.com/343840/205089185-3c065551-0792-43d6-a13c-a52762856209.png)

The `:nu` command is interesting because you can type pipelines like
`:nu ls | sort-by type size` or another pipeline of your choosing such
as `:nu sys` and that will show the table that looks like this, which
we're calling "table mode".

![image](https://user-images.githubusercontent.com/343840/205090809-e686ff0f-6d0b-4347-8ed0-8c59adfbd741.png)

If you hit the `t` key it will now transpose the view to look like this.

![image](https://user-images.githubusercontent.com/343840/205090948-a834d7f2-1713-4dfe-92fe-5432f287df3d.png)

In table mode or transposed table mode you can use the `i` key to
inspect any collapsed field like `{record 8 fields}`, `[table 16 rows]`,
`[list x]`, etc.

One of the original benefits was that when you're in a view that has a
lot of columns, `explore` gives you the ability to scroll left, right,
up, and down.

`explore` is also smart enough to know when you're in table mode versus
preview mode. If you do `open Cargo.toml | explore` you get this.

![image](https://user-images.githubusercontent.com/343840/205091822-cac79130-3a52-4ca8-9210-eba5be30ed58.png)

If you type `open --raw Cargo.toml | explore` you get this where you can
scroll left, right, up, down. This is called preview mode.

![image](https://user-images.githubusercontent.com/343840/205091990-69455191-ab78-4fea-a961-feafafc16d70.png)

When you're in table mode, you can also type `:preview`. So, with `open
--raw Cargo.toml | explore`, if you type `:preview`, it will look like
this.

![image](https://user-images.githubusercontent.com/343840/205092569-436aa55a-0474-48d5-ab71-baddb1f43027.png)

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2022-12-01 09:32:10 -06:00
e92678ea2c Add a deprecation note for removed build-string (#7307)
Build string was removed for 0.72 by #7144

Adds a deprecation message
2022-12-01 16:26:59 +01:00
1f175d4c98 Add natural logarithm (#7258)
- `math ln`
2022-12-01 15:58:05 +01:00
4d6ccf2540 Add inverse hyperbolic functions (#7258)
- `math arcsinh`
- `math arccosh`
- `math arctanh`
2022-12-01 15:58:05 +01:00
aa6c3936d2 Add inverse for trigonometric functions (#7258)
- `math arcsin`
- `math arccos`
- `math arctan`

Again include `--degrees` or `-d` for convenient output in degrees
2022-12-01 15:58:05 +01:00
4f05994b36 Add basic hyperbolic functions (#7258)
`math sinh`
`math cosh`
`math tanh`
2022-12-01 15:58:05 +01:00
b27d6b2cb1 Add basic trigonometric functions (#7258)
`math sin`
`math cos`
`math tan`

Support degrees with the flag `--degrees`/`-d`
2022-12-01 15:58:05 +01:00
64f226f7da Add math pi and math e constants (#7258)
Currently implemented as commands

Work towards #7073

Add them to the example test harness together with `math round`
2022-12-01 15:58:05 +01:00
5c1606ed82 Add -n flag to sort (formerly only available on sort-by) (#7293)
# Description

* `-n`, `--natural` flag from `sort-by` is now on the plain `sort`.
* The `-i`, `-n` and `-r` flags now work with single record sorting
(formerly they didn't)

# User-Facing Changes

See above.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-01 07:11:30 -06:00
11977759ce fix cal input_output_types signature (#7306)
# Description

This is one of many commands that needs the `input_output_types()` part
of the signature filled in so that `$nu.scope.commands` shows the
signature properly which leads to the documentation being updated
properly.

TIL that when commands like `cal` don't have Example tests that can
easily be expressed and require the use of `None` results that we need
to use this as part of the signature.

```rust
.allow_variants_without_examples(true) // TODO: supply exhaustive examples
```

Related to https://github.com/nushell/nushell/issues/7287

# User-Facing Changes



# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-01 07:10:49 -06:00
bc3dc98b34 add -f, --force for save command (#7262)
# Description

Closes: #6920 

# User-Facing Changes

```
❯ "asdf" | save dump.rdb
Error:
  × Destination file already exists
   ╭─[entry #21:1:1]
 1 │ "asdf" | save dump.rdb
   ·               ────┬───
   ·                   ╰── Destination file '/tmp/dump.rdb' already exists
   ╰────
  help: you can use -f, --force to force overwriting the destination
```
# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-01 06:26:17 -06:00
6fadc72553 Remove unused dev-dependencies (#7285)
Warning: the `nu-json` crate seems to be undertested as the main test
code is commented out. Thus the unused dependencies there were just
commented out
2022-12-01 11:53:24 +01:00
a9e6b1ec6b Add did-you-mean suggestions for bitwise ops (#7252)
Continues work from #7251 to include the bitwise operations.
Covers the C style conventions as well as the typo `bits-*` instead of
`bit-*`
2022-12-01 11:34:41 +01:00
cbc7b94b02 Remove inactive actions-rs/toolchain@v1.0.6 for release workflow (#7302)
# Description

Remove inactive actions-rs/toolchain@v1.0.6 for release workflow,
https://github.com/actions-rs/toolchain is inactive for more than two
years, and have lots of unfixed warnings:
https://github.com/actions-rs/toolchain/issues?q=is%3Aissue+is%3Aopen+warning

After this PR:

Workflow running result:
https://github.com/hustcer/nu-release/actions/runs/3590194180
Release Test: https://github.com/hustcer/nu-release/releases/tag/v0.72.7
2022-12-01 16:30:25 +08:00
45c66e2090 Update release script to nu v0.71 and use ubuntu-20.04 to build nu binary (#7290)
# Description

1. Update nu to v0.71 for release script
2. Remove the usage of `set-output` see:
https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
3. Use `ubuntu-20.04` instead of `ubuntu-latest` to fix #7282 

To check the workflow running result see:
https://github.com/hustcer/nu-release/actions/runs/3588720720/jobs/6040412953

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-12-01 10:44:21 +08:00
11b2423544 add comments to release-pkg for manual running (#7277)
# Description

This PR is just some comments in the release-pkg.nu script. We had to
figure out how to run it manually so I thought it would be good to
document those requirements just in case we need to do it again
sometime.

# User-Facing Changes

N/A

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-11-30 20:18:28 -06:00
1f9907d2ff Fix failing test after #7051 (#7299)
Numerics as record names have to be quoted
Changed to string
2022-12-01 00:48:02 +01:00
fd503fceaf allow tables in ++ operator (#7051)
This PR closes #6916, which now allows table/table operations on the
`++` operator.
```
[[a b]; [1 2]] ++ [[a b]; [1 3]]
╭───┬───┬───╮
│ # │ a │ b │
├───┼───┼───┤
│ 0 │ 1 │ 2 │
│ 1 │ 1 │ 3 │
╰───┴───┴───╯
```
2022-12-01 00:21:59 +01:00
b7e5790cd1 fix dfr datetime conversion (#7264)
# Description

Closes #7257

This fixes an issue where dataframes would always try to convert
datetimes with milliseconds. Since the timeunit is passed in, I make use
of it and try to choose the appropriate divisor.


# User-Facing Changes


# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-11-30 17:10:28 -06:00
3caab5de36 bump to dev release v0.72.1 (#7281)
# Description

Just bumping to the next dev version. Submitting as a draft until we're
ready.

# User-Facing Changes



# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-11-30 16:06:22 -06:00
fa97e819eb Suggest using float on Value::Int overflow (#7253)
# Description

Suggest that floats support a larger range of values but warn about the
loss in precision.


![image](https://user-images.githubusercontent.com/15833959/204114339-c987cd47-f035-4c01-853f-e9a00441bf49.png)


(Doesn't apply to the types with associated units)

# Tests + Formatting

(-)
2022-11-29 13:30:02 -08:00
bdc4bf97a7 Upgrade windows and trash crates (#7259)
This upgrades the `windows` and `trash` crates so we are only compiling
1 version of the `windows` crate ([I recently upgraded the version used
in `trash`](https://github.com/Byron/trash-rs/pull/58)).

I was hoping that this would lead to some decent compile time
improvements, but unfortunately it did not. Compiling 1 version of
`windows` with all the features unified is about as slow as compiling 2
versions with distinct feature sets. Still, might as well upgrade.
2022-11-29 13:05:32 -08:00
JT
cfb0f3961b Simple README updates (#7279)
# Description

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

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

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-11-30 08:10:11 +13:00
JT
8fa965118c Update release.yml 2022-11-30 06:35:16 +13:00
JT
9c800bcb2c bump to 0.72 (#7272)
# Description

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

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

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-11-29 20:17:23 +13:00
ea4d8c5f49 update release-pkg.nu to include more recent less version (#7265)
# Description

This PR upgrades the Windows less version from v590 to v608

# User-Facing Changes


# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-11-29 15:21:00 +13:00
5d2abdd1c3 add a more verbose description of operators (#7263)
# Description

I was thinking that it may be helpful to have a more verbose description
of our operators. Please let me know if you have better wording.

Also, while not strictly considered an operator, i added `not` to avoid
some confusion.
<img width="1574" alt="Screenshot 2022-11-28 at 7 57 30 PM"
src="https://user-images.githubusercontent.com/343840/204419666-7c4dbb43-26f5-4cd5-9a4e-a1555a9e700f.png">


# User-Facing Changes

Adds description column

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-11-29 15:20:17 +13:00
7d5333db3b Clean up .sh scripts with shellcheck (#7261)
Ran [`shellcheck`](https://github.com/koalaman/shellcheck) on our 3
shell scripts and fixed the warnings. This caught that the scripts were
[broken because of their
shebang](https://www.shellcheck.net/wiki/SC3030):

```
〉./uninstall-all.sh

----------------------------------------------
Uninstall nu and all plugins from cargo/bin...
----------------------------------------------
./uninstall-all.sh: 8: Syntax error: "(" unexpected
```

```
〉shellcheck *.sh

In build-all-maclin.sh line 8:
NU_PLUGINS=(
           ^-- SC3030 (warning): In POSIX sh, arrays are undefined.


In build-all-maclin.sh line 18:
for plugin in "${NU_PLUGINS[@]}"
               ^--------------^ SC3054 (warning): In POSIX sh, array references are undefined.


In build-all-maclin.sh line 20:
    echo '' && cd crates/$plugin
               ^---------------^ SC2164 (warning): Use 'cd ... || exit' or 'cd ... || return' in case cd fails.
                         ^-----^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
    echo '' && cd crates/"$plugin" || exit


In install-all.sh line 14:
NU_PLUGINS=(
           ^-- SC3030 (warning): In POSIX sh, arrays are undefined.


In install-all.sh line 22:
for plugin in "${NU_PLUGINS[@]}"
               ^--------------^ SC3054 (warning): In POSIX sh, array references are undefined.


In install-all.sh line 28:
    cd crates/$plugin && cargo install --path . && cd ../../
              ^-----^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
    cd crates/"$plugin" && cargo install --path . && cd ../../


In uninstall-all.sh line 8:
NU_PLUGINS=(
           ^-- SC3030 (warning): In POSIX sh, arrays are undefined.


In uninstall-all.sh line 16:
for plugin in "${NU_PLUGINS[@]}"
               ^--------------^ SC3054 (warning): In POSIX sh, array references are undefined.


In uninstall-all.sh line 18:
    cargo uninstall $plugin
                    ^-----^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
    cargo uninstall "$plugin"

For more information:
  https://www.shellcheck.net/wiki/SC2164 -- Use 'cd ... || exit' or 'cd ... |...
  https://www.shellcheck.net/wiki/SC3030 -- In POSIX sh, arrays are undefined.
  https://www.shellcheck.net/wiki/SC3054 -- In POSIX sh, array references are...
  ```
 
To fix SC2164  I used `set -euo pipefail` as per this Julia Evans suggestion:
  
![image](https://user-images.githubusercontent.com/26268125/204181003-22283dcb-924d-4c0d-91f6-1ea635dbf0fc.png)
2022-11-27 22:13:06 -05:00
2a8a628b72 add help operators command (#7254)
# Description

This PR adds a new command called `help operators`. The intention is to
make nushell's operators more discoverable.

Operations are evaluated in the precedence order (from highest to
lowest).

<img width="737" alt="Screenshot 2022-11-26 at 7 23 15 PM"
src="https://user-images.githubusercontent.com/343840/204115311-56765517-c36d-44d5-b303-43ffc0e980f6.png">

# User-Facing Changes



# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-11-27 21:03:17 +13:00
c4d2b787aa Add did-you-mean suggestions for operators (#7251)
# Description

Adds a `ParseError::UnkownOperator` and covers `^`,`pow`,`is`,`===`,`%`,
and `contains` as likely operators based on other languages. Provides
suggestion for the user to find the nu language feature they are looking
for.


![image](https://user-images.githubusercontent.com/15833959/204108373-d1165988-ad87-4a2e-bd81-b67a44072571.png)


# Tests + Formatting

(-)
2022-11-27 10:59:43 +13:00
a4e11726cf pin to rust v1.65 (#7249)
# Description

This fixes the compilation problems with `aarch64-apple-darwin` on rust
1.64 as well as the `zstd` problems. We recently found out that `zstd`
pinned to 1.65.



# User-Facing Changes

N/A

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-11-27 09:26:54 +13:00
9850fbd77d chore: chrono_update (#7132)
chrono version update

# Description

upgrade chrono to 0.4.23

# Major Changes

If you're considering making any major change to nushell, before
starting work on it, seek feedback from regular contributors and get
approval for the idea from the core team either on
[Discord](https://discordapp.com/invite/NtAbbGn) or [GitHub
issue](https://github.com/nushell/nushell/issues/new/choose).
Making sure we're all on board with the change saves everybody's time.
Thanks!

# Tests + Formatting

Make sure you've done the following, if applicable:

- Add tests that cover your changes (either in the command examples, the
crate/tests folder, or in the /tests folder)
- Try to think about corner cases and various ways how your changes
could break. Cover those in the tests

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 --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass

# After Submitting

* Help us keep the docs up to date: If your PR affects the user
experience of Nushell (adding/removing a command, changing an
input/output type, etc.), make sure the changes are reflected in the
documentation (https://github.com/nushell/nushell.github.io) after the
PR is merged.

Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2022-11-27 07:19:02 +13:00
2ccb91dc6a Add logical xor operator (#7242)
We already have the binary `bit-xor` and the shortcircuiting logical
`or`(`||`) and `and`(`&&`).
This introduces `xor` as a compact form for both brevity and clarity.
You can express the operation through `not`/`and`/`or` with a slight
risk of introducing bugs through typos.

Operator precedence

`and` > `xor` > `or`

Added logic and precedence tests.
2022-11-26 17:02:37 +01:00
3e76ed9122 add into record command (#7225)
# Description

This command converts things into records.
<img width="466" alt="Screenshot 2022-11-24 at 2 10 54 PM"
src="https://user-images.githubusercontent.com/343840/203858104-0e4445da-9c37-4c7c-97ec-68ec3515bc4b.png">

<img width="716" alt="Screenshot 2022-11-24 at 5 04 11 PM"
src="https://user-images.githubusercontent.com/343840/203872621-48cab199-ba57-44fe-8f36-9e1469b9c4ef.png">



It also converts dates into record but I couldn't get the test harness
to accept an example.

Thanks to @WindSoilder for writing the "hard" parts of this. :)


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

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

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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: WindSoilder <WindSoilder@outlook.com>
2022-11-26 09:00:47 -06:00
JT
2223fd663a Clean up keyword lines in help (#7243)
# Description

This makes the help messages cleaner for keyword-style arguments.

Before:
```
  (optional) else_expression <Keyword([101, 108, 115, 101], Expression)>: expression or block to run if check fails
```

Now:
```
  (optional) "else" + <expression>: expression or block to run if check fails
```


# User-Facing Changes

Changes how help is printed, so we use slightly different shape names

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-11-26 20:16:39 +13:00
3f960012cd Revert "remove zstd warning message" (#7235)
This reverts commit ee81030600.


# Description

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

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

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-11-24 20:01:22 -08:00
0b094e2bf2 remove zstd warning message (#7232)
# Description

This removes the warning message we were getting on compilation...

```rust
warning: /Users/ma/j/tmp17/nushell/crates/nu-command/Cargo.toml: version requirement `=2.0.1+zstd.1.5.2` for dependency `zstd-sys` includes semver metadata which will be ignored, removing the metadata is recommended to avoid confusion
```

https://github.com/nushell/nushell/pull/7227

a slight modification of this PR

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

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

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-11-24 18:39:32 -08:00
2388e1e80b Reorder export-env eval and allow reloading an overlay (#7231)
# Description

This PR is a response to the issues raised in
https://github.com/nushell/nushell/pull/7087. It consists of two
changes:
* `export-env`, when evaluated in `overlay use`, will see the original
environment. Previously, it would see the environment from previous
overlay activation.
* Added a new `--reload` flag that reloads the overlay. Custom
definitions will be kept but the original definitions and environment
will be reloaded.

This enables a pattern when an overlay is supposed to shadow an existing
environment variable, such as `PROMPT_COMMAND`, but `overlay use` would
keep loading the value from the first activation. You can easily test it
by defining a module
```
module prompt {
    export-env {
        let-env PROMPT_COMMAND = (date now | into string)
    }
}
```
Calling `overlay use prompt` for the first time changes the prompt to
the current time, however, subsequent calls of `overlay use` won't
change the time. That's because overlays, once activated, store their
state so they can be hidden and restored at later time. To force-reload
the environment, use the new flag: Calling `overlay use --reload prompt`
repeatedly now updates the prompt with the current time each time.

# User-Facing Changes

* When calling `overlay use`, if the module has an `export-env` block,
the block will see the environment as it is _before_ the overlay is
activated. Previously, it was _after_.
* A new `overlay use --reload` flag.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-11-24 23:45:24 +01:00
JT
62e34b69b3 New commands: break, continue, return, and loop (#7230)
# Description

This adds `break`, `continue`, `return`, and `loop`.

* `break` - breaks out a loop
* `continue` - continues a loop at the next iteration
* `return` - early return from a function call
* `loop` - loop forever (until the loop hits a break)

Examples:
```
for i in 1..10 {
    if $i == 5 {
       continue
    } 
    print $i
}
```

```
for i in 1..10 {
    if $i == 5 {
        break
    } 
    print $i
}
```

```
def foo [x] {
    if true {
        return 2
    }
    $x
}
foo 100
```

```
loop { print "hello, forever" }
```

```
[1, 2, 3, 4, 5] | each {|x| 
    if $x > 3 { break }
    $x
}
```

# User-Facing Changes

Adds the above commands.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-11-25 09:39:16 +13:00
fd68767216 pin to a version of zstd that doesn't break dataframe compilation (#7227)
# Description

The `zstd` team released a version that breaks dataframe compilation.
This change pins to `zstd-sys = "=2.0.1+zstd.1.5.2"` in order to prevent
the required `+nightly` build flag.

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

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

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-11-25 08:43:23 +13:00
JT
93202d4529 Remove And and Or pipeline elements (#7229)
# Description

Since we're not implementing `&&` or `||`, let's remove their pipeline
elements.

# User-Facing Changes

Nothing user facing. These were not yet implemented.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-11-25 07:06:12 +13:00
ed1f0eb231 Make catch block a closure w/ access to error (#7228)
A small follow-up to #7221. This changes the `catch` block from a block
to a closure, so that it can access the error returned from the `try`
block. This helps with a common scenario: "the `try` block failed, and I
want to log why it failed."

### Example


![image](https://user-images.githubusercontent.com/26268125/203841966-f1f8f102-fd73-41e6-83bc-bf69ed436fa8.png)

### Future Work

Nu's closure syntax is a little awkward here; it might be nicer to allow
something like `catch err { print $err }`. We discussed this on Discord
and it will require special parser code similar to what's already done
for `for`.

I'm not feeling confident enough in my parser knowledge to make that
change; I will spend some more time looking at the `for` code but I
doubt I will be able to implement anything in the next few days.
Volunteers welcome.
2022-11-25 07:02:20 +13:00
JT
04612809ab Add try/catch functionality (#7221)
# Description

This adds `try` (with an optional `catch` piece). Much like other
languages, `try` will try to run a block. If the block fails to run
successfully, the optional `catch` block will run if it is available.

# User-Facing Changes

This adds the `try` command.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-11-24 17:52:11 +13:00
JT
8cca447e8c A set of fixes for stderr redirect (#7219)
# Description

This is a set of fixes to `err>` to make it work a bit more predictably.

I've also revised the tests, which accidentally tested the wrong thing
for redirection, but should be more correct 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 -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-11-24 16:58:15 +13:00
651e86a3c0 uniq -i does not convert to lowercase (#7192) (#7209)
# Description
`uniq -i` does not convert output strings to lowercase.

Also, `uniq -i` did not ignore case in strings below the first level of
Tables and Records. Now all strings case are ignored for all children
Values for tables, Records, and List.

Fixes https://github.com/nushell/nushell/issues/7192


# Tests + Formatting
About the issue https://github.com/nushell/nushell/issues/7192, the
output will be:
```
〉[AAA BBB CCC] | uniq -i
╭───┬─────╮
│ 0 │ AAA │
│ 1 │ BBB │
│ 2 │ CCC │
╰───┴─────╯
```

About ignoring case for all children string, I expect this to be true:
```
([[origin, people];
    [World, (
        [[name, meal];
            ['Geremias', {plate: 'bitoque', carbs: 100}]
        ]
    )],
    [World, (
        [[name, meal];
            ['Martin', {plate: 'bitoque', carbs: 100}]
        ]
    )],
    [World, (
        [[name, meal];
            ['Geremias', {plate: 'Bitoque', carbs: 100}]
        ]
    )],
] | uniq -i
) == ([[origin, people];
    [World, (
        [[name, meal];
            ['Geremias', {plate: 'bitoque', carbs: 100}]
        ]
    )],
    [World, (
        [[name, meal];
            ['Martin', {plate: 'bitoque', carbs: 100}]
        ]
    )]
])
```
2022-11-23 15:46:20 -08:00
c3c3481ef5 fix color_config crashing on nonstring data (#7215)
This PR closses issue #7155, where now providing a non valid color will
just ignore it and use the default.

Making the same changes as the original issue just starts nushell
without crashing.
2022-11-23 23:32:25 +01:00
0732d8bbba Remove samples/wasm folder (#7214)
# Description

This folder doesn't seem to get used in active testing and the state of
the code seems to be close to an example stub for a general wasm
project.
2022-11-23 10:06:07 -08:00
bdca31cc2d Rename dataframe describe to summary so that the normal describe isn't overloaded (#7176)
This closes #6770.
2022-11-23 17:58:28 +01:00
ed7aea8dd3 Add binstall metadata (#7212)
# Description

To make `cargo binstall nu` works out of the box, `Cargo.toml` needs to
be slightly modified, likely because the URL to the download does not
exactly match.

# User-Facing Changes

None

# Tests + Formatting

Tested by cherry-picking this commit on top of the 0.71.0 tag, running
`cargo package --allow-dirty --no-verify`, then:

```
~
❯ cargo binstall --manifest-path ~/src/github/nushell/nushell/Cargo.toml nu --force
 INFO resolve: Resolving package: 'nu'
 WARN resolve: The package will be downloaded from github.com
 INFO resolve: This will install the following binaries:
 INFO resolve:   - nu (nu -> /home/michel/.cargo/bin/nu-v0.71.0)
 INFO resolve: And create (or update) the following symlinks:
 INFO resolve:   - nu (/home/michel/.cargo/bin/nu -> nu-v0.71.0)
Do you wish to continue? yes/[no]
? yes
 INFO install: Installing binaries...
 INFO Done in 8.538106765s
```

`--force` was needed because I've previously tried this to manually test
the `pkg-url`:

```
cargo binstall \
        --pkg-url="{ repo }/releases/download/{ version }/{ name }-{ version }-{ target }.{ archive-format }" \
        --pkg-fmt="tgz" nu
```

Fixes #7201.

Signed-off-by: Michel Alexandre Salim <michel@michel-slm.name>

Signed-off-by: Michel Alexandre Salim <michel@michel-slm.name>
2022-11-23 08:46:06 -08:00
e813e44501 Fix fetch/post not erroring on 4xx and 5xx statuses (#7213)
# Description

Closes #6803.

You can look at the code and see this was always supposed to work this
way, but was broken due to 1 line (per file).

# User-Facing Changes

See above.

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-11-23 08:43:12 -08:00
f46c45343a uniq code refactoring (#7188)
# Description

While trying to add a new `uniq-by` command I refactored the `uniq`
command code to understand it and try to reuse. I think this is more
compact and easier to understand.
The part that I think it's a little confusing in this refactor is the
conditions inside `.filters()`, for example: `!flag_show_repeated ||
(value.1 > 1)`. I could use `if (flag_show_repeated) {value.1 > 1} else
{true}` but it is more verbose, what do you think?

PS: Not sure if you like this kind of PR, sorry if not.

# Tests + Formatting

I also added a test where the `uniq` has a table as input.
2022-11-23 11:18:13 +01:00
b12ffb8888 Fix sort-by, path join and size error arrows (#7199)
# Description
BEFORE:
```
〉ls | size
Error: nu:🐚:pipeline_mismatch (link)

  × Pipeline mismatch.
   ╭─[entry #22:1:1]
 1 │ ls | size
   ·      ──┬─
   ·        │╰── value originates from here
   ·        ╰── expected: string
   ╰────

〉ls | sort-by SIZE
Error: nu:🐚:column_not_found (link)

  × Cannot find column
   ╭─[entry #17:1:1]
 1 │ ls | sort-by SIZE
   ·      ───┬───
   ·         │╰── value originates here
   ·         ╰── cannot find column
   ╰────

〉[4kb] | path join 'b'
Error: nu:🐚:pipeline_mismatch (link)

  × Pipeline mismatch.
   ╭─[entry #6:1:1]
 1 │ [4kb] | path join 'b'
   · ──┬──
   ·   │╰── value originates from here
   ·   ╰── expected: string or record
   ╰────
```
AFTER:
```
〉ls | size
Error: nu:🐚:pipeline_mismatch (link)

  × Pipeline mismatch.
   ╭─[entry #1:1:1]
 1 │ ls | size
   · ─┬   ──┬─
   ·  │     ╰── expected: string
   ·  ╰── value originates from here
   ╰────

〉ls | get 0 | sort-by SIZE
Error: nu:🐚:column_not_found (link)

  × Cannot find column
   ╭─[entry #2:1:1]
 1 │ ls | get 0 | sort-by SIZE
   · ─┬           ───┬───
   ·  │              ╰── cannot find column 'SIZE'
   ·  ╰── value originates here
   ╰────

〉[4kb] | path join 'b'
Error: nu:🐚:pipeline_mismatch (link)

  × Pipeline mismatch.
   ╭─[entry #1:1:1]
 1 │ [4kb] | path join 'b'
   · ──┬──   ────┬────
   ·   │         ╰── expected: string or record
   ·   ╰── value originates from here
   ╰────

```

(Hey, anyone noticed that there's TWO wordings of "value originates from
here" in this codebase………?)

# User-Facing Changes

See above.

# 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 --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass

# 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.
2022-11-23 19:22:23 +13:00
cf96677c78 Error on negative argument of first (#7186)
Fixes a two's complement underflow/overflow when given a negative arg.

Breaking change as it is throwing an error instead of most likely
returning most of the output.

Same behavior as #7184


# Tests + Formatting

+ 1 failure test

# After Submitting

If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-11-23 17:04:28 +13:00
ce03d8eb12 Error on negative argument to last (#7184)
# Description

- Error on negative argument to `last`
- Add test for negative value in last

Follow-up for #7178

# User-Facing Changes

Breaking change:

even before #7178 `last` returned an empty `list<any>` when given
negative indices.
Now this is an
[error](https://docs.rs/nu-protocol/latest/nu_protocol/enum.ShellError.html#variant.NeedsPositiveValue)

Note:
In #7136 we are considering supporting negative indexing

# Tests + Formatting

+ 1 failure test

# After Submitting

If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-11-23 17:04:04 +13:00
21dedef7f6 remove block input support in merge (#7177)
# Description

Closes: #6937

# User-Facing Changes

N/A

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass

# 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.
2022-11-23 17:01:27 +13:00
da7f77867a Fixed json parsing (#7175)
# Description

I noticed that some json values are not parsed at the top level, for
example: `null`, `true`, `false`. Although this is a valid json.
```
> "null" | from json
Error:
  × Error while parsing JSON text
   ╭─[entry #12:1:1]
 1 │ "null" | from json
   ·          ────┬────
   ·              ╰── error parsing JSON text
   ╰────

Error:
  × Error while parsing JSON text
   ╭────
 1 │ null
   ╰────
```

I tried to fix it and it seems to work fine.

# User-Facing Changes

It should give fewer errors.

# 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 --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass

# After Submitting

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

Co-authored-by: sholderbach <sholderbach@users.noreply.github.com>
2022-11-23 17:00:00 +13:00
3415594877 Bump minimatch from 3.0.4 to 3.1.2 in /samples/wasm (#7181)
Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.0.4 to
3.1.2.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="699c459443"><code>699c459</code></a>
3.1.2</li>
<li><a
href="2f2b5ff1bb"><code>2f2b5ff</code></a>
fix: trim pattern</li>
<li><a
href="25d7c0d09c"><code>25d7c0d</code></a>
3.1.1</li>
<li><a
href="55dda291df"><code>55dda29</code></a>
fix: treat nocase:true as always having magic</li>
<li><a
href="5e1fb8dd2b"><code>5e1fb8d</code></a>
3.1.0</li>
<li><a
href="f8145c54f3"><code>f8145c5</code></a>
Add 'allowWindowsEscape' option</li>
<li><a
href="570e8b1aef"><code>570e8b1</code></a>
add publishConfig for v3 publishes</li>
<li><a
href="5b7cd3372b"><code>5b7cd33</code></a>
3.0.6</li>
<li><a
href="20b4b56283"><code>20b4b56</code></a>
[fix] revert all breaking syntax changes</li>
<li><a
href="2ff038852e"><code>2ff0388</code></a>
document, expose, and test 'partial:true' option</li>
<li>Additional commits viewable in <a
href="https://github.com/isaacs/minimatch/compare/v3.0.4...v3.1.2">compare
view</a></li>
</ul>
</details>
<br />


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

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

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

---

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

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot 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)
- `@dependabot use these labels` will set the current labels as the
default for future PRs for this repo and language
- `@dependabot use these reviewers` will set the current reviewers as
the default for future PRs for this repo and language
- `@dependabot use these assignees` will set the current assignees as
the default for future PRs for this repo and language
- `@dependabot use this milestone` will set the current milestone as the
default for future PRs for this repo and language

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>
2022-11-23 16:57:55 +13:00
0c38729735 Apply clippy fix (#7193)
# Description

rust 1.65.0 has been released for a while, this pr applies lint
suggestions from rust 1.65.0.

# User-Facing Changes

N/A

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass

# 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.
2022-11-23 16:57:27 +13:00
a0b3a48e8b Fix mv error message issues (arrows, Windows paths) (#7197)
# Description

BEFORE (notice Windows paths look wrong):
```
〉mv 8 9
Error:
  × Destination file already exists
   ╭─[entry #22:1:1]
 1 │ mv 8 9
   ·      ┬
   ·      ╰── you can use -f, --force to force overwriting the destination
   ╰────

〉mv d1 tmp
Error:
  × Can't move "C:\\Users\\Leon\\TODO\\d1" to "C:\\Users\\Leon\\TODO\\tmp\\d1"
   ╭─[entry #19:1:1]
 1 │ mv d1 tmp
   ·       ─┬─
   ·        ╰── Directory not empty
   ╰────

```
AFTER (full paths are now included in the arrows' messages to make lines
like `mv $foo` entirely unambiguous):
```
〉mv 8 9
Error:
  × Destination file already exists
   ╭─[entry #4:1:1]
 1 │ mv 8 9
   ·      ┬
   ·      ╰── Destination file 'C:\Users\Leon\TODO\tmp\9' already exists
   ╰────
  help: you can use -f, --force to force overwriting the destination

〉mv d1 tmp
Error:
  × Can't move 'C:\Users\Leon\TODO\d1' to 'C:\Users\Leon\TODO\tmp\d1'
   ╭─[entry #3:1:1]
 1 │ mv d1 tmp
   ·       ─┬─
   ·        ╰── Directory 'C:\Users\Leon\TODO\tmp' is not empty
   ╰────

```
# User-Facing Changes

See above.

# 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 --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass

# 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.
2022-11-23 16:55:13 +13:00
b662c2eb96 Make external command substitution works friendly(like fish shell, trailing ending newlines) (#7156)
# Description

As title, when execute external sub command, auto-trimming end
new-lines, like how fish shell does.

And if the command is executed directly like: `cat tmp`, the result
won't change.

Fixes: #6816
Fixes: #3980


Note that although nushell works correctly by directly replace output of
external command to variable(or other places like string interpolation),
it's not friendly to user, and users almost want to use `str trim` to
trim trailing newline, I think that's why fish shell do this
automatically.

If the pr is ok, as a result, no more `str trim -r` is required when
user is writing scripts which using external commands.

# User-Facing Changes
Before:
<img width="523" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468810-86b04dbb-c147-459a-96a5-e0095eeaab3d.png">

After:
<img width="505" alt="img"
src="https://user-images.githubusercontent.com/22256154/202468599-7b537488-3d6b-458e-9d75-d85780826db0.png">


# 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 --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass

# 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.
2022-11-23 16:51:57 +13:00
JT
8cda641350 Don't redirect stdout when only redirecting stderr (#7206)
# Description

Spotted by @WindSoilder - don't redirect stdout if the user requests
`err>`.

# User-Facing Changes

_(List of all changes that impact the user experience here. This helps
us keep track of breaking changes.)_

# Tests + Formatting

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

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

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# 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.
2022-11-23 15:18:34 +13:00
efdfeac55e Feature cleanup (#7182)
Following up on #7180 with some feature cleanup:

- Move the `database` feature from `plugin` to `default`
- Rename the `database` feature to `sqlite`
- Remove `--features=extra` from a lot of scripts etc. 
- No need to specify this, the `extra` feature is now the same as the
default feature set
- Remove the now-redundant 2nd Ubuntu test run
2022-11-22 16:58:11 -08:00
e0577e15f2 Restore original do -i behavior and add flags to break down shell vs program errors (#7122)
Closes https://github.com/nushell/nushell/issues/7076, fixes
https://github.com/nushell/nushell/issues/6956

cc @WindSoilder @fdncred

Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
2022-11-22 15:58:36 -06:00
bb0b0870ea Change all --insensitive flags to --ignore-case (#7198)
# Description

Support for this breaking change was raised in #7191. This affects
`sort`, `sort-by`, `str contains` and `find`. `--ignore-case` is used by
a few POSIX programs such as `less` and `grep`, as well as a few other
popular utils like `tree` and `wget`. Since long names aren't especially
popular (existing primarily for self-documentation purposes), I consider
this on the shallow end of the compat-break scale.

Note that the `-i` short flag is not affected.
 
# User-Facing Changes

See above.

# 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 --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- `cargo test --workspace --features=extra` to check that all tests pass

# 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.
2022-11-22 15:38:30 -06:00
JT
74a73f9838 Stdout/Stderr redirection (#7185)
This adds new pipeline connectors called out> and err> which redirect either stdout or stderr to a file. You can also use out+err> (or err+out>) to redirect both streams into a file.
2022-11-23 07:26:13 +13:00
c9f9078726 Fix while ctrlc behavior (#7195)
Currently while didn't respect ctrl-c, and thus non-terminating loops
couldn't be interrupted. This patch fixes this.
2022-11-22 15:47:12 +01:00
eb875ea949 Fix glob error arrows (#7194) 2022-11-22 14:23:01 +01:00
JT
b4a0e4c0dc Move dataframe out of extra (#7180) 2022-11-22 06:24:25 +13:00
88a0705df1 Fix last memory use (#7178)
Currently `last n` memory use is O(input), while it should be O(n). This
patch replaces code collecting all of last's input into a Vec<_> with
collecting into a bounded VecDeque<_>. UI/UX remain are unchanged.
2022-11-22 06:19:31 +13:00
7bcd96fc65 Remove erroneous test (#7179) 2022-11-21 17:04:36 +01:00
833825ae9a Allow iteration blocks to have an optional extra index parameter (alternative to -n flags) (#6994)
Alters `all`, `any`, `each while`, `each`, `insert`, `par-each`, `reduce`, `update`, `upsert` and `where`,
so that their blocks take an optional parameter containing the index.
2022-11-21 14:35:11 +01:00
899383c30c feat: Use Raw Text to save if pipeline data is ExternalStream (#7082)
if not value type or Value as String in nushell, save will use raw type
2022-11-20 19:32:15 -06:00
d9d6cea5a9 Make json require string and pass around metadata (#7010)
* Make json require string and pass around metadata

The json deserializer was accepting any inputs by coercing non-strings
into strings. As an example, if the input was `[1, 2]` the coercion
would turn into `[12]` and deserialize as a list containing number
twelve instead of a list of two numbers, one and two. This could lead
to silent data corruption.

Aside from that pipeline metadata wasn't passed aroud.

This commit fixes the type issue by adding a strict conversion
function that errors if the input type is not a string or external
stream. It then uses this function instead of the original
`collect_string()`. In addition, this function returns the pipeline
metadata so it can be passed along.

* Make other formats require string

The problem with json coercing non-string types to string was present in
all other text formats. This reuses the `collect_string_strict` function
to fix them.

* `IntoPipelineData` cleanup

The method `into_pipeline_data_with_metadata` can now be conveniently
used.
2022-11-20 17:06:09 -08:00
d01ccd5a54 add signature information when get help on one command (#7079)
* add signature information when help on one command

* tell user that one command support operated on cell paths

Also, make type output to be more friendly, like `record<>` should just be `record`

And the same to `table<>`, which should be `table`

* simplify code

* don't show signatures for parser keyword

* update comment

* output arg syntax shape as type, so it's the same as describe command

* fix string when no positional args

* update signature body

* update

* add help signature test

* fix arg output format for composed data type like list or record

* fix clippy

* add comment
2022-11-20 07:22:42 -06:00
JT
a896892ac9 Add auto-expanding table view to default config (#7172) 2022-11-20 20:52:38 +13:00
d89d1894d0 Add missing legacy support for config.table_index_mode. (#7170) 2022-11-20 00:46:13 -05:00
587536ddcc Edit rm help messages (#7165)
* Edit `rm` help messages

* Restore accidental missing changes
2022-11-19 10:33:30 -08:00
ced5e1065f new command url parse (#6854) and url subcommands tests (#7124)
*code refactor from PR tips & clippy fixes

*added username, password, and fragment

*commands `url host`, `url scheme`, `url query`, and `url path` removed

*tests refactoring - avoid formatted output
2022-11-19 10:14:29 -08:00
7479173811 Grouped config commands better (closes #6911) (#6983)
* Grouped config commands better

* Tweaked test slightly

* Fix merge conflict(?)

* Remove recently-added test case

* Revert rm.always_trash default

* Untweak rm help messages

* Formatting

* Remove example

* Add deprecation warning

* Remove deprecation timeline

Not sure we want to commit to a specific timeline just yet

Co-authored-by: Reilly Wood <26268125+rgwood@users.noreply.github.com>
2022-11-19 09:52:09 -08:00
4b83a2d27a Improve CantFindColumn and ColumnAlreadyExists errors (#7164)
* Improve CantFindColumn and ColumnAlreadyExists errors

* Update tests
2022-11-19 09:35:55 -08:00
41f72b1236 Friendly error message for missing plugin executable (#7163) 2022-11-19 12:12:18 +01:00
c98a6705e6 Fix needs_quotes() in to nuon (closes #6989) (#7056)
* to nuon: fix needs_quotes()

Also, null now serialises as null instead of $nothing.

* Clippy

* Add missing quote

* Remove two unnecessary characters

* Add short datetime tests

* Make regex simplificatified

* Alphabetise 'use' statements

* Improve perf by putting case-insensitive cases in regex

* Fix 1 test
2022-11-19 12:09:39 +01:00
JT
6454bf69aa Parser refactoring for improving pipelines (#7162)
* Remove lite_parse file

* Add LiteElement to represent different pipeline elem types

* Add PipelineElement to Pipelines

* Remove lite_parse specific tests
2022-11-19 10:46:48 +13:00
bd30ea723e Consistent wrap (#7159)
* Consistent wrap

* Signature fix
2022-11-19 10:39:40 +13:00
2dd4cb9f7d Improve "Cannot convert argument to string" msg (#7161) 2022-11-18 21:33:01 +01:00
1784b4bf50 fix #7145 (#7148)
* fix #7145

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Improve fix

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2022-11-17 07:51:04 -06:00
8e4b85e29b update default_config.nu with display_output (#7146)
Added a default display_output hook to help people know about this feature.
2022-11-16 19:08:09 -05:00
7098e56ccf Remove build-string command (#7144) 2022-11-16 09:37:52 -08:00
02ad491dea [WIP] table: Change Record view in expand-mode (#6885)
* table: Change Record view in expand-mode

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Fix width issue

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Remove debug println!

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Update logic

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Improve the logic via a wrapping

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* `table -e` spread table to the whole width

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* fix CI

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Fixing tests

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Fix coloring issues

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Don't expand when can

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Fix tests

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Change the logic

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Fix cargo fmt

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2022-11-16 08:03:56 -06:00
708fee535c fix: ls not show pattern error (#7143)
Log: fix pattern error show in ls command
2022-11-16 09:15:19 +01:00
7636cc7fe4 avoid test failure caused by locale thousand separator (#7142)
Co-authored-by: Ricardo Monteiro <ricardo.monteiro@getmanta.com>
2022-11-16 11:15:15 +13:00
f856e64fb3 to html --list now returns a table (#7080)
* `to html --list` now returns a table

* Re-add screenshots link
2022-11-15 11:12:56 -06:00
a783a084d4 Update PR template; Add some tests instructions (#7135) 2022-11-15 00:43:15 +01:00
81b12d02ec Change parser cwd when running a file (#7134)
* Change parser cwd when running a file

* Add test

* Add missing file
2022-11-15 00:05:27 +01:00
336df6c65e Return errors on unexpected inputs to take and first (#7123)
* Fix `take` behaviour for unexpected input types

* Fix `first` behaviour for unexpected input types

* Fix copy paste mistake
2022-11-13 15:15:27 -08:00
35f9299fc6 fix ansi --osc parameter adding extra semi-colon (#7113) 2022-11-12 23:27:58 +01:00
649c8319e6 Add input-output types to $nu.scope.commands (#7105)
* Add input and output types to $nu.scope.commands

This commit changes the schema: instead of

command.signature: table

we now have

command.signatures: list<table>

with one signature for every input-output type pair.

* Represent signatures as a map from input_type to signature

* Sort signature entries

* Drop command name from signature tables

* Don't use "rest" as name of rest parameter; use empty string instead

* Bug fix: was creating records with repeated keys

E.g.
$nu.scope.commands | where name == 'hash sha256' | get signatures.0 | table -e
$nu.scope.commands | where name == 'transpose' | get signatures.0 | table -e
2022-11-12 14:26:20 -08:00
99cf5871aa Try --locked install in virtualenv CI tests (#7117)
Currently we see CI failures due to a `chrono` upgrade with
deprecations.
Also on every new reedline release we also suffer from regular compile
problems.
2022-11-12 18:53:57 +01:00
da04e9d801 Remove accidental strip-ansi-escapes after #6938 (#7115) 2022-11-12 17:12:40 +01:00
2db2d98ef0 Add missing dependency to Cargo.lock (#7114) 2022-11-12 16:13:42 +01:00
817eacccd8 removes unused features. (#6938)
* removes unused features.

* Adds back multithreading feature to sysinfo.

* Adds back alloc for percent-encoding

* Adds updated lock file.

* Missed one sysinfo.

* `indexmap` just defaults

* Revert `miette``default-features=false`

Co-authored-by: Stefan Holderbach <sholderbach@users.noreply.github.com>
Co-authored-by: JT <547158+jntrnr@users.noreply.github.com>
2022-11-12 18:44:56 +13:00
ce6d3c6eb2 Refactor creation of $nu.scope in eval.rs (#7104)
The function was ~400 lines long and hence very hard to work with.
2022-11-11 23:20:28 +01:00
ef32e1ce1a reset stack size to 10mb vs 2gb (#7103) 2022-11-11 15:22:26 -06:00
JT
c1105e945e Add additional assignment operators (#7102) 2022-11-12 07:50:43 +13:00
JT
69b089845c Add support for while loops (#7101) 2022-11-12 07:21:45 +13:00
75556f6c5f fix(#7097): let-env should not be able to set PWD (#7100) 2022-11-12 05:45:51 +13:00
b650d1ef79 Remove --separator from seq date (#7096) 2022-11-11 20:16:44 +13:00
JT
099b571e8f All field assignment into the env variable (#7099) 2022-11-11 20:16:07 +13:00
cb926f7b49 Better error message when rm can't find files (#7098) 2022-11-10 23:05:09 -08:00
JT
13515c5eb0 Limited mutable variables (#7089)
This adds support for (limited) mutable variables. Mutable variables are created with mut much the same way immutable variables are made with let.

Mutable variables allow mutation via the assignment operator (=).

❯ mut x = 100
❯ $x = 200
❯ print $x
200

Mutable variables are limited in that they're only tended to be used in the local code block. Trying to capture a local variable will result in an error:

❯ mut x = 123; {|| $x }
Error: nu::parser::expected_keyword (link)

  × Capture of mutable variable.

The intent of this limitation is to reduce some of the issues with mutable variables in general: namely they make code that's harder to reason about. By reducing the scope that a mutable variable can be used it, we can help create local reasoning about them.

Mutation can occur with fields as well, as in this case:

❯ mut y = {abc: 123}
❯ $y.abc = 456
❯ $y

On a historical note: mutable variables are something that we resisted for quite a long time, leaning as much as we could on the functional style of pipelines and dataflow. That said, we've watched folks struggle to work with reduce as an approximation for patterns that would be trivial to express with local mutation. With that in mind, we're leaning towards the happy path.
2022-11-11 19:51:08 +13:00
JT
58d960d914 Update README re: typechecking (#7094) 2022-11-11 15:16:10 +13:00
JT
4a83bb6c93 Fix environment conversions (#7092) 2022-11-11 13:13:07 +13:00
3e56e81d06 fix plugin detection in help commands (#7088) 2022-11-10 16:12:09 -06:00
312e9bf5d6 fix overflow on negative bytes (#7070) 2022-11-10 22:33:15 +01:00
JT
18d7e64660 Convert 'for' to a statement (#7086) 2022-11-11 09:05:34 +13:00
f1118020a1 add commented out mold linker usage (#7081) 2022-11-10 08:41:06 -06:00
JT
63433f1bc8 Split blocks and closures (#7075)
* Split closures and blocks

* Tests mostly working

* finish last fixes, passes all tests

* fmt
2022-11-10 21:21:49 +13:00
921a66554e Replace all instances of 'column path' in help messages with 'cell path' (#7063)
* Rewrite all 'column path' instances to 'cell path'

* Minor tweak
2022-11-09 21:49:11 -08:00
bb0d08a721 Fix command_type classification (#7074)
- Custom commands are true for builtin and custom
- Add classification as external command
- Specify wildcard in keyword: keyword is true for builtin and keyword
2022-11-09 19:09:33 -08:00
fe14e52e77 Collapse some help commands columns into a single column (#7052) 2022-11-09 17:44:32 -08:00
24d72ca43c Simplify seq char (#7054)
* Simplify `seq char`

* Fix input/output tests
2022-11-09 17:06:47 -08:00
457f7889df use path.try_exist() to fix silent errors (#7069) 2022-11-09 16:54:43 -08:00
7b0c0692dc Type validation for headers command (#6918) (#7047)
cargo clippy lints

tests

format

Co-authored-by: Ricardo Monteiro <ricardo.monteiro@getmanta.com>
2022-11-09 16:43:24 -08:00
c4cb3a77cb command open returns error when does not have parameters (#7048) (#7058)
test

Co-authored-by: Ricardo Monteiro <ricardo.monteiro@getmanta.com>
2022-11-10 00:25:32 +01:00
aed8d3800b Fix CI failures after PR merge conflicts (#7072) 2022-11-10 00:24:57 +01:00
53a9264b67 return value::int instead of value::record in history session (#7049)
* return value::int instead of value::record

* clippy
2022-11-10 11:20:52 +13:00
e18fb13616 Make seq output type consistent (#7045) 2022-11-10 11:19:02 +13:00
2201bd9b09 Require column name(s) in sort-by (#7041) 2022-11-10 11:16:51 +13:00
da8f6c5682 Require input for date format (#7043) 2022-11-10 11:16:14 +13:00
14d7ba5cc9 Remove --predicate flag from find (#7042) 2022-11-10 11:15:17 +13:00
5ee096232c Remove sqlparser SQLite commands (#7040) 2022-11-10 11:14:48 +13:00
c259ef41bd update polar to 0.25 (#6988) 2022-11-10 11:07:38 +13:00
2c238aea6a Fixed $in in where blocks (#6976) 2022-11-10 11:05:15 +13:00
c600c1ebe7 Fix ignore-errors for select (#6896)
* Fix ignore-errors for select

* fix Value::List match

* fix invalid rows

* add tests

* fix ListStream match

* add one more test for ListStream

* add more tests

* tweak words
2022-11-10 10:57:44 +13:00
df94052180 Declare input and output types of commands (#6796)
* Add failing test that list of ints and floats is List<Number>

* Start defining subtype relation

* Make it possible to declare input and output types for commands

- Enforce them in tests

* Declare input and output types of commands

* Add formatted signatures to `help commands` table

* Revert SyntaxShape::Table -> Type::Table change

* Revert unnecessary derive(Hash) on SyntaxShape

Co-authored-by: JT <547158+jntrnr@users.noreply.github.com>
2022-11-10 10:55:05 +13:00
JT
f878276de7 Turn off foreground processes on macOS (#7068)
* Turn off foreground processes on macOS

* fmt
2022-11-10 07:39:09 +13:00
cd89304706 Add help warnings for path exists and path type regarding usage (#7062)
* Add help warnings to `path exists` and `path type`

* Correction
2022-11-09 13:41:55 +01:00
2b9f258126 bump to dev release 0.71.1 (#7064) 2022-11-09 13:18:34 +01:00
85587c0c2a make take behave like first (#6893)
* fix take_1 behavior

* fix test case

* simplify code

* reverse back for first command

* fix example

* make arg required

* add test

* fix test message
2022-11-09 11:32:16 +01:00
JT
6cc4ef6c70 bump to 0.71, use 1.63 toolchain (#7061) 2022-11-09 06:54:00 +13:00
JT
517173bb8c Update rust-toolchain.toml 2022-11-09 06:06:33 +13:00
JT
e415be6c0e Revert back to 1.63 because of macOS build issues 2022-11-09 06:05:53 +13:00
59332562bb Update contributing guide and PR template (#7008)
* Update contributing guide

* Refactor pull request template

* Reword PR template a bit

* Update CONTRIBUTING.md

Co-authored-by: Reilly Wood <26268125+rgwood@users.noreply.github.com>

* Reformulate

* Make "Before Submitting" a top-level header

* Add review requirement to After Submitting

* Reformulate

* Update .github/pull_request_template.md

Co-authored-by: Dan Davison <dandavison7@gmail.com>

* Reformulate contributing guide

Co-authored-by: Reilly Wood <26268125+rgwood@users.noreply.github.com>
Co-authored-by: Dan Davison <dandavison7@gmail.com>
2022-11-07 22:57:29 +01:00
3d8d7787de Pin reedline to 0.14.0 release (#7050)
See release notes:
https://github.com/nushell/reedline/releases/tag/v0.14.0
2022-11-07 21:31:15 +01:00
611fe41788 Make the example names unique across workspace (#7046)
Avoids name collision in the target directory when running test
compilation.

cc @rgwood
2022-11-07 09:00:21 +01:00
a6118eed8d Revert "Fix for escaping backslashes in interpolated strings (fixes #6737) (#7020)" (#7038)
This reverts commit d4798d6ee1.
2022-11-06 16:17:00 -06:00
d4798d6ee1 Fix for escaping backslashes in interpolated strings (fixes #6737) (#7020)
Co-authored-by: Gavin Foley <gavinmfoley@gmail.com>
2022-11-07 08:57:28 +13:00
5ea245badf Make example binaries proper cargo examples (#7019)
Should not be built by default with `cargo build`
Instead are compiled with `cargo test` to avoid bitrot
Run with `cargo run -p ... --example ...`
2022-11-06 11:39:27 -08:00
5ee7847035 Add accidentally missing tests of some command examples (#7035)
* Add missing tests of examples

* Fix broken tests due to externals not being in working set

* Comment out `where` test due to bug
2022-11-06 09:53:25 -08:00
8a812cf03c added some search-terms to the platform category (#7021)
* added some search-terms to the `platform` category

* removed the redundant `sleep` search-term

* removed the redundant `gradients` search-term
2022-11-06 18:11:04 +01:00
9a1cedfd08 Add expected result to test (#7031) 2022-11-06 18:09:56 +01:00
766d1ef374 Update reedline (#7023)
Fixes #6991
2022-11-06 09:37:36 +01:00
beec658872 New "display_output" hook. (#6915)
* New "display_output" hook.

* Fix unrelated "clippy" complaint in nu-tables crate.

* Fix code-formattng and style issues in "display_output" hook

* Enhance eval_hook to return PipelineData.

This allows a hook (including display_output) to return a value.

Co-authored-by: JT <547158+jntrnr@users.noreply.github.com>
2022-11-06 13:46:40 +13:00
b90d701f89 Rename column name from command to name for consistency (#7007) 2022-11-05 10:46:30 +13:00
be5d71ea47 Run a round of clippy --fix to fix a ton of lints (#7006)
Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>

Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
2022-11-04 15:11:17 -05:00
f1bde69131 Fix panic when encountering ENOTTY. (#7001) 2022-11-05 09:06:04 +13:00
36ae384fb3 Improve do command docs (#6975) 2022-11-05 07:50:56 +13:00
2c4048eb43 Refactor ansi stripping into nu-utils functions (#6966)
Allows use of slightly optimized variants that check if they have to use
the heavier vte parser. Tries to avoid unnnecessary allocations. Initial
performance characteristics proven out in #4378.

Also reduces boilerplate with right-ward drift.
2022-11-05 07:49:45 +13:00
b9195c2668 fix: fixcd (#6799)
* fix: fixcd

try to fix

Log: try to fix the bug with can enter a permisson error fold

* change wording

* fat

* fmt

Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2022-11-05 07:38:39 +13:00
bb968304da bump rust-toolchain to 1.64 (#7005)
* bump rust-toolchain to 1.64

* 1.64 clippy
2022-11-04 10:27:23 -05:00
ca9bf19041 highlight term on PipelineData::Value() (#6997) 2022-11-04 08:42:16 -05:00
JT
ecfee4c542 Remove unnecessary clone in par-each (#6995)
* Remove unnecessary clone in par-each

* clippy
2022-11-04 18:07:28 +13:00
acb34561eb category tweak (#6982) 2022-11-02 12:17:17 -05:00
43aec8cdbe Fix $in in blocks given to any and all (#6951)
* Fix $in in blocks given to `any` and `all` (closes #6917)

* Fix help message typos

* Fix tests ($in doesn't work in examples?!)

* Fix formatting
2022-11-01 11:36:54 -07:00
e46d610f77 Refactor: finish refactor on commands which take optional cell paths. (#6961)
* refactor on conversions module

* finish refactor on strings command

* simplify code

* rename from ArgumentsCp to CellPathOnlyArgs

* fmt code

* refactor on hash relative commands
2022-11-01 12:40:11 +01:00
1d95861a09 Remove inadvertent dep on original ansi_term (#6965)
Is default feature in `lscolors`. Not needed for function as we use
crossterm backend in this case.
2022-11-01 12:27:20 +13:00
f48de73236 change str distance to output value::int (#6963)
* change str distance to output value::int

* update the test
2022-10-31 10:28:04 -05:00
0b4daa66b0 tweak upsert help text (#6962)
* tweak upsert help text

* more tweaks
2022-10-31 08:18:11 -05:00
412952182f Update reedline to latest dev (#6953)
- Reedline now properly supports the `sqlite-dynlib` feature flag
- Reorganized examples allow removal of `gethostname` as reedline
dev-dependency
2022-10-30 22:08:07 +01:00
014d36b17a Use nt-api 4 on Windows (#6949)
* Bump nushell-sytem dep to ntapi 0.4

0.3.7 trigger a warning about code being incompatible
with future rust versions. This is resolved in 0.4
https://github.com/MSxDOS/ntapi/issues/11

* Upgrade Cargo.lock for ntapi 0.4
2022-10-30 14:29:41 +01:00
f44f3a8af1 Fix double cache read in CI (#6948) 2022-10-30 08:24:10 +01:00
457514590d Refactor: introduce general operate commands to reduce duplicate code (#6879)
* make format filesize more flexible

* make code simpler

* finish refactor on bytes commands

* finish refactor on str commands

* fimplify code

* rename from column_paths to cell_paths
2022-10-29 16:29:46 -05:00
843d8c2242 Make default for mv safer, require -f to overwrite (#6904)
* fix:  "saner" default for mv

fixes #6747

As highlighted in the issue, the default behavior of nu currently
is to overwrite the destination file without notice.
This is not a "standard" expectation users that want this behavior
can create a dedicated alias.

* fix: 📝 edit the comment

* fix:  updated the tests

* fix: 🚧 use --force for case test
2022-10-29 22:16:29 +02:00
ce4ae00a6f Remove unused dependencies (#6945)
* Remove unused dependencies

Inspired by #6938 ran `cargo +nightly udeps --features extra`.
Removes 2 crates and should remove an unnecessary intra-workspace
dependency which might open up further opportunities for compilation.

* Make windows-only dependency conditional in toml

`omnipath` is only used on Windows and already behind a `#[cfg]` block
in the code. Made the dependency in `Cargo.toml` conditional as well.

* Make `nu-pretty-hex` example a proper example

This allows making `rand` a dev-dependency in this crate.
2022-10-29 21:19:12 +02:00
4f7f6a2932 Friendly error message for access beyond end (#6944)
Adds `ShellError::AccessEmptyContent`
2022-10-29 19:47:50 +02:00
7039602e4d Move nu-test-support into dev deps on nu-command (#6940)
This reduces the number of dependencies to build for `cargo build` or
`cargo run` by around 19.

Will not speed up CI as we need to `cargo test` but should help for
`cargo install` or users just building from source.
Time saved on my machine ~0.8 secs so likely unnoticable in noise.

Larger future goal is reducing longer dependency chains to allow more
parallel compilation.
2022-10-29 19:39:27 +02:00
acb7aff6fb Fix feature flag for open test (#6935) 2022-10-28 20:25:19 -07:00
8940ee6c3f enable ability to upsert into a list like update (#6932) 2022-10-28 18:13:14 -05:00
3b26b4355e Fix bug with alias handling when searching for matching brackets (#6931)
* [4325] - fix slicing

* [4325] - fix style
2022-10-28 16:21:24 -05:00
b56e603c58 Update PR template to mention user-facing changes (#6923)
* Update PR template to mention user-facing changes

* remove checkboxes
2022-10-28 09:14:08 -07:00
66c2a36123 table: Show truncated record differently (#6884)
Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2022-10-28 14:00:10 +02:00
8838815737 Update nix crate to 0.25 and narrow features (#6924)
Avoids compiling the crate twice due to incompatible versions from
dependencies. This avoids binary bloat before linking as well.
Narrow our feature selection to the used modules/functions to save
compile time. On my machine reduces `nix` crate compile time from 
around 9 secs to 0.9 secs.
2022-10-28 01:07:13 +02:00
834522d002 Fix each while behavior when printing. (#6897)
Fixes #6895

Warning: `Iterator::map_while` does not return a `FusedIterator`!
Depending on the consuming adaptor or code (e.g. for loop) the iteration
may be stopped but this is not guaranteed.

Adds a test example but Examples handle iterators like
`FusedIterator` and thus don't catch the regression

Cleanup the message on another test
2022-10-27 23:45:45 +02:00
f281cd5aa3 Update merge to also take single records (#6919) 2022-10-27 09:00:26 -07:00
5add5cbd12 Further edits to help messages (#6913) 2022-10-26 09:36:42 -07:00
902aad6016 fix description of build-string's second example (#6912) 2022-10-26 09:36:31 -05:00
13f87857cf docs: 📝 add "map" to each's search terms (#6903) 2022-10-25 21:24:27 +02:00
e0cc2c9112 Make get 1 error message better (#6892) 2022-10-24 18:22:57 -07:00
92ab8b831b Reduce required dependencies for diagnostics (#6648)
Disable backtrace on miette
- gimli crate requires several seconds
Disable diagnostics on wax
- depends on an outdated miette version

Builds fine, no observable loss in diagnostics quality of life

Removes 10 crates that have to be compiled.
2022-10-24 21:42:32 +02:00
6a7a60429f Remove unnecessary #[allow(...)] annotations (#6870)
* Remove unnecessary `#[allow]` annots

Reduce the number of lint exceptions that are not necessary with the
current state of the code (or more recent toolchain)

* Remove dead code from `FileStructure` in nu-command

* Replace `allow(unused)` with relevant feature switch

* Deal with `needless_collect` with annotations

* Change hack for needless_collect in `from json`

This change obviates the need for `allow(needless_collect)`
Removes a pessimistic allocation for empty strings, but increases
allocation size to `Value`

Probably not really worth it.

* Revert "Deal with `needless_collect` with annotations"

This reverts commit 05aca98445.

The previous state seems to better from a performance perspective as a
`Vec<String>` is lighter weight than `Vec<Value>`
2022-10-24 20:12:16 +02:00
79fd7d54b2 Wrap open parse errors from from commands (#6877)
* Wrap `open` parse errors from `from` commands

Minimal fix for #6843

This propagates the underlying errors from the called `from` commands
and adds a top-level error with the full path and the understood file
extension and resulting called command.

* Repoint inner span for `from ...` to `open`

* Add actionable message: refer to help or use --raw
2022-10-24 20:09:19 +02:00
ebca840d91 Add support to render right prompt on last line of the prompt (#6781)
* Add support to render right prompt on last line of the prompt

* reset reedline to main branch

* update reedline to fix right prompt to be rendered correctly

* reset reedline to main branch again
2022-10-23 16:18:26 +02:00
17b2bcc125 Support range in str substring (#6867) 2022-10-23 11:42:17 +02:00
24a98f8999 Mildly edited a small handful of help messages (#6868)
* Edited a handful of help messages

* Remove line break as instructed by clippy
2022-10-23 02:02:52 -04:00
e49b359848 Bumps Windows 0.37 -> 0.42. (#6865) 2022-10-22 17:59:44 -07:00
c9fb381d69 feat: coredump (#6791)
fix issue in https://github.com/nushell/nushell/issues/5903
return Error to pipeline_data, if match error, then return error
directly
2022-10-22 20:24:58 +02:00
8224ec49bc Highlight matching brackets / parentheses (#6655)
* [4325] - wip

* [4325] - hightlight only matched symbol

* [4325] - cleanup

* [4325] - match bracket while typing

* [4325] - fix clippy

* [4325] - add bracket highlight configuration

* [4325] - fix working with non-ascii
2022-10-22 11:55:45 -05:00
fe7e87ee02 Fixes for ps on Linux (#6858)
* Fix ps returning nothing when process dies

* Fix ps CPU calcs on Linux, remove unused thread code
2022-10-22 11:54:46 -05:00
a3dce8ff19 table -e Fix stackoverflow (cause endless empty list) (#6847)
Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2022-10-22 11:52:32 -05:00
89f3cbf318 Try not to use verbatim paths for UNC shares (#6824) 2022-10-22 11:51:52 -05:00
3f555a6836 add more helpful error for calling a decl that exists in a module (#6752)
* add more helpful error for calling a decl that exists in a module

* accord to suggestions

* make error more helpful
2022-10-22 11:41:31 -05:00
4fdf5c663c Prepend directory to the binary tarball (#6701)
* Prepend directory to the binary tarball

According to https://www.gnu.org/software/tar/manual/html_section/transform.html, use
`--transform` parameter to prepend directory to each file name.

Closes #6676

* Don't depend on GNU tar
2022-10-22 11:39:11 -05:00
1ec41a0ab4 Expose reedline EditCommand::Complete command (#6863)
This should have been done in 5eee33c7e4
2022-10-22 11:32:07 -05:00
ab0a6b6ca6 path: fix error message (#6860)
Closes #6819
2022-10-22 06:42:46 -05:00
e3bf6fdfc0 Print command help in base from+to commands (#6856) 2022-10-21 10:08:57 -07:00
46c0d29c08 table/ Fix paging indexing (#6850)
* table/ Fix paging indexing

close #6840

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Add test for pagging with row_overlapping

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2022-10-21 18:02:25 +02:00
76ccd5668a Remove perf flag to streamline logging configuration (#6834) 2022-10-21 10:20:21 -05:00
c6436eb32f rm: don't update target_exists every time in the loop (#6837) 2022-10-21 07:42:29 -07:00
b2c29117d9 table -e align key to 2nd line (#6842)
Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2022-10-21 06:29:55 -05:00
ffb1dfb012 Update ci workflow actions, fix #6713 (#6841)
* Update ci workflow actions, fix #6713

* Upgrade actions/setup-python to v4
2022-10-21 15:25:02 +08:00
88c6fa9933 Update reedline to fix history search filtering (#6835)
https://github.com/nushell/nushell/pull/6802#issuecomment-1285826499
2022-10-21 09:04:54 +02:00
60df45a390 Add missing shape_directory to default_config.nu (#6836)
Closes #6832
2022-10-20 21:25:09 -07:00
10aa86272b Allow captured stderr saving to file (#6793)
* support redirect stderr to file

* fix test

* fix test

* fix test
2022-10-20 07:56:44 -05:00
d37e6ba3b5 nu-table: Check perf improvements (#6710)
* nu-table: Checkout to test vte parsing

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Bump tabled version

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
2022-10-20 07:52:15 -05:00
5eee33c7e4 Tab inline completion (#6802)
* Make Tab insert (partial) completion instead of select next menu item

* Use reedline feature branch

Co-authored-by: JT <547158+jntrnr@users.noreply.github.com>
2022-10-20 23:39:48 +13:00
5e748ae8fc make ++ append lists (#6766)
* make `++` append lists

* fmt

* fix for database
2022-10-20 23:28:18 +13:00
50e53e788a Simplify and reduce allocations in pipeline data loop (#6790) 2022-10-20 23:22:07 +13:00
7336e1df1a rm: fix error span when targets doesn't exists (#6815)
Closes #6810
2022-10-20 10:00:25 +02:00
a724a8fe7d bump to dev version 0.70.1 (#6814) 2022-10-20 18:04:10 +13:00
JT
c731a4e275 Update Cargo.toml 2022-10-19 11:44:04 +13:00
1042 changed files with 56364 additions and 31274 deletions

View File

@ -12,3 +12,17 @@ rustflags = ["-C", "link-args=-stack:10000000", "-C", "target-feature=+crt-stati
# set a 2 gb stack size (0x80000000 = 2147483648 bytes = 2 GB)
# [target.x86_64-apple-darwin]
# rustflags = ["-C", "link-args=-Wl,-stack_size,0x80000000"]
# How to use mold in linux and mac
# [target.x86_64-unknown-linux-gnu]
# linker = "clang"
# rustflags = ["-C", "link-arg=-fuse-ld=/usr/local/bin/mold"]
# [target.x86_64-apple-darwin]
# linker = "clang"
# rustflags = ["-C", "link-arg=-fuse-ld=mold"]
# [target.aarch64-apple-darwin]
# linker = "clang"
# rustflags = ["-C", "link-arg=-fuse-ld=mold"]

20
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,20 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
# docs
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2
updates:
- package-ecosystem: "cargo"
directory: "/"
schedule:
interval: "weekly"
ignore:
- dependency-name: "*"
update-types: ["version-update:semver-patch"]
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

View File

@ -1,21 +1,24 @@
# Description
(description of your pull request here)
_(Thank you for improving Nushell. Please, check our [contributing guide](../CONTRIBUTING.md) and talk to the core team before making major changes.)_
# Tests
_(Description of your pull request goes here. **Provide examples and/or screenshots** if your changes affect the user experience.)_
Make sure you've done the following:
# User-Facing Changes
- [ ] Add tests that cover your changes, either in the command examples, the crate/tests folder, or in the /tests folder.
- [ ] Try to think about corner cases and various ways how your changes could break. Cover them with tests.
- [ ] If adding tests is not possible, please document in the PR body a minimal example with steps on how to reproduce so one can verify your change works.
_(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 --features=extra -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect` to check that you're using the standard code style
- [ ] `cargo test --workspace --features=extra` to check that all the tests pass
- `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect` to check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass
# Documentation
# After Submitting
- [ ] If your PR touches a user-facing nushell feature then make sure that there is an entry in the documentation (https://github.com/nushell/nushell.github.io) for the feature, and update it if necessary.
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.

View File

@ -11,41 +11,42 @@ jobs:
strategy:
fail-fast: true
matrix:
platform: [windows-latest, macos-latest, ubuntu-latest]
# Pinning to Ubuntu 20.04 because building on newer Ubuntu versions causes linux-gnu
# builds to link against a too-new-for-many-Linux-installs glibc version. Consider
# revisiting this when 20.04 is closer to EOL (April 2025)
platform: [windows-latest, macos-latest, ubuntu-20.04]
style: [default, dataframe]
rust:
- stable
include:
- style: default
flags: ""
- style: dataframe
flags: "--features=dataframe "
exclude:
# only test dataframes on Ubuntu (the fastest platform)
- platform: windows-latest
style: dataframe
- platform: macos-latest
style: dataframe
runs-on: ${{ matrix.platform }}
env:
NUSHELL_CARGO_TARGET: ci
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Setup Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
# makes ci use rust-toolchain.toml
# with:
# profile: minimal
# toolchain: ${{ matrix.rust }}
# override: true
# components: rustfmt, clippy
- name: Setup Rust toolchain and cache
uses: actions-rust-lang/setup-rust-toolchain@v1.4.2
- uses: Swatinem/rust-cache@v1
with:
key: "v2" # increment this to bust the cache if needed
- name: Rustfmt
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
- name: cargo fmt
run: cargo fmt --all -- --check
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --features=extra --workspace --exclude nu_plugin_* -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect
run: cargo clippy --workspace ${{ matrix.flags }}--exclude nu_plugin_* -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect
nu-tests:
env:
@ -54,43 +55,32 @@ jobs:
strategy:
fail-fast: true
matrix:
platform: [windows-latest, macos-latest, ubuntu-latest]
style: [extra, default]
platform: [windows-latest, macos-latest, ubuntu-20.04]
style: [default, dataframe]
rust:
- stable
include:
- style: extra
flags: "--features=extra"
- style: default
flags: ""
- style: dataframe
flags: "--features=dataframe"
exclude:
# only test dataframes on Ubuntu (the fastest platform)
- platform: windows-latest
style: default
style: dataframe
- platform: macos-latest
style: default
style: dataframe
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Setup Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
# makes ci use rust-toolchain.toml
# with:
# profile: minimal
# toolchain: ${{ matrix.rust }}
# override: true
- uses: Swatinem/rust-cache@v1
with:
key: ${{ matrix.style }}v3 # increment this to bust the cache if needed
- name: Setup Rust toolchain and cache
uses: actions-rust-lang/setup-rust-toolchain@v1.4.2
- name: Tests
uses: actions-rs/cargo@v1
with:
command: test
args: --workspace --profile ci --exclude nu_plugin_* ${{ matrix.flags }}
run: cargo test --workspace --profile ci --exclude nu_plugin_* ${{ matrix.flags }}
python-virtualenv:
env:
@ -99,7 +89,7 @@ jobs:
strategy:
fail-fast: true
matrix:
platform: [ubuntu-latest, macos-latest, windows-latest]
platform: [ubuntu-20.04, macos-latest, windows-latest]
rust:
- stable
py:
@ -108,39 +98,33 @@ jobs:
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Setup Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
# makes ci use rust-toolchain.toml
# with:
# profile: minimal
# toolchain: ${{ matrix.rust }}
# override: true
- uses: Swatinem/rust-cache@v1
with:
key: "2" # increment this to bust the cache if needed
- name: Setup Rust toolchain and cache
uses: actions-rust-lang/setup-rust-toolchain@v1.4.2
- name: Install Nushell
uses: actions-rs/cargo@v1
with:
command: install
args: --path=. --profile ci --no-default-features
run: cargo install --locked --path=. --profile ci --no-default-features
- name: Setup Python
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: "3.10"
- run: python -m pip install tox
# Get only the latest tagged version for stability reasons
- name: Install virtualenv
run: git clone https://github.com/pypa/virtualenv.git
run: git clone https://github.com/pypa/virtualenv.git && cd virtualenv && git checkout $(git describe --tags | cut -d - -f 1)
shell: bash
- name: Test Nushell in virtualenv
run: cd virtualenv && tox -e ${{ matrix.py }} -- -k nushell
run: |
cd virtualenv
# We need to disable failing on coverage levels.
nu -c "open pyproject.toml | upsert tool.coverage.report.fail_under 1 | save patchproject.toml"
mv patchproject.toml pyproject.toml
tox -e ${{ matrix.py }} -- -k nushell
shell: bash
# Build+test plugins on their own, without the rest of Nu. This helps with CI parallelization and
@ -152,31 +136,57 @@ jobs:
strategy:
fail-fast: true
matrix:
platform: [windows-latest, macos-latest, ubuntu-latest]
platform: [windows-latest, macos-latest, ubuntu-20.04]
rust:
- stable
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Setup Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
# makes ci use rust-toolchain.toml
# with:
# profile: minimal
# toolchain: ${{ matrix.rust }}
# override: true
- name: Setup Rust toolchain and cache
uses: actions-rust-lang/setup-rust-toolchain@v1.4.2
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --package nu_plugin_* ${{ matrix.flags }} -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect
run: cargo clippy --package nu_plugin_* ${{ matrix.flags }} -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect
- name: Tests
uses: actions-rs/cargo@v1
run: cargo test --profile ci --package nu_plugin_*
nu-coverage:
needs: nu-tests
env:
NUSHELL_CARGO_TARGET: ci
strategy:
fail-fast: true
matrix:
platform: [windows-latest, ubuntu-20.04]
rust:
- stable
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v3
- name: Setup Rust toolchain and cache
uses: actions-rust-lang/setup-rust-toolchain@v1.4.2
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov
- name: Tests
shell: bash
run: |
source <(cargo llvm-cov show-env --export-prefix) # Set the environment variables needed to get coverage.
cargo llvm-cov clean --workspace # Remove artifacts that may affect the coverage results.
cargo build --lib --bins --examples --workspace --profile ci
cargo test --lib --bins --examples --workspace --profile ci --exclude nu_plugin_* ${{ matrix.flags }}
cargo llvm-cov report --profile ci --lcov --output-path lcov.info
- name: Upload coverage reports to Codecov with GitHub Action
uses: codecov/codecov-action@v3
with:
command: test
args: --profile ci --package nu_plugin_*
files: lcov.info

View File

@ -6,6 +6,32 @@
# REF:
# 1. https://github.com/volks73/cargo-wix
# Added 2022-11-29 when Windows packaging wouldn't work
# To run this manual for windows
# unset CARGO_TARGET_DIR if set
# hide-env CARGO_TARGET_DIR
# let-env TARGET = 'x86_64-pc-windows-msvc'
# let-env TARGET_RUSTFLAGS = ''
# let-env GITHUB_WORKSPACE = 'C:\Users\dschroeder\source\repos\forks\nushell'
# let-env GITHUB_OUTPUT = 'C:\Users\dschroeder\source\repos\forks\nushell\output\out.txt'
# let-env OS = 'windows-latest'
# You need to run this twice. The first pass makes the output folder and builds everything
# The second pass generates the msi file
# Pass 1 let-env _EXTRA_ = 'bin'
# Pass 2 let-env _EXTRA_ = 'msi'
# make sure 7z.exe is in your path https://www.7-zip.org/download.html
# let-env Path = ($env.Path | append 'c:\apps\7-zip')
# make sure aria2c.exe is in your path https://github.com/aria2/aria2
# let-env Path = ($env.Path | append 'c:\path\to\aria2c')
# make sure you have the wixtools installed https://wixtoolset.org/
# let-env Path = ($env.Path | append 'C:\Users\dschroeder\AppData\Local\tauri\WixTools')
# After msi is generated, if you have to update winget-pkgs repo, you'll need to patch the release
# by deleting the existing msi and uploading this new msi. Then you'll need to update the hash
# on the winget-pkgs PR. To generate the hash, run this command
# open target\wix\nu-0.74.0-x86_64-pc-windows-msvc.msi | hash sha256
# Then, just take the output and put it in the winget-pkgs PR for the hash on the msi
# The main binary file to be released
let bin = 'nu'
let os = $env.OS
@ -16,8 +42,13 @@ let flags = $env.TARGET_RUSTFLAGS
let dist = $'($env.GITHUB_WORKSPACE)/output'
let version = (open Cargo.toml | get package.version)
$'Debugging info:'
print { version: $version, bin: $bin, os: $os, target: $target, src: $src, flags: $flags, dist: $dist }; hr-line -b
# $env
let USE_UBUNTU = 'ubuntu-20.04'
$'(char nl)Packaging ($bin) v($version) for ($target) in ($src)...'; hr-line -b
if not ('Cargo.lock' | path exists) { cargo generate-lockfile }
@ -26,8 +57,9 @@ $'Start building ($bin)...'; hr-line
# ----------------------------------------------------------------------------
# Build for Ubuntu and macOS
# ----------------------------------------------------------------------------
if $os in ['ubuntu-latest', 'macos-latest'] {
if $os == 'ubuntu-latest' {
if $os in [$USE_UBUNTU, 'macos-latest'] {
if $os == $USE_UBUNTU {
sudo apt update
sudo apt-get install libxcb-composite0-dev -y
}
if $target == 'aarch64-unknown-linux-gnu' {
@ -38,10 +70,14 @@ if $os in ['ubuntu-latest', 'macos-latest'] {
sudo apt-get install pkg-config gcc-arm-linux-gnueabihf -y
let-env CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER = 'arm-linux-gnueabihf-gcc'
cargo-build-nu $flags
} else if $target == 'riscv64gc-unknown-linux-gnu' {
sudo apt-get install gcc-riscv64-linux-gnu -y
let-env CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER = 'riscv64-linux-gnu-gcc'
cargo-build-nu $flags
} else {
# musl-tools to fix 'Failed to find tool. Is `musl-gcc` installed?'
# Actually just for x86_64-unknown-linux-musl target
if $os == 'ubuntu-latest' { sudo apt install musl-tools -y }
if $os == $USE_UBUNTU { sudo apt install musl-tools -y }
cargo-build-nu $flags
}
}
@ -51,9 +87,9 @@ if $os in ['ubuntu-latest', 'macos-latest'] {
# ----------------------------------------------------------------------------
if $os in ['windows-latest'] {
if ($flags | str trim | is-empty) {
cargo build --release --all --target $target --features=extra
cargo build --release --all --target $target
} else {
cargo build --release --all --target $target --features=extra $flags
cargo build --release --all --target $target $flags
}
}
@ -88,21 +124,28 @@ if ($ver | str trim | is-empty) {
# Create a release archive and send it to output for the following steps
# ----------------------------------------------------------------------------
cd $dist; $'(char nl)Creating release archive...'; hr-line
if $os in ['ubuntu-latest', 'macos-latest'] {
if $os in [$USE_UBUNTU, 'macos-latest'] {
$'(char nl)(ansi g)Archive contents:(ansi reset)'; hr-line; ls
let files = (ls | get name)
let dest = $'($bin)-($version)-($target)'
let archive = $'($dist)/($dest).tar.gz'
let archive = $'($dist)/($bin)-($version)-($target).tar.gz'
tar czf $archive *
mkdir $dest
$files | each {|it| mv $it $dest } | ignore
$'(char nl)(ansi g)Archive contents:(ansi reset)'; hr-line; ls $dest
tar -czf $archive $dest
print $'archive: ---> ($archive)'; ls $archive
echo $'::set-output name=archive::($archive)'
# REF: https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
echo $"archive=($archive)" | save --append $env.GITHUB_OUTPUT
} else if $os == 'windows-latest' {
let releaseStem = $'($bin)-($version)-($target)'
$'(char nl)Download less related stuffs...'; hr-line
aria2c https://github.com/jftuga/less-Windows/releases/download/less-v590/less.exe -o less.exe
aria2c https://github.com/jftuga/less-Windows/releases/download/less-v608/less.exe -o less.exe
aria2c https://raw.githubusercontent.com/jftuga/less-Windows/master/LICENSE -o LICENSE-for-less.txt
# Create Windows msi release package
@ -113,9 +156,10 @@ if $os in ['ubuntu-latest', 'macos-latest'] {
cd $src; hr-line
# Wix need the binaries be stored in target/release/
cp -r $'($dist)/*' target/release/
cargo install cargo-wix --version 0.3.3
cargo install cargo-wix --version 0.3.4
cargo wix --no-build --nocapture --package nu --output $wixRelease
echo $'::set-output name=archive::($wixRelease)'
print $'archive: ---> ($wixRelease)';
echo $"archive=($wixRelease)" | save --append $env.GITHUB_OUTPUT
} else {
@ -125,16 +169,16 @@ if $os in ['ubuntu-latest', 'macos-latest'] {
print $'archive: ---> ($archive)';
let pkg = (ls -f $archive | get name)
if not ($pkg | is-empty) {
echo $'::set-output name=archive::($pkg | get 0)'
echo $"archive=($pkg | get 0)" | save --append $env.GITHUB_OUTPUT
}
}
}
def 'cargo-build-nu' [ options: string ] {
if ($options | str trim | is-empty) {
cargo build --release --all --target $target --features=extra,static-link-openssl
cargo build --release --all --target $target --features=static-link-openssl
} else {
cargo build --release --all --target $target --features=extra,static-link-openssl $options
cargo build --release --all --target $target --features=static-link-openssl $options
}
}

View File

@ -27,6 +27,7 @@ jobs:
- x86_64-unknown-linux-musl
- aarch64-unknown-linux-gnu
- armv7-unknown-linux-gnueabihf
- riscv64gc-unknown-linux-gnu
extra: ['bin']
include:
- target: aarch64-apple-darwin
@ -44,35 +45,37 @@ jobs:
os: windows-latest
target_rustflags: ''
- target: x86_64-unknown-linux-gnu
os: ubuntu-latest
os: ubuntu-20.04
target_rustflags: ''
- target: x86_64-unknown-linux-musl
os: ubuntu-latest
os: ubuntu-20.04
target_rustflags: ''
- target: aarch64-unknown-linux-gnu
os: ubuntu-latest
os: ubuntu-20.04
target_rustflags: ''
- target: armv7-unknown-linux-gnueabihf
os: ubuntu-latest
os: ubuntu-20.04
target_rustflags: ''
- target: riscv64gc-unknown-linux-gnu
os: ubuntu-20.04
target_rustflags: ''
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v3.0.2
- uses: actions/checkout@v3.1.0
- name: Install Rust Toolchain Components
uses: actions-rs/toolchain@v1.0.6
with:
override: true
profile: minimal
toolchain: stable
target: ${{ matrix.target }}
- name: Update Rust Toolchain Target
run: |
echo "targets = ['${{matrix.target}}']" >> rust-toolchain.toml
- name: Setup Rust toolchain and cache
uses: actions-rust-lang/setup-rust-toolchain@v1.4.2
- name: Setup Nushell
uses: hustcer/setup-nu@v2.1
uses: hustcer/setup-nu@v3
with:
version: 0.69.1
version: 0.72.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -88,7 +91,7 @@ jobs:
# REF: https://github.com/marketplace/actions/gh-release
- name: Publish Archive
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v0.1.13
if: ${{ startsWith(github.ref, 'refs/tags/') }}
with:
draft: true

View File

@ -12,7 +12,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v3
- uses: actions/stale@v6
with:
#debug-only: true
ascending: true

13
.github/workflows/typos.yml vendored Normal file
View File

@ -0,0 +1,13 @@
name: Typos
on: [pull_request]
jobs:
run:
name: Spell Check with Typos
runs-on: ubuntu-latest
steps:
- name: Checkout Actions Repository
uses: actions/checkout@v2
- name: Check spelling
uses: crate-ci/typos@master

4
.gitignore vendored
View File

@ -22,6 +22,10 @@ debian/nu/
# VSCode's IDE items
.vscode/*
# Visual Studio Extension SourceGear Rust items
VSWorkspaceSettings.json
unstable_cargo_features.txt
# Helix configuration folder
.helix/*
.helix

12
.typos.toml Normal file
View File

@ -0,0 +1,12 @@
[files]
extend-exclude = ["crates/nu-command/tests/commands/table.rs", "*.tsv", "*.json", "*.txt"]
[default.extend-words]
# Ignore false-positives
nd = "nd"
fo = "fo"
ons = "ons"
ba = "ba"
Plasticos = "Plasticos"
IIF = "IIF"
numer = "numer"

View File

@ -1,8 +1,23 @@
# Contributing
Welcome to Nushell!
Welcome to Nushell and thank you for considering contributing!
To get live support from the community see our [Discord](https://discordapp.com/invite/NtAbbGn), [Twitter](https://twitter.com/nu_shell) or file an issue or feature request here on [GitHub](https://github.com/nushell/nushell/issues/new/choose)!
## Review Process
First of all, before diving into the code, if you want to create a new feature, change something significantly, and especially if the change is user-facing, it is a good practice to first get an approval from the core team before starting to work on it.
This saves both your and our time if we realize the change needs to go another direction before spending time on it.
So, please, reach out and tell us what you want to do.
This will significantly increase the chance of your PR being accepted.
The review process can be summarized as follows:
1. You want to make some change to Nushell that is more involved than simple bug-fixing.
2. Go to [Discord](https://discordapp.com/invite/NtAbbGn) or a [GitHub issue](https://github.com/nushell/nushell/issues/new/choose) and chat with some core team members and/or other contributors about it.
3. After getting a green light from the core team, implement the feature, open a pull request (PR) and write a concise but comprehensive description of the change.
4. If your PR includes any use-facing features (such as adding a flag to a command), clearly list them in the PR description.
5. Then, core team members and other regular contributors will review the PR and suggest changes.
6. When we all agree, the PR will be merged.
7. If your PR includes any user-facing features, make sure the changes are also reflected in [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged.
8. Congratulate yourself, you just improved Nushell! :-)
## Developing
@ -16,6 +31,18 @@ cd nushell
cargo build
```
### Tests
It is a good practice to cover your changes with a test. Also, try to think about corner cases and various ways how your changes could break. Cover those in the tests as well.
Tests can be found in different places:
* `/tests`
* `src/tests`
* command examples
* crate-specific tests
The most comprehensive test suite we have is the `nu-test-support` crate. For testing specific features, such as running Nushell in a REPL mode, we have so called "testbins". For simple tests, you can find `run_test()` and `fail_test()` functions.
### Useful Commands
- Build and run Nushell:
@ -24,21 +51,21 @@ cargo build
cargo run
```
- Build and run with extra features. Currently extra features include dataframes and sqlite database support.
- Build and run with dataframe support.
```shell
cargo run --features=extra
cargo run --features=dataframe
```
- Run Clippy on Nushell:
```shell
cargo clippy --workspace --features=extra -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect
cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect
```
- Run all tests:
```shell
cargo test --workspace --features=extra
cargo test --workspace
```
- Run all tests for a specific command
@ -64,11 +91,11 @@ cargo build
- To view verbose logs when developing, enable the `trace` log level.
```shell
cargo run --release --features=extra -- --log-level trace
cargo run --release -- --log-level trace
```
- To redirect trace logs to a file, enable the `--log-target file` switch.
```shell
cargo run --release --features=extra -- --log-level trace --log-target file
cargo run --release -- --log-level trace --log-target file
open $"($nu.temp-path)/nu-($nu.pid).log"
```

1469
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -3,17 +3,24 @@ authors = ["The Nushell Project Developers"]
default-run = "nu"
description = "A new type of shell"
documentation = "https://www.nushell.sh/book/"
edition = "2018"
edition = "2021"
exclude = ["images"]
homepage = "https://www.nushell.sh"
license = "MIT"
name = "nu"
repository = "https://github.com/nushell/nushell"
rust-version = "1.60"
version = "0.70.0"
version = "0.76.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[package.metadata.binstall]
pkg-url = "{ repo }/releases/download/{ version }/{ name }-{ version }-{ target }.{ archive-format }"
pkg-fmt = "tgz"
[package.metadata.binstall.overrides.x86_64-pc-windows-msvc]
pkg-fmt = "zip"
[workspace]
members = [
"crates/nu-cli",
@ -28,33 +35,35 @@ members = [
"crates/nu_plugin_example",
"crates/nu_plugin_query",
"crates/nu_plugin_custom_values",
"crates/nu_plugin_formats",
"crates/nu-utils",
]
[dependencies]
chrono = { version = "0.4.21", features = ["serde"] }
chrono = { version = "0.4.23", features = ["serde"] }
crossterm = "0.24.0"
ctrlc = "3.2.1"
log = "0.4"
miette = "5.1.0"
miette = { version = "5.5.0", features = ["fancy-no-backtrace"] }
nu-ansi-term = "0.46.0"
nu-cli = { path="./crates/nu-cli", version = "0.70.0" }
nu-color-config = { path = "./crates/nu-color-config", version = "0.70.0" }
nu-command = { path="./crates/nu-command", version = "0.70.0" }
nu-engine = { path="./crates/nu-engine", version = "0.70.0" }
nu-json = { path="./crates/nu-json", version = "0.70.0" }
nu-parser = { path="./crates/nu-parser", version = "0.70.0" }
nu-path = { path="./crates/nu-path", version = "0.70.0" }
nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.70.0" }
nu-pretty-hex = { path = "./crates/nu-pretty-hex", version = "0.70.0" }
nu-protocol = { path = "./crates/nu-protocol", version = "0.70.0" }
nu-system = { path = "./crates/nu-system", version = "0.70.0" }
nu-table = { path = "./crates/nu-table", version = "0.70.0" }
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.70.0" }
nu-utils = { path = "./crates/nu-utils", version = "0.70.0" }
reedline = { version = "0.13.0", features = ["bashisms", "sqlite"]}
nu-cli = { path = "./crates/nu-cli", version = "0.76.0" }
nu-color-config = { path = "./crates/nu-color-config", version = "0.76.0" }
nu-command = { path = "./crates/nu-command", version = "0.76.0" }
nu-engine = { path = "./crates/nu-engine", version = "0.76.0" }
nu-json = { path = "./crates/nu-json", version = "0.76.0" }
nu-parser = { path = "./crates/nu-parser", version = "0.76.0" }
nu-path = { path = "./crates/nu-path", version = "0.76.0" }
nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.76.0" }
nu-pretty-hex = { path = "./crates/nu-pretty-hex", version = "0.76.0" }
nu-protocol = { path = "./crates/nu-protocol", version = "0.76.0" }
nu-system = { path = "./crates/nu-system", version = "0.76.0" }
nu-table = { path = "./crates/nu-table", version = "0.76.0" }
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.76.0" }
nu-utils = { path = "./crates/nu-utils", version = "0.76.0" }
rayon = "1.5.1"
reedline = { version = "0.16.0", features = ["bashisms", "sqlite"] }
rayon = "1.6.1"
is_executable = "1.0.1"
simplelog = "0.12.0"
time = "0.3.12"
@ -69,25 +78,40 @@ signal-hook = { version = "0.3.14", default-features = false }
winres = "0.1"
[target.'cfg(target_family = "unix")'.dependencies]
nix = "0.24"
nix = { version = "0.25", default-features = false, features = [
"signal",
"process",
"fs",
"term",
] }
atty = "0.2"
[dev-dependencies]
nu-test-support = { path="./crates/nu-test-support", version = "0.70.0" }
nu-test-support = { path = "./crates/nu-test-support", version = "0.76.0" }
tempfile = "3.2.0"
assert_cmd = "2.0.2"
criterion = "0.4"
pretty_assertions = "1.0.0"
serial_test = "0.8.0"
serial_test = "1.0.0"
hamcrest2 = "0.3.0"
rstest = {version = "0.15.0", default-features = false}
rstest = { version = "0.16.0", default-features = false }
itertools = "0.10.3"
[features]
plugin = ["nu-plugin", "nu-cli/plugin", "nu-parser/plugin", "nu-command/plugin", "nu-protocol/plugin", "nu-engine/plugin"]
extra = ["default", "dataframe", "database"]
default = ["plugin", "which-support", "trash-support"]
plugin = [
"nu-plugin",
"nu-cli/plugin",
"nu-parser/plugin",
"nu-command/plugin",
"nu-protocol/plugin",
"nu-engine/plugin",
]
# extra used to be more useful but now it's the same as default. Leaving it in for backcompat with existing build scripts
extra = ["default"]
default = ["plugin", "which-support", "trash-support", "sqlite"]
stable = ["default"]
wasi = []
# Enable to statically link OpenSSL; otherwise the system version will be used. Not enabled by default because it takes a while to build
static-link-openssl = ["dep:openssl"]
@ -100,11 +124,11 @@ trash-support = ["nu-command/trash-support"]
# Dataframe feature for nushell
dataframe = ["nu-command/dataframe"]
# Database commands for nushell
database = ["nu-command/database"]
# SQLite commands for nushell
sqlite = ["nu-command/sqlite"]
[profile.release]
opt-level = "s" # Optimize for size
opt-level = "s" # Optimize for size
strip = "debuginfo"
lto = "thin"
@ -126,8 +150,16 @@ debug = false
[[bin]]
name = "nu"
path = "src/main.rs"
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" }
# Criterion benchmarking setup
# Run all benchmarks with `cargo bench`
# Run individual benchmarks like `cargo bench -- <regex>` e.g. `cargo bench -- parse`
[[bench]]
name = "benchmarks"
harness = false

9
Cross.toml Normal file
View File

@ -0,0 +1,9 @@
# Configuration for cross-rs: https://github.com/cross-rs/cross
# Run cross-rs like this:
# cross build --target aarch64-unknown-linux-musl --release
[target.aarch64-unknown-linux-gnu]
dockerfile = "./docker/cross-rs/aarch64-unknown-linux-gnu.dockerfile"
[target.aarch64-unknown-linux-musl]
dockerfile = "./docker/cross-rs/aarch64-unknown-linux-musl.dockerfile"

View File

@ -1,11 +1,12 @@
# Nushell <!-- omit in toc -->
[![Crates.io](https://img.shields.io/crates/v/nu.svg)](https://crates.io/crates/nu)
![Build Status](https://img.shields.io/github/workflow/status/nushell/nushell/continuous-integration)
![Build Status](https://img.shields.io/github/actions/workflow/status/nushell/nushell/ci.yml?branch=main)
[![Discord](https://img.shields.io/discord/601130461678272522.svg?logo=discord)](https://discord.gg/NtAbbGn)
[![The Changelog #363](https://img.shields.io/badge/The%20Changelog-%23363-61c192.svg)](https://changelog.com/podcast/363)
[![@nu_shell](https://img.shields.io/badge/twitter-@nu_shell-1DA1F3?style=flat-square)](https://twitter.com/nu_shell)
![GitHub commit activity](https://img.shields.io/github/commit-activity/m/nushell/nushell)
![GitHub contributors](https://img.shields.io/github/contributors/nushell/nushell)
[![codecov](https://codecov.io/github/nushell/nushell/branch/main/graph/badge.svg?token=JheS8qu2II)](https://codecov.io/github/nushell/nushell)
A new type of shell.
@ -32,7 +33,7 @@ This project has reached a minimum-viable-product level of quality. Many people
## Learning About Nu
The [Nushell book](https://www.nushell.sh/book/) is the primary source of Nushell documentation. You can find [a full list of Nu commands in the book](https://www.nushell.sh/book/command_reference.html), and we have many examples of using Nu in our [cookbook](https://www.nushell.sh/cookbook/).
The [Nushell book](https://www.nushell.sh/book/) is the primary source of Nushell documentation. You can find [a full list of Nu commands in the book](https://www.nushell.sh/commands/), and we have many examples of using Nu in our [cookbook](https://www.nushell.sh/cookbook/).
We're also active on [Discord](https://discord.gg/NtAbbGn) and [Twitter](https://twitter.com/nu_shell); come and chat with us!
@ -47,7 +48,7 @@ brew install nushell
winget install nushell
```
To use `Nu` in Github Action, check [setup-nu](https://github.com/marketplace/actions/setup-nu) for more detail.
To use `Nu` in GitHub Action, check [setup-nu](https://github.com/marketplace/actions/setup-nu) for more detail.
Detailed installation instructions can be found in the [installation chapter of the book](https://www.nushell.sh/book/installation.html). Nu is available via many package managers:
@ -126,12 +127,13 @@ For example, you can load a .toml file as structured data and explore it:
> open Cargo.toml
╭──────────────────┬────────────────────╮
│ bin │ [table 1 row]
│ dependencies │ {record 24 fields}
│ dependencies │ {record 25 fields}
│ dev-dependencies │ {record 8 fields}
│ features │ {record 10 fields}
│ package │ {record 13 fields}
│ patch │ {record 1 field}
│ profile │ {record 3 fields}
│ target │ {record 2 fields}
│ target │ {record 3 fields}
│ workspace │ {record 1 field}
╰──────────────────┴────────────────────╯
```
@ -149,11 +151,11 @@ We can pipe this into a command that gets the contents of one of the columns:
│ exclude │ [list 1 item]
│ homepage │ https://www.nushell.sh │
│ license │ MIT │
│ metadata │ {record 1 field}
│ name │ nu │
│ readme │ README.md │
│ repository │ https://github.com/nushell/nushell │
│ rust-version │ 1.60 │
│ version │ 0.63.1
│ version │ 0.72.0
╰───────────────┴────────────────────────────────────╯
```
@ -161,7 +163,7 @@ And if needed we can drill down further:
```shell
> open Cargo.toml | get package.version
0.63.1
0.72.0
```
### Plugins
@ -173,6 +175,8 @@ These binaries interact with nu via a simple JSON-RPC protocol where the command
If the plugin is a filter, data streams to it one element at a time, and it can stream data back in return via stdin/stdout.
If the plugin is a sink, it is given the full vector of final data and is given free reign over stdin/stdout to use as it pleases.
The [awesome-nu repo](https://github.com/nushell/awesome-nu#plugins) lists a variety of nu-plugins.
## Goals
Nu adheres closely to a set of goals that make up its design philosophy. As features are added, they are checked against these goals.
@ -206,7 +210,7 @@ Nu is under heavy development and will naturally change as it matures. The chart
| Functions | | | | X | | Functions and aliases are supported |
| Variables | | | | X | | Nu supports variables and environment variables |
| Completions | | | | X | | Completions for filepaths |
| Type-checking | | | X | | | Commands check basic types, but input/output isn't checked |
| Type-checking | | | | x | | Commands check basic types, and input/output types |
## Officially Supported By

7
benches/README.md Normal file
View File

@ -0,0 +1,7 @@
# Criterion benchmarks
These are benchmarks using [Criterion](https://github.com/bheisler/criterion.rs), a microbenchmarking tool for Rust.
Run all benchmarks with `cargo bench`
Or run individual benchmarks like `cargo bench -- <regex>` e.g. `cargo bench -- parse`

191
benches/benchmarks.rs Normal file
View File

@ -0,0 +1,191 @@
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
use nu_cli::eval_source;
use nu_parser::parse;
use nu_plugin::{EncodingType, PluginResponse};
use nu_protocol::{PipelineData, Span, Value};
use nu_utils::{get_default_config, get_default_env};
// FIXME: All benchmarks live in this 1 file to speed up build times when benchmarking.
// When the *_benchmarks functions were in different files, `cargo bench` would build
// an executable for every single one - incredibly slowly. Would be nice to figure out
// a way to split things up again.
fn parser_benchmarks(c: &mut Criterion) {
let mut engine_state = nu_command::create_default_context();
// parsing config.nu breaks without PWD set
engine_state.add_env_var(
"PWD".into(),
Value::string("/some/dir".to_string(), Span::test_data()),
);
let default_env = get_default_env().as_bytes();
c.bench_function("parse_default_env_file", |b| {
b.iter_batched(
|| nu_protocol::engine::StateWorkingSet::new(&engine_state),
|mut working_set| parse(&mut working_set, None, default_env, false, &[]),
BatchSize::SmallInput,
)
});
let default_config = get_default_config().as_bytes();
c.bench_function("parse_default_config_file", |b| {
b.iter_batched(
|| nu_protocol::engine::StateWorkingSet::new(&engine_state),
|mut working_set| parse(&mut working_set, None, default_config, false, &[]),
BatchSize::SmallInput,
)
});
c.bench_function("eval default_env.nu", |b| {
b.iter(|| {
let mut engine_state = nu_command::create_default_context();
let mut stack = nu_protocol::engine::Stack::new();
eval_source(
&mut engine_state,
&mut stack,
get_default_env().as_bytes(),
"default_env.nu",
PipelineData::empty(),
false,
)
})
});
c.bench_function("eval default_config.nu", |b| {
b.iter(|| {
let mut engine_state = nu_command::create_default_context();
// parsing config.nu breaks without PWD set
engine_state.add_env_var(
"PWD".into(),
Value::string("/some/dir".to_string(), Span::test_data()),
);
let mut stack = nu_protocol::engine::Stack::new();
eval_source(
&mut engine_state,
&mut stack,
get_default_config().as_bytes(),
"default_config.nu",
PipelineData::empty(),
false,
)
})
});
}
fn eval_benchmarks(c: &mut Criterion) {
c.bench_function("eval default_env.nu", |b| {
b.iter(|| {
let mut engine_state = nu_command::create_default_context();
let mut stack = nu_protocol::engine::Stack::new();
eval_source(
&mut engine_state,
&mut stack,
get_default_env().as_bytes(),
"default_env.nu",
PipelineData::empty(),
false,
)
})
});
c.bench_function("eval default_config.nu", |b| {
b.iter(|| {
let mut engine_state = nu_command::create_default_context();
// parsing config.nu breaks without PWD set
engine_state.add_env_var(
"PWD".into(),
Value::string("/some/dir".to_string(), Span::test_data()),
);
let mut stack = nu_protocol::engine::Stack::new();
eval_source(
&mut engine_state,
&mut stack,
get_default_config().as_bytes(),
"default_config.nu",
PipelineData::empty(),
false,
)
})
});
}
// generate a new table data with `row_cnt` rows, `col_cnt` columns.
fn encoding_test_data(row_cnt: usize, col_cnt: usize) -> Value {
let columns: Vec<String> = (0..col_cnt).map(|x| format!("col_{x}")).collect();
let vals: Vec<Value> = (0..col_cnt as i64).map(Value::test_int).collect();
Value::List {
vals: (0..row_cnt)
.map(|_| Value::test_record(columns.clone(), vals.clone()))
.collect(),
span: Span::test_data(),
}
}
fn encoding_benchmarks(c: &mut Criterion) {
let mut group = c.benchmark_group("Encoding");
let test_cnt_pairs = [
(100, 5),
(100, 10),
(100, 15),
(1000, 5),
(1000, 10),
(1000, 15),
(10000, 5),
(10000, 10),
(10000, 15),
];
for (row_cnt, col_cnt) in test_cnt_pairs.into_iter() {
for fmt in ["json", "msgpack"] {
group.bench_function(&format!("{fmt} encode {row_cnt} * {col_cnt}"), |b| {
let mut res = vec![];
let test_data =
PluginResponse::Value(Box::new(encoding_test_data(row_cnt, col_cnt)));
let encoder = EncodingType::try_from_bytes(fmt.as_bytes()).unwrap();
b.iter(|| encoder.encode_response(&test_data, &mut res))
});
}
}
group.finish();
}
fn decoding_benchmarks(c: &mut Criterion) {
let mut group = c.benchmark_group("Decoding");
let test_cnt_pairs = [
(100, 5),
(100, 10),
(100, 15),
(1000, 5),
(1000, 10),
(1000, 15),
(10000, 5),
(10000, 10),
(10000, 15),
];
for (row_cnt, col_cnt) in test_cnt_pairs.into_iter() {
for fmt in ["json", "msgpack"] {
group.bench_function(&format!("{fmt} decode for {row_cnt} * {col_cnt}"), |b| {
let mut res = vec![];
let test_data =
PluginResponse::Value(Box::new(encoding_test_data(row_cnt, col_cnt)));
let encoder = EncodingType::try_from_bytes(fmt.as_bytes()).unwrap();
encoder.encode_response(&test_data, &mut res).unwrap();
let mut binary_data = std::io::Cursor::new(res);
b.iter(|| {
binary_data.set_position(0);
encoder.decode_response(&mut binary_data)
})
});
}
}
group.finish();
}
criterion_group!(
benches,
parser_benchmarks,
eval_benchmarks,
encoding_benchmarks,
decoding_benchmarks
);
criterion_main!(benches);

View File

@ -1,7 +1,8 @@
#!/bin/sh
#!/usr/bin/env bash
set -euo pipefail
echo "---------------------------------------------------------------"
echo "Building nushell (nu) with --features=extra and all the plugins"
echo "Building nushell (nu) with dataframes and all the plugins"
echo "---------------------------------------------------------------"
echo ""
@ -14,10 +15,10 @@ NU_PLUGINS=(
)
echo "Building nushell"
cargo build --features=extra
cargo build --features=dataframe
for plugin in "${NU_PLUGINS[@]}"
do
echo '' && cd crates/$plugin
echo '' && cd crates/"$plugin"
echo "Building $plugin..."
echo "-----------------------------"
cargo build && cd ../..

View File

@ -1,11 +1,11 @@
@echo off
@echo -------------------------------------------------------------------
@echo Building nushell (nu.exe) with --features=extra and all the plugins
@echo Building nushell (nu.exe) with dataframes and all the plugins
@echo -------------------------------------------------------------------
@echo.
echo Building nushell.exe
cargo build --features=extra
cargo build --features=dataframe
@echo.
@cd crates\nu_plugin_example

View File

@ -1,10 +1,10 @@
echo '-------------------------------------------------------------------'
echo 'Building nushell (nu) with --features=extra and all the plugins'
echo 'Building nushell (nu) with dataframes and all the plugins'
echo '-------------------------------------------------------------------'
echo $'(char nl)Building nushell'
echo '----------------------------'
cargo build --features=extra
cargo build --features=dataframe
let plugins = [
nu_plugin_inc,
@ -12,6 +12,7 @@ let plugins = [
nu_plugin_query,
nu_plugin_example,
nu_plugin_custom_values,
nu_plugin_formats,
]
for plugin in $plugins {

17
codecov.yml Normal file
View File

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

54
coverage-local.nu Executable file
View File

@ -0,0 +1,54 @@
#!/usr/bin/env nu
let start = (date now)
# Script to generate coverage locally
#
# Output: `lcov.info` file
#
# Relies on `cargo-llvm-cov`. Install via `cargo install cargo-llvm-cov`
# https://github.com/taiki-e/cargo-llvm-cov
# You probably have to run `cargo llvm-cov clean` once manually,
# as you have to confirm to install additional tooling for your rustup toolchain.
# Else the script might stall waiting for your `y<ENTER>`
# Some of the internal tests rely on the exact cargo profile
# (This is somewhat criminal itself)
# but we have to signal to the tests that we use the `ci` `--profile`
let-env NUSHELL_CARGO_TARGET = "ci"
# Manual gathering of coverage to catch invocation of the `nu` binary.
# This is relevant for tests using the `nu!` macro from `nu-test-support`
# see: https://github.com/taiki-e/cargo-llvm-cov#get-coverage-of-external-tests
print "Setting up environment variables for coverage"
# Enable LLVM coverage tracking through environment variables
# show env outputs .ini/.toml style description of the variables
# In order to use from toml, we need to make sure our string literals are single quoted
# This is especially important when running on Windows since "C:\blah" is treated as an escape
cargo llvm-cov show-env | str replace (char dq) (char sq) -a | from toml | load-env
print "Cleaning up coverage data"
cargo llvm-cov clean --workspace
print "Building with workspace and profile=ci"
# Apparently we need to explicitly build the necessary parts
# using the `--profile=ci` is basically `debug` build with unnecessary symbols stripped
# leads to smaller binaries and potential savings when compiling and running
cargo build --workspace --profile=ci
print "Running tests with --workspace and profile=ci"
cargo test --workspace --profile=ci
# You need to provide the used profile to find the raw data
print "Generating coverage report as lcov.info"
cargo llvm-cov report --lcov --output-path lcov.info --profile=ci
let end = (date now)
$"Coverage generation took ($end - $start)."
# To display the coverage in your editor see:
#
# - https://marketplace.visualstudio.com/items?itemName=ryanluker.vscode-coverage-gutters
# - https://github.com/umaumax/vim-lcov
# - https://github.com/andythigpen/nvim-coverage (probably needs some additional config)

38
coverage-local.sh Executable file
View File

@ -0,0 +1,38 @@
#!/usr/bin/env bash
# Script to generate coverage locally
#
# Output: `lcov.info` file
#
# Relies on `cargo-llvm-cov`. Install via `cargo install cargo-llvm-cov`
# https://github.com/taiki-e/cargo-llvm-cov
# You probably have to run `cargo llvm-cov clean` once manually,
# as you have to confirm to install additional tooling for your rustup toolchain.
# Else the script might stall waiting for your `y<ENTER>`
# Some of the internal tests rely on the exact cargo profile
# (This is somewhat criminal itself)
# but we have to signal to the tests that we use the `ci` `--profile`
export NUSHELL_CARGO_TARGET=ci
# Manual gathering of coverage to catch invocation of the `nu` binary.
# This is relevant for tests using the `nu!` macro from `nu-test-support`
# see: https://github.com/taiki-e/cargo-llvm-cov#get-coverage-of-external-tests
# Enable LLVM coverage tracking through environment variables
source <(cargo llvm-cov show-env --export-prefix)
cargo llvm-cov clean --workspace
# Apparently we need to explicitly build the necessary parts
# using the `--profile=ci` is basically `debug` build with unnecessary symbols stripped
# leads to smaller binaries and potential savings when compiling and running
cargo build --workspace --profile=ci
cargo test --workspace --profile=ci
# You need to provide the used profile to find the raw data
cargo llvm-cov report --lcov --output-path lcov.info --profile=ci
# To display the coverage in your editor see:
#
# - https://marketplace.visualstudio.com/items?itemName=ryanluker.vscode-coverage-gutters
# - https://github.com/umaumax/vim-lcov
# - https://github.com/andythigpen/nvim-coverage (probably needs some additional config)

View File

@ -5,35 +5,38 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cli"
edition = "2021"
license = "MIT"
name = "nu-cli"
version = "0.70.0"
version = "0.76.0"
[lib]
bench = false
[dev-dependencies]
nu-test-support = { path="../nu-test-support", version = "0.70.0" }
nu-command = { path = "../nu-command", version = "0.70.0" }
rstest = {version = "0.15.0", default-features = false}
nu-test-support = { path = "../nu-test-support", version = "0.76.0" }
nu-command = { path = "../nu-command", version = "0.76.0" }
rstest = { version = "0.16.0", default-features = false }
[dependencies]
nu-engine = { path = "../nu-engine", version = "0.70.0" }
nu-path = { path = "../nu-path", version = "0.70.0" }
nu-parser = { path = "../nu-parser", version = "0.70.0" }
nu-protocol = { path = "../nu-protocol", version = "0.70.0" }
nu-utils = { path = "../nu-utils", version = "0.70.0" }
nu-engine = { path = "../nu-engine", version = "0.76.0" }
nu-path = { path = "../nu-path", version = "0.76.0" }
nu-parser = { path = "../nu-parser", version = "0.76.0" }
nu-protocol = { path = "../nu-protocol", version = "0.76.0" }
nu-utils = { path = "../nu-utils", version = "0.76.0" }
nu-ansi-term = "0.46.0"
nu-color-config = { path = "../nu-color-config", version = "0.70.0" }
reedline = { version = "0.13.0", features = ["bashisms", "sqlite"]}
nu-color-config = { path = "../nu-color-config", version = "0.76.0" }
reedline = { version = "0.16.0", features = ["bashisms", "sqlite"] }
atty = "0.2.14"
chrono = "0.4.21"
chrono = { default-features = false, features = ["std"], version = "0.4.23" }
crossterm = "0.24.0"
fancy-regex = "0.10.0"
fancy-regex = "0.11.0"
fuzzy-matcher = "0.3.7"
is_executable = "1.0.1"
lazy_static = "1.4.0"
once_cell = "1.17.0"
log = "0.4"
miette = { version = "5.1.0", features = ["fancy"] }
miette = { version = "5.5.0", features = ["fancy-no-backtrace"] }
percent-encoding = "2"
strip-ansi-escapes = "0.1.1"
sysinfo = "0.26.2"
sysinfo = "0.28.0"
thiserror = "1.0.31"
[features]

View File

@ -15,7 +15,6 @@ pub fn evaluate_commands(
engine_state: &mut EngineState,
stack: &mut Stack,
input: PipelineData,
is_perf_true: bool,
table_mode: Option<Value>,
) -> Result<Option<i64>> {
// Translate environment variables from Strings to Values
@ -68,9 +67,7 @@ pub fn evaluate_commands(
}
};
if is_perf_true {
info!("evaluate {}:{}:{}", file!(), line!(), column!());
}
info!("evaluate {}:{}:{}", file!(), line!(), column!());
Ok(exit_code)
}

View File

@ -37,7 +37,8 @@ impl CommandCompletion {
) -> Vec<String> {
let mut executables = vec![];
let paths = self.engine_state.get_env_var("PATH");
// os agnostic way to get the PATH env var
let paths = self.engine_state.get_path_env_var();
if let Some(paths) = paths {
if let Ok(paths) = paths.as_list() {
@ -60,7 +61,7 @@ impl CommandCompletion {
.matches_str(&x.to_string_lossy(), prefix)),
Some(true)
)
&& is_executable::is_executable(&item.path())
&& is_executable::is_executable(item.path())
{
if let Ok(name) = item.file_name().into_string() {
executables.push(name);
@ -94,10 +95,7 @@ impl CommandCompletion {
value: String::from_utf8_lossy(&x.0).to_string(),
description: x.1,
extra: None,
span: reedline::Span {
start: span.start - offset,
end: span.end - offset,
},
span: reedline::Span::new(span.start - offset, span.end - offset),
append_whitespace: true,
});
@ -108,10 +106,7 @@ impl CommandCompletion {
value: String::from_utf8_lossy(&x).to_string(),
description: None,
extra: None,
span: reedline::Span {
start: span.start - offset,
end: span.end - offset,
},
span: reedline::Span::new(span.start - offset, span.end - offset),
append_whitespace: true,
});
@ -128,15 +123,15 @@ impl CommandCompletion {
value: x,
description: None,
extra: None,
span: reedline::Span {
start: span.start - offset,
end: span.end - offset,
},
span: reedline::Span::new(span.start - offset, span.end - offset),
append_whitespace: true,
});
let results_strings: Vec<String> =
results.clone().into_iter().map(|x| x.value).collect();
for external in results_external {
if results.contains(&external) {
if results_strings.contains(&external.value) {
results.push(Suggestion {
value: format!("^{}", external.value),
description: None,
@ -187,10 +182,7 @@ impl Completer for CommandCompletion {
let subcommands = if let Some(last) = last {
self.complete_commands(
working_set,
Span {
start: last.0.start,
end: pos,
},
Span::new(last.0.start, pos),
offset,
false,
options.match_algorithm,

View File

@ -5,6 +5,7 @@ use crate::completions::{
use nu_engine::eval_block;
use nu_parser::{flatten_expression, parse, FlatShape};
use nu_protocol::{
ast::PipelineElement,
engine::{EngineState, Stack, StateWorkingSet},
BlockId, PipelineData, Span, Value,
};
@ -76,10 +77,7 @@ impl NuCompleter {
Value::List {
vals: spans
.iter()
.map(|it| Value::String {
val: it.to_string(),
span: Span::unknown(),
})
.map(|it| Value::string(it, Span::unknown()))
.collect(),
span: Span::unknown(),
},
@ -91,7 +89,7 @@ impl NuCompleter {
&self.engine_state,
&mut callee_stack,
block,
PipelineData::new(span),
PipelineData::empty(),
true,
true,
);
@ -100,19 +98,13 @@ impl NuCompleter {
Ok(pd) => {
let value = pd.into_value(span);
if let Value::List { vals, span: _ } = value {
let result = map_value_completions(
vals.iter(),
Span {
start: span.start,
end: span.end,
},
offset,
);
let result =
map_value_completions(vals.iter(), Span::new(span.start, span.end), offset);
return Some(result);
}
}
Err(err) => println!("failed to eval completer block: {}", err),
Err(err) => println!("failed to eval completer block: {err}"),
}
None
@ -131,139 +123,60 @@ impl NuCompleter {
let (output, _err) = parse(&mut working_set, Some("completer"), &new_line, false, &[]);
for pipeline in output.pipelines.into_iter() {
for expr in pipeline.expressions {
let flattened: Vec<_> = flatten_expression(&working_set, &expr);
let span_offset: usize = alias_offset.iter().sum();
let mut spans: Vec<String> = vec![];
for pipeline_element in pipeline.elements {
match pipeline_element {
PipelineElement::Expression(_, expr)
| PipelineElement::Redirection(_, _, expr)
| PipelineElement::And(_, expr)
| PipelineElement::Or(_, expr)
| PipelineElement::SeparateRedirection { out: (_, expr), .. } => {
let flattened: Vec<_> = flatten_expression(&working_set, &expr);
let span_offset: usize = alias_offset.iter().sum();
let mut spans: Vec<String> = vec![];
for (flat_idx, flat) in flattened.iter().enumerate() {
// Read the current spam to string
let current_span = working_set.get_span_contents(flat.0).to_vec();
let current_span_str = String::from_utf8_lossy(&current_span);
for (flat_idx, flat) in flattened.iter().enumerate() {
// Read the current spam to string
let current_span = working_set.get_span_contents(flat.0).to_vec();
let current_span_str = String::from_utf8_lossy(&current_span);
// Skip the last 'a' as span item
if flat_idx == flattened.len() - 1 {
let mut chars = current_span_str.chars();
chars.next_back();
let current_span_str = chars.as_str().to_owned();
spans.push(current_span_str.to_string());
} else {
spans.push(current_span_str.to_string());
}
// Complete based on the last span
if pos + span_offset >= flat.0.start && pos + span_offset < flat.0.end {
// Context variables
let most_left_var =
most_left_variable(flat_idx, &working_set, flattened.clone());
// Create a new span
let new_span = if flat_idx == 0 {
Span {
start: flat.0.start,
end: flat.0.end - 1 - span_offset,
}
} else {
Span {
start: flat.0.start - span_offset,
end: flat.0.end - 1 - span_offset,
}
};
// Parses the prefix. Completion should look up to the cursor position, not after.
let mut prefix = working_set.get_span_contents(flat.0).to_vec();
let index = pos - (flat.0.start - span_offset);
prefix.drain(index..);
// Variables completion
if prefix.starts_with(b"$") || most_left_var.is_some() {
let mut completer = VariableCompletion::new(
self.engine_state.clone(),
self.stack.clone(),
most_left_var.unwrap_or((vec![], vec![])),
);
return self.process_completion(
&mut completer,
&working_set,
prefix,
new_span,
offset,
pos,
);
}
// Flags completion
if prefix.starts_with(b"-") {
// Try to complete flag internally
let mut completer = FlagCompletion::new(expr.clone());
let result = self.process_completion(
&mut completer,
&working_set,
prefix.clone(),
new_span,
offset,
pos,
);
if !result.is_empty() {
return result;
// Skip the last 'a' as span item
if flat_idx == flattened.len() - 1 {
let mut chars = current_span_str.chars();
chars.next_back();
let current_span_str = chars.as_str().to_owned();
spans.push(current_span_str.to_string());
} else {
spans.push(current_span_str.to_string());
}
// 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)
{
return external_result;
}
}
}
// Complete based on the last span
if pos + span_offset >= flat.0.start && pos + span_offset < flat.0.end {
// Context variables
let most_left_var =
most_left_variable(flat_idx, &working_set, flattened.clone());
// specially check if it is currently empty - always complete commands
if flat_idx == 0 && working_set.get_span_contents(new_span).is_empty() {
let mut completer = CommandCompletion::new(
self.engine_state.clone(),
&working_set,
flattened.clone(),
// flat_idx,
FlatShape::String,
true,
);
return self.process_completion(
&mut completer,
&working_set,
prefix,
new_span,
offset,
pos,
);
}
// Create a new span
let new_span = if flat_idx == 0 {
Span::new(flat.0.start, flat.0.end - 1 - span_offset)
} else {
Span::new(
flat.0.start - span_offset,
flat.0.end - 1 - span_offset,
)
};
// Completions that depends on the previous expression (e.g: use, source-env)
if flat_idx > 0 {
if let Some(previous_expr) = flattened.get(flat_idx - 1) {
// Read the content for the previous expression
let prev_expr_str =
working_set.get_span_contents(previous_expr.0).to_vec();
// Parses the prefix. Completion should look up to the cursor position, not after.
let mut prefix = working_set.get_span_contents(flat.0).to_vec();
let index = pos - (flat.0.start - span_offset);
prefix.drain(index..);
// Completion for .nu files
if prev_expr_str == b"use" || prev_expr_str == b"source-env" {
let mut completer =
DotNuCompletion::new(self.engine_state.clone());
return self.process_completion(
&mut completer,
&working_set,
prefix,
new_span,
offset,
pos,
// Variables completion
if prefix.starts_with(b"$") || most_left_var.is_some() {
let mut completer = VariableCompletion::new(
self.engine_state.clone(),
self.stack.clone(),
most_left_var.unwrap_or((vec![], vec![])),
);
} else if prev_expr_str == b"ls" {
let mut completer =
FileCompletion::new(self.engine_state.clone());
return self.process_completion(
&mut completer,
@ -274,101 +187,190 @@ impl NuCompleter {
pos,
);
}
}
}
// Match other types
match &flat.1 {
FlatShape::Custom(decl_id) => {
let mut completer = CustomCompletion::new(
self.engine_state.clone(),
self.stack.clone(),
*decl_id,
initial_line,
);
// Flags completion
if prefix.starts_with(b"-") {
// Try to complete flag internally
let mut completer = FlagCompletion::new(expr.clone());
let result = self.process_completion(
&mut completer,
&working_set,
prefix.clone(),
new_span,
offset,
pos,
);
return self.process_completion(
&mut completer,
&working_set,
prefix,
new_span,
offset,
pos,
);
}
FlatShape::Directory => {
let mut completer =
DirectoryCompletion::new(self.engine_state.clone());
if !result.is_empty() {
return result;
}
return self.process_completion(
&mut completer,
&working_set,
prefix,
new_span,
offset,
pos,
);
}
FlatShape::Filepath | FlatShape::GlobPattern => {
let mut completer = FileCompletion::new(self.engine_state.clone());
return self.process_completion(
&mut completer,
&working_set,
prefix,
new_span,
offset,
pos,
);
}
flat_shape => {
let mut completer = CommandCompletion::new(
self.engine_state.clone(),
&working_set,
flattened.clone(),
// flat_idx,
flat_shape.clone(),
false,
);
let mut out: Vec<_> = self.process_completion(
&mut completer,
&working_set,
prefix.clone(),
new_span,
offset,
pos,
);
if !out.is_empty() {
return out;
}
// 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)
{
return external_result;
// 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)
{
return external_result;
}
}
}
// Check for file completion
let mut completer = FileCompletion::new(self.engine_state.clone());
out = self.process_completion(
&mut completer,
&working_set,
prefix,
new_span,
offset,
pos,
);
if !out.is_empty() {
return out;
// specially check if it is currently empty - always complete commands
if flat_idx == 0
&& working_set.get_span_contents(new_span).is_empty()
{
let mut completer = CommandCompletion::new(
self.engine_state.clone(),
&working_set,
flattened.clone(),
// flat_idx,
FlatShape::String,
true,
);
return self.process_completion(
&mut completer,
&working_set,
prefix,
new_span,
offset,
pos,
);
}
// Completions that depends on the previous expression (e.g: use, source-env)
if flat_idx > 0 {
if let Some(previous_expr) = flattened.get(flat_idx - 1) {
// Read the content for the previous expression
let prev_expr_str =
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"
{
let mut completer =
DotNuCompletion::new(self.engine_state.clone());
return self.process_completion(
&mut completer,
&working_set,
prefix,
new_span,
offset,
pos,
);
} else if prev_expr_str == b"ls" {
let mut completer =
FileCompletion::new(self.engine_state.clone());
return self.process_completion(
&mut completer,
&working_set,
prefix,
new_span,
offset,
pos,
);
}
}
}
// Match other types
match &flat.1 {
FlatShape::Custom(decl_id) => {
let mut completer = CustomCompletion::new(
self.engine_state.clone(),
self.stack.clone(),
*decl_id,
initial_line,
);
return self.process_completion(
&mut completer,
&working_set,
prefix,
new_span,
offset,
pos,
);
}
FlatShape::Directory => {
let mut completer =
DirectoryCompletion::new(self.engine_state.clone());
return self.process_completion(
&mut completer,
&working_set,
prefix,
new_span,
offset,
pos,
);
}
FlatShape::Filepath | FlatShape::GlobPattern => {
let mut completer =
FileCompletion::new(self.engine_state.clone());
return self.process_completion(
&mut completer,
&working_set,
prefix,
new_span,
offset,
pos,
);
}
flat_shape => {
let mut completer = CommandCompletion::new(
self.engine_state.clone(),
&working_set,
flattened.clone(),
// flat_idx,
flat_shape.clone(),
false,
);
let mut out: Vec<_> = self.process_completion(
&mut completer,
&working_set,
prefix.clone(),
new_span,
offset,
pos,
);
if !out.is_empty() {
return out;
}
// 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,
) {
return external_result;
}
}
// Check for file completion
let mut completer =
FileCompletion::new(self.engine_state.clone());
out = self.process_completion(
&mut completer,
&working_set,
prefix,
new_span,
offset,
pos,
);
if !out.is_empty() {
return out;
}
}
};
}
};
}
}
}
}

View File

@ -52,13 +52,13 @@ impl Completer for CustomCompletion {
head: span,
arguments: vec![
Argument::Positional(Expression {
span: Span { start: 0, end: 0 },
span: Span::unknown(),
ty: Type::String,
expr: Expr::String(self.line.clone()),
custom_completion: None,
}),
Argument::Positional(Expression {
span: Span { start: 0, end: 0 },
span: Span::unknown(),
ty: Type::Int,
expr: Expr::Int(line_pos as i64),
custom_completion: None,
@ -66,15 +66,16 @@ impl Completer for CustomCompletion {
],
redirect_stdout: true,
redirect_stderr: true,
parser_info: vec![],
},
PipelineData::new(span),
PipelineData::empty(),
);
let mut custom_completion_options = None;
// Parse result
let suggestions = match result {
Ok(pd) => {
let suggestions = result
.map(|pd| {
let value = pd.into_value(span);
match &value {
Value::Record { .. } => {
@ -131,9 +132,8 @@ impl Completer for CustomCompletion {
Value::List { vals, .. } => map_value_completions(vals.iter(), span, offset),
_ => vec![],
}
}
_ => vec![],
};
})
.unwrap_or_default();
if let Some(custom_completion_options) = custom_completion_options {
filter(&prefix, suggestions, &custom_completion_options)

View File

@ -33,14 +33,7 @@ impl Completer for DirectoryCompletion {
_: usize,
options: &CompletionOptions,
) -> Vec<Suggestion> {
let cwd = if let Some(d) = self.engine_state.get_env_var("PWD") {
match d.as_string() {
Ok(s) => s,
Err(_) => "".to_string(),
}
} else {
"".to_string()
};
let cwd = self.engine_state.current_work_dir();
let partial = String::from_utf8_lossy(&prefix).to_string();
// Filter only the folders
@ -126,7 +119,7 @@ pub fn directory_completion(
let mut file_name = entry.file_name().to_string_lossy().into_owned();
if matches(&partial, &file_name, options) {
let mut path = if prepend_base_dir(original_input, &base_dir_name) {
format!("{}{}", base_dir_name, file_name)
format!("{base_dir_name}{file_name}")
} else {
file_name.to_string()
};
@ -136,9 +129,13 @@ pub fn directory_completion(
file_name.push(SEP);
}
// Fix files or folders with quotes
if path.contains('\'') || path.contains('"') || path.contains(' ') {
path = format!("`{}`", path);
// Fix files or folders with quotes or hash
if path.contains('\'')
|| path.contains('"')
|| path.contains(' ')
|| path.contains('#')
{
path = format!("`{path}`");
}
Some((span, path))

View File

@ -58,7 +58,7 @@ impl Completer for DotNuCompletion {
};
// Check if the base_dir is a folder
if base_dir != format!(".{}", SEP) {
if base_dir != format!(".{SEP}") {
// Add the base dir into the directories to be searched
search_dirs.push(base_dir.clone());
@ -70,14 +70,7 @@ impl Completer for DotNuCompletion {
partial = base_dir_partial;
} else {
// Fetch the current folder
let current_folder = if let Some(d) = self.engine_state.get_env_var("PWD") {
match d.as_string() {
Ok(s) => s,
Err(_) => "".to_string(),
}
} else {
"".to_string()
};
let current_folder = self.engine_state.current_work_dir();
is_current_folder = true;
// Add the current folder and the lib dirs into the

View File

@ -30,14 +30,7 @@ impl Completer for FileCompletion {
_: usize,
options: &CompletionOptions,
) -> Vec<Suggestion> {
let cwd = if let Some(d) = self.engine_state.get_env_var("PWD") {
match d.as_string() {
Ok(s) => s,
Err(_) => "".to_string(),
}
} else {
"".to_string()
};
let cwd = self.engine_state.current_work_dir();
let prefix = String::from_utf8_lossy(&prefix).to_string();
let output: Vec<_> = file_path_completion(span, &prefix, &cwd, options)
.into_iter()
@ -131,7 +124,7 @@ pub fn file_path_completion(
let mut file_name = entry.file_name().to_string_lossy().into_owned();
if matches(&partial, &file_name, options) {
let mut path = if prepend_base_dir(original_input, &base_dir_name) {
format!("{}{}", base_dir_name, file_name)
format!("{base_dir_name}{file_name}")
} else {
file_name.to_string()
};
@ -141,9 +134,25 @@ pub fn file_path_completion(
file_name.push(SEP);
}
// Fix files or folders with quotes
if path.contains('\'') || path.contains('"') || path.contains(' ') {
path = format!("`{}`", path);
// Fix files or folders with quotes or hashes
if path.contains('\'')
|| path.contains('"')
|| path.contains(' ')
|| path.contains('#')
|| path.contains('(')
|| path.contains(')')
|| path.starts_with('0')
|| path.starts_with('1')
|| path.starts_with('2')
|| path.starts_with('3')
|| path.starts_with('4')
|| path.starts_with('5')
|| path.starts_with('6')
|| path.starts_with('7')
|| path.starts_with('8')
|| path.starts_with('9')
{
path = format!("`{path}`");
}
Some((span, path))
@ -171,7 +180,7 @@ pub fn matches(partial: &str, from: &str, options: &CompletionOptions) -> bool {
/// Returns whether the base_dir should be prepended to the file path
pub fn prepend_base_dir(input: &str, base_dir: &str) -> bool {
if base_dir == format!(".{}", SEP) {
if base_dir == format!(".{SEP}") {
// if the current base_dir path is the local folder we only add a "./" prefix if the user
// input already includes a local folder prefix.
let manually_entered = {

View File

@ -9,6 +9,8 @@ use reedline::Suggestion;
use std::str;
use std::sync::Arc;
use super::MatchAlgorithm;
#[derive(Clone)]
pub struct VariableCompletion {
engine_state: Arc<EngineState>, // TODO: Is engine state necessary? It's already a part of working set in fetch()
@ -73,10 +75,11 @@ impl Completer for VariableCompletion {
for suggestion in
nested_suggestions(val.clone(), nested_levels, current_span)
{
if options
.match_algorithm
.matches_u8(suggestion.value.as_bytes(), &prefix)
{
if options.match_algorithm.matches_u8_insensitive(
options.case_sensitive,
suggestion.value.as_bytes(),
&prefix,
) {
output.push(suggestion);
}
}
@ -86,10 +89,11 @@ impl Completer for VariableCompletion {
} else {
// No nesting provided, return all env vars
for env_var in env_vars {
if options
.match_algorithm
.matches_u8(env_var.0.as_bytes(), &prefix)
{
if options.match_algorithm.matches_u8_insensitive(
options.case_sensitive,
env_var.0.as_bytes(),
&prefix,
) {
output.push(Suggestion {
value: env_var.0,
description: None,
@ -111,18 +115,16 @@ impl Completer for VariableCompletion {
&self.engine_state,
&self.stack,
nu_protocol::NU_VARIABLE_ID,
nu_protocol::Span {
start: current_span.start,
end: current_span.end,
},
nu_protocol::Span::new(current_span.start, current_span.end),
) {
for suggestion in
nested_suggestions(nuval, self.var_context.1.clone(), current_span)
{
if options
.match_algorithm
.matches_u8(suggestion.value.as_bytes(), &prefix)
{
if options.match_algorithm.matches_u8_insensitive(
options.case_sensitive,
suggestion.value.as_bytes(),
&prefix,
) {
output.push(suggestion);
}
}
@ -134,23 +136,18 @@ impl Completer for VariableCompletion {
// Completion other variable types
if let Some(var_id) = var_id {
// Extract the variable value from the stack
let var = self.stack.get_var(
var_id,
Span {
start: span.start,
end: span.end,
},
);
let var = self.stack.get_var(var_id, Span::new(span.start, span.end));
// If the value exists and it's of type Record
if let Ok(value) = var {
for suggestion in
nested_suggestions(value, self.var_context.1.clone(), current_span)
{
if options
.match_algorithm
.matches_u8(suggestion.value.as_bytes(), &prefix)
{
if options.match_algorithm.matches_u8_insensitive(
options.case_sensitive,
suggestion.value.as_bytes(),
&prefix,
) {
output.push(suggestion);
}
}
@ -162,10 +159,11 @@ impl Completer for VariableCompletion {
// Variable completion (e.g: $en<tab> to complete $env)
for builtin in builtins {
if options
.match_algorithm
.matches_u8(builtin.as_bytes(), &prefix)
{
if options.match_algorithm.matches_u8_insensitive(
options.case_sensitive,
builtin.as_bytes(),
&prefix,
) {
output.push(Suggestion {
value: builtin.to_string(),
description: None,
@ -187,7 +185,11 @@ impl Completer for VariableCompletion {
.rev()
{
for v in &overlay_frame.vars {
if options.match_algorithm.matches_u8(v.0, &prefix) {
if options.match_algorithm.matches_u8_insensitive(
options.case_sensitive,
v.0,
&prefix,
) {
output.push(Suggestion {
value: String::from_utf8_lossy(v.0).to_string(),
description: None,
@ -209,7 +211,11 @@ impl Completer for VariableCompletion {
.rev()
{
for v in &overlay_frame.vars {
if options.match_algorithm.matches_u8(v.0, &prefix) {
if options.match_algorithm.matches_u8_insensitive(
options.case_sensitive,
v.0,
&prefix,
) {
output.push(Suggestion {
value: String::from_utf8_lossy(v.0).to_string(),
description: None,
@ -256,6 +262,20 @@ fn nested_suggestions(
output
}
Value::LazyRecord { val, .. } => {
// Add all the columns as completion
for column_name in val.column_names() {
output.push(Suggestion {
value: column_name.to_string(),
description: None,
extra: None,
span: current_span,
append_whitespace: false,
});
}
output
}
_ => output,
}
@ -281,7 +301,7 @@ fn recursive_value(val: Value, sublevels: Vec<Vec<u8>>) -> Value {
// Current sublevel value not found
return Value::Nothing {
span: Span { start: 0, end: 0 },
span: Span::unknown(),
};
}
_ => return val,
@ -290,3 +310,13 @@ fn recursive_value(val: Value, sublevels: Vec<Vec<u8>>) -> Value {
val
}
impl MatchAlgorithm {
pub fn matches_u8_insensitive(&self, sensitive: bool, haystack: &[u8], needle: &[u8]) -> bool {
if sensitive {
self.matches_u8(haystack, needle)
} else {
self.matches_u8(&haystack.to_ascii_lowercase(), &needle.to_ascii_lowercase())
}
}
}

View File

@ -1,14 +1,14 @@
use crate::util::{eval_source, report_error};
#[cfg(feature = "plugin")]
use log::info;
#[cfg(feature = "plugin")]
use nu_parser::ParseError;
#[cfg(feature = "plugin")]
use nu_path::canonicalize_with;
use nu_protocol::engine::{EngineState, Stack, StateWorkingSet};
#[cfg(feature = "plugin")]
use nu_protocol::Spanned;
use nu_protocol::{HistoryFileFormat, PipelineData, Span};
use nu_protocol::{HistoryFileFormat, PipelineData};
#[cfg(feature = "plugin")]
use nu_utils::utils::perf;
use std::path::PathBuf;
#[cfg(feature = "plugin")]
@ -23,30 +23,37 @@ pub fn read_plugin_file(
stack: &mut Stack,
plugin_file: Option<Spanned<String>>,
storage_path: &str,
is_perf_true: bool,
) {
let start_time = std::time::Instant::now();
let mut plug_path = String::new();
// Reading signatures from signature file
// The plugin.nu file stores the parsed signature collected from each registered plugin
add_plugin_file(engine_state, plugin_file, storage_path);
let plugin_path = engine_state.plugin_signatures.clone();
if let Some(plugin_path) = plugin_path {
let plugin_filename = plugin_path.to_string_lossy().to_owned();
let plugin_filename = plugin_path.to_string_lossy();
plug_path = plugin_filename.to_string();
if let Ok(contents) = std::fs::read(&plugin_path) {
eval_source(
engine_state,
stack,
&contents,
&plugin_filename,
PipelineData::new(Span::new(0, 0)),
PipelineData::empty(),
false,
);
}
}
if is_perf_true {
info!("read_plugin_file {}:{}:{}", file!(), line!(), column!());
}
perf(
&format!("read_plugin_file {}", &plug_path),
start_time,
file!(),
line!(),
column!(),
engine_state.get_config().use_ansi_coloring,
);
}
#[cfg(feature = "plugin")]
@ -59,12 +66,11 @@ pub fn add_plugin_file(
let working_set = StateWorkingSet::new(engine_state);
let cwd = working_set.get_cwd();
match canonicalize_with(&plugin_file.item, cwd) {
Ok(path) => engine_state.plugin_signatures = Some(path),
Err(_) => {
let e = ParseError::FileNotFound(plugin_file.item, plugin_file.span);
report_error(&working_set, &e);
}
if let Ok(path) = canonicalize_with(&plugin_file.item, cwd) {
engine_state.plugin_signatures = Some(path)
} else {
let e = ParseError::FileNotFound(plugin_file.item, plugin_file.span);
report_error(&working_set, &e);
}
} else if let Some(mut plugin_path) = nu_path::config_dir() {
// Path to store plugins signatures
@ -80,7 +86,7 @@ pub fn eval_config_contents(
stack: &mut Stack,
) {
if config_path.exists() & config_path.is_file() {
let config_filename = config_path.to_string_lossy().to_owned();
let config_filename = config_path.to_string_lossy();
if let Ok(contents) = std::fs::read(&config_path) {
eval_source(
@ -88,7 +94,8 @@ pub fn eval_config_contents(
stack,
&contents,
&config_filename,
PipelineData::new(Span::new(0, 0)),
PipelineData::empty(),
false,
);
// Merge the environment in case env vars changed in the config

View File

@ -2,13 +2,13 @@ use crate::util::{eval_source, report_error};
use log::info;
use log::trace;
use miette::{IntoDiagnostic, Result};
use nu_engine::convert_env_values;
use nu_engine::{convert_env_values, current_dir};
use nu_parser::parse;
use nu_protocol::Type;
use nu_path::canonicalize_with;
use nu_protocol::{
ast::Call,
engine::{EngineState, Stack, StateWorkingSet},
Config, PipelineData, Span, Value,
Config, PipelineData, ShellError, Span, Type, Value,
};
use nu_utils::stdout_write_all_and_flush;
@ -19,7 +19,6 @@ pub fn evaluate_file(
engine_state: &mut EngineState,
stack: &mut Stack,
input: PipelineData,
is_perf_true: bool,
) -> Result<()> {
// Translate environment variables from Strings to Values
if let Some(e) = convert_env_values(engine_state, stack) {
@ -28,12 +27,75 @@ pub fn evaluate_file(
std::process::exit(1);
}
let file = std::fs::read(&path).into_diagnostic()?;
let cwd = current_dir(engine_state, stack)?;
let file_path = canonicalize_with(&path, cwd).unwrap_or_else(|e| {
let working_set = StateWorkingSet::new(engine_state);
report_error(
&working_set,
&ShellError::FileNotFoundCustom(
format!("Could not access file '{}': {:?}", path, e.to_string()),
Span::unknown(),
),
);
std::process::exit(1);
});
let file_path_str = file_path.to_str().unwrap_or_else(|| {
let working_set = StateWorkingSet::new(engine_state);
report_error(
&working_set,
&ShellError::NonUtf8Custom(
format!(
"Input file name '{}' is not valid UTF8",
file_path.to_string_lossy()
),
Span::unknown(),
),
);
std::process::exit(1);
});
let file = std::fs::read(&file_path)
.into_diagnostic()
.unwrap_or_else(|e| {
let working_set = StateWorkingSet::new(engine_state);
report_error(
&working_set,
&ShellError::FileNotFoundCustom(
format!(
"Could not read file '{}': {:?}",
file_path_str,
e.to_string()
),
Span::unknown(),
),
);
std::process::exit(1);
});
engine_state.start_in_file(Some(file_path_str));
let parent = file_path.parent().unwrap_or_else(|| {
let working_set = StateWorkingSet::new(engine_state);
report_error(
&working_set,
&ShellError::FileNotFoundCustom(
format!("The file path '{file_path_str}' does not have a parent"),
Span::unknown(),
),
);
std::process::exit(1);
});
stack.add_env_var(
"FILE_PWD".to_string(),
Value::string(parent.to_string_lossy(), Span::unknown()),
);
let mut working_set = StateWorkingSet::new(engine_state);
trace!("parsing file: {}", path);
let _ = parse(&mut working_set, Some(&path), &file, false, &[]);
trace!("parsing file: {}", file_path_str);
let _ = parse(&mut working_set, Some(file_path_str), &file, false, &[]);
if working_set.find_decl(b"main", &Type::Any).is_some() {
let args = format!("main {}", args.join(" "));
@ -42,26 +104,32 @@ pub fn evaluate_file(
engine_state,
stack,
&file,
&path,
PipelineData::new(Span::new(0, 0)),
file_path_str,
PipelineData::empty(),
true,
) {
std::process::exit(1);
}
if !eval_source(engine_state, stack, args.as_bytes(), "<commandline>", input) {
if !eval_source(
engine_state,
stack,
args.as_bytes(),
"<commandline>",
input,
true,
) {
std::process::exit(1);
}
} else if !eval_source(engine_state, stack, &file, &path, input) {
} else if !eval_source(engine_state, stack, &file, file_path_str, input, true) {
std::process::exit(1);
}
if is_perf_true {
info!("evaluate {}:{}:{}", file!(), line!(), column!());
}
info!("evaluate {}:{}:{}", file!(), line!(), column!());
Ok(())
}
pub fn print_table_or_error(
pub(crate) fn print_table_or_error(
engine_state: &mut EngineState,
stack: &mut Stack,
mut pipeline_data: PipelineData,
@ -75,37 +143,38 @@ pub fn print_table_or_error(
// Change the engine_state config to use the passed in configuration
engine_state.set_config(config);
match engine_state.find_decl("table".as_bytes(), &[]) {
Some(decl_id) => {
let command = engine_state.get_decl(decl_id);
if command.get_block_id().is_some() {
print_or_exit(pipeline_data, engine_state, config);
} else {
let table = command.run(
engine_state,
stack,
&Call::new(Span::new(0, 0)),
pipeline_data,
);
if let PipelineData::Value(Value::Error { error }, ..) = &pipeline_data {
let working_set = StateWorkingSet::new(engine_state);
report_error(&working_set, error);
std::process::exit(1);
}
match table {
Ok(table) => {
print_or_exit(table, engine_state, config);
}
Err(error) => {
let working_set = StateWorkingSet::new(engine_state);
if let Some(decl_id) = engine_state.find_decl("table".as_bytes(), &[]) {
let command = engine_state.get_decl(decl_id);
if command.get_block_id().is_some() {
print_or_exit(pipeline_data, engine_state, config);
} else {
let table = command.run(
engine_state,
stack,
&Call::new(Span::new(0, 0)),
pipeline_data,
);
report_error(&working_set, &error);
std::process::exit(1);
}
match table {
Ok(table) => {
print_or_exit(table, engine_state, config);
}
Err(error) => {
let working_set = StateWorkingSet::new(engine_state);
report_error(&working_set, &error);
std::process::exit(1);
}
}
}
None => {
print_or_exit(pipeline_data, engine_state, config);
}
};
} else {
print_or_exit(pipeline_data, engine_state, config);
}
// Make sure everything has finished
if let Some(exit_code) = exit_code {
@ -131,9 +200,7 @@ fn print_or_exit(pipeline_data: PipelineData, engine_state: &mut EngineState, co
std::process::exit(1);
}
let mut out = item.into_string("\n", config);
out.push('\n');
let _ = stdout_write_all_and_flush(out).map_err(|err| eprintln!("{}", err));
let out = item.into_string("\n", config) + "\n";
let _ = stdout_write_all_and_flush(out).map_err(|err| eprintln!("{err}"));
}
}

View File

@ -372,7 +372,7 @@ impl DescriptionMenu {
let description = self
.get_value()
.and_then(|suggestion| suggestion.description)
.unwrap_or_else(|| "".to_string())
.unwrap_or_default()
.lines()
.skip(self.skipped_rows)
.take(self.working_details.description_rows)
@ -411,10 +411,10 @@ impl DescriptionMenu {
RESET
)
} else {
format!(" {}\r\n", example)
format!(" {example}\r\n")
}
} else {
format!(" {}\r\n", example)
format!(" {example}\r\n")
}
})
.collect();
@ -429,7 +429,7 @@ impl DescriptionMenu {
examples,
)
} else {
format!("\r\n\r\nExamples:\r\n{}", examples,)
format!("\r\n\r\nExamples:\r\n{examples}",)
}
}
}
@ -610,7 +610,7 @@ impl Menu for DescriptionMenu {
let description_rows = self
.get_value()
.and_then(|suggestion| suggestion.description)
.unwrap_or_else(|| "".to_string())
.unwrap_or_default()
.lines()
.count();

View File

@ -17,7 +17,7 @@ impl NuHelpCompleter {
//Vec<(Signature, Vec<Example>, bool, bool)> {
let mut commands = full_commands
.iter()
.filter(|(sig, _, _, _)| {
.filter(|(sig, _, _, _, _)| {
sig.name.to_lowercase().contains(&line.to_lowercase())
|| sig.usage.to_lowercase().contains(&line.to_lowercase())
|| sig
@ -31,7 +31,7 @@ impl NuHelpCompleter {
})
.collect::<Vec<_>>();
commands.sort_by(|(a, _, _, _), (b, _, _, _)| {
commands.sort_by(|(a, _, _, _, _), (b, _, _, _, _)| {
let a_distance = levenshtein_distance(line, &a.name);
let b_distance = levenshtein_distance(line, &b.name);
a_distance.cmp(&b_distance)
@ -39,7 +39,7 @@ impl NuHelpCompleter {
commands
.into_iter()
.map(|(sig, examples, _, _)| {
.map(|(sig, examples, _, _, _)| {
let mut long_desc = String::new();
let usage = &sig.usage;

View File

@ -42,20 +42,14 @@ impl Completer for NuMenuCompleter {
if let Some(buffer) = block.signature.get_positional(0) {
if let Some(buffer_id) = &buffer.var_id {
let line_buffer = Value::String {
val: parsed.remainder.to_string(),
span: self.span,
};
let line_buffer = Value::string(parsed.remainder, self.span);
self.stack.add_var(*buffer_id, line_buffer);
}
}
if let Some(position) = block.signature.get_positional(1) {
if let Some(position_id) = &position.var_id {
let line_buffer = Value::Int {
val: pos as i64,
span: self.span,
};
let line_buffer = Value::int(pos as i64, self.span);
self.stack.add_var(*position_id, line_buffer);
}
}
@ -87,13 +81,10 @@ fn convert_to_suggestions(
) -> Vec<Suggestion> {
match value {
Value::Record { .. } => {
let text = match value
let text = value
.get_data_by_key("value")
.and_then(|val| val.as_string().ok())
{
Some(val) => val,
None => "No value key".to_string(),
};
.unwrap_or_else(|| "No value key".to_string());
let description = value
.get_data_by_key("description")
@ -163,7 +154,7 @@ fn convert_to_suggestions(
.flat_map(|val| convert_to_suggestions(val, line, pos, only_buffer_difference))
.collect(),
_ => vec![Suggestion {
value: format!("Not a record: {:?}", value),
value: format!("Not a record: {value:?}"),
description: None,
extra: None,
span: reedline::Span {

View File

@ -1,6 +1,6 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Value};
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Type, Value};
use reedline::Highlighter;
#[derive(Clone)]
@ -12,7 +12,9 @@ impl Command for NuHighlight {
}
fn signature(&self) -> Signature {
Signature::build("nu-highlight").category(Category::Strings)
Signature::build("nu-highlight")
.category(Category::Strings)
.input_output_types(vec![(Type::String, Type::String)])
}
fn usage(&self) -> &str {
@ -33,7 +35,7 @@ impl Command for NuHighlight {
let head = call.head;
let ctrlc = engine_state.ctrlc.clone();
let engine_state = engine_state.clone();
let engine_state = std::sync::Arc::new(engine_state.clone());
let config = engine_state.get_config().clone();
let highlighter = crate::NuHighlighter {

View File

@ -2,7 +2,8 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Type,
Value,
};
#[derive(Clone)]
@ -15,6 +16,7 @@ impl Command for Print {
fn signature(&self) -> Signature {
Signature::build("print")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.rest("rest", SyntaxShape::Any, "the values to print")
.switch(
"no-newline",
@ -50,14 +52,13 @@ Since this command has no output, there is no point in piping it with other comm
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 head = call.head;
for arg in args {
arg.into_pipeline_data()
.print(engine_state, stack, no_newline, to_stderr)?;
}
Ok(PipelineData::new(head))
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {

View File

@ -17,6 +17,7 @@ pub struct NushellPrompt {
default_vi_insert_prompt_indicator: Option<String>,
default_vi_normal_prompt_indicator: Option<String>,
default_multiline_indicator: Option<String>,
render_right_prompt_on_last_line: bool,
}
impl Default for NushellPrompt {
@ -34,6 +35,7 @@ impl NushellPrompt {
default_vi_insert_prompt_indicator: None,
default_vi_normal_prompt_indicator: None,
default_multiline_indicator: None,
render_right_prompt_on_last_line: false,
}
}
@ -41,8 +43,13 @@ impl NushellPrompt {
self.left_prompt_string = prompt_string;
}
pub fn update_prompt_right(&mut self, prompt_string: Option<String>) {
pub fn update_prompt_right(
&mut self,
prompt_string: Option<String>,
render_right_prompt_on_last_line: bool,
) {
self.right_prompt_string = prompt_string;
self.render_right_prompt_on_last_line = render_right_prompt_on_last_line;
}
pub fn update_prompt_indicator(&mut self, prompt_indicator_string: Option<String>) {
@ -68,6 +75,7 @@ impl NushellPrompt {
prompt_indicator_string: Option<String>,
prompt_multiline_indicator_string: Option<String>,
prompt_vi: (Option<String>, Option<String>),
render_right_prompt_on_last_line: bool,
) {
let (prompt_vi_insert_string, prompt_vi_normal_string) = prompt_vi;
@ -78,10 +86,12 @@ impl NushellPrompt {
self.default_vi_insert_prompt_indicator = prompt_vi_insert_string;
self.default_vi_normal_prompt_indicator = prompt_vi_normal_string;
self.render_right_prompt_on_last_line = render_right_prompt_on_last_line;
}
fn default_wrapped_custom_string(&self, str: String) -> String {
format!("({})", str)
format!("({str})")
}
}
@ -95,7 +105,7 @@ impl Prompt for NushellPrompt {
if let Some(prompt_string) = &self.left_prompt_string {
prompt_string.replace('\n', "\r\n").into()
} else {
let default = DefaultPrompt::new();
let default = DefaultPrompt::default();
default
.render_prompt_left()
.to_string()
@ -108,7 +118,7 @@ impl Prompt for NushellPrompt {
if let Some(prompt_string) = &self.right_prompt_string {
prompt_string.replace('\n', "\r\n").into()
} else {
let default = DefaultPrompt::new();
let default = DefaultPrompt::default();
default
.render_prompt_right()
.to_string()
@ -120,32 +130,36 @@ impl Prompt for NushellPrompt {
fn render_prompt_indicator(&self, edit_mode: PromptEditMode) -> Cow<str> {
match edit_mode {
PromptEditMode::Default => match &self.default_prompt_indicator {
Some(indicator) => indicator.as_str().into(),
None => "".into(),
},
Some(indicator) => indicator,
None => "",
}
.into(),
PromptEditMode::Emacs => match &self.default_prompt_indicator {
Some(indicator) => indicator.as_str().into(),
None => "".into(),
},
Some(indicator) => indicator,
None => "",
}
.into(),
PromptEditMode::Vi(vi_mode) => match vi_mode {
PromptViMode::Normal => match &self.default_vi_normal_prompt_indicator {
Some(indicator) => indicator.as_str().into(),
None => ": ".into(),
Some(indicator) => indicator,
None => ": ",
},
PromptViMode::Insert => match &self.default_vi_insert_prompt_indicator {
Some(indicator) => indicator.as_str().into(),
None => "".into(),
Some(indicator) => indicator,
None => "",
},
},
}
.into(),
PromptEditMode::Custom(str) => self.default_wrapped_custom_string(str).into(),
}
}
fn render_prompt_multiline_indicator(&self) -> Cow<str> {
match &self.default_multiline_indicator {
Some(indicator) => indicator.as_str().into(),
None => "::: ".into(),
Some(indicator) => indicator,
None => "::: ",
}
.into()
}
fn render_prompt_history_search_indicator(
@ -162,4 +176,8 @@ impl Prompt for NushellPrompt {
prefix, history_search.term
))
}
fn right_prompt_on_last_line(&self) -> bool {
self.render_right_prompt_on_last_line
}
}

View File

@ -1,10 +1,10 @@
use crate::util::report_error;
use crate::NushellPrompt;
use log::info;
use log::trace;
use nu_engine::eval_subexpression;
use nu_protocol::{
engine::{EngineState, Stack, StateWorkingSet},
Config, PipelineData, Span, Value,
Config, PipelineData, Value,
};
use reedline::Prompt;
@ -25,12 +25,11 @@ fn get_prompt_string(
config: &Config,
engine_state: &EngineState,
stack: &mut Stack,
is_perf_true: bool,
) -> Option<String> {
stack
.get_env_var(engine_state, prompt)
.and_then(|v| match v {
Value::Block {
Value::Closure {
val: block_id,
captures,
..
@ -38,29 +37,39 @@ fn get_prompt_string(
let block = engine_state.get_block(block_id);
let mut stack = stack.captures_to_stack(&captures);
// Use eval_subexpression to force a redirection of output, so we can use everything in prompt
let ret_val = eval_subexpression(
engine_state,
&mut stack,
block,
PipelineData::new(Span::new(0, 0)), // Don't try this at home, 0 span is ignored
let ret_val =
eval_subexpression(engine_state, &mut stack, block, PipelineData::empty());
trace!(
"get_prompt_string (block) {}:{}:{}",
file!(),
line!(),
column!()
);
if is_perf_true {
info!(
"get_prompt_string (block) {}:{}:{}",
file!(),
line!(),
column!()
);
}
match ret_val {
Ok(ret_val) => Some(ret_val),
Err(err) => {
ret_val
.map_err(|err| {
let working_set = StateWorkingSet::new(engine_state);
report_error(&working_set, &err);
None
}
}
})
.ok()
}
Value::Block { val: block_id, .. } => {
let block = engine_state.get_block(block_id);
// Use eval_subexpression to force a redirection of output, so we can use everything in prompt
let ret_val = eval_subexpression(engine_state, stack, block, PipelineData::empty());
trace!(
"get_prompt_string (block) {}:{}:{}",
file!(),
line!(),
column!()
);
ret_val
.map_err(|err| {
let working_set = StateWorkingSet::new(engine_state);
report_error(&working_set, &err);
})
.ok()
}
Value::String { .. } => Some(PipelineData::Value(v.clone(), None)),
_ => None,
@ -68,20 +77,17 @@ fn get_prompt_string(
.and_then(|pipeline_data| {
let output = pipeline_data.collect_string("", config).ok();
match output {
Some(mut x) => {
// Just remove the very last newline.
if x.ends_with('\n') {
x.pop();
}
if x.ends_with('\r') {
x.pop();
}
Some(x)
output.map(|mut x| {
// Just remove the very last newline.
if x.ends_with('\n') {
x.pop();
}
None => None,
}
if x.ends_with('\r') {
x.pop();
}
x
})
})
}
@ -90,71 +96,39 @@ pub(crate) fn update_prompt<'prompt>(
engine_state: &EngineState,
stack: &Stack,
nu_prompt: &'prompt mut NushellPrompt,
is_perf_true: bool,
) -> &'prompt dyn Prompt {
let mut stack = stack.clone();
let left_prompt_string = get_prompt_string(
PROMPT_COMMAND,
config,
engine_state,
&mut stack,
is_perf_true,
);
let left_prompt_string = get_prompt_string(PROMPT_COMMAND, config, engine_state, &mut stack);
// Now that we have the prompt string lets ansify it.
// <133 A><prompt><133 B><command><133 C><command output>
let left_prompt_string = if config.shell_integration {
match left_prompt_string {
Some(prompt_string) => Some(format!(
"{}{}{}",
PRE_PROMPT_MARKER, prompt_string, POST_PROMPT_MARKER
)),
None => left_prompt_string,
if let Some(prompt_string) = left_prompt_string {
Some(format!(
"{PRE_PROMPT_MARKER}{prompt_string}{POST_PROMPT_MARKER}"
))
} else {
left_prompt_string
}
} else {
left_prompt_string
};
let right_prompt_string = get_prompt_string(
PROMPT_COMMAND_RIGHT,
config,
engine_state,
&mut stack,
is_perf_true,
);
let right_prompt_string =
get_prompt_string(PROMPT_COMMAND_RIGHT, config, engine_state, &mut stack);
let prompt_indicator_string = get_prompt_string(
PROMPT_INDICATOR,
config,
engine_state,
&mut stack,
is_perf_true,
);
let prompt_indicator_string =
get_prompt_string(PROMPT_INDICATOR, config, engine_state, &mut stack);
let prompt_multiline_string = get_prompt_string(
PROMPT_MULTILINE_INDICATOR,
config,
engine_state,
&mut stack,
is_perf_true,
);
let prompt_multiline_string =
get_prompt_string(PROMPT_MULTILINE_INDICATOR, config, engine_state, &mut stack);
let prompt_vi_insert_string = get_prompt_string(
PROMPT_INDICATOR_VI_INSERT,
config,
engine_state,
&mut stack,
is_perf_true,
);
let prompt_vi_insert_string =
get_prompt_string(PROMPT_INDICATOR_VI_INSERT, config, engine_state, &mut stack);
let prompt_vi_normal_string = get_prompt_string(
PROMPT_INDICATOR_VI_NORMAL,
config,
engine_state,
&mut stack,
is_perf_true,
);
let prompt_vi_normal_string =
get_prompt_string(PROMPT_INDICATOR_VI_NORMAL, config, engine_state, &mut stack);
// apply the other indicators
nu_prompt.update_all_prompt_strings(
@ -163,12 +137,11 @@ pub(crate) fn update_prompt<'prompt>(
prompt_indicator_string,
prompt_multiline_string,
(prompt_vi_insert_string, prompt_vi_normal_string),
config.render_right_prompt_on_last_line,
);
let ret_val = nu_prompt as &dyn Prompt;
if is_perf_true {
info!("update_prompt {}:{}:{}", file!(), line!(), column!());
}
trace!("update_prompt {}:{}:{}", file!(), line!(), column!());
ret_val
}

View File

@ -1,14 +1,13 @@
use super::DescriptionMenu;
use crate::{menus::NuMenuCompleter, NuHelpCompleter};
use crossterm::event::{KeyCode, KeyModifiers};
use nu_color_config::lookup_ansi_color_style;
use nu_color_config::{color_record_to_nustyle, lookup_ansi_color_style};
use nu_engine::eval_block;
use nu_parser::parse;
use nu_protocol::{
color_value_string, create_menus,
create_menus,
engine::{EngineState, Stack, StateWorkingSet},
extract_value, Config, IntoPipelineData, ParsedKeybinding, ParsedMenu, PipelineData,
ShellError, Span, Value,
extract_value, Config, ParsedKeybinding, ParsedMenu, PipelineData, ShellError, Span, Value,
};
use reedline::{
default_emacs_keybindings, default_vi_insert_keybindings, default_vi_normal_keybindings,
@ -110,11 +109,11 @@ pub(crate) fn add_menus(
};
let mut temp_stack = Stack::new();
let input = Value::nothing(Span::test_data()).into_pipeline_data();
let input = PipelineData::Empty;
let res = eval_block(&engine_state, &mut temp_stack, &block, input, false, false)?;
if let PipelineData::Value(value, None) = res {
for menu in create_menus(&value, config)? {
for menu in create_menus(&value)? {
line_editor =
add_menu(line_editor, &menu, engine_state.clone(), stack, config)?;
}
@ -159,14 +158,11 @@ macro_rules! add_style {
($name:expr, $cols: expr, $vals:expr, $span:expr, $config: expr, $menu:expr, $f:expr) => {
$menu = match extract_value($name, $cols, $vals, $span) {
Ok(text) => {
let text = match text {
Value::String { val, .. } => val.clone(),
Value::Record { cols, vals, span } => {
color_value_string(span, cols, vals, $config).into_string("", $config)
}
_ => "green".to_string(),
let style = match text {
Value::String { val, .. } => lookup_ansi_color_style(&val),
Value::Record { .. } => color_record_to_nustyle(&text),
_ => lookup_ansi_color_style("green"),
};
let style = lookup_ansi_color_style(&text);
$f($menu, style)
}
Err(_) => $menu,
@ -251,7 +247,7 @@ pub(crate) fn add_columnar_menu(
Value::Nothing { .. } => {
Ok(line_editor.with_menu(ReedlineMenu::EngineCompleter(Box::new(columnar_menu))))
}
Value::Block {
Value::Closure {
val,
captures,
span,
@ -337,7 +333,7 @@ pub(crate) fn add_list_menu(
Value::Nothing { .. } => {
Ok(line_editor.with_menu(ReedlineMenu::HistoryMenu(Box::new(list_menu))))
}
Value::Block {
Value::Closure {
val,
captures,
span,
@ -459,7 +455,7 @@ pub(crate) fn add_description_menu(
completer,
}))
}
Value::Block {
Value::Closure {
val,
captures,
span,
@ -477,7 +473,7 @@ pub(crate) fn add_description_menu(
}))
}
_ => Err(ShellError::UnsupportedConfigValue(
"block or omitted value".to_string(),
"closure or omitted value".to_string(),
menu.source.into_abbreviated_string(config),
menu.source.span()?,
)),
@ -491,7 +487,7 @@ fn add_menu_keybindings(keybindings: &mut Keybindings) {
KeyCode::Tab,
ReedlineEvent::UntilFound(vec![
ReedlineEvent::Menu("completion_menu".to_string()),
ReedlineEvent::MenuNext,
ReedlineEvent::Edit(vec![EditCommand::Complete]),
]),
);
@ -655,14 +651,15 @@ fn add_parsed_keybinding(
let pos1 = char_iter.next();
let pos2 = char_iter.next();
let char = match (pos1, pos2) {
(Some(char), None) => Ok(char),
_ => Err(ShellError::UnsupportedConfigValue(
let char = if let (Some(char), None) = (pos1, pos2) {
char
} else {
return Err(ShellError::UnsupportedConfigValue(
"char_<CHAR: unicode codepoint>".to_string(),
c.to_string(),
keybinding.keycode.span()?,
)),
}?;
));
};
KeyCode::Char(char)
}
@ -683,10 +680,10 @@ fn add_parsed_keybinding(
let fn_num: u8 = c[1..]
.parse()
.ok()
.filter(|num| matches!(num, 1..=12))
.filter(|num| matches!(num, 1..=20))
.ok_or(ShellError::UnsupportedConfigValue(
"(f1|f2|...|f12)".to_string(),
format!("unknown function key: {}", c),
"(f1|f2|...|f20)".to_string(),
format!("unknown function key: {c}"),
keybinding.keycode.span()?,
))?;
KeyCode::F(fn_num)
@ -964,6 +961,7 @@ fn edit_from_record(
let char = extract_char(value, config)?;
EditCommand::MoveLeftBefore(char)
}
"complete" => EditCommand::Complete,
e => {
return Err(ShellError::UnsupportedConfigValue(
"reedline EditCommand".to_string(),
@ -992,10 +990,7 @@ mod test {
#[test]
fn test_send_event() {
let cols = vec!["send".to_string()];
let vals = vec![Value::String {
val: "Enter".to_string(),
span: Span::test_data(),
}];
let vals = vec![Value::test_string("Enter")];
let span = Span::test_data();
let b = EventType::try_from_columns(&cols, &vals, &span).unwrap();
@ -1015,10 +1010,7 @@ mod test {
#[test]
fn test_edit_event() {
let cols = vec!["edit".to_string()];
let vals = vec![Value::String {
val: "Clear".to_string(),
span: Span::test_data(),
}];
let vals = vec![Value::test_string("Clear")];
let span = Span::test_data();
let b = EventType::try_from_columns(&cols, &vals, &span).unwrap();
@ -1042,14 +1034,8 @@ mod test {
fn test_send_menu() {
let cols = vec!["send".to_string(), "name".to_string()];
let vals = vec![
Value::String {
val: "Menu".to_string(),
span: Span::test_data(),
},
Value::String {
val: "history_menu".to_string(),
span: Span::test_data(),
},
Value::test_string("Menu"),
Value::test_string("history_menu"),
];
let span = Span::test_data();
@ -1075,14 +1061,8 @@ mod test {
// Menu event
let cols = vec!["send".to_string(), "name".to_string()];
let vals = vec![
Value::String {
val: "Menu".to_string(),
span: Span::test_data(),
},
Value::String {
val: "history_menu".to_string(),
span: Span::test_data(),
},
Value::test_string("Menu"),
Value::test_string("history_menu"),
];
let menu_event = Value::Record {
@ -1093,10 +1073,7 @@ mod test {
// Enter event
let cols = vec!["send".to_string()];
let vals = vec![Value::String {
val: "Enter".to_string(),
span: Span::test_data(),
}];
let vals = vec![Value::test_string("Enter")];
let enter_event = Value::Record {
cols,
@ -1137,14 +1114,8 @@ mod test {
// Menu event
let cols = vec!["send".to_string(), "name".to_string()];
let vals = vec![
Value::String {
val: "Menu".to_string(),
span: Span::test_data(),
},
Value::String {
val: "history_menu".to_string(),
span: Span::test_data(),
},
Value::test_string("Menu"),
Value::test_string("history_menu"),
];
let menu_event = Value::Record {
@ -1155,10 +1126,7 @@ mod test {
// Enter event
let cols = vec!["send".to_string()];
let vals = vec![Value::String {
val: "Enter".to_string(),
span: Span::test_data(),
}];
let vals = vec![Value::test_string("Enter")];
let enter_event = Value::Record {
cols,
@ -1186,10 +1154,7 @@ mod test {
#[test]
fn test_error() {
let cols = vec!["not_exist".to_string()];
let vals = vec![Value::String {
val: "Enter".to_string(),
span: Span::test_data(),
}];
let vals = vec![Value::test_string("Enter")];
let span = Span::test_data();
let b = EventType::try_from_columns(&cols, &vals, &span);

View File

@ -5,26 +5,26 @@ use crate::{
util::{eval_source, get_guaranteed_cwd, report_error, report_error_new},
NuHighlighter, NuValidator, NushellPrompt,
};
use fancy_regex::Regex;
use lazy_static::lazy_static;
use log::{info, trace, warn};
use crossterm::cursor::CursorShape;
use log::{trace, warn};
use miette::{IntoDiagnostic, Result};
use nu_color_config::get_color_config;
use nu_engine::{convert_env_values, eval_block};
use nu_color_config::StyleComputer;
use nu_engine::{convert_env_values, eval_block, eval_block_with_early_return};
use nu_parser::{lex, parse, trim_quotes_str};
use nu_protocol::{
ast::PathMember,
config::NuCursorShape,
engine::{EngineState, ReplOperation, Stack, StateWorkingSet},
format_duration, BlockId, HistoryFileFormat, PipelineData, PositionalArg, ShellError, Span,
Spanned, Type, Value, VarId,
};
use reedline::{DefaultHinter, EditCommand, Emacs, SqliteBackedHistory, Vi};
use nu_utils::utils::perf;
use reedline::{CursorConfig, DefaultHinter, EditCommand, Emacs, SqliteBackedHistory, Vi};
use std::{
io::{self, Write},
sync::atomic::Ordering,
time::Instant,
};
use strip_ansi_escapes::strip;
use sysinfo::SystemExt;
// According to Daniel Imms @Tyriar, we need to do these this way:
@ -41,17 +41,18 @@ pub fn evaluate_repl(
engine_state: &mut EngineState,
stack: &mut Stack,
nushell_path: &str,
is_perf_true: bool,
prerun_command: Option<Spanned<String>>,
entire_start_time: Instant,
) -> Result<()> {
use reedline::{FileBackedHistory, Reedline, Signal};
let use_color = engine_state.get_config().use_ansi_coloring;
// Guard against invocation without a connected terminal.
// reedline / crossterm event polling will fail without a connected tty
if !atty::is(atty::Stream::Stdin) {
return Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
"Nushell launched as interactive REPL but STDIN is not a TTY, either launch in a valid terminal or provide arguments to invoke a script!",
"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();
}
@ -60,71 +61,55 @@ pub fn evaluate_repl(
let mut nu_prompt = NushellPrompt::new();
if is_perf_true {
info!(
"translate environment vars {}:{}:{}",
file!(),
line!(),
column!()
);
}
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);
}
perf(
"translate env vars",
start_time,
file!(),
line!(),
column!(),
use_color,
);
// seed env vars
stack.add_env_var(
"CMD_DURATION_MS".into(),
Value::String {
val: "0823".to_string(),
span: Span { start: 0, end: 0 },
},
Value::string("0823", Span::unknown()),
);
stack.add_env_var(
"LAST_EXIT_CODE".into(),
Value::Int {
val: 0,
span: Span { start: 0, end: 0 },
},
);
if is_perf_true {
info!(
"load config initially {}:{}:{}",
file!(),
line!(),
column!()
);
}
if is_perf_true {
info!("setup reedline {}:{}:{}", file!(), line!(), column!());
}
stack.add_env_var("LAST_EXIT_CODE".into(), Value::int(0, Span::unknown()));
let mut start_time = std::time::Instant::now();
let mut line_editor = Reedline::create();
// Now that reedline is created, get the history session id and store it in engine_state
let hist_sesh = match line_editor.get_history_session_id() {
Some(id) => i64::from(id),
None => 0,
};
let hist_sesh = line_editor
.get_history_session_id()
.map(i64::from)
.unwrap_or(0);
engine_state.history_session_id = hist_sesh;
perf(
"setup reedline",
start_time,
file!(),
line!(),
column!(),
use_color,
);
let config = engine_state.get_config();
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() {
if is_perf_true {
info!("setup history {}:{}:{}", file!(), line!(), column!());
}
let history: Box<dyn reedline::History> = match engine_state.config.history_file_format {
HistoryFileFormat::PlainText => Box::new(
FileBackedHistory::with_file(
@ -139,7 +124,16 @@ pub fn evaluate_repl(
};
line_editor = line_editor.with_history(history);
};
perf(
"setup history",
start_time,
file!(),
line!(),
column!(),
use_color,
);
start_time = std::time::Instant::now();
let sys = sysinfo::System::new();
let show_banner = config.show_banner;
@ -147,77 +141,113 @@ pub fn evaluate_repl(
if show_banner {
let banner = get_banner(engine_state, stack);
if use_ansi {
println!("{}", banner);
println!("{banner}");
} else {
let stripped_string = {
if let Ok(bytes) = strip(&banner) {
String::from_utf8_lossy(&bytes).to_string()
} else {
banner
}
};
println!("{}", stripped_string);
println!("{}", nu_utils::strip_ansi_string_likely(banner));
}
}
perf(
"get sysinfo/show banner",
start_time,
file!(),
line!(),
column!(),
use_color,
);
if let Some(s) = prerun_command {
eval_source(
engine_state,
stack,
s.item.as_bytes(),
&format!("entry #{}", entry_num),
PipelineData::new(Span::new(0, 0)),
&format!("entry #{entry_num}"),
PipelineData::empty(),
false,
);
engine_state.merge_env(stack, get_guaranteed_cwd(engine_state, stack))?;
}
loop {
if is_perf_true {
info!(
"load config each loop {}:{}:{}",
file!(),
line!(),
column!()
);
}
let loop_start_time = std::time::Instant::now();
let cwd = get_guaranteed_cwd(engine_state, stack);
start_time = std::time::Instant::now();
// Before doing anything, merge the environment from the previous REPL iteration into the
// permanent state.
if let Err(err) = engine_state.merge_env(stack, cwd) {
report_error_new(engine_state, &err);
}
perf(
"merge env",
start_time,
file!(),
line!(),
column!(),
use_color,
);
start_time = std::time::Instant::now();
//Reset the ctrl-c handler
if let Some(ctrlc) = &mut engine_state.ctrlc {
ctrlc.store(false, Ordering::SeqCst);
}
perf(
"reset ctrlc",
start_time,
file!(),
line!(),
column!(),
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();
if is_perf_true {
info!("setup colors {}:{}:{}", file!(), line!(), column!());
}
let color_hm = get_color_config(config);
if is_perf_true {
info!("update reedline {}:{}:{}", file!(), line!(), column!());
}
let engine_reference = std::sync::Arc::new(engine_state.clone());
// Find the configured cursor shapes for each mode
let cursor_config = CursorConfig {
vi_insert: Some(map_nucursorshape_to_cursorshape(
config.cursor_shape_vi_insert,
)),
vi_normal: Some(map_nucursorshape_to_cursorshape(
config.cursor_shape_vi_normal,
)),
emacs: Some(map_nucursorshape_to_cursorshape(config.cursor_shape_emacs)),
};
perf(
"get config/cursor config",
start_time,
file!(),
line!(),
column!(),
use_color,
);
start_time = std::time::Instant::now();
line_editor = line_editor
.with_highlighter(Box::new(NuHighlighter {
engine_state: engine_state.clone(),
engine_state: engine_reference.clone(),
config: config.clone(),
}))
.with_validator(Box::new(NuValidator {
engine_state: engine_state.clone(),
engine_state: engine_reference.clone(),
}))
.with_completer(Box::new(NuCompleter::new(
engine_reference.clone(),
@ -225,25 +255,54 @@ pub fn evaluate_repl(
)))
.with_quick_completions(config.quick_completions)
.with_partial_completions(config.partial_completions)
.with_ansi_colors(config.use_ansi_coloring);
.with_ansi_colors(config.use_ansi_coloring)
.with_cursor_config(cursor_config);
perf(
"reedline builder",
start_time,
file!(),
line!(),
column!(),
use_color,
);
let style_computer = StyleComputer::from_config(engine_state, stack);
start_time = std::time::Instant::now();
line_editor = if config.use_ansi_coloring {
line_editor.with_hinter(Box::new(
DefaultHinter::default().with_style(color_hm["hints"]),
))
line_editor.with_hinter(Box::new({
// As of Nov 2022, "hints" color_config closures only get `null` passed in.
let style = style_computer.compute("hints", &Value::nothing(Span::unknown()));
DefaultHinter::default().with_style(style)
}))
} else {
line_editor.disable_hints()
};
perf(
"reedline coloring/style_computer",
start_time,
file!(),
line!(),
column!(),
use_color,
);
line_editor = match add_menus(line_editor, engine_reference, stack, config) {
Ok(line_editor) => line_editor,
Err(e) => {
let working_set = StateWorkingSet::new(engine_state);
report_error(&working_set, &e);
Reedline::create()
}
};
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);
Reedline::create()
});
perf(
"reedline menus",
start_time,
file!(),
line!(),
column!(),
use_color,
);
start_time = std::time::Instant::now();
let buffer_editor = if !config.buffer_editor.is_empty() {
Some(config.buffer_editor.clone())
} else {
@ -264,21 +323,31 @@ pub fn evaluate_repl(
} else {
line_editor
};
perf(
"reedline buffer_editor",
start_time,
file!(),
line!(),
column!(),
use_color,
);
start_time = std::time::Instant::now();
if config.sync_history_on_enter {
if is_perf_true {
info!("sync history {}:{}:{}", file!(), line!(), column!());
}
if let Err(e) = line_editor.sync_history() {
warn!("Failed to sync history: {}", e);
}
}
perf(
"sync_history",
start_time,
file!(),
line!(),
column!(),
use_color,
);
if is_perf_true {
info!("setup keybindings {}:{}:{}", file!(), line!(), column!());
}
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 {
@ -300,19 +369,33 @@ pub fn evaluate_repl(
line_editor
}
};
perf(
"keybindings",
start_time,
file!(),
line!(),
column!(),
use_color,
);
if is_perf_true {
info!("prompt_update {}:{}:{}", file!(), line!(), column!());
}
start_time = std::time::Instant::now();
// Right before we start our prompt and take input from the user,
// fire the "pre_prompt" hook
if let Some(hook) = config.hooks.pre_prompt.clone() {
if let Err(err) = eval_hook(engine_state, stack, vec![], &hook) {
if let Err(err) = eval_hook(engine_state, stack, None, vec![], &hook) {
report_error_new(engine_state, &err);
}
}
perf(
"pre-prompt hook",
start_time,
file!(),
line!(),
column!(),
use_color,
);
start_time = std::time::Instant::now();
// Next, check all the environment variables they ask for
// fire the "env_change" hook
let config = engine_state.get_config();
@ -321,22 +404,37 @@ pub fn evaluate_repl(
{
report_error_new(engine_state, &error)
}
perf(
"env-change hook",
start_time,
file!(),
line!(),
column!(),
use_color,
);
start_time = std::time::Instant::now();
let config = engine_state.get_config();
let prompt =
prompt_update::update_prompt(config, engine_state, stack, &mut nu_prompt, is_perf_true);
let prompt = prompt_update::update_prompt(config, engine_state, stack, &mut nu_prompt);
perf(
"update_prompt",
start_time,
file!(),
line!(),
column!(),
use_color,
);
entry_num += 1;
if is_perf_true {
info!(
"finished setup, starting repl {}:{}:{}",
file!(),
line!(),
column!()
if entry_num == 1 && show_banner {
println!(
"Startup Time: {}",
format_duration(entire_start_time.elapsed().as_nanos() as i64)
);
}
start_time = std::time::Instant::now();
let input = line_editor.read_line(prompt);
let shell_integration = config.shell_integration;
@ -367,7 +465,7 @@ pub fn evaluate_repl(
// Right before we start running the code the user gave us,
// fire the "pre_execution" hook
if let Some(hook) = config.hooks.pre_execution.clone() {
if let Err(err) = eval_hook(engine_state, stack, vec![], &hook) {
if let Err(err) = eval_hook(engine_state, stack, None, vec![], &hook) {
report_error_new(engine_state, &err);
}
}
@ -408,7 +506,7 @@ pub fn evaluate_repl(
"OLDPWD".into(),
Value::String {
val: cwd.clone(),
span: Span { start: 0, end: 0 },
span: Span::unknown(),
},
);
@ -418,7 +516,7 @@ pub fn evaluate_repl(
"PWD".into(),
Value::String {
val: path.clone(),
span: Span { start: 0, end: 0 },
span: Span::unknown(),
},
);
let cwd = Value::String { val: cwd, span };
@ -463,8 +561,9 @@ pub fn evaluate_repl(
engine_state,
stack,
s.as_bytes(),
&format!("entry #{}", entry_num),
PipelineData::new(Span::new(0, 0)),
&format!("entry #{entry_num}"),
PipelineData::empty(),
false,
);
}
let cmd_duration = start_time.elapsed();
@ -473,7 +572,7 @@ pub fn evaluate_repl(
"CMD_DURATION_MS".into(),
Value::String {
val: format!("{}", cmd_duration.as_millis()),
span: Span { start: 0, end: 0 },
span: Span::unknown(),
},
);
@ -521,7 +620,7 @@ pub fn evaluate_repl(
// 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;{}\x07", maybe_abbrev_path))?;
run_ansi_sequence(&format!("\x1b]2;{maybe_abbrev_path}\x07"))?;
}
run_ansi_sequence(RESET_APPLICATION_MODE)?;
}
@ -561,7 +660,7 @@ pub fn evaluate_repl(
Err(err) => {
let message = err.to_string();
if !message.contains("duration") {
println!("Error: {:?}", err);
eprintln!("Error: {err:?}");
// TODO: Identify possible error cases where a hard failure is preferable
// Ignoring and reporting could hide bigger problems
// e.g. https://github.com/nushell/nushell/issues/6452
@ -572,11 +671,36 @@ pub fn evaluate_repl(
}
}
}
perf(
"processing line editor input",
start_time,
file!(),
line!(),
column!(),
use_color,
);
perf(
"finished repl loop",
loop_start_time,
file!(),
line!(),
column!(),
use_color,
);
}
Ok(())
}
fn map_nucursorshape_to_cursorshape(shape: NuCursorShape) -> CursorShape {
match shape {
NuCursorShape::Block => CursorShape::Block,
NuCursorShape::UnderScore => CursorShape::UnderScore,
NuCursorShape::Line => CursorShape::Line,
}
}
fn get_banner(engine_state: &mut EngineState, stack: &mut Stack) -> String {
let age = match eval_string_with_input(
engine_state,
@ -600,15 +724,7 @@ Our {}Documentation{} is located at {}http://nushell.sh{}
{}Tweet{} us at {}@nu_shell{}
It's been this long since {}Nushell{}'s first commit:
{}
{}You can disable this banner using the {}config nu{}{} command
to modify the config.nu file and setting show_banner to false.
let-env config = {{
show_banner: false
...
}}{}
{}{}
"#,
"\x1b[32m", //start line 1 green
"\x1b[32m", //start line 2
@ -640,11 +756,7 @@ let-env config = {{
"\x1b[32m", //before Nushell
"\x1b[0m", //after Nushell
age,
"\x1b[2;37m", //before banner disable dim white
"\x1b[2;36m", //before config nu dim cyan
"\x1b[0m", //after config nu
"\x1b[2;37m", //after config nu dim white
"\x1b[0m", //after banner disable
"\x1b[0m", //after banner disable
);
banner
@ -670,7 +782,7 @@ pub fn eval_string_with_input(
let input_as_pipeline_data = match input {
Some(input) => PipelineData::Value(input, None),
None => PipelineData::new(Span::test_data()),
None => PipelineData::empty(),
};
eval_block(
@ -681,7 +793,7 @@ pub fn eval_string_with_input(
false,
true,
)
.map(|x| x.into_value(Span::test_data()))
.map(|x| x.into_value(Span::unknown()))
}
pub fn get_command_finished_marker(stack: &Stack, engine_state: &EngineState) -> String {
@ -719,6 +831,7 @@ pub fn eval_env_change_hook(
eval_hook(
engine_state,
stack,
None,
vec![("$before".into(), before), ("$after".into(), after.clone())],
hook_value,
)?;
@ -744,15 +857,24 @@ pub fn eval_env_change_hook(
pub fn eval_hook(
engine_state: &mut EngineState,
stack: &mut Stack,
input: Option<PipelineData>,
arguments: Vec<(String, Value)>,
value: &Value,
) -> Result<(), ShellError> {
) -> Result<PipelineData, ShellError> {
let value_span = value.span()?;
// Hooks can optionally be a record in this form:
// {
// condition: {|before, after| ... } # block that evaluates to true/false
// code: # block or a string
// }
// The condition block will be run to check whether the main hook (in `code`) should be run.
// If it returns true (the default if a condition block is not specified), the hook should be run.
let condition_path = PathMember::String {
val: "condition".to_string(),
span: value_span,
};
let mut output = PipelineData::empty();
let code_path = PathMember::String {
val: "code".to_string(),
@ -762,55 +884,67 @@ pub fn eval_hook(
match value {
Value::List { vals, .. } => {
for val in vals {
eval_hook(engine_state, stack, arguments.clone(), val)?
eval_hook(engine_state, stack, None, arguments.clone(), val)?;
}
}
Value::Record { .. } => {
let do_run_hook =
if let Ok(condition) = value.clone().follow_cell_path(&[condition_path], false) {
match condition {
Value::Block {
val: block_id,
span: block_span,
..
} => {
match run_hook_block(
engine_state,
stack,
block_id,
arguments.clone(),
block_span,
) {
Ok(value) => match value {
Value::Bool { val, .. } => val,
other => {
return Err(ShellError::UnsupportedConfigValue(
"boolean output".to_string(),
format!("{}", other.get_type()),
other.span()?,
));
}
},
Err(err) => {
return Err(err);
let do_run_hook = if let Ok(condition) =
value
.clone()
.follow_cell_path(&[condition_path], false, false)
{
match condition {
Value::Block {
val: block_id,
span: block_span,
..
}
| Value::Closure {
val: block_id,
span: block_span,
..
} => {
match run_hook_block(
engine_state,
stack,
block_id,
None,
arguments.clone(),
block_span,
) {
Ok(pipeline_data) => {
if let PipelineData::Value(Value::Bool { val, .. }, ..) =
pipeline_data
{
val
} else {
return Err(ShellError::UnsupportedConfigValue(
"boolean output".to_string(),
"other PipelineData variant".to_string(),
block_span,
));
}
}
}
other => {
return Err(ShellError::UnsupportedConfigValue(
"block".to_string(),
format!("{}", other.get_type()),
other.span()?,
));
Err(err) => {
return Err(err);
}
}
}
} else {
// always run the hook
true
};
other => {
return Err(ShellError::UnsupportedConfigValue(
"block".to_string(),
format!("{}", other.get_type()),
other.span()?,
));
}
}
} else {
// always run the hook
true
};
if do_run_hook {
match value.clone().follow_cell_path(&[code_path], false)? {
match value.clone().follow_cell_path(&[code_path], false, false)? {
Value::String {
val,
span: source_span,
@ -825,6 +959,7 @@ pub fn eval_hook(
name.as_bytes().to_vec(),
val.span()?,
Type::Any,
false,
);
vars.push((var_id, val));
@ -846,7 +981,7 @@ pub fn eval_hook(
};
engine_state.merge_delta(delta)?;
let input = PipelineData::new(value_span);
let input = PipelineData::empty();
let var_ids: Vec<VarId> = vars
.into_iter()
@ -857,7 +992,9 @@ pub fn eval_hook(
.collect();
match eval_block(engine_state, stack, &block, input, false, false) {
Ok(_) => {}
Ok(pipeline_data) => {
output = pipeline_data;
}
Err(err) => {
report_error_new(engine_state, &err);
}
@ -872,7 +1009,28 @@ pub fn eval_hook(
span: block_span,
..
} => {
run_hook_block(engine_state, stack, block_id, arguments, block_span)?;
run_hook_block(
engine_state,
stack,
block_id,
input,
arguments,
block_span,
)?;
}
Value::Closure {
val: block_id,
span: block_span,
..
} => {
run_hook_block(
engine_state,
stack,
block_id,
input,
arguments,
block_span,
)?;
}
other => {
return Err(ShellError::UnsupportedConfigValue(
@ -889,7 +1047,28 @@ pub fn eval_hook(
span: block_span,
..
} => {
run_hook_block(engine_state, stack, *block_id, arguments, *block_span)?;
output = run_hook_block(
engine_state,
stack,
*block_id,
input,
arguments,
*block_span,
)?;
}
Value::Closure {
val: block_id,
span: block_span,
..
} => {
output = run_hook_block(
engine_state,
stack,
*block_id,
input,
arguments,
*block_span,
)?;
}
other => {
return Err(ShellError::UnsupportedConfigValue(
@ -903,19 +1082,20 @@ pub fn eval_hook(
let cwd = get_guaranteed_cwd(engine_state, stack);
engine_state.merge_env(stack, cwd)?;
Ok(())
Ok(output)
}
pub fn run_hook_block(
fn run_hook_block(
engine_state: &EngineState,
stack: &mut Stack,
block_id: BlockId,
optional_input: Option<PipelineData>,
arguments: Vec<(String, Value)>,
span: Span,
) -> Result<Value, ShellError> {
) -> Result<PipelineData, ShellError> {
let block = engine_state.get_block(block_id);
let input = PipelineData::new(span);
let input = optional_input.unwrap_or_else(PipelineData::empty);
let mut callee_stack = stack.gather_captures(&block.captures);
@ -934,62 +1114,58 @@ pub fn run_hook_block(
}
}
match eval_block(engine_state, &mut callee_stack, block, input, false, false) {
Ok(pipeline_data) => match pipeline_data.into_value(span) {
Value::Error { error } => Err(error),
val => {
// If all went fine, preserve the environment of the called block
let caller_env_vars = stack.get_env_var_names(engine_state);
let pipeline_data =
eval_block_with_early_return(engine_state, &mut callee_stack, block, input, false, false)?;
// remove env vars that are present in the caller but not in the callee
// (the callee hid them)
for var in caller_env_vars.iter() {
if !callee_stack.has_env_var(engine_state, var) {
stack.remove_env_var(engine_state, var);
}
}
// add new env vars from callee to caller
for (var, value) in callee_stack.get_stack_env_vars() {
stack.add_env_var(var, value);
}
Ok(val)
}
},
Err(err) => Err(err),
if let PipelineData::Value(Value::Error { error }, _) = pipeline_data {
return Err(error);
}
// If all went fine, preserve the environment of the called block
let caller_env_vars = stack.get_env_var_names(engine_state);
// remove env vars that are present in the caller but not in the callee
// (the callee hid them)
for var in caller_env_vars.iter() {
if !callee_stack.has_env_var(engine_state, var) {
stack.remove_env_var(engine_state, var);
}
}
// add new env vars from callee to caller
for (var, value) in callee_stack.get_stack_env_vars() {
stack.add_env_var(var, value);
}
Ok(pipeline_data)
}
fn run_ansi_sequence(seq: &str) -> Result<(), ShellError> {
match io::stdout().write_all(seq.as_bytes()) {
Ok(it) => it,
Err(err) => {
return Err(ShellError::GenericError(
"Error writing ansi sequence".into(),
err.to_string(),
Some(Span { start: 0, end: 0 }),
None,
Vec::new(),
));
}
};
io::stdout().write_all(seq.as_bytes()).map_err(|e| {
ShellError::GenericError(
"Error writing ansi sequence".into(),
e.to_string(),
Some(Span::unknown()),
None,
Vec::new(),
)
})?;
io::stdout().flush().map_err(|e| {
ShellError::GenericError(
"Error flushing stdio".into(),
e.to_string(),
Some(Span { start: 0, end: 0 }),
Some(Span::unknown()),
None,
Vec::new(),
)
})
}
lazy_static! {
// Absolute paths with a drive letter, like 'C:', 'D:\', 'E:\foo'
static ref DRIVE_PATH_REGEX: Regex =
Regex::new(r"^[a-zA-Z]:[/\\]?").expect("Internal error: regex creation");
}
// Absolute paths with a drive letter, like 'C:', 'D:\', 'E:\foo'
#[cfg(windows)]
static DRIVE_PATH_REGEX: once_cell::sync::Lazy<fancy_regex::Regex> =
once_cell::sync::Lazy::new(|| {
fancy_regex::Regex::new(r"^[a-zA-Z]:[/\\]?").expect("Internal error: regex creation")
});
// A best-effort "does this string look kinda like a path?" function to determine whether to auto-cd
fn looks_like_path(orig: &str) -> bool {

View File

@ -1,13 +1,15 @@
use log::trace;
use nu_ansi_term::Style;
use nu_color_config::get_shape_color;
use nu_color_config::{get_matching_brackets_style, get_shape_color};
use nu_parser::{flatten_block, parse, FlatShape};
use nu_protocol::ast::{Argument, Block, Expr, Expression, PipelineElement};
use nu_protocol::engine::{EngineState, StateWorkingSet};
use nu_protocol::Config;
use nu_protocol::{Config, Span};
use reedline::{Highlighter, StyledText};
use std::sync::Arc;
pub struct NuHighlighter {
pub engine_state: EngineState,
pub engine_state: Arc<EngineState>,
pub config: Config,
}
@ -15,10 +17,12 @@ impl Highlighter for NuHighlighter {
fn highlight(&self, line: &str, _cursor: usize) -> StyledText {
trace!("highlighting: {}", line);
let (shapes, global_span_offset) = {
let mut working_set = StateWorkingSet::new(&self.engine_state);
let mut working_set = StateWorkingSet::new(&self.engine_state);
let block = {
let (block, _) = parse(&mut working_set, None, line.as_bytes(), false, &[]);
block
};
let (shapes, global_span_offset) = {
let shapes = flatten_block(&working_set, &block);
(shapes, self.engine_state.next_span_start())
};
@ -26,6 +30,15 @@ impl Highlighter for NuHighlighter {
let mut output = StyledText::default();
let mut last_seen_span = global_span_offset;
let global_cursor_offset = _cursor + global_span_offset;
let matching_brackets_pos = find_matching_brackets(
line,
&working_set,
&block,
global_span_offset,
global_cursor_offset,
);
for shape in &shapes {
if shape.0.end <= last_seen_span
|| last_seen_span < global_span_offset
@ -44,166 +57,75 @@ impl Highlighter for NuHighlighter {
let next_token = line
[(shape.0.start - global_span_offset)..(shape.0.end - global_span_offset)]
.to_string();
macro_rules! add_colored_token_with_bracket_highlight {
($shape:expr, $span:expr, $text:expr) => {{
let spans = split_span_by_highlight_positions(
line,
&$span,
&matching_brackets_pos,
global_span_offset,
);
spans.iter().for_each(|(part, highlight)| {
let start = part.start - $span.start;
let end = part.end - $span.start;
let text = (&next_token[start..end]).to_string();
let mut style = get_shape_color($shape.to_string(), &self.config);
if *highlight {
style = get_matching_brackets_style(style, &self.config);
}
output.push((style, text));
});
}};
}
macro_rules! add_colored_token {
($shape:expr, $text:expr) => {
output.push((get_shape_color($shape.to_string(), &self.config), $text))
};
}
match shape.1 {
FlatShape::Garbage => output.push((
// nushell Garbage
get_shape_color(shape.1.to_string(), &self.config),
next_token,
)),
FlatShape::Nothing => output.push((
// nushell Nothing
get_shape_color(shape.1.to_string(), &self.config),
next_token,
)),
FlatShape::Binary => {
// nushell ?
output.push((
get_shape_color(shape.1.to_string(), &self.config),
next_token,
))
}
FlatShape::Bool => {
// nushell ?
output.push((
get_shape_color(shape.1.to_string(), &self.config),
next_token,
))
}
FlatShape::Int => {
// nushell Int
output.push((
get_shape_color(shape.1.to_string(), &self.config),
next_token,
))
}
FlatShape::Float => {
// nushell Decimal
output.push((
get_shape_color(shape.1.to_string(), &self.config),
next_token,
))
}
FlatShape::Range => output.push((
// nushell DotDot ?
get_shape_color(shape.1.to_string(), &self.config),
next_token,
)),
FlatShape::InternalCall => output.push((
// nushell InternalCommand
get_shape_color(shape.1.to_string(), &self.config),
next_token,
)),
FlatShape::External => {
// nushell ExternalCommand
output.push((
get_shape_color(shape.1.to_string(), &self.config),
next_token,
))
}
FlatShape::ExternalArg => {
// nushell ExternalWord
output.push((
get_shape_color(shape.1.to_string(), &self.config),
next_token,
))
}
FlatShape::Literal => {
// nushell ?
output.push((
get_shape_color(shape.1.to_string(), &self.config),
next_token,
))
}
FlatShape::Operator => output.push((
// nushell Operator
get_shape_color(shape.1.to_string(), &self.config),
next_token,
)),
FlatShape::Signature => output.push((
// nushell ?
get_shape_color(shape.1.to_string(), &self.config),
next_token,
)),
FlatShape::String => {
// nushell String
output.push((
get_shape_color(shape.1.to_string(), &self.config),
next_token,
))
}
FlatShape::StringInterpolation => {
// nushell ???
output.push((
get_shape_color(shape.1.to_string(), &self.config),
next_token,
))
}
FlatShape::DateTime => {
// nushell ???
output.push((
get_shape_color(shape.1.to_string(), &self.config),
next_token,
))
}
FlatShape::Garbage => add_colored_token!(shape.1, next_token),
FlatShape::Nothing => add_colored_token!(shape.1, next_token),
FlatShape::Binary => add_colored_token!(shape.1, next_token),
FlatShape::Bool => add_colored_token!(shape.1, next_token),
FlatShape::Int => add_colored_token!(shape.1, next_token),
FlatShape::Float => add_colored_token!(shape.1, next_token),
FlatShape::Range => add_colored_token!(shape.1, next_token),
FlatShape::InternalCall => add_colored_token!(shape.1, next_token),
FlatShape::External => add_colored_token!(shape.1, next_token),
FlatShape::ExternalArg => add_colored_token!(shape.1, next_token),
FlatShape::Literal => add_colored_token!(shape.1, next_token),
FlatShape::Operator => add_colored_token!(shape.1, next_token),
FlatShape::Signature => add_colored_token!(shape.1, next_token),
FlatShape::String => add_colored_token!(shape.1, next_token),
FlatShape::StringInterpolation => add_colored_token!(shape.1, next_token),
FlatShape::DateTime => add_colored_token!(shape.1, next_token),
FlatShape::List => {
// nushell ???
output.push((
get_shape_color(shape.1.to_string(), &self.config),
next_token,
))
add_colored_token_with_bracket_highlight!(shape.1, shape.0, next_token)
}
FlatShape::Table => {
// nushell ???
output.push((
get_shape_color(shape.1.to_string(), &self.config),
next_token,
))
add_colored_token_with_bracket_highlight!(shape.1, shape.0, next_token)
}
FlatShape::Record => {
// nushell ???
output.push((
get_shape_color(shape.1.to_string(), &self.config),
next_token,
))
add_colored_token_with_bracket_highlight!(shape.1, shape.0, next_token)
}
FlatShape::Block => {
// nushell ???
output.push((
get_shape_color(shape.1.to_string(), &self.config),
next_token,
))
add_colored_token_with_bracket_highlight!(shape.1, shape.0, next_token)
}
FlatShape::Filepath => output.push((
// nushell Path
get_shape_color(shape.1.to_string(), &self.config),
next_token,
)),
FlatShape::Directory => output.push((
// nushell Directory
get_shape_color(shape.1.to_string(), &self.config),
next_token,
)),
FlatShape::GlobPattern => output.push((
// nushell GlobPattern
get_shape_color(shape.1.to_string(), &self.config),
next_token,
)),
FlatShape::Variable => output.push((
// nushell Variable
get_shape_color(shape.1.to_string(), &self.config),
next_token,
)),
FlatShape::Flag => {
// nushell Flag
output.push((
get_shape_color(shape.1.to_string(), &self.config),
next_token,
))
}
FlatShape::Custom(..) => output.push((
get_shape_color(shape.1.to_string(), &self.config),
next_token,
)),
FlatShape::Filepath => add_colored_token!(shape.1, next_token),
FlatShape::Directory => add_colored_token!(shape.1, next_token),
FlatShape::GlobPattern => add_colored_token!(shape.1, next_token),
FlatShape::Variable => add_colored_token!(shape.1, next_token),
FlatShape::Flag => add_colored_token!(shape.1, next_token),
FlatShape::Pipe => add_colored_token!(shape.1, next_token),
FlatShape::And => add_colored_token!(shape.1, next_token),
FlatShape::Or => add_colored_token!(shape.1, next_token),
FlatShape::Redirection => add_colored_token!(shape.1, next_token),
FlatShape::Custom(..) => add_colored_token!(shape.1, next_token),
}
last_seen_span = shape.0.end;
}
@ -216,3 +138,301 @@ impl Highlighter for NuHighlighter {
output
}
}
fn split_span_by_highlight_positions(
line: &str,
span: &Span,
highlight_positions: &Vec<usize>,
global_span_offset: usize,
) -> Vec<(Span, bool)> {
let mut start = span.start;
let mut result: Vec<(Span, bool)> = Vec::new();
for pos in highlight_positions {
if start <= *pos && pos < &span.end {
if start < *pos {
result.push((Span::new(start, *pos), false));
}
let span_str = &line[pos - global_span_offset..span.end - global_span_offset];
let end = span_str
.chars()
.next()
.map(|c| pos + get_char_length(c))
.unwrap_or(pos + 1);
result.push((Span::new(*pos, end), true));
start = end;
}
}
if start < span.end {
result.push((Span::new(start, span.end), false));
}
result
}
fn find_matching_brackets(
line: &str,
working_set: &StateWorkingSet,
block: &Block,
global_span_offset: usize,
global_cursor_offset: usize,
) -> Vec<usize> {
const BRACKETS: &str = "{}[]()";
// calculate first bracket position
let global_end_offset = line.len() + global_span_offset;
let global_bracket_pos =
if global_cursor_offset == global_end_offset && global_end_offset > global_span_offset {
// cursor is at the end of a non-empty string -- find block end at the previous position
if let Some(last_char) = line.chars().last() {
global_cursor_offset - get_char_length(last_char)
} else {
global_cursor_offset
}
} else {
// cursor is in the middle of a string -- find block end at the current position
global_cursor_offset
};
// check that position contains bracket
let match_idx = global_bracket_pos - global_span_offset;
if match_idx >= line.len()
|| !BRACKETS.contains(get_char_at_index(line, match_idx).unwrap_or_default())
{
return Vec::new();
}
// find matching bracket by finding matching block end
let matching_block_end = find_matching_block_end_in_block(
line,
working_set,
block,
global_span_offset,
global_bracket_pos,
);
if let Some(pos) = matching_block_end {
let matching_idx = pos - global_span_offset;
if BRACKETS.contains(get_char_at_index(line, matching_idx).unwrap_or_default()) {
return if global_bracket_pos < pos {
vec![global_bracket_pos, pos]
} else {
vec![pos, global_bracket_pos]
};
}
}
Vec::new()
}
fn find_matching_block_end_in_block(
line: &str,
working_set: &StateWorkingSet,
block: &Block,
global_span_offset: usize,
global_cursor_offset: usize,
) -> Option<usize> {
for p in &block.pipelines {
for e in &p.elements {
match e {
PipelineElement::Expression(_, e)
| PipelineElement::Redirection(_, _, e)
| PipelineElement::And(_, e)
| PipelineElement::Or(_, e)
| PipelineElement::SeparateRedirection { out: (_, e), .. } => {
if e.span.contains(global_cursor_offset) {
if let Some(pos) = find_matching_block_end_in_expr(
line,
working_set,
e,
global_span_offset,
global_cursor_offset,
) {
return Some(pos);
}
}
}
}
}
}
None
}
fn find_matching_block_end_in_expr(
line: &str,
working_set: &StateWorkingSet,
expression: &Expression,
global_span_offset: usize,
global_cursor_offset: usize,
) -> Option<usize> {
macro_rules! find_in_expr_or_continue {
($inner_expr:ident) => {
if let Some(pos) = find_matching_block_end_in_expr(
line,
working_set,
$inner_expr,
global_span_offset,
global_cursor_offset,
) {
return Some(pos);
}
};
}
if expression.span.contains(global_cursor_offset) && expression.span.start >= global_span_offset
{
let expr_first = expression.span.start;
let span_str = &line
[expression.span.start - global_span_offset..expression.span.end - global_span_offset];
let expr_last = span_str
.chars()
.last()
.map(|c| expression.span.end - get_char_length(c))
.unwrap_or(expression.span.start);
return match &expression.expr {
Expr::Bool(_) => None,
Expr::Int(_) => None,
Expr::Float(_) => None,
Expr::Binary(_) => None,
Expr::Range(..) => None,
Expr::Var(_) => None,
Expr::VarDecl(_) => None,
Expr::ExternalCall(..) => None,
Expr::Operator(_) => None,
Expr::UnaryNot(_) => None,
Expr::Keyword(..) => None,
Expr::ValueWithUnit(..) => None,
Expr::DateTime(_) => 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::Nothing => None,
Expr::Garbage => None,
Expr::Table(hdr, rows) => {
if expr_last == global_cursor_offset {
// cursor is at table end
Some(expr_first)
} else if expr_first == global_cursor_offset {
// cursor is at table start
Some(expr_last)
} else {
// cursor is inside table
for inner_expr in hdr {
find_in_expr_or_continue!(inner_expr);
}
for row in rows {
for inner_expr in row {
find_in_expr_or_continue!(inner_expr);
}
}
None
}
}
Expr::Record(exprs) => {
if expr_last == global_cursor_offset {
// cursor is at record end
Some(expr_first)
} else if expr_first == global_cursor_offset {
// cursor is at record start
Some(expr_last)
} else {
// cursor is inside record
for (k, v) in exprs {
find_in_expr_or_continue!(k);
find_in_expr_or_continue!(v);
}
None
}
}
Expr::Call(call) => {
for arg in &call.arguments {
let opt_expr = match arg {
Argument::Named((_, _, opt_expr)) => opt_expr.as_ref(),
Argument::Positional(inner_expr) => Some(inner_expr),
Argument::Unknown(inner_expr) => Some(inner_expr),
};
if let Some(inner_expr) = opt_expr {
find_in_expr_or_continue!(inner_expr);
}
}
None
}
Expr::FullCellPath(b) => find_matching_block_end_in_expr(
line,
working_set,
&b.head,
global_span_offset,
global_cursor_offset,
),
Expr::BinaryOp(lhs, op, rhs) => {
find_in_expr_or_continue!(lhs);
find_in_expr_or_continue!(op);
find_in_expr_or_continue!(rhs);
None
}
Expr::Block(block_id)
| Expr::Closure(block_id)
| Expr::RowCondition(block_id)
| Expr::Subexpression(block_id) => {
if expr_last == global_cursor_offset {
// cursor is at block end
Some(expr_first)
} else if expr_first == global_cursor_offset {
// cursor is at block start
Some(expr_last)
} else {
// cursor is inside block
let nested_block = working_set.get_block(*block_id);
find_matching_block_end_in_block(
line,
working_set,
nested_block,
global_span_offset,
global_cursor_offset,
)
}
}
Expr::StringInterpolation(inner_expr) => {
for inner_expr in inner_expr {
find_in_expr_or_continue!(inner_expr);
}
None
}
Expr::List(inner_expr) => {
if expr_last == global_cursor_offset {
// cursor is at list end
Some(expr_first)
} else if expr_first == global_cursor_offset {
// cursor is at list start
Some(expr_last)
} else {
// cursor is inside list
for inner_expr in inner_expr {
find_in_expr_or_continue!(inner_expr);
}
None
}
}
};
}
None
}
fn get_char_at_index(s: &str, index: usize) -> Option<char> {
s[index..].chars().next()
}
fn get_char_length(c: char) -> usize {
c.to_string().len()
}

View File

@ -1,14 +1,15 @@
use log::trace;
use nu_engine::eval_block;
use crate::repl::eval_hook;
use nu_engine::{eval_block, eval_block_with_early_return};
use nu_parser::{escape_quote_string, lex, parse, unescape_unquote_string, Token, TokenContents};
use nu_protocol::engine::StateWorkingSet;
use nu_protocol::CliError;
use nu_protocol::{
engine::{EngineState, Stack},
PipelineData, ShellError, Span, Value,
print_if_stream, PipelineData, ShellError, Span, Value,
};
#[cfg(windows)]
use nu_utils::enable_vt_processing;
use nu_utils::utils::perf;
use std::path::{Path, PathBuf};
// This will collect environment variables from std::env and adds them to a stack.
@ -43,7 +44,7 @@ fn gather_env_vars(
report_error(
&working_set,
&ShellError::GenericError(
format!("Environment variable was not captured: {}", env_str),
format!("Environment variable was not captured: {env_str}"),
"".to_string(),
None,
Some(msg.into()),
@ -79,8 +80,7 @@ fn gather_env_vars(
"".to_string(),
None,
Some(format!(
"Retrieving current directory failed: {:?} not a valid utf-8 path",
init_cwd
"Retrieving current directory failed: {init_cwd:?} not a valid utf-8 path"
)),
Vec::new(),
),
@ -203,8 +203,9 @@ pub fn eval_source(
source: &[u8],
fname: &str,
input: PipelineData,
allow_return: bool,
) -> bool {
trace!("eval_source");
let start_time = std::time::Instant::now();
let (block, delta) = {
let mut working_set = StateWorkingSet::new(engine_state);
@ -230,9 +231,38 @@ pub fn eval_source(
return false;
}
match eval_block(engine_state, stack, &block, input, false, false) {
let b = if allow_return {
eval_block_with_early_return(engine_state, stack, &block, input, false, false)
} else {
eval_block(engine_state, stack, &block, input, false, false)
};
match b {
Ok(pipeline_data) => {
match pipeline_data.print(engine_state, stack, false, false) {
let config = engine_state.get_config();
let result;
if let PipelineData::ExternalStream {
stdout: stream,
stderr: stderr_stream,
exit_code,
..
} = pipeline_data
{
result = print_if_stream(stream, stderr_stream, false, exit_code);
} else if let Some(hook) = config.hooks.display_output.clone() {
match eval_hook(engine_state, stack, Some(pipeline_data), vec![], &hook) {
Err(err) => {
result = Err(err);
}
Ok(val) => {
result = val.print(engine_state, stack, false, false);
}
}
} else {
result = pipeline_data.print(engine_state, stack, true, false);
}
match result {
Err(err) => {
let working_set = StateWorkingSet::new(engine_state);
@ -261,6 +291,14 @@ pub fn eval_source(
return false;
}
}
perf(
&format!("eval_source {}", &fname),
start_time,
file!(),
line!(),
column!(),
engine_state.get_config().use_ansi_coloring,
);
true
}
@ -268,10 +306,7 @@ pub fn eval_source(
fn set_last_exit_code(stack: &mut Stack, exit_code: i64) {
stack.add_env_var(
"LAST_EXIT_CODE".to_string(),
Value::Int {
val: exit_code,
span: Span { start: 0, end: 0 },
},
Value::int(exit_code, Span::unknown()),
);
}
@ -297,27 +332,19 @@ pub fn report_error_new(
}
pub fn get_init_cwd() -> PathBuf {
match std::env::current_dir() {
Ok(cwd) => cwd,
Err(_) => match std::env::var("PWD") {
Ok(cwd) => PathBuf::from(cwd),
Err(_) => match nu_path::home_dir() {
Some(cwd) => cwd,
None => PathBuf::new(),
},
},
}
std::env::current_dir().unwrap_or_else(|_| {
std::env::var("PWD")
.map(Into::into)
.unwrap_or_else(|_| nu_path::home_dir().unwrap_or_default())
})
}
pub fn get_guaranteed_cwd(engine_state: &EngineState, stack: &Stack) -> PathBuf {
match nu_engine::env::current_dir(engine_state, stack) {
Ok(p) => p,
Err(e) => {
let working_set = StateWorkingSet::new(engine_state);
report_error(&working_set, &e);
get_init_cwd()
}
}
nu_engine::env::current_dir(engine_state, stack).unwrap_or_else(|e| {
let working_set = StateWorkingSet::new(engine_state);
report_error(&working_set, &e);
get_init_cwd()
})
}
#[cfg(test)]

View File

@ -1,9 +1,10 @@
use nu_parser::{parse, ParseError};
use nu_protocol::engine::{EngineState, StateWorkingSet};
use reedline::{ValidationResult, Validator};
use std::sync::Arc;
pub struct NuValidator {
pub engine_state: EngineState,
pub engine_state: Arc<EngineState>,
}
impl Validator for NuValidator {

View File

@ -5,7 +5,7 @@ use nu_parser::parse;
use nu_protocol::engine::StateWorkingSet;
use reedline::{Completer, Suggestion};
use rstest::{fixture, rstest};
use support::{file, folder, match_suggestions, new_engine};
use support::{completions_helpers::new_quote_engine, file, folder, match_suggestions, new_engine};
#[fixture]
fn completer() -> NuCompleter {
@ -34,6 +34,26 @@ fn completer_strings() -> NuCompleter {
NuCompleter::new(std::sync::Arc::new(engine), stack)
}
#[fixture]
fn extern_completer() -> NuCompleter {
// Create a new engine
let (dir, _, mut engine, mut stack) = new_engine();
// Add record value as example
let record = r#"
def animals [] { [ "cat", "dog", "eel" ] }
extern spam [
animal: string@animals
--foo (-f): string@animals
-b: string@animals
]
"#;
assert!(support::merge_input(record.as_bytes(), &mut engine, &mut stack, dir).is_ok());
// Instantiate a new completer
NuCompleter::new(std::sync::Arc::new(engine), stack)
}
#[test]
fn variables_dollar_sign_with_varialblecompletion() {
let (_, _, engine, stack) = new_engine();
@ -89,7 +109,7 @@ fn dotnu_completions() {
// Create a new engine
let (_, _, engine, stack) = new_engine();
// Instatiate a new completer
// Instantiate a new completer
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
// Test source completion
@ -149,11 +169,11 @@ fn file_completions() {
// Create a new engine
let (dir, dir_str, engine, stack) = new_engine();
// Instatiate a new completer
// Instantiate a new completer
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
// Test completions for the current folder
let target_dir = format!("cp {}", dir_str);
let target_dir = format!("cp {dir_str}");
let suggestions = completer.complete(&target_dir, target_dir.len());
// Create the expected values
@ -411,17 +431,36 @@ fn command_watch_with_filecompletion() {
match_suggestions(expected_paths, suggestions)
}
#[test]
fn file_completion_quoted() {
let (_, _, engine, stack) = new_quote_engine();
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
let target_dir = "open ";
let suggestions = completer.complete(target_dir, target_dir.len());
let expected_paths: Vec<String> = vec![
"`te st.txt`".to_string(),
"`te#st.txt`".to_string(),
"`te'st.txt`".to_string(),
"`te(st).txt`".to_string(),
];
match_suggestions(expected_paths, suggestions)
}
#[test]
fn flag_completions() {
// Create a new engine
let (_, _, engine, stack) = new_engine();
// Instatiate a new completer
// Instantiate a new completer
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
// Test completions for the 'ls' flags
let suggestions = completer.complete("ls -", 4);
assert_eq!(14, suggestions.len());
assert_eq!(16, suggestions.len());
let expected: Vec<String> = vec![
"--all".into(),
@ -430,6 +469,7 @@ fn flag_completions() {
"--full-paths".into(),
"--help".into(),
"--long".into(),
"--mime-type".into(),
"--short-names".into(),
"-D".into(),
"-a".into(),
@ -437,6 +477,7 @@ fn flag_completions() {
"-f".into(),
"-h".into(),
"-l".into(),
"-m".into(),
"-s".into(),
];
@ -449,11 +490,11 @@ fn folder_with_directorycompletions() {
// Create a new engine
let (dir, dir_str, engine, stack) = new_engine();
// Instatiate a new completer
// Instantiate a new completer
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
// Test completions for the current folder
let target_dir = format!("cd {}", dir_str);
let target_dir = format!("cd {dir_str}");
let suggestions = completer.complete(&target_dir, target_dir.len());
// Create the expected values
@ -477,7 +518,7 @@ fn variables_completions() {
let record = "let actor = { name: 'Tom Hardy', age: 44 }";
assert!(support::merge_input(record.as_bytes(), &mut engine, &mut stack, dir).is_ok());
// Instatiate a new completer
// Instantiate a new completer
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
// Test completions for $nu
@ -533,9 +574,12 @@ fn variables_completions() {
// Test completions for $env
let suggestions = completer.complete("$env.", 5);
assert_eq!(2, suggestions.len());
assert_eq!(3, suggestions.len());
let expected: Vec<String> = vec!["PWD".into(), "TEST".into()];
#[cfg(windows)]
let expected: Vec<String> = vec!["PWD".into(), "Path".into(), "TEST".into()];
#[cfg(not(windows))]
let expected: Vec<String> = vec!["PATH".into(), "PWD".into(), "TEST".into()];
// Match results
match_suggestions(expected, suggestions);
@ -634,7 +678,7 @@ fn run_external_completion(block: &str, input: &str) -> Vec<Suggestion> {
config.external_completer = Some(latest_block_id);
engine_state.set_config(&config);
// Instatiate a new completer
// Instantiate a new completer
let mut completer = NuCompleter::new(std::sync::Arc::new(engine_state), stack);
completer.complete(input, input.len())
@ -732,3 +776,92 @@ fn filecompletions_triggers_after_cursor() {
match_suggestions(expected_paths, suggestions);
}
#[rstest]
fn extern_custom_completion_positional(mut extern_completer: NuCompleter) {
let suggestions = extern_completer.complete("spam ", 5);
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
match_suggestions(expected, suggestions);
}
#[rstest]
fn extern_custom_completion_long_flag_1(mut extern_completer: NuCompleter) {
let suggestions = extern_completer.complete("spam --foo=", 11);
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
match_suggestions(expected, suggestions);
}
#[rstest]
fn extern_custom_completion_long_flag_2(mut extern_completer: NuCompleter) {
let suggestions = extern_completer.complete("spam --foo ", 11);
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
match_suggestions(expected, suggestions);
}
#[rstest]
fn extern_custom_completion_long_flag_short(mut extern_completer: NuCompleter) {
let suggestions = extern_completer.complete("spam -f ", 8);
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
match_suggestions(expected, suggestions);
}
#[rstest]
fn extern_custom_completion_short_flag(mut extern_completer: NuCompleter) {
let suggestions = extern_completer.complete("spam -b ", 8);
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
match_suggestions(expected, suggestions);
}
#[rstest]
fn extern_complete_flags(mut extern_completer: NuCompleter) {
let suggestions = extern_completer.complete("spam -", 6);
let expected: Vec<String> = vec!["--foo".into(), "-b".into(), "-f".into()];
match_suggestions(expected, suggestions);
}
#[ignore = "was reverted, still needs fixing"]
#[rstest]
fn alias_offset_bug_7648() {
let (dir, _, mut engine, mut stack) = new_engine();
// Create an alias
let alias = r#"alias ea = ^$env.EDITOR /tmp/test.s"#;
assert!(support::merge_input(alias.as_bytes(), &mut engine, &mut stack, dir).is_ok());
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
// Issue #7648
// Nushell crashes when an alias name is shorter than the alias command
// and the alias command is a external command
// This happens because of offset is not correct.
// This crashes before PR #7779
let _suggestions = completer.complete("e", 1);
}
#[ignore = "was reverted, still needs fixing"]
#[rstest]
fn alias_offset_bug_7754() {
let (dir, _, mut engine, mut stack) = new_engine();
// Create an alias
let alias = r#"alias ll = ls -l"#;
assert!(support::merge_input(alias.as_bytes(), &mut engine, &mut stack, dir).is_ok());
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
// Issue #7754
// Nushell crashes when an alias name is shorter than the alias command
// and the alias command contains pipes.
// This crashes before PR #7756
let _suggestions = completer.complete("ll -a | c", 9);
}
#[test]
fn get_path_env_var_8003() {
// Create a new engine
let (_, _, engine, _) = new_engine();
// Get the path env var in a platform agnostic way
let the_path = engine.get_path_env_var();
// Make sure it's not empty
assert!(the_path.is_some());
}

View File

@ -33,20 +33,69 @@ pub fn new_engine() -> (PathBuf, String, EngineState, Stack) {
"PWD".to_string(),
Value::String {
val: dir_str.clone(),
span: nu_protocol::Span {
start: 0,
end: dir_str.len(),
},
span: nu_protocol::Span::new(0, dir_str.len()),
},
);
stack.add_env_var(
"TEST".to_string(),
Value::String {
val: "NUSHELL".to_string(),
span: nu_protocol::Span {
start: 0,
end: dir_str.len(),
},
span: nu_protocol::Span::new(0, dir_str.len()),
},
);
#[cfg(windows)]
stack.add_env_var(
"Path".to_string(),
Value::String {
val: "c:\\some\\path;c:\\some\\other\\path".to_string(),
span: nu_protocol::Span::new(0, dir_str.len()),
},
);
#[cfg(not(windows))]
stack.add_env_var(
"PATH".to_string(),
Value::String {
val: "/some/path:/some/other/path".to_string(),
span: nu_protocol::Span::new(0, dir_str.len()),
},
);
// Merge environment into the permanent state
let merge_result = engine_state.merge_env(&mut stack, &dir);
assert!(merge_result.is_ok());
(dir, dir_str, engine_state, stack)
}
pub fn new_quote_engine() -> (PathBuf, String, EngineState, Stack) {
// Target folder inside assets
let dir = fs::fixtures().join("quoted_completions");
let mut dir_str = dir
.clone()
.into_os_string()
.into_string()
.unwrap_or_default();
dir_str.push(SEP);
// Create a new engine with default context
let mut engine_state = create_default_context();
// New stack
let mut stack = Stack::new();
// Add pwd as env var
stack.add_env_var(
"PWD".to_string(),
Value::String {
val: dir_str.clone(),
span: nu_protocol::Span::new(0, dir_str.len()),
},
);
stack.add_env_var(
"TEST".to_string(),
Value::String {
val: "NUSHELL".to_string(),
span: nu_protocol::Span::new(0, dir_str.len()),
},
);
@ -112,7 +161,7 @@ pub fn merge_input(
&block,
PipelineData::Value(
Value::Nothing {
span: Span { start: 0, end: 0 },
span: Span::unknown(),
},
None
),

View File

@ -5,11 +5,21 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-color-confi
edition = "2021"
license = "MIT"
name = "nu-color-config"
version = "0.70.0"
version = "0.76.0"
[lib]
bench = false
[dependencies]
nu-protocol = { path = "../nu-protocol", version = "0.70.0" }
nu-ansi-term = "0.46.0"
nu-json = { path = "../nu-json", version = "0.70.0" }
nu-table = { path = "../nu-table", version = "0.70.0" }
serde = { version="1.0.123", features=["derive"] }
# used only for text_style Alignments
tabled = { version = "0.10.0", features = ["color"], default-features = false }
nu-protocol = { path = "../nu-protocol", version = "0.76.0" }
nu-ansi-term = "0.46.0"
nu-utils = { path = "../nu-utils", version = "0.76.0" }
nu-engine = { path = "../nu-engine", version = "0.76.0" }
nu-json = { path="../nu-json", version = "0.76.0" }
[dev-dependencies]
nu-test-support = { path="../nu-test-support", version = "0.76.0" }

View File

@ -1,418 +1,89 @@
use crate::nu_style::{color_from_hex, color_string_to_nustyle};
use nu_ansi_term::{Color, Style};
use nu_protocol::Config;
use nu_table::{Alignment, TextStyle};
use crate::{
nu_style::{color_from_hex, lookup_style},
parse_nustyle, NuStyle,
};
use nu_ansi_term::Style;
use nu_protocol::Value;
use std::collections::HashMap;
pub fn lookup_ansi_color_style(s: &str) -> Style {
if s.starts_with('#') {
match color_from_hex(s) {
Ok(c) => match c {
Some(c) => c.normal(),
None => Style::default(),
},
Err(_) => Style::default(),
}
color_from_hex(s)
.ok()
.and_then(|c| c.map(|c| c.normal()))
.unwrap_or_default()
} else if s.starts_with('{') {
color_string_to_nustyle(s.to_string())
} else {
match s {
"g" | "green" => Color::Green.normal(),
"gb" | "green_bold" => Color::Green.bold(),
"gu" | "green_underline" => Color::Green.underline(),
"gi" | "green_italic" => Color::Green.italic(),
"gd" | "green_dimmed" => Color::Green.dimmed(),
"gr" | "green_reverse" => Color::Green.reverse(),
"gbl" | "green_blink" => Color::Green.blink(),
"gst" | "green_strike" => Color::Green.strikethrough(),
"lg" | "light_green" => Color::LightGreen.normal(),
"lgb" | "light_green_bold" => Color::LightGreen.bold(),
"lgu" | "light_green_underline" => Color::LightGreen.underline(),
"lgi" | "light_green_italic" => Color::LightGreen.italic(),
"lgd" | "light_green_dimmed" => Color::LightGreen.dimmed(),
"lgr" | "light_green_reverse" => Color::LightGreen.reverse(),
"lgbl" | "light_green_blink" => Color::LightGreen.blink(),
"lgst" | "light_green_strike" => Color::LightGreen.strikethrough(),
"r" | "red" => Color::Red.normal(),
"rb" | "red_bold" => Color::Red.bold(),
"ru" | "red_underline" => Color::Red.underline(),
"ri" | "red_italic" => Color::Red.italic(),
"rd" | "red_dimmed" => Color::Red.dimmed(),
"rr" | "red_reverse" => Color::Red.reverse(),
"rbl" | "red_blink" => Color::Red.blink(),
"rst" | "red_strike" => Color::Red.strikethrough(),
"lr" | "light_red" => Color::LightRed.normal(),
"lrb" | "light_red_bold" => Color::LightRed.bold(),
"lru" | "light_red_underline" => Color::LightRed.underline(),
"lri" | "light_red_italic" => Color::LightRed.italic(),
"lrd" | "light_red_dimmed" => Color::LightRed.dimmed(),
"lrr" | "light_red_reverse" => Color::LightRed.reverse(),
"lrbl" | "light_red_blink" => Color::LightRed.blink(),
"lrst" | "light_red_strike" => Color::LightRed.strikethrough(),
"u" | "blue" => Color::Blue.normal(),
"ub" | "blue_bold" => Color::Blue.bold(),
"uu" | "blue_underline" => Color::Blue.underline(),
"ui" | "blue_italic" => Color::Blue.italic(),
"ud" | "blue_dimmed" => Color::Blue.dimmed(),
"ur" | "blue_reverse" => Color::Blue.reverse(),
"ubl" | "blue_blink" => Color::Blue.blink(),
"ust" | "blue_strike" => Color::Blue.strikethrough(),
"lu" | "light_blue" => Color::LightBlue.normal(),
"lub" | "light_blue_bold" => Color::LightBlue.bold(),
"luu" | "light_blue_underline" => Color::LightBlue.underline(),
"lui" | "light_blue_italic" => Color::LightBlue.italic(),
"lud" | "light_blue_dimmed" => Color::LightBlue.dimmed(),
"lur" | "light_blue_reverse" => Color::LightBlue.reverse(),
"lubl" | "light_blue_blink" => Color::LightBlue.blink(),
"lust" | "light_blue_strike" => Color::LightBlue.strikethrough(),
"b" | "black" => Color::Black.normal(),
"bb" | "black_bold" => Color::Black.bold(),
"bu" | "black_underline" => Color::Black.underline(),
"bi" | "black_italic" => Color::Black.italic(),
"bd" | "black_dimmed" => Color::Black.dimmed(),
"br" | "black_reverse" => Color::Black.reverse(),
"bbl" | "black_blink" => Color::Black.blink(),
"bst" | "black_strike" => Color::Black.strikethrough(),
"ligr" | "light_gray" => Color::LightGray.normal(),
"ligrb" | "light_gray_bold" => Color::LightGray.bold(),
"ligru" | "light_gray_underline" => Color::LightGray.underline(),
"ligri" | "light_gray_italic" => Color::LightGray.italic(),
"ligrd" | "light_gray_dimmed" => Color::LightGray.dimmed(),
"ligrr" | "light_gray_reverse" => Color::LightGray.reverse(),
"ligrbl" | "light_gray_blink" => Color::LightGray.blink(),
"ligrst" | "light_gray_strike" => Color::LightGray.strikethrough(),
"y" | "yellow" => Color::Yellow.normal(),
"yb" | "yellow_bold" => Color::Yellow.bold(),
"yu" | "yellow_underline" => Color::Yellow.underline(),
"yi" | "yellow_italic" => Color::Yellow.italic(),
"yd" | "yellow_dimmed" => Color::Yellow.dimmed(),
"yr" | "yellow_reverse" => Color::Yellow.reverse(),
"ybl" | "yellow_blink" => Color::Yellow.blink(),
"yst" | "yellow_strike" => Color::Yellow.strikethrough(),
"ly" | "light_yellow" => Color::LightYellow.normal(),
"lyb" | "light_yellow_bold" => Color::LightYellow.bold(),
"lyu" | "light_yellow_underline" => Color::LightYellow.underline(),
"lyi" | "light_yellow_italic" => Color::LightYellow.italic(),
"lyd" | "light_yellow_dimmed" => Color::LightYellow.dimmed(),
"lyr" | "light_yellow_reverse" => Color::LightYellow.reverse(),
"lybl" | "light_yellow_blink" => Color::LightYellow.blink(),
"lyst" | "light_yellow_strike" => Color::LightYellow.strikethrough(),
"p" | "purple" => Color::Purple.normal(),
"pb" | "purple_bold" => Color::Purple.bold(),
"pu" | "purple_underline" => Color::Purple.underline(),
"pi" | "purple_italic" => Color::Purple.italic(),
"pd" | "purple_dimmed" => Color::Purple.dimmed(),
"pr" | "purple_reverse" => Color::Purple.reverse(),
"pbl" | "purple_blink" => Color::Purple.blink(),
"pst" | "purple_strike" => Color::Purple.strikethrough(),
"lp" | "light_purple" => Color::LightPurple.normal(),
"lpb" | "light_purple_bold" => Color::LightPurple.bold(),
"lpu" | "light_purple_underline" => Color::LightPurple.underline(),
"lpi" | "light_purple_italic" => Color::LightPurple.italic(),
"lpd" | "light_purple_dimmed" => Color::LightPurple.dimmed(),
"lpr" | "light_purple_reverse" => Color::LightPurple.reverse(),
"lpbl" | "light_purple_blink" => Color::LightPurple.blink(),
"lpst" | "light_purple_strike" => Color::LightPurple.strikethrough(),
"c" | "cyan" => Color::Cyan.normal(),
"cb" | "cyan_bold" => Color::Cyan.bold(),
"cu" | "cyan_underline" => Color::Cyan.underline(),
"ci" | "cyan_italic" => Color::Cyan.italic(),
"cd" | "cyan_dimmed" => Color::Cyan.dimmed(),
"cr" | "cyan_reverse" => Color::Cyan.reverse(),
"cbl" | "cyan_blink" => Color::Cyan.blink(),
"cst" | "cyan_strike" => Color::Cyan.strikethrough(),
"lc" | "light_cyan" => Color::LightCyan.normal(),
"lcb" | "light_cyan_bold" => Color::LightCyan.bold(),
"lcu" | "light_cyan_underline" => Color::LightCyan.underline(),
"lci" | "light_cyan_italic" => Color::LightCyan.italic(),
"lcd" | "light_cyan_dimmed" => Color::LightCyan.dimmed(),
"lcr" | "light_cyan_reverse" => Color::LightCyan.reverse(),
"lcbl" | "light_cyan_blink" => Color::LightCyan.blink(),
"lcst" | "light_cyan_strike" => Color::LightCyan.strikethrough(),
"w" | "white" => Color::White.normal(),
"wb" | "white_bold" => Color::White.bold(),
"wu" | "white_underline" => Color::White.underline(),
"wi" | "white_italic" => Color::White.italic(),
"wd" | "white_dimmed" => Color::White.dimmed(),
"wr" | "white_reverse" => Color::White.reverse(),
"wbl" | "white_blink" => Color::White.blink(),
"wst" | "white_strike" => Color::White.strikethrough(),
"dgr" | "dark_gray" => Color::DarkGray.normal(),
"dgrb" | "dark_gray_bold" => Color::DarkGray.bold(),
"dgru" | "dark_gray_underline" => Color::DarkGray.underline(),
"dgri" | "dark_gray_italic" => Color::DarkGray.italic(),
"dgrd" | "dark_gray_dimmed" => Color::DarkGray.dimmed(),
"dgrr" | "dark_gray_reverse" => Color::DarkGray.reverse(),
"dgrbl" | "dark_gray_blink" => Color::DarkGray.blink(),
"dgrst" | "dark_gray_strike" => Color::DarkGray.strikethrough(),
"def" | "default" => Color::Default.normal(),
"defb" | "default_bold" => Color::Default.bold(),
"defu" | "default_underline" => Color::Default.underline(),
"defi" | "default_italic" => Color::Default.italic(),
"defd" | "default_dimmed" => Color::Default.dimmed(),
"defr" | "default_reverse" => Color::Default.reverse(),
_ => Color::White.normal(),
}
lookup_style(s)
}
}
fn update_hashmap(key: &str, val: &str, hm: &mut HashMap<String, Style>) {
// eprintln!("key: {}, val: {}", &key, &val);
let color = lookup_ansi_color_style(val);
if let Some(v) = hm.get_mut(key) {
*v = color;
} else {
hm.insert(key.to_string(), color);
}
}
pub fn get_color_config(config: &Config) -> HashMap<String, Style> {
let config = config;
// create the hashmap
pub fn get_color_map(colors: &HashMap<String, Value>) -> HashMap<String, Style> {
let mut hm: HashMap<String, Style> = HashMap::new();
// set some defaults
// hm.insert("primitive_line".to_string(), Color::White.normal());
// hm.insert("primitive_pattern".to_string(), Color::White.normal());
// hm.insert("primitive_path".to_string(), Color::White.normal());
hm.insert("separator".to_string(), Color::White.normal());
hm.insert(
"leading_trailing_space_bg".to_string(),
Style::default().on(Color::Rgb(128, 128, 128)),
);
hm.insert("header".to_string(), Color::Green.bold());
hm.insert("empty".to_string(), Color::Blue.normal());
hm.insert("bool".to_string(), Color::White.normal());
hm.insert("int".to_string(), Color::White.normal());
hm.insert("filesize".to_string(), Color::White.normal());
hm.insert("duration".to_string(), Color::White.normal());
hm.insert("date".to_string(), Color::White.normal());
hm.insert("range".to_string(), Color::White.normal());
hm.insert("float".to_string(), Color::White.normal());
hm.insert("string".to_string(), Color::White.normal());
hm.insert("nothing".to_string(), Color::White.normal());
hm.insert("binary".to_string(), Color::White.normal());
hm.insert("cellpath".to_string(), Color::White.normal());
hm.insert("row_index".to_string(), Color::Green.bold());
hm.insert("record".to_string(), Color::White.normal());
hm.insert("list".to_string(), Color::White.normal());
hm.insert("block".to_string(), Color::White.normal());
hm.insert("hints".to_string(), Color::DarkGray.normal());
for (key, value) in &config.color_config {
let value = value
.as_string()
.expect("the only values for config color must be strings");
update_hashmap(key, &value, &mut hm);
// eprintln!(
// "config: {}:{}\t\t\thashmap: {}:{:?}",
// &key, &value, &key, &hm[key]
// );
for (key, value) in colors {
parse_map_entry(&mut hm, key, value);
}
hm
}
// This function will assign a text style to a primitive, or really any string that's
// in the hashmap. The hashmap actually contains the style to be applied.
pub fn style_primitive(primitive: &str, color_hm: &HashMap<String, Style>) -> TextStyle {
match primitive {
"bool" => {
let style = color_hm.get(primitive);
match style {
Some(s) => TextStyle::with_style(Alignment::Left, *s),
None => TextStyle::basic_left(),
}
}
"int" => {
let style = color_hm.get(primitive);
match style {
Some(s) => TextStyle::with_style(Alignment::Right, *s),
None => TextStyle::basic_right(),
}
}
"filesize" => {
let style = color_hm.get(primitive);
match style {
Some(s) => TextStyle::with_style(Alignment::Right, *s),
None => TextStyle::basic_right(),
}
}
"duration" => {
let style = color_hm.get(primitive);
match style {
Some(s) => TextStyle::with_style(Alignment::Left, *s),
None => TextStyle::basic_left(),
}
}
"date" => {
let style = color_hm.get(primitive);
match style {
Some(s) => TextStyle::with_style(Alignment::Left, *s),
None => TextStyle::basic_left(),
}
}
"range" => {
let style = color_hm.get(primitive);
match style {
Some(s) => TextStyle::with_style(Alignment::Left, *s),
None => TextStyle::basic_left(),
}
}
"float" => {
let style = color_hm.get(primitive);
match style {
Some(s) => TextStyle::with_style(Alignment::Right, *s),
None => TextStyle::basic_right(),
}
}
"string" => {
let style = color_hm.get(primitive);
match style {
Some(s) => TextStyle::with_style(Alignment::Left, *s),
None => TextStyle::basic_left(),
}
}
"nothing" => {
let style = color_hm.get(primitive);
match style {
Some(s) => TextStyle::with_style(Alignment::Left, *s),
None => TextStyle::basic_left(),
}
}
// not sure what to do with error
// "error" => {}
"binary" => {
let style = color_hm.get(primitive);
match style {
Some(s) => TextStyle::with_style(Alignment::Left, *s),
None => TextStyle::basic_left(),
}
}
"cellpath" => {
let style = color_hm.get(primitive);
match style {
Some(s) => TextStyle::with_style(Alignment::Left, *s),
None => TextStyle::basic_left(),
}
}
"row_index" => {
let style = color_hm.get(primitive);
match style {
Some(s) => TextStyle::with_style(Alignment::Right, *s),
None => TextStyle::new()
.alignment(Alignment::Right)
.fg(Color::Green)
.bold(Some(true)),
}
}
"record" | "list" | "block" => {
let style = color_hm.get(primitive);
match style {
Some(s) => TextStyle::with_style(Alignment::Left, *s),
None => TextStyle::basic_left(),
}
}
// types in nushell but not in engine-q
// "Line" => {
// let style = color_hm.get("Primitive::Line");
// match style {
// Some(s) => TextStyle::with_style(Alignment::Left, *s),
// None => TextStyle::basic_left(),
// }
// }
// "GlobPattern" => {
// let style = color_hm.get("Primitive::GlobPattern");
// match style {
// Some(s) => TextStyle::with_style(Alignment::Left, *s),
// None => TextStyle::basic_left(),
// }
// }
// "FilePath" => {
// let style = color_hm.get("Primitive::FilePath");
// match style {
// Some(s) => TextStyle::with_style(Alignment::Left, *s),
// None => TextStyle::basic_left(),
// }
// }
// "BeginningOfStream" => {
// let style = color_hm.get("Primitive::BeginningOfStream");
// match style {
// Some(s) => TextStyle::with_style(Alignment::Left, *s),
// None => TextStyle::basic_left(),
// }
// }
// "EndOfStream" => {
// let style = color_hm.get("Primitive::EndOfStream");
// match style {
// Some(s) => TextStyle::with_style(Alignment::Left, *s),
// None => TextStyle::basic_left(),
// }
// }
_ => TextStyle::basic_left(),
fn parse_map_entry(hm: &mut HashMap<String, Style>, key: &str, value: &Value) {
let value = match value {
Value::String { val, .. } => Some(lookup_ansi_color_style(val)),
Value::Record { cols, vals, .. } => get_style_from_value(cols, vals).map(parse_nustyle),
_ => None,
};
if let Some(value) = value {
hm.entry(key.to_owned()).or_insert(value);
}
}
#[test]
fn test_hm() {
use nu_ansi_term::{Color, Style};
fn get_style_from_value(cols: &[String], vals: &[Value]) -> Option<NuStyle> {
let mut was_set = false;
let mut style = NuStyle::from(Style::default());
for (col, val) in cols.iter().zip(vals) {
match col.as_str() {
"bg" => {
if let Value::String { val, .. } = val {
style.bg = Some(val.clone());
was_set = true;
}
}
"fg" => {
if let Value::String { val, .. } = val {
style.fg = Some(val.clone());
was_set = true;
}
}
"attr" => {
if let Value::String { val, .. } = val {
style.attr = Some(val.clone());
was_set = true;
}
}
_ => (),
}
}
let mut hm: HashMap<String, Style> = HashMap::new();
hm.insert("primitive_int".to_string(), Color::White.normal());
hm.insert("primitive_decimal".to_string(), Color::White.normal());
hm.insert("primitive_filesize".to_string(), Color::White.normal());
hm.insert("primitive_string".to_string(), Color::White.normal());
hm.insert("primitive_line".to_string(), Color::White.normal());
hm.insert("primitive_columnpath".to_string(), Color::White.normal());
hm.insert("primitive_pattern".to_string(), Color::White.normal());
hm.insert("primitive_boolean".to_string(), Color::White.normal());
hm.insert("primitive_date".to_string(), Color::White.normal());
hm.insert("primitive_duration".to_string(), Color::White.normal());
hm.insert("primitive_range".to_string(), Color::White.normal());
hm.insert("primitive_path".to_string(), Color::White.normal());
hm.insert("primitive_binary".to_string(), Color::White.normal());
hm.insert("separator".to_string(), Color::White.normal());
hm.insert("header_align".to_string(), Color::Green.bold());
hm.insert("header".to_string(), Color::Green.bold());
hm.insert("header_style".to_string(), Style::default());
hm.insert("row_index".to_string(), Color::Green.bold());
hm.insert(
"leading_trailing_space_bg".to_string(),
Style::default().on(Color::Rgb(128, 128, 128)),
);
update_hashmap("primitive_int", "green", &mut hm);
assert_eq!(hm["primitive_int"], Color::Green.normal());
if was_set {
Some(style)
} else {
None
}
}
fn color_string_to_nustyle(color_string: String) -> Style {
// eprintln!("color_string: {}", &color_string);
if color_string.is_empty() {
return Style::default();
}
let nu_style = match nu_json::from_str::<NuStyle>(&color_string) {
Ok(s) => s,
Err(_) => return Style::default(),
};
parse_nustyle(nu_style)
}

View File

@ -1,7 +1,13 @@
mod color_config;
mod matching_brackets_style;
mod nu_style;
mod shape_color;
mod style_computer;
mod text_style;
pub use color_config::*;
pub use matching_brackets_style::*;
pub use nu_style::*;
pub use shape_color::*;
pub use style_computer::*;
pub use text_style::*;

View File

@ -0,0 +1,30 @@
use crate::color_config::lookup_ansi_color_style;
use nu_ansi_term::Style;
use nu_protocol::Config;
pub fn get_matching_brackets_style(default_style: Style, conf: &Config) -> Style {
const MATCHING_BRACKETS_CONFIG_KEY: &str = "shape_matching_brackets";
match conf.color_config.get(MATCHING_BRACKETS_CONFIG_KEY) {
Some(int_color) => match int_color.as_string() {
Ok(int_color) => merge_styles(default_style, lookup_ansi_color_style(&int_color)),
Err(_) => default_style,
},
None => default_style,
}
}
fn merge_styles(base: Style, extra: Style) -> Style {
Style {
foreground: extra.foreground.or(base.foreground),
background: extra.background.or(base.background),
is_bold: extra.is_bold || base.is_bold,
is_dimmed: extra.is_dimmed || base.is_dimmed,
is_italic: extra.is_italic || base.is_italic,
is_underline: extra.is_underline || base.is_underline,
is_blink: extra.is_blink || base.is_blink,
is_reverse: extra.is_reverse || base.is_reverse,
is_hidden: extra.is_hidden || base.is_hidden,
is_strikethrough: extra.is_strikethrough || base.is_strikethrough,
}
}

View File

@ -1,88 +1,113 @@
use nu_ansi_term::{Color, Style};
use serde::Deserialize;
use nu_protocol::Value;
use serde::{Deserialize, Serialize};
#[derive(Deserialize, PartialEq, Eq, Debug)]
#[derive(Deserialize, Serialize, PartialEq, Eq, Debug)]
pub struct NuStyle {
pub fg: Option<String>,
pub bg: Option<String>,
pub attr: Option<String>,
}
pub fn parse_nustyle(nu_style: NuStyle) -> Style {
// get the nu_ansi_term::Color foreground color
let fg_color = match nu_style.fg {
Some(fg) => color_from_hex(&fg).unwrap_or_default(),
_ => None,
};
// get the nu_ansi_term::Color background color
let bg_color = match nu_style.bg {
Some(bg) => color_from_hex(&bg).unwrap_or_default(),
_ => None,
};
// get the attributes
let color_attr = match nu_style.attr {
Some(attr) => attr,
_ => "".to_string(),
};
// setup the attributes available in nu_ansi_term::Style
let mut bold = false;
let mut dimmed = false;
let mut italic = false;
let mut underline = false;
let mut blink = false;
let mut reverse = false;
let mut hidden = false;
let mut strikethrough = false;
// since we can combine styles like bold-italic, iterate through the chars
// and set the bools for later use in the nu_ansi_term::Style application
for ch in color_attr.to_lowercase().chars() {
match ch {
'l' => blink = true,
'b' => bold = true,
'd' => dimmed = true,
'h' => hidden = true,
'i' => italic = true,
'r' => reverse = true,
's' => strikethrough = true,
'u' => underline = true,
'n' => (),
_ => (),
impl From<Style> for NuStyle {
fn from(s: Style) -> Self {
Self {
bg: s.background.and_then(color_to_string),
fg: s.foreground.and_then(color_to_string),
attr: style_get_attr(s),
}
}
// here's where we build the nu_ansi_term::Style
Style {
foreground: fg_color,
background: bg_color,
is_blink: blink,
is_bold: bold,
is_dimmed: dimmed,
is_hidden: hidden,
is_italic: italic,
is_reverse: reverse,
is_strikethrough: strikethrough,
is_underline: underline,
}
}
pub fn color_string_to_nustyle(color_string: String) -> Style {
// eprintln!("color_string: {}", &color_string);
if color_string.chars().count() < 1 {
Style::default()
} else {
let nu_style = match nu_json::from_str::<NuStyle>(&color_string) {
Ok(s) => s,
Err(_) => NuStyle {
fg: None,
bg: None,
attr: None,
},
fn style_get_attr(s: Style) -> Option<String> {
macro_rules! check {
($attrs:expr, $b:expr, $c:expr) => {
if $b {
$attrs.push($c);
}
};
parse_nustyle(nu_style)
}
let mut attrs = String::new();
check!(attrs, s.is_blink, 'l');
check!(attrs, s.is_bold, 'b');
check!(attrs, s.is_dimmed, 'd');
check!(attrs, s.is_reverse, 'r');
check!(attrs, s.is_strikethrough, 's');
check!(attrs, s.is_underline, 'u');
if attrs.is_empty() {
None
} else {
Some(attrs)
}
}
fn color_to_string(color: Color) -> Option<String> {
match color {
Color::Black => Some(String::from("black")),
Color::DarkGray => Some(String::from("dark_gray")),
Color::Red => Some(String::from("red")),
Color::LightRed => Some(String::from("light_red")),
Color::Green => Some(String::from("green")),
Color::LightGreen => Some(String::from("light_green")),
Color::Yellow => Some(String::from("yellow")),
Color::LightYellow => Some(String::from("light_yellow")),
Color::Blue => Some(String::from("blue")),
Color::LightBlue => Some(String::from("light_blue")),
Color::Purple => Some(String::from("purple")),
Color::LightPurple => Some(String::from("light_purple")),
Color::Magenta => Some(String::from("magenta")),
Color::LightMagenta => Some(String::from("light_magenta")),
Color::Cyan => Some(String::from("cyan")),
Color::LightCyan => Some(String::from("light_cyan")),
Color::White => Some(String::from("white")),
Color::LightGray => Some(String::from("light_gray")),
Color::Default => Some(String::from("default")),
Color::Rgb(r, g, b) => Some(format!("#{r:X}{g:X}{b:X}")),
Color::Fixed(_) => None,
}
}
pub fn parse_nustyle(nu_style: NuStyle) -> Style {
let mut style = Style {
foreground: nu_style.fg.and_then(|fg| lookup_color_str(&fg)),
background: nu_style.bg.and_then(|bg| lookup_color_str(&bg)),
..Default::default()
};
if let Some(attrs) = nu_style.attr {
fill_modifiers(&attrs, &mut style)
}
style
}
// Converts the color_config records, { fg, bg, attr }, into a Style.
pub fn color_record_to_nustyle(value: &Value) -> Style {
let mut fg = None;
let mut bg = None;
let mut attr = None;
let v = value.as_record();
if let Ok((cols, inner_vals)) = v {
for (k, v) in cols.iter().zip(inner_vals) {
// Because config already type-checked the color_config records, this doesn't bother giving errors
// if there are unrecognised keys or bad values.
if let Ok(v) = v.as_string() {
match k.as_str() {
"fg" => fg = Some(v),
"bg" => bg = Some(v),
"attr" => attr = Some(v),
_ => (),
}
}
}
}
parse_nustyle(NuStyle { fg, bg, attr })
}
pub fn color_from_hex(
@ -101,3 +126,471 @@ pub fn color_from_hex(
)))
}
}
pub fn lookup_style(s: &str) -> Style {
match s {
"g" | "green" => Color::Green.normal(),
"gb" | "green_bold" => Color::Green.bold(),
"gu" | "green_underline" => Color::Green.underline(),
"gi" | "green_italic" => Color::Green.italic(),
"gd" | "green_dimmed" => Color::Green.dimmed(),
"gr" | "green_reverse" => Color::Green.reverse(),
"gbl" | "green_blink" => Color::Green.blink(),
"gst" | "green_strike" => Color::Green.strikethrough(),
"lg" | "light_green" => Color::LightGreen.normal(),
"lgb" | "light_green_bold" => Color::LightGreen.bold(),
"lgu" | "light_green_underline" => Color::LightGreen.underline(),
"lgi" | "light_green_italic" => Color::LightGreen.italic(),
"lgd" | "light_green_dimmed" => Color::LightGreen.dimmed(),
"lgr" | "light_green_reverse" => Color::LightGreen.reverse(),
"lgbl" | "light_green_blink" => Color::LightGreen.blink(),
"lgst" | "light_green_strike" => Color::LightGreen.strikethrough(),
"r" | "red" => Color::Red.normal(),
"rb" | "red_bold" => Color::Red.bold(),
"ru" | "red_underline" => Color::Red.underline(),
"ri" | "red_italic" => Color::Red.italic(),
"rd" | "red_dimmed" => Color::Red.dimmed(),
"rr" | "red_reverse" => Color::Red.reverse(),
"rbl" | "red_blink" => Color::Red.blink(),
"rst" | "red_strike" => Color::Red.strikethrough(),
"lr" | "light_red" => Color::LightRed.normal(),
"lrb" | "light_red_bold" => Color::LightRed.bold(),
"lru" | "light_red_underline" => Color::LightRed.underline(),
"lri" | "light_red_italic" => Color::LightRed.italic(),
"lrd" | "light_red_dimmed" => Color::LightRed.dimmed(),
"lrr" | "light_red_reverse" => Color::LightRed.reverse(),
"lrbl" | "light_red_blink" => Color::LightRed.blink(),
"lrst" | "light_red_strike" => Color::LightRed.strikethrough(),
"u" | "blue" => Color::Blue.normal(),
"ub" | "blue_bold" => Color::Blue.bold(),
"uu" | "blue_underline" => Color::Blue.underline(),
"ui" | "blue_italic" => Color::Blue.italic(),
"ud" | "blue_dimmed" => Color::Blue.dimmed(),
"ur" | "blue_reverse" => Color::Blue.reverse(),
"ubl" | "blue_blink" => Color::Blue.blink(),
"ust" | "blue_strike" => Color::Blue.strikethrough(),
"lu" | "light_blue" => Color::LightBlue.normal(),
"lub" | "light_blue_bold" => Color::LightBlue.bold(),
"luu" | "light_blue_underline" => Color::LightBlue.underline(),
"lui" | "light_blue_italic" => Color::LightBlue.italic(),
"lud" | "light_blue_dimmed" => Color::LightBlue.dimmed(),
"lur" | "light_blue_reverse" => Color::LightBlue.reverse(),
"lubl" | "light_blue_blink" => Color::LightBlue.blink(),
"lust" | "light_blue_strike" => Color::LightBlue.strikethrough(),
"b" | "black" => Color::Black.normal(),
"bb" | "black_bold" => Color::Black.bold(),
"bu" | "black_underline" => Color::Black.underline(),
"bi" | "black_italic" => Color::Black.italic(),
"bd" | "black_dimmed" => Color::Black.dimmed(),
"br" | "black_reverse" => Color::Black.reverse(),
"bbl" | "black_blink" => Color::Black.blink(),
"bst" | "black_strike" => Color::Black.strikethrough(),
"ligr" | "light_gray" => Color::LightGray.normal(),
"ligrb" | "light_gray_bold" => Color::LightGray.bold(),
"ligru" | "light_gray_underline" => Color::LightGray.underline(),
"ligri" | "light_gray_italic" => Color::LightGray.italic(),
"ligrd" | "light_gray_dimmed" => Color::LightGray.dimmed(),
"ligrr" | "light_gray_reverse" => Color::LightGray.reverse(),
"ligrbl" | "light_gray_blink" => Color::LightGray.blink(),
"ligrst" | "light_gray_strike" => Color::LightGray.strikethrough(),
"y" | "yellow" => Color::Yellow.normal(),
"yb" | "yellow_bold" => Color::Yellow.bold(),
"yu" | "yellow_underline" => Color::Yellow.underline(),
"yi" | "yellow_italic" => Color::Yellow.italic(),
"yd" | "yellow_dimmed" => Color::Yellow.dimmed(),
"yr" | "yellow_reverse" => Color::Yellow.reverse(),
"ybl" | "yellow_blink" => Color::Yellow.blink(),
"yst" | "yellow_strike" => Color::Yellow.strikethrough(),
"ly" | "light_yellow" => Color::LightYellow.normal(),
"lyb" | "light_yellow_bold" => Color::LightYellow.bold(),
"lyu" | "light_yellow_underline" => Color::LightYellow.underline(),
"lyi" | "light_yellow_italic" => Color::LightYellow.italic(),
"lyd" | "light_yellow_dimmed" => Color::LightYellow.dimmed(),
"lyr" | "light_yellow_reverse" => Color::LightYellow.reverse(),
"lybl" | "light_yellow_blink" => Color::LightYellow.blink(),
"lyst" | "light_yellow_strike" => Color::LightYellow.strikethrough(),
"p" | "purple" => Color::Purple.normal(),
"pb" | "purple_bold" => Color::Purple.bold(),
"pu" | "purple_underline" => Color::Purple.underline(),
"pi" | "purple_italic" => Color::Purple.italic(),
"pd" | "purple_dimmed" => Color::Purple.dimmed(),
"pr" | "purple_reverse" => Color::Purple.reverse(),
"pbl" | "purple_blink" => Color::Purple.blink(),
"pst" | "purple_strike" => Color::Purple.strikethrough(),
"lp" | "light_purple" => Color::LightPurple.normal(),
"lpb" | "light_purple_bold" => Color::LightPurple.bold(),
"lpu" | "light_purple_underline" => Color::LightPurple.underline(),
"lpi" | "light_purple_italic" => Color::LightPurple.italic(),
"lpd" | "light_purple_dimmed" => Color::LightPurple.dimmed(),
"lpr" | "light_purple_reverse" => Color::LightPurple.reverse(),
"lpbl" | "light_purple_blink" => Color::LightPurple.blink(),
"lpst" | "light_purple_strike" => Color::LightPurple.strikethrough(),
"c" | "cyan" => Color::Cyan.normal(),
"cb" | "cyan_bold" => Color::Cyan.bold(),
"cu" | "cyan_underline" => Color::Cyan.underline(),
"ci" | "cyan_italic" => Color::Cyan.italic(),
"cd" | "cyan_dimmed" => Color::Cyan.dimmed(),
"cr" | "cyan_reverse" => Color::Cyan.reverse(),
"cbl" | "cyan_blink" => Color::Cyan.blink(),
"cst" | "cyan_strike" => Color::Cyan.strikethrough(),
"lc" | "light_cyan" => Color::LightCyan.normal(),
"lcb" | "light_cyan_bold" => Color::LightCyan.bold(),
"lcu" | "light_cyan_underline" => Color::LightCyan.underline(),
"lci" | "light_cyan_italic" => Color::LightCyan.italic(),
"lcd" | "light_cyan_dimmed" => Color::LightCyan.dimmed(),
"lcr" | "light_cyan_reverse" => Color::LightCyan.reverse(),
"lcbl" | "light_cyan_blink" => Color::LightCyan.blink(),
"lcst" | "light_cyan_strike" => Color::LightCyan.strikethrough(),
"w" | "white" => Color::White.normal(),
"wb" | "white_bold" => Color::White.bold(),
"wu" | "white_underline" => Color::White.underline(),
"wi" | "white_italic" => Color::White.italic(),
"wd" | "white_dimmed" => Color::White.dimmed(),
"wr" | "white_reverse" => Color::White.reverse(),
"wbl" | "white_blink" => Color::White.blink(),
"wst" | "white_strike" => Color::White.strikethrough(),
"dgr" | "dark_gray" => Color::DarkGray.normal(),
"dgrb" | "dark_gray_bold" => Color::DarkGray.bold(),
"dgru" | "dark_gray_underline" => Color::DarkGray.underline(),
"dgri" | "dark_gray_italic" => Color::DarkGray.italic(),
"dgrd" | "dark_gray_dimmed" => Color::DarkGray.dimmed(),
"dgrr" | "dark_gray_reverse" => Color::DarkGray.reverse(),
"dgrbl" | "dark_gray_blink" => Color::DarkGray.blink(),
"dgrst" | "dark_gray_strike" => Color::DarkGray.strikethrough(),
"def" | "default" => Color::Default.normal(),
"defb" | "default_bold" => Color::Default.bold(),
"defu" | "default_underline" => Color::Default.underline(),
"defi" | "default_italic" => Color::Default.italic(),
"defd" | "default_dimmed" => Color::Default.dimmed(),
"defr" | "default_reverse" => Color::Default.reverse(),
// Add xterm 256 colors adding an x prefix where the name conflicts
"xblack" | "xterm_black" => Color::Fixed(0).normal(),
"maroon" | "xterm_maroon" => Color::Fixed(1).normal(),
"xgreen" | "xterm_green" => Color::Fixed(2).normal(),
"olive" | "xterm_olive" => Color::Fixed(3).normal(),
"navy" | "xterm_navy" => Color::Fixed(4).normal(),
"xpurplea" | "xterm_purplea" => Color::Fixed(5).normal(),
"teal" | "xterm_teal" => Color::Fixed(6).normal(),
"silver" | "xterm_silver" => Color::Fixed(7).normal(),
"grey" | "xterm_grey" => Color::Fixed(8).normal(),
"xred" | "xterm_red" => Color::Fixed(9).normal(),
"lime" | "xterm_lime" => Color::Fixed(10).normal(),
"xyellow" | "xterm_yellow" => Color::Fixed(11).normal(),
"xblue" | "xterm_blue" => Color::Fixed(12).normal(),
"fuchsia" | "xterm_fuchsia" => Color::Fixed(13).normal(),
"aqua" | "xterm_aqua" => Color::Fixed(14).normal(),
"xwhite" | "xterm_white" => Color::Fixed(15).normal(),
"grey0" | "xterm_grey0" => Color::Fixed(16).normal(),
"navyblue" | "xterm_navyblue" => Color::Fixed(17).normal(),
"darkblue" | "xterm_darkblue" => Color::Fixed(18).normal(),
"blue3a" | "xterm_blue3a" => Color::Fixed(19).normal(),
"blue3b" | "xterm_blue3b" => Color::Fixed(20).normal(),
"blue1" | "xterm_blue1" => Color::Fixed(21).normal(),
"darkgreen" | "xterm_darkgreen" => Color::Fixed(22).normal(),
"deepskyblue4a" | "xterm_deepskyblue4a" => Color::Fixed(23).normal(),
"deepskyblue4b" | "xterm_deepskyblue4b" => Color::Fixed(24).normal(),
"deepskyblue4c" | "xterm_deepskyblue4c" => Color::Fixed(25).normal(),
"dodgerblue3" | "xterm_dodgerblue3" => Color::Fixed(26).normal(),
"dodgerblue2" | "xterm_dodgerblue2" => Color::Fixed(27).normal(),
"green4" | "xterm_green4" => Color::Fixed(28).normal(),
"springgreen4" | "xterm_springgreen4" => Color::Fixed(29).normal(),
"turquoise4" | "xterm_turquoise4" => Color::Fixed(30).normal(),
"deepskyblue3a" | "xterm_deepskyblue3a" => Color::Fixed(31).normal(),
"deepskyblue3b" | "xterm_deepskyblue3b" => Color::Fixed(32).normal(),
"dodgerblue1" | "xterm_dodgerblue1" => Color::Fixed(33).normal(),
"green3a" | "xterm_green3a" => Color::Fixed(34).normal(),
"springgreen3a" | "xterm_springgreen3a" => Color::Fixed(35).normal(),
"darkcyan" | "xterm_darkcyan" => Color::Fixed(36).normal(),
"lightseagreen" | "xterm_lightseagreen" => Color::Fixed(37).normal(),
"deepskyblue2" | "xterm_deepskyblue2" => Color::Fixed(38).normal(),
"deepskyblue1" | "xterm_deepskyblue1" => Color::Fixed(39).normal(),
"green3b" | "xterm_green3b" => Color::Fixed(40).normal(),
"springgreen3b" | "xterm_springgreen3b" => Color::Fixed(41).normal(),
"springgreen2a" | "xterm_springgreen2a" => Color::Fixed(42).normal(),
"cyan3" | "xterm_cyan3" => Color::Fixed(43).normal(),
"darkturquoise" | "xterm_darkturquoise" => Color::Fixed(44).normal(),
"turquoise2" | "xterm_turquoise2" => Color::Fixed(45).normal(),
"green1" | "xterm_green1" => Color::Fixed(46).normal(),
"springgreen2b" | "xterm_springgreen2b" => Color::Fixed(47).normal(),
"springgreen1" | "xterm_springgreen1" => Color::Fixed(48).normal(),
"mediumspringgreen" | "xterm_mediumspringgreen" => Color::Fixed(49).normal(),
"cyan2" | "xterm_cyan2" => Color::Fixed(50).normal(),
"cyan1" | "xterm_cyan1" => Color::Fixed(51).normal(),
"darkreda" | "xterm_darkreda" => Color::Fixed(52).normal(),
"deeppink4a" | "xterm_deeppink4a" => Color::Fixed(53).normal(),
"purple4a" | "xterm_purple4a" => Color::Fixed(54).normal(),
"purple4b" | "xterm_purple4b" => Color::Fixed(55).normal(),
"purple3" | "xterm_purple3" => Color::Fixed(56).normal(),
"blueviolet" | "xterm_blueviolet" => Color::Fixed(57).normal(),
"orange4a" | "xterm_orange4a" => Color::Fixed(58).normal(),
"grey37" | "xterm_grey37" => Color::Fixed(59).normal(),
"mediumpurple4" | "xterm_mediumpurple4" => Color::Fixed(60).normal(),
"slateblue3a" | "xterm_slateblue3a" => Color::Fixed(61).normal(),
"slateblue3b" | "xterm_slateblue3b" => Color::Fixed(62).normal(),
"royalblue1" | "xterm_royalblue1" => Color::Fixed(63).normal(),
"chartreuse4" | "xterm_chartreuse4" => Color::Fixed(64).normal(),
"darkseagreen4a" | "xterm_darkseagreen4a" => Color::Fixed(65).normal(),
"paleturquoise4" | "xterm_paleturquoise4" => Color::Fixed(66).normal(),
"steelblue" | "xterm_steelblue" => Color::Fixed(67).normal(),
"steelblue3" | "xterm_steelblue3" => Color::Fixed(68).normal(),
"cornflowerblue" | "xterm_cornflowerblue" => Color::Fixed(69).normal(),
"chartreuse3a" | "xterm_chartreuse3a" => Color::Fixed(70).normal(),
"darkseagreen4b" | "xterm_darkseagreen4b" => Color::Fixed(71).normal(),
"cadetbluea" | "xterm_cadetbluea" => Color::Fixed(72).normal(),
"cadetblueb" | "xterm_cadetblueb" => Color::Fixed(73).normal(),
"skyblue3" | "xterm_skyblue3" => Color::Fixed(74).normal(),
"steelblue1a" | "xterm_steelblue1a" => Color::Fixed(75).normal(),
"chartreuse3b" | "xterm_chartreuse3b" => Color::Fixed(76).normal(),
"palegreen3a" | "xterm_palegreen3a" => Color::Fixed(77).normal(),
"seagreen3" | "xterm_seagreen3" => Color::Fixed(78).normal(),
"aquamarine3" | "xterm_aquamarine3" => Color::Fixed(79).normal(),
"mediumturquoise" | "xterm_mediumturquoise" => Color::Fixed(80).normal(),
"steelblue1b" | "xterm_steelblue1b" => Color::Fixed(81).normal(),
"chartreuse2a" | "xterm_chartreuse2a" => Color::Fixed(82).normal(),
"seagreen2" | "xterm_seagreen2" => Color::Fixed(83).normal(),
"seagreen1a" | "xterm_seagreen1a" => Color::Fixed(84).normal(),
"seagreen1b" | "xterm_seagreen1b" => Color::Fixed(85).normal(),
"aquamarine1a" | "xterm_aquamarine1a" => Color::Fixed(86).normal(),
"darkslategray2" | "xterm_darkslategray2" => Color::Fixed(87).normal(),
"darkredb" | "xterm_darkredb" => Color::Fixed(88).normal(),
"deeppink4b" | "xterm_deeppink4b" => Color::Fixed(89).normal(),
"darkmagentaa" | "xterm_darkmagentaa" => Color::Fixed(90).normal(),
"darkmagentab" | "xterm_darkmagentab" => Color::Fixed(91).normal(),
"darkvioleta" | "xterm_darkvioleta" => Color::Fixed(92).normal(),
"xpurpleb" | "xterm_purpleb" => Color::Fixed(93).normal(),
"orange4b" | "xterm_orange4b" => Color::Fixed(94).normal(),
"lightpink4" | "xterm_lightpink4" => Color::Fixed(95).normal(),
"plum4" | "xterm_plum4" => Color::Fixed(96).normal(),
"mediumpurple3a" | "xterm_mediumpurple3a" => Color::Fixed(97).normal(),
"mediumpurple3b" | "xterm_mediumpurple3b" => Color::Fixed(98).normal(),
"slateblue1" | "xterm_slateblue1" => Color::Fixed(99).normal(),
"yellow4a" | "xterm_yellow4a" => Color::Fixed(100).normal(),
"wheat4" | "xterm_wheat4" => Color::Fixed(101).normal(),
"grey53" | "xterm_grey53" => Color::Fixed(102).normal(),
"lightslategrey" | "xterm_lightslategrey" => Color::Fixed(103).normal(),
"mediumpurple" | "xterm_mediumpurple" => Color::Fixed(104).normal(),
"lightslateblue" | "xterm_lightslateblue" => Color::Fixed(105).normal(),
"yellow4b" | "xterm_yellow4b" => Color::Fixed(106).normal(),
"darkolivegreen3a" | "xterm_darkolivegreen3a" => Color::Fixed(107).normal(),
"darkseagreen" | "xterm_darkseagreen" => Color::Fixed(108).normal(),
"lightskyblue3a" | "xterm_lightskyblue3a" => Color::Fixed(109).normal(),
"lightskyblue3b" | "xterm_lightskyblue3b" => Color::Fixed(110).normal(),
"skyblue2" | "xterm_skyblue2" => Color::Fixed(111).normal(),
"chartreuse2b" | "xterm_chartreuse2b" => Color::Fixed(112).normal(),
"darkolivegreen3b" | "xterm_darkolivegreen3b" => Color::Fixed(113).normal(),
"palegreen3b" | "xterm_palegreen3b" => Color::Fixed(114).normal(),
"darkseagreen3a" | "xterm_darkseagreen3a" => Color::Fixed(115).normal(),
"darkslategray3" | "xterm_darkslategray3" => Color::Fixed(116).normal(),
"skyblue1" | "xterm_skyblue1" => Color::Fixed(117).normal(),
"chartreuse1" | "xterm_chartreuse1" => Color::Fixed(118).normal(),
"lightgreena" | "xterm_lightgreena" => Color::Fixed(119).normal(),
"lightgreenb" | "xterm_lightgreenb" => Color::Fixed(120).normal(),
"palegreen1a" | "xterm_palegreen1a" => Color::Fixed(121).normal(),
"aquamarine1b" | "xterm_aquamarine1b" => Color::Fixed(122).normal(),
"darkslategray1" | "xterm_darkslategray1" => Color::Fixed(123).normal(),
"red3a" | "xterm_red3a" => Color::Fixed(124).normal(),
"deeppink4c" | "xterm_deeppink4c" => Color::Fixed(125).normal(),
"mediumvioletred" | "xterm_mediumvioletred" => Color::Fixed(126).normal(),
"magenta3" | "xterm_magenta3" => Color::Fixed(127).normal(),
"darkvioletb" | "xterm_darkvioletb" => Color::Fixed(128).normal(),
"purplec" | "xterm_purplec" => Color::Fixed(129).normal(),
"darkorange3a" | "xterm_darkorange3a" => Color::Fixed(130).normal(),
"indianreda" | "xterm_indianreda" => Color::Fixed(131).normal(),
"hotpink3a" | "xterm_hotpink3a" => Color::Fixed(132).normal(),
"mediumorchid3" | "xterm_mediumorchid3" => Color::Fixed(133).normal(),
"mediumorchid" | "xterm_mediumorchid" => Color::Fixed(134).normal(),
"mediumpurple2a" | "xterm_mediumpurple2a" => Color::Fixed(135).normal(),
"darkgoldenrod" | "xterm_darkgoldenrod" => Color::Fixed(136).normal(),
"lightsalmon3a" | "xterm_lightsalmon3a" => Color::Fixed(137).normal(),
"rosybrown" | "xterm_rosybrown" => Color::Fixed(138).normal(),
"grey63" | "xterm_grey63" => Color::Fixed(139).normal(),
"mediumpurple2b" | "xterm_mediumpurple2b" => Color::Fixed(140).normal(),
"mediumpurple1" | "xterm_mediumpurple1" => Color::Fixed(141).normal(),
"gold3a" | "xterm_gold3a" => Color::Fixed(142).normal(),
"darkkhaki" | "xterm_darkkhaki" => Color::Fixed(143).normal(),
"navajowhite3" | "xterm_navajowhite3" => Color::Fixed(144).normal(),
"grey69" | "xterm_grey69" => Color::Fixed(145).normal(),
"lightsteelblue3" | "xterm_lightsteelblue3" => Color::Fixed(146).normal(),
"lightsteelblue" | "xterm_lightsteelblue" => Color::Fixed(147).normal(),
"yellow3a" | "xterm_yellow3a" => Color::Fixed(148).normal(),
"darkolivegreen3c" | "xterm_darkolivegreen3c" => Color::Fixed(149).normal(),
"darkseagreen3b" | "xterm_darkseagreen3b" => Color::Fixed(150).normal(),
"darkseagreen2a" | "xterm_darkseagreen2a" => Color::Fixed(151).normal(),
"lightcyan3" | "xterm_lightcyan3" => Color::Fixed(152).normal(),
"lightskyblue1" | "xterm_lightskyblue1" => Color::Fixed(153).normal(),
"greenyellow" | "xterm_greenyellow" => Color::Fixed(154).normal(),
"darkolivegreen2" | "xterm_darkolivegreen2" => Color::Fixed(155).normal(),
"palegreen1b" | "xterm_palegreen1b" => Color::Fixed(156).normal(),
"darkseagreen2b" | "xterm_darkseagreen2b" => Color::Fixed(157).normal(),
"darkseagreen1a" | "xterm_darkseagreen1a" => Color::Fixed(158).normal(),
"paleturquoise1" | "xterm_paleturquoise1" => Color::Fixed(159).normal(),
"red3b" | "xterm_red3b" => Color::Fixed(160).normal(),
"deeppink3a" | "xterm_deeppink3a" => Color::Fixed(161).normal(),
"deeppink3b" | "xterm_deeppink3b" => Color::Fixed(162).normal(),
"magenta3a" | "xterm_magenta3a" => Color::Fixed(163).normal(),
"magenta3b" | "xterm_magenta3b" => Color::Fixed(164).normal(),
"magenta2a" | "xterm_magenta2a" => Color::Fixed(165).normal(),
"darkorange3b" | "xterm_darkorange3b" => Color::Fixed(166).normal(),
"indianredb" | "xterm_indianredb" => Color::Fixed(167).normal(),
"hotpink3b" | "xterm_hotpink3b" => Color::Fixed(168).normal(),
"hotpink2" | "xterm_hotpink2" => Color::Fixed(169).normal(),
"orchid" | "xterm_orchid" => Color::Fixed(170).normal(),
"mediumorchid1a" | "xterm_mediumorchid1a" => Color::Fixed(171).normal(),
"orange3" | "xterm_orange3" => Color::Fixed(172).normal(),
"lightsalmon3b" | "xterm_lightsalmon3b" => Color::Fixed(173).normal(),
"lightpink3" | "xterm_lightpink3" => Color::Fixed(174).normal(),
"pink3" | "xterm_pink3" => Color::Fixed(175).normal(),
"plum3" | "xterm_plum3" => Color::Fixed(176).normal(),
"violet" | "xterm_violet" => Color::Fixed(177).normal(),
"gold3b" | "xterm_gold3b" => Color::Fixed(178).normal(),
"lightgoldenrod3" | "xterm_lightgoldenrod3" => Color::Fixed(179).normal(),
"tan" | "xterm_tan" => Color::Fixed(180).normal(),
"mistyrose3" | "xterm_mistyrose3" => Color::Fixed(181).normal(),
"thistle3" | "xterm_thistle3" => Color::Fixed(182).normal(),
"plum2" | "xterm_plum2" => Color::Fixed(183).normal(),
"yellow3b" | "xterm_yellow3b" => Color::Fixed(184).normal(),
"khaki3" | "xterm_khaki3" => Color::Fixed(185).normal(),
"lightgoldenrod2" | "xterm_lightgoldenrod2" => Color::Fixed(186).normal(),
"lightyellow3" | "xterm_lightyellow3" => Color::Fixed(187).normal(),
"grey84" | "xterm_grey84" => Color::Fixed(188).normal(),
"lightsteelblue1" | "xterm_lightsteelblue1" => Color::Fixed(189).normal(),
"yellow2" | "xterm_yellow2" => Color::Fixed(190).normal(),
"darkolivegreen1a" | "xterm_darkolivegreen1a" => Color::Fixed(191).normal(),
"darkolivegreen1b" | "xterm_darkolivegreen1b" => Color::Fixed(192).normal(),
"darkseagreen1b" | "xterm_darkseagreen1b" => Color::Fixed(193).normal(),
"honeydew2" | "xterm_honeydew2" => Color::Fixed(194).normal(),
"lightcyan1" | "xterm_lightcyan1" => Color::Fixed(195).normal(),
"red1" | "xterm_red1" => Color::Fixed(196).normal(),
"deeppink2" | "xterm_deeppink2" => Color::Fixed(197).normal(),
"deeppink1a" | "xterm_deeppink1a" => Color::Fixed(198).normal(),
"deeppink1b" | "xterm_deeppink1b" => Color::Fixed(199).normal(),
"magenta2b" | "xterm_magenta2b" => Color::Fixed(200).normal(),
"magenta1" | "xterm_magenta1" => Color::Fixed(201).normal(),
"orangered1" | "xterm_orangered1" => Color::Fixed(202).normal(),
"indianred1a" | "xterm_indianred1a" => Color::Fixed(203).normal(),
"indianred1b" | "xterm_indianred1b" => Color::Fixed(204).normal(),
"hotpinka" | "xterm_hotpinka" => Color::Fixed(205).normal(),
"hotpinkb" | "xterm_hotpinkb" => Color::Fixed(206).normal(),
"mediumorchid1b" | "xterm_mediumorchid1b" => Color::Fixed(207).normal(),
"darkorange" | "xterm_darkorange" => Color::Fixed(208).normal(),
"salmon1" | "xterm_salmon1" => Color::Fixed(209).normal(),
"lightcoral" | "xterm_lightcoral" => Color::Fixed(210).normal(),
"palevioletred1" | "xterm_palevioletred1" => Color::Fixed(211).normal(),
"orchid2" | "xterm_orchid2" => Color::Fixed(212).normal(),
"orchid1" | "xterm_orchid1" => Color::Fixed(213).normal(),
"orange1" | "xterm_orange1" => Color::Fixed(214).normal(),
"sandybrown" | "xterm_sandybrown" => Color::Fixed(215).normal(),
"lightsalmon1" | "xterm_lightsalmon1" => Color::Fixed(216).normal(),
"lightpink1" | "xterm_lightpink1" => Color::Fixed(217).normal(),
"pink1" | "xterm_pink1" => Color::Fixed(218).normal(),
"plum1" | "xterm_plum1" => Color::Fixed(219).normal(),
"gold1" | "xterm_gold1" => Color::Fixed(220).normal(),
"lightgoldenrod2a" | "xterm_lightgoldenrod2a" => Color::Fixed(221).normal(),
"lightgoldenrod2b" | "xterm_lightgoldenrod2b" => Color::Fixed(222).normal(),
"navajowhite1" | "xterm_navajowhite1" => Color::Fixed(223).normal(),
"mistyrose1" | "xterm_mistyrose1" => Color::Fixed(224).normal(),
"thistle1" | "xterm_thistle1" => Color::Fixed(225).normal(),
"yellow1" | "xterm_yellow1" => Color::Fixed(226).normal(),
"lightgoldenrod1" | "xterm_lightgoldenrod1" => Color::Fixed(227).normal(),
"khaki1" | "xterm_khaki1" => Color::Fixed(228).normal(),
"wheat1" | "xterm_wheat1" => Color::Fixed(229).normal(),
"cornsilk1" | "xterm_cornsilk1" => Color::Fixed(230).normal(),
"grey100" | "xterm_grey100" => Color::Fixed(231).normal(),
"grey3" | "xterm_grey3" => Color::Fixed(232).normal(),
"grey7" | "xterm_grey7" => Color::Fixed(233).normal(),
"grey11" | "xterm_grey11" => Color::Fixed(234).normal(),
"grey15" | "xterm_grey15" => Color::Fixed(235).normal(),
"grey19" | "xterm_grey19" => Color::Fixed(236).normal(),
"grey23" | "xterm_grey23" => Color::Fixed(237).normal(),
"grey27" | "xterm_grey27" => Color::Fixed(238).normal(),
"grey30" | "xterm_grey30" => Color::Fixed(239).normal(),
"grey35" | "xterm_grey35" => Color::Fixed(240).normal(),
"grey39" | "xterm_grey39" => Color::Fixed(241).normal(),
"grey42" | "xterm_grey42" => Color::Fixed(242).normal(),
"grey46" | "xterm_grey46" => Color::Fixed(243).normal(),
"grey50" | "xterm_grey50" => Color::Fixed(244).normal(),
"grey54" | "xterm_grey54" => Color::Fixed(245).normal(),
"grey58" | "xterm_grey58" => Color::Fixed(246).normal(),
"grey62" | "xterm_grey62" => Color::Fixed(247).normal(),
"grey66" | "xterm_grey66" => Color::Fixed(248).normal(),
"grey70" | "xterm_grey70" => Color::Fixed(249).normal(),
"grey74" | "xterm_grey74" => Color::Fixed(250).normal(),
"grey78" | "xterm_grey78" => Color::Fixed(251).normal(),
"grey82" | "xterm_grey82" => Color::Fixed(252).normal(),
"grey85" | "xterm_grey85" => Color::Fixed(253).normal(),
"grey89" | "xterm_grey89" => Color::Fixed(254).normal(),
"grey93" | "xterm_grey93" => Color::Fixed(255).normal(),
_ => Color::White.normal(),
}
}
pub fn lookup_color(s: &str) -> Option<Color> {
let color = match s {
"g" | "green" => Color::Green,
"lg" | "light_green" => Color::LightGreen,
"r" | "red" => Color::Red,
"lr" | "light_red" => Color::LightRed,
"u" | "blue" => Color::Blue,
"lu" | "light_blue" => Color::LightBlue,
"b" | "black" => Color::Black,
"ligr" | "light_gray" => Color::LightGray,
"y" | "yellow" => Color::Yellow,
"ly" | "light_yellow" => Color::LightYellow,
"p" | "purple" => Color::Purple,
"lp" | "light_purple" => Color::LightPurple,
"c" | "cyan" => Color::Cyan,
"lc" | "light_cyan" => Color::LightCyan,
"w" | "white" => Color::White,
"dgr" | "dark_gray" => Color::DarkGray,
"def" | "default" => Color::Default,
_ => return None,
};
Some(color)
}
fn fill_modifiers(attrs: &str, style: &mut Style) {
// setup the attributes available in nu_ansi_term::Style
//
// since we can combine styles like bold-italic, iterate through the chars
// and set the bools for later use in the nu_ansi_term::Style application
for ch in attrs.to_lowercase().chars() {
match ch {
'l' => style.is_blink = true,
'b' => style.is_bold = true,
'd' => style.is_dimmed = true,
'h' => style.is_hidden = true,
'i' => style.is_italic = true,
'r' => style.is_reverse = true,
's' => style.is_strikethrough = true,
'u' => style.is_underline = true,
'n' => (),
_ => (),
}
}
}
fn lookup_color_str(s: &str) -> Option<Color> {
if s.starts_with('#') {
color_from_hex(s).ok().and_then(|c| c)
} else {
lookup_color(s)
}
}

View File

@ -1,41 +1,56 @@
use crate::color_config::lookup_ansi_color_style;
use crate::{color_config::lookup_ansi_color_style, color_record_to_nustyle};
use nu_ansi_term::{Color, Style};
use nu_protocol::Config;
use nu_protocol::{Config, Value};
// The default colors for shapes, used when there is no config for them.
pub fn default_shape_color(shape: String) -> Style {
match shape.as_ref() {
"shape_and" => Style::new().fg(Color::Purple).bold(),
"shape_binary" => Style::new().fg(Color::Purple).bold(),
"shape_block" => Style::new().fg(Color::Blue).bold(),
"shape_bool" => Style::new().fg(Color::LightCyan),
"shape_custom" => Style::new().fg(Color::Green),
"shape_datetime" => Style::new().fg(Color::Cyan).bold(),
"shape_directory" => Style::new().fg(Color::Cyan),
"shape_external" => Style::new().fg(Color::Cyan),
"shape_externalarg" => Style::new().fg(Color::Green).bold(),
"shape_filepath" => Style::new().fg(Color::Cyan),
"shape_flag" => Style::new().fg(Color::Blue).bold(),
"shape_float" => Style::new().fg(Color::Purple).bold(),
"shape_garbage" => Style::new().fg(Color::White).on(Color::Red).bold(),
"shape_globpattern" => Style::new().fg(Color::Cyan).bold(),
"shape_int" => Style::new().fg(Color::Purple).bold(),
"shape_internalcall" => Style::new().fg(Color::Cyan).bold(),
"shape_list" => Style::new().fg(Color::Cyan).bold(),
"shape_literal" => Style::new().fg(Color::Blue),
"shape_nothing" => Style::new().fg(Color::LightCyan),
"shape_operator" => Style::new().fg(Color::Yellow),
"shape_or" => Style::new().fg(Color::Purple).bold(),
"shape_pipe" => Style::new().fg(Color::Purple).bold(),
"shape_range" => Style::new().fg(Color::Yellow).bold(),
"shape_record" => Style::new().fg(Color::Cyan).bold(),
"shape_redirection" => Style::new().fg(Color::Purple).bold(),
"shape_signature" => Style::new().fg(Color::Green).bold(),
"shape_string" => Style::new().fg(Color::Green),
"shape_string_interpolation" => Style::new().fg(Color::Cyan).bold(),
"shape_table" => Style::new().fg(Color::Blue).bold(),
"shape_variable" => Style::new().fg(Color::Purple),
_ => Style::default(),
}
}
pub fn get_shape_color(shape: String, conf: &Config) -> Style {
match conf.color_config.get(shape.as_str()) {
Some(int_color) => match int_color.as_string() {
Ok(int_color) => lookup_ansi_color_style(&int_color),
Err(_) => Style::default(),
},
None => match shape.as_ref() {
"shape_garbage" => Style::new().fg(Color::White).on(Color::Red).bold(),
"shape_binary" => Style::new().fg(Color::Purple).bold(),
"shape_bool" => Style::new().fg(Color::LightCyan),
"shape_int" => Style::new().fg(Color::Purple).bold(),
"shape_float" => Style::new().fg(Color::Purple).bold(),
"shape_range" => Style::new().fg(Color::Yellow).bold(),
"shape_internalcall" => Style::new().fg(Color::Cyan).bold(),
"shape_external" => Style::new().fg(Color::Cyan),
"shape_externalarg" => Style::new().fg(Color::Green).bold(),
"shape_literal" => Style::new().fg(Color::Blue),
"shape_operator" => Style::new().fg(Color::Yellow),
"shape_signature" => Style::new().fg(Color::Green).bold(),
"shape_string" => Style::new().fg(Color::Green),
"shape_string_interpolation" => Style::new().fg(Color::Cyan).bold(),
"shape_datetime" => Style::new().fg(Color::Cyan).bold(),
"shape_list" => Style::new().fg(Color::Cyan).bold(),
"shape_table" => Style::new().fg(Color::Blue).bold(),
"shape_record" => Style::new().fg(Color::Cyan).bold(),
"shape_block" => Style::new().fg(Color::Blue).bold(),
"shape_filepath" => Style::new().fg(Color::Cyan),
"shape_directory" => Style::new().fg(Color::Cyan),
"shape_globpattern" => Style::new().fg(Color::Cyan).bold(),
"shape_variable" => Style::new().fg(Color::Purple),
"shape_flag" => Style::new().fg(Color::Blue).bold(),
"shape_custom" => Style::new().fg(Color::Green),
"shape_nothing" => Style::new().fg(Color::LightCyan),
_ => Style::default(),
},
Some(int_color) => {
// Shapes do not use color_config closures, currently.
match int_color {
Value::Record { .. } => color_record_to_nustyle(int_color),
Value::String { val, .. } => lookup_ansi_color_style(val),
// Defer to the default in the event of incorrect types being given
// (i.e. treat null, etc. as the value being unset)
_ => default_shape_color(shape),
}
}
None => default_shape_color(shape),
}
}

View File

@ -0,0 +1,285 @@
use crate::{color_record_to_nustyle, lookup_ansi_color_style, TextStyle};
use nu_ansi_term::{Color, Style};
use nu_engine::eval_block;
use nu_protocol::{
engine::{EngineState, Stack, StateWorkingSet},
CliError, IntoPipelineData, Value,
};
use tabled::alignment::AlignmentHorizontal;
use std::{
collections::HashMap,
fmt::{Debug, Formatter, Result},
};
// ComputableStyle represents the valid user style types: a single color value, or a closure which
// takes an input value and produces a color value. The latter represents a value which
// is computed at use-time.
#[derive(Debug, Clone)]
pub enum ComputableStyle {
Static(Style),
Closure(Value),
}
// macro used for adding initial values to the style hashmap
macro_rules! initial {
($a:expr, $b:expr) => {
($a.to_string(), ComputableStyle::Static($b))
};
}
// An alias for the mapping used internally by StyleComputer.
pub type StyleMapping = HashMap<String, ComputableStyle>;
//
// A StyleComputer is an all-in-one way to compute styles. A nu command can
// simply create it with from_config(), and then use it with compute().
// It stores the engine state and stack needed to run closures that
// may be defined as a user style.
//
pub struct StyleComputer<'a> {
engine_state: &'a EngineState,
stack: &'a Stack,
map: StyleMapping,
}
impl<'a> StyleComputer<'a> {
// This is NOT meant to be used in most cases - please use from_config() instead.
// This only exists for testing purposes.
pub fn new(
engine_state: &'a EngineState,
stack: &'a Stack,
map: StyleMapping,
) -> StyleComputer<'a> {
StyleComputer {
engine_state,
stack,
map,
}
}
// The main method. Takes a string name which maps to a color_config style name,
// and a Nu value to pipe into any closures that may have been defined there.
pub fn compute(&self, style_name: &str, value: &Value) -> Style {
match self.map.get(style_name) {
// Static values require no computation.
Some(ComputableStyle::Static(s)) => *s,
// Closures are run here.
Some(ComputableStyle::Closure(Value::Closure {
val: block_id,
captures,
span,
})) => {
let block = self.engine_state.get_block(*block_id).clone();
// Because captures_to_stack() clones, we don't need to use with_env() here
// (contrast with_env() usage in `each` or `do`).
let mut stack = self.stack.captures_to_stack(captures);
// Support 1-argument blocks as well as 0-argument blocks.
if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id {
stack.add_var(*var_id, value.clone());
}
}
// Run the block.
match eval_block(
self.engine_state,
&mut stack,
&block,
value.clone().into_pipeline_data(),
false,
false,
) {
Ok(v) => {
let value = v.into_value(*span);
// These should be the same color data forms supported by color_config.
match value {
Value::Record { .. } => color_record_to_nustyle(&value),
Value::String { val, .. } => lookup_ansi_color_style(&val),
_ => Style::default(),
}
}
// This is basically a copy of nu_cli::report_error(), but that isn't usable due to
// dependencies. While crudely spitting out a bunch of errors like this is not ideal,
// currently hook closure errors behave roughly the same.
Err(e) => {
eprintln!(
"Error: {:?}",
CliError(&e, &StateWorkingSet::new(self.engine_state))
);
Style::default()
}
}
}
// There should be no other kinds of values (due to create_map() in config.rs filtering them out)
// so this is just a fallback.
_ => Style::default(),
}
}
// Used only by the `table` command.
pub fn style_primitive(&self, value: &Value) -> TextStyle {
let s = self.compute(&value.get_type().to_string(), value);
match *value {
Value::Bool { .. } => TextStyle::with_style(AlignmentHorizontal::Left, s),
Value::Int { .. } => TextStyle::with_style(AlignmentHorizontal::Right, s),
Value::Filesize { .. } => TextStyle::with_style(AlignmentHorizontal::Right, s),
Value::Duration { .. } => TextStyle::with_style(AlignmentHorizontal::Right, s),
Value::Date { .. } => TextStyle::with_style(AlignmentHorizontal::Left, s),
Value::Range { .. } => TextStyle::with_style(AlignmentHorizontal::Left, s),
Value::Float { .. } => TextStyle::with_style(AlignmentHorizontal::Right, s),
Value::String { .. } => TextStyle::with_style(AlignmentHorizontal::Left, s),
Value::Nothing { .. } => TextStyle::with_style(AlignmentHorizontal::Left, s),
Value::Binary { .. } => TextStyle::with_style(AlignmentHorizontal::Left, s),
Value::CellPath { .. } => TextStyle::with_style(AlignmentHorizontal::Left, s),
Value::Record { .. } | Value::List { .. } | Value::Block { .. } => {
TextStyle::with_style(AlignmentHorizontal::Left, s)
}
_ => TextStyle::basic_left(),
}
}
// The main constructor.
pub fn from_config(engine_state: &'a EngineState, stack: &'a Stack) -> StyleComputer<'a> {
let config = engine_state.get_config();
// Create the hashmap
let mut map: StyleMapping = HashMap::from([
initial!("separator", Color::White.normal()),
initial!(
"leading_trailing_space_bg",
Style::default().on(Color::Rgb(128, 128, 128))
),
initial!("header", Color::White.normal()),
initial!("empty", Color::White.normal()),
initial!("bool", Color::White.normal()),
initial!("int", Color::White.normal()),
initial!("filesize", Color::White.normal()),
initial!("duration", Color::White.normal()),
initial!("date", Color::White.normal()),
initial!("range", Color::White.normal()),
initial!("float", Color::White.normal()),
initial!("string", Color::White.normal()),
initial!("nothing", Color::White.normal()),
initial!("binary", Color::White.normal()),
initial!("cellpath", Color::White.normal()),
initial!("row_index", Color::Green.bold()),
initial!("record", Color::White.normal()),
initial!("list", Color::White.normal()),
initial!("block", Color::White.normal()),
initial!("hints", Color::DarkGray.normal()),
]);
for (key, value) in &config.color_config {
match value {
Value::Closure { .. } => {
map.insert(key.to_string(), ComputableStyle::Closure(value.clone()));
}
Value::Record { .. } => {
map.insert(
key.to_string(),
ComputableStyle::Static(color_record_to_nustyle(value)),
);
}
Value::String { val, .. } => {
// update the stylemap with the found key
let color = lookup_ansi_color_style(val.as_str());
if let Some(v) = map.get_mut(key) {
*v = ComputableStyle::Static(color);
} else {
map.insert(key.to_string(), ComputableStyle::Static(color));
}
}
// This should never occur.
_ => (),
}
}
StyleComputer::new(engine_state, stack, map)
}
}
// Because EngineState doesn't have Debug (Dec 2022),
// this incomplete representation must be used.
impl<'a> Debug for StyleComputer<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
f.debug_struct("StyleComputer")
.field("map", &self.map)
.finish()
}
}
#[test]
fn test_computable_style_static() {
use nu_protocol::Span;
let style1 = Style::default().italic();
let style2 = Style::default().underline();
// Create a "dummy" style_computer for this test.
let dummy_engine_state = EngineState::new();
let dummy_stack = Stack::new();
let style_computer = StyleComputer::new(
&dummy_engine_state,
&dummy_stack,
HashMap::from([
("string".into(), ComputableStyle::Static(style1)),
("row_index".into(), ComputableStyle::Static(style2)),
]),
);
assert_eq!(
style_computer.compute("string", &Value::nothing(Span::unknown())),
style1
);
assert_eq!(
style_computer.compute("row_index", &Value::nothing(Span::unknown())),
style2
);
}
// Because each closure currently runs in a separate environment, checks that the closures have run
// must use the filesystem.
#[test]
fn test_computable_style_closure_basic() {
use nu_test_support::{nu, nu_repl_code, playground::Playground};
Playground::setup("computable_style_closure_basic", |dirs, _| {
let inp = [
r#"let-env config = {
color_config: {
string: {|e| touch ($e + '.obj'); 'red' }
}
};"#,
"[bell book candle] | table | ignore",
"ls | get name | to nuon",
];
let actual_repl = nu!(cwd: dirs.test(), nu_repl_code(&inp));
assert_eq!(actual_repl.err, "");
assert_eq!(actual_repl.out, "[bell.obj, book.obj, candle.obj]");
});
}
#[test]
fn test_computable_style_closure_errors() {
use nu_test_support::{nu, nu_repl_code};
let inp = [
r#"let-env config = {
color_config: {
string: {|e| $e + 2 }
}
};"#,
"[bell] | table",
];
let actual_repl = nu!(cwd: ".", nu_repl_code(&inp));
// Check that the error was printed
assert!(actual_repl.err.contains("type mismatch for operator"));
// Check that the value was printed
assert!(actual_repl.out.contains("bell"));
}

View File

@ -1,4 +1,5 @@
use nu_ansi_term::{Color, Style};
use std::fmt::Display;
pub type Alignment = tabled::alignment::AlignmentHorizontal;
@ -239,3 +240,23 @@ impl Default for TextStyle {
Self::new()
}
}
impl tabled::papergrid::Color for TextStyle {
fn fmt_prefix(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(color) = &self.color_style {
color.prefix().fmt(f)?;
}
Ok(())
}
fn fmt_suffix(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(color) = &self.color_style {
if !color.is_plain() {
f.write_str("\u{1b}[0m")?;
}
}
Ok(())
}
}

View File

@ -1,112 +1,118 @@
[package]
authors = ["The Nushell Project Developers"]
build = "build.rs"
description = "Nushell's built-in commands"
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-command"
edition = "2021"
license = "MIT"
name = "nu-command"
version = "0.70.0"
build = "build.rs"
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-command"
version = "0.76.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
bench = false
[dependencies]
nu-color-config = { path = "../nu-color-config", version = "0.70.0" }
nu-engine = { path = "../nu-engine", version = "0.70.0" }
nu-glob = { path = "../nu-glob", version = "0.70.0" }
nu-json = { path = "../nu-json", version = "0.70.0" }
nu-parser = { path = "../nu-parser", version = "0.70.0" }
nu-path = { path = "../nu-path", version = "0.70.0" }
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.70.0" }
nu-protocol = { path = "../nu-protocol", version = "0.70.0" }
nu-system = { path = "../nu-system", version = "0.70.0" }
nu-table = { path = "../nu-table", version = "0.70.0" }
nu-term-grid = { path = "../nu-term-grid", version = "0.70.0" }
nu-test-support = { path = "../nu-test-support", version = "0.70.0" }
nu-utils = { path = "../nu-utils", version = "0.70.0" }
nu-ansi-term = "0.46.0"
nu-color-config = { path = "../nu-color-config", version = "0.76.0" }
nu-engine = { path = "../nu-engine", version = "0.76.0" }
nu-explore = { path = "../nu-explore", version = "0.76.0" }
nu-glob = { path = "../nu-glob", version = "0.76.0" }
nu-json = { path = "../nu-json", version = "0.76.0" }
nu-parser = { path = "../nu-parser", version = "0.76.0" }
nu-path = { path = "../nu-path", version = "0.76.0" }
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.76.0" }
nu-protocol = { path = "../nu-protocol", version = "0.76.0" }
nu-system = { path = "../nu-system", version = "0.76.0" }
nu-table = { path = "../nu-table", version = "0.76.0" }
nu-term-grid = { path = "../nu-term-grid", version = "0.76.0" }
nu-utils = { path = "../nu-utils", version = "0.76.0" }
num-format = { version = "0.4.3" }
# Potential dependencies for extras
Inflector = "0.11"
alphanumeric-sort = "1.4.4"
base64 = "0.13.0"
atty = "0.2.14"
base64 = "0.21.0"
byteorder = "1.4.3"
bytesize = "1.1.0"
calamine = "0.18.0"
chrono = { version = "0.4.21", features = ["serde", "unstable-locales"] }
calamine = "0.19.1"
chrono = { version = "0.4.23", features = ["std", "unstable-locales"], default-features = false }
chrono-humanize = "0.2.1"
chrono-tz = "0.6.3"
chrono-tz = "0.8.1"
crossterm = "0.24.0"
csv = "1.1.6"
dialoguer = "0.9.0"
digest = "0.10.0"
dialoguer = { default-features = false, version = "0.10.3" }
digest = { default-features = false, version = "0.10.0" }
dtparse = "1.2.0"
eml-parser = "0.1.0"
encoding_rs = "0.8.30"
fancy-regex = "0.10.0"
fancy-regex = "0.11.0"
filesize = "0.2.0"
filetime = "0.2.15"
fs_extra = "1.2.0"
fs_extra = "1.3.0"
htmlescape = "0.3.1"
ical = "0.7.0"
indexmap = { version="1.7", features=["serde-1"] }
Inflector = "0.11"
indexmap = { version = "1.7", features = ["serde-1"] }
indicatif = "0.17.2"
is-root = "0.1.2"
itertools = "0.10.0"
lazy_static = "1.4.0"
log = "0.4.14"
lscolors = { version = "0.12.0", features = ["crossterm"]}
lscolors = { version = "0.12.0", features = ["crossterm"], default-features = false }
md5 = { package = "md-5", version = "0.10.0" }
meval = "0.2.0"
mime = "0.3.16"
mime_guess = "2.0.4"
notify = "4.0.17"
num = { version = "0.4.0", optional = true }
num-traits = "0.2.14"
once_cell = "1.17"
open = "3.2.0"
pathdiff = "0.2.1"
powierza-coefficient = "1.0.1"
quick-xml = "0.23.0"
powierza-coefficient = "1.0.2"
quick-xml = "0.27"
rand = "0.8"
rayon = "1.5.1"
reqwest = {version = "0.11", features = ["blocking", "json"] }
roxmltree = "0.14.0"
rayon = "1.6.1"
regex = "1.7.1"
reqwest = { version = "0.11", features = ["blocking", "json"] }
roxmltree = "0.18.0"
rust-embed = "6.3.0"
same-file = "1.0.6"
serde = { version="1.0.123", features=["derive"] }
serde_ini = "0.2.0"
serde = { version = "1.0.123", features = ["derive"] }
serde_urlencoded = "0.7.0"
serde_yaml = "0.9.4"
sha2 = "0.10.0"
# Disable default features b/c the default features build Git (very slow to compile)
shadow-rs = { version = "0.16.1", default-features = false }
strip-ansi-escapes = "0.1.1"
sysinfo = "0.26.2"
percent-encoding = "2.2.0"
reedline = { version = "0.16.0", features = ["bashisms", "sqlite"] }
rusqlite = { version = "0.28.0", features = ["bundled"], optional = true }
shadow-rs = { version = "0.20.0", default-features = false }
sqlparser = { version = "0.30.0", features = ["serde"], optional = true }
sysinfo = "0.28.0"
tabled = "0.10.0"
terminal_size = "0.2.1"
thiserror = "1.0.31"
titlecase = "2.0.0"
toml = "0.5.8"
unicode-segmentation = "1.8.0"
toml = "0.7.1"
unicode-segmentation = "1.10.0"
unicode-width = "0.1.10"
url = "2.2.1"
uuid = { version = "1.1.2", features = ["v4"] }
which = { version = "4.3.0", optional = true }
reedline = { version = "0.13.0", features = ["bashisms", "sqlite"]}
wax = { version = "0.5.0", features = ["diagnostics"] }
rusqlite = { version = "0.28.0", features = ["bundled"], optional = true }
sqlparser = { version = "0.23.0", features = ["serde"], optional = true }
uuid = { version = "1.2.2", features = ["v4"] }
wax = { version = "0.5.0" }
which = { version = "4.4.0", optional = true }
print-positions = "0.6.1"
[target.'cfg(windows)'.dependencies]
winreg = "0.10.1"
winreg = "0.11.0"
[target.'cfg(unix)'.dependencies]
libc = "0.2"
umask = "2.0.0"
users = "0.11.0"
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies.trash]
version = "2.1.3"
optional = true
version = "3.0.1"
[dependencies.polars]
version = "0.23.2"
optional = true
features = [
"arg_where",
"checked_arithmetic",
@ -115,9 +121,9 @@ features = [
"csv-file",
"cum_agg",
"default",
"dtype-categorical",
"dtype-datetime",
"dtype-struct",
"dtype-categorical",
"dynamic_groupby",
"ipc",
"is_in",
@ -134,30 +140,29 @@ features = [
"strings",
"to_dummies",
]
optional = true
version = "0.26.1"
[target.'cfg(windows)'.dependencies.windows]
version = "0.37.0"
features = [
"alloc",
"Win32_Foundation",
"Win32_Storage_FileSystem",
"Win32_System_SystemServices",
]
features = ["Win32_Foundation", "Win32_Storage_FileSystem", "Win32_System_SystemServices"]
version = "0.44.0"
[features]
dataframe = ["num", "polars", "sqlparser"]
plugin = ["nu-parser/plugin"]
sqlite = ["rusqlite"] # TODO: given that rusqlite is included in reedline, should we just always include it?
trash-support = ["trash"]
which-support = ["which"]
plugin = ["nu-parser/plugin"]
dataframe = ["polars", "num"]
database = ["sqlparser", "rusqlite"]
[build-dependencies]
shadow-rs = { version = "0.16.1", default-features = false }
shadow-rs = { version = "0.20.0", default-features = false }
[dev-dependencies]
hamcrest2 = "0.3.0"
nu-test-support = { path = "../nu-test-support", version = "0.76.0" }
dirs-next = "2.0.0"
proptest = "1.0.0"
hamcrest2 = "0.3.0"
proptest = "1.1.0"
quickcheck = "1.0.3"
quickcheck_macros = "1.0.0"
rstest = {version = "0.15.0", default-features = false}
rstest = { version = "0.16.0", default-features = false }

View File

@ -4,7 +4,7 @@ fn main() -> shadow_rs::SdResult<()> {
// Look up the current Git commit ourselves instead of relying on shadow_rs,
// because shadow_rs does it in a really slow-to-compile way (it builds libgit2)
let hash = get_git_hash().unwrap_or_default();
println!("cargo:rustc-env=NU_COMMIT_HASH={}", hash);
println!("cargo:rustc-env=NU_COMMIT_HASH={hash}");
shadow_rs::new()
}

View File

@ -2,7 +2,7 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
#[derive(Clone)]
@ -15,6 +15,8 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("bits and")
.input_output_types(vec![(Type::Int, Type::Int)])
.vectorizes_over_list(true)
.required(
"target",
SyntaxShape::Int,
@ -37,10 +39,14 @@ impl Command for SubCommand {
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
) -> Result<PipelineData, ShellError> {
let head = call.head;
let target: i64 = call.req(engine_state, stack, 0)?;
// This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) {
return Err(ShellError::PipelineEmpty(head));
}
input.map(
move |value| operate(value, target, head),
engine_state.ctrlc.clone(),
@ -52,10 +58,7 @@ impl Command for SubCommand {
Example {
description: "Apply bits and to two numbers",
example: "2 | bits and 2",
result: Some(Value::Int {
val: 2,
span: Span::test_data(),
}),
result: Some(Value::test_int(2)),
},
Example {
description: "Apply logical and to a list of numbers",
@ -75,13 +78,15 @@ fn operate(value: Value, target: i64, head: Span) -> Value {
val: val & target,
span,
},
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value,
other => Value::Error {
error: ShellError::UnsupportedInput(
format!(
"Only integer values are supported, input type: {:?}",
other.get_type()
),
other.span().unwrap_or(head),
error: ShellError::OnlySupportsThisInputType(
"integer".into(),
other.get_type().to_string(),
head,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}

View File

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

View File

@ -3,7 +3,7 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value,
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
};
#[derive(Clone)]
@ -16,6 +16,8 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("bits not")
.input_output_types(vec![(Type::Int, Type::Int)])
.vectorizes_over_list(true)
.switch(
"signed",
"always treat input number as a signed number",
@ -44,7 +46,7 @@ impl Command for SubCommand {
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
) -> Result<PipelineData, ShellError> {
let head = call.head;
let signed = call.has_flag("signed");
let number_bytes: Option<Spanned<String>> =
@ -54,11 +56,17 @@ impl Command for SubCommand {
if let Some(val) = number_bytes {
return Err(ShellError::UnsupportedInput(
"Only 1, 2, 4, 8, or 'auto' bytes are supported as word sizes".to_string(),
"value originates from here".to_string(),
head,
val.span,
));
}
}
// This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) {
return Err(ShellError::PipelineEmpty(head));
}
input.map(
move |value| operate(value, head, signed, bytes_len),
engine_state.ctrlc.clone(),
@ -138,14 +146,17 @@ fn operate(value: Value, head: Span, signed: bool, number_size: NumberBytes) ->
Value::Int { val: out_val, span }
}
}
other => Value::Error {
error: ShellError::UnsupportedInput(
format!(
"Only numerical values are supported, input type: {:?}",
other.get_type()
other => match other {
// Propagate errors inside the value
Value::Error { .. } => other,
_ => Value::Error {
error: ShellError::OnlySupportsThisInputType(
"numeric".into(),
other.get_type().to_string(),
head,
other.expect_span(),
),
other.span().unwrap_or(head),
),
},
},
}
}

View File

@ -2,7 +2,7 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
#[derive(Clone)]
@ -15,6 +15,8 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("bits or")
.input_output_types(vec![(Type::Int, Type::Int)])
.vectorizes_over_list(true)
.required(
"target",
SyntaxShape::Int,
@ -37,10 +39,14 @@ impl Command for SubCommand {
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
) -> Result<PipelineData, ShellError> {
let head = call.head;
let target: i64 = call.req(engine_state, stack, 0)?;
// This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) {
return Err(ShellError::PipelineEmpty(head));
}
input.map(
move |value| operate(value, target, head),
engine_state.ctrlc.clone(),
@ -52,10 +58,7 @@ impl Command for SubCommand {
Example {
description: "Apply bits or to two numbers",
example: "2 | bits or 6",
result: Some(Value::Int {
val: 6,
span: Span::test_data(),
}),
result: Some(Value::test_int(6)),
},
Example {
description: "Apply logical or to a list of numbers",
@ -75,13 +78,15 @@ fn operate(value: Value, target: i64, head: Span) -> Value {
val: val | target,
span,
},
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value,
other => Value::Error {
error: ShellError::UnsupportedInput(
format!(
"Only integer values are supported, input type: {:?}",
other.get_type()
),
other.span().unwrap_or(head),
error: ShellError::OnlySupportsThisInputType(
"integer".into(),
other.get_type().to_string(),
head,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}

View File

@ -3,7 +3,7 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value,
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
};
use num_traits::int::PrimInt;
use std::fmt::Display;
@ -18,6 +18,8 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("bits rol")
.input_output_types(vec![(Type::Int, Type::Int)])
.vectorizes_over_list(true)
.required("bits", SyntaxShape::Int, "number of bits to rotate left")
.switch(
"signed",
@ -47,7 +49,7 @@ impl Command for SubCommand {
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
) -> Result<PipelineData, ShellError> {
let head = call.head;
let bits: usize = call.req(engine_state, stack, 0)?;
let signed = call.has_flag("signed");
@ -58,11 +60,16 @@ impl Command for SubCommand {
if let Some(val) = number_bytes {
return Err(ShellError::UnsupportedInput(
"Only 1, 2, 4, 8, or 'auto' bytes are supported as word sizes".to_string(),
"value originates from here".to_string(),
head,
val.span,
));
}
}
// This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) {
return Err(ShellError::PipelineEmpty(head));
}
input.map(
move |value| operate(value, bits, head, signed, bytes_len),
engine_state.ctrlc.clone(),
@ -74,10 +81,7 @@ impl Command for SubCommand {
Example {
description: "Rotate left a number with 2 bits",
example: "17 | bits rol 2",
result: Some(Value::Int {
val: 68,
span: Span::test_data(),
}),
result: Some(Value::test_int(68)),
},
Example {
description: "Rotate left a list of numbers with 2 bits",
@ -102,8 +106,7 @@ where
error: ShellError::GenericError(
"Rotate left result beyond the range of 64 bit signed number".to_string(),
format!(
"{} of the specified number of bytes rotate left {} bits exceed limit",
val, bits
"{val} of the specified number of bytes rotate left {bits} bits exceed limit"
),
Some(span),
None,
@ -128,16 +131,18 @@ fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: Num
SignedOne => get_rotate_left(val as i8, bits, span),
SignedTwo => get_rotate_left(val as i16, bits, span),
SignedFour => get_rotate_left(val as i32, bits, span),
SignedEight => get_rotate_left(val as i64, bits, span),
SignedEight => get_rotate_left(val, bits, span),
}
}
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value,
other => Value::Error {
error: ShellError::UnsupportedInput(
format!(
"Only integer values are supported, input type: {:?}",
other.get_type()
),
other.span().unwrap_or(head),
error: ShellError::OnlySupportsThisInputType(
"integer".into(),
other.get_type().to_string(),
head,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}

View File

@ -3,7 +3,7 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value,
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
};
use num_traits::int::PrimInt;
use std::fmt::Display;
@ -18,6 +18,8 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("bits ror")
.input_output_types(vec![(Type::Int, Type::Int)])
.vectorizes_over_list(true)
.required("bits", SyntaxShape::Int, "number of bits to rotate right")
.switch(
"signed",
@ -47,7 +49,7 @@ impl Command for SubCommand {
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
) -> Result<PipelineData, ShellError> {
let head = call.head;
let bits: usize = call.req(engine_state, stack, 0)?;
let signed = call.has_flag("signed");
@ -58,11 +60,16 @@ impl Command for SubCommand {
if let Some(val) = number_bytes {
return Err(ShellError::UnsupportedInput(
"Only 1, 2, 4, 8, or 'auto' bytes are supported as word sizes".to_string(),
"value originates from here".to_string(),
head,
val.span,
));
}
}
// This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) {
return Err(ShellError::PipelineEmpty(head));
}
input.map(
move |value| operate(value, bits, head, signed, bytes_len),
engine_state.ctrlc.clone(),
@ -74,10 +81,7 @@ impl Command for SubCommand {
Example {
description: "Rotate right a number with 60 bits",
example: "17 | bits ror 60",
result: Some(Value::Int {
val: 272,
span: Span::test_data(),
}),
result: Some(Value::test_int(272)),
},
Example {
description: "Rotate right a list of numbers of one byte",
@ -106,8 +110,7 @@ where
error: ShellError::GenericError(
"Rotate right result beyond the range of 64 bit signed number".to_string(),
format!(
"{} of the specified number of bytes rotate right {} bits exceed limit",
val, bits
"{val} of the specified number of bytes rotate right {bits} bits exceed limit"
),
Some(span),
None,
@ -132,16 +135,18 @@ fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: Num
SignedOne => get_rotate_right(val as i8, bits, span),
SignedTwo => get_rotate_right(val as i16, bits, span),
SignedFour => get_rotate_right(val as i32, bits, span),
SignedEight => get_rotate_right(val as i64, bits, span),
SignedEight => get_rotate_right(val, bits, span),
}
}
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value,
other => Value::Error {
error: ShellError::UnsupportedInput(
format!(
"Only integer values are supported, input type: {:?}",
other.get_type()
),
other.span().unwrap_or(head),
error: ShellError::OnlySupportsThisInputType(
"integer".into(),
other.get_type().to_string(),
head,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}

View File

@ -3,7 +3,7 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value,
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
};
use num_traits::CheckedShl;
use std::fmt::Display;
@ -18,6 +18,8 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("bits shl")
.input_output_types(vec![(Type::Int, Type::Int)])
.vectorizes_over_list(true)
.required("bits", SyntaxShape::Int, "number of bits to shift left")
.switch(
"signed",
@ -47,7 +49,7 @@ impl Command for SubCommand {
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
) -> Result<PipelineData, ShellError> {
let head = call.head;
let bits: usize = call.req(engine_state, stack, 0)?;
let signed = call.has_flag("signed");
@ -58,11 +60,16 @@ impl Command for SubCommand {
if let Some(val) = number_bytes {
return Err(ShellError::UnsupportedInput(
"Only 1, 2, 4, 8, or 'auto' bytes are supported as word sizes".to_string(),
"value originates from here".to_string(),
head,
val.span,
));
}
}
// This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) {
return Err(ShellError::PipelineEmpty(head));
}
input.map(
move |value| operate(value, bits, head, signed, bytes_len),
engine_state.ctrlc.clone(),
@ -74,26 +81,17 @@ impl Command for SubCommand {
Example {
description: "Shift left a number by 7 bits",
example: "2 | bits shl 7",
result: Some(Value::Int {
val: 256,
span: Span::test_data(),
}),
result: Some(Value::test_int(256)),
},
Example {
description: "Shift left a number with 1 byte by 7 bits",
example: "2 | bits shl 7 -n 1",
result: Some(Value::Int {
val: 0,
span: Span::test_data(),
}),
result: Some(Value::test_int(0)),
},
Example {
description: "Shift left a signed number by 1 bit",
example: "0x7F | bits shl 1 -s",
result: Some(Value::Int {
val: 254,
span: Span::test_data(),
}),
result: Some(Value::test_int(254)),
},
Example {
description: "Shift left a list of numbers",
@ -120,8 +118,7 @@ where
error: ShellError::GenericError(
"Shift left result beyond the range of 64 bit signed number".to_string(),
format!(
"{} of the specified number of bytes shift left {} bits exceed limit",
val, bits
"{val} of the specified number of bytes shift left {bits} bits exceed limit"
),
Some(span),
None,
@ -133,10 +130,7 @@ where
None => Value::Error {
error: ShellError::GenericError(
"Shift left failed".to_string(),
format!(
"{} shift left {} bits failed, you may shift too many bits",
val, bits
),
format!("{val} shift left {bits} bits failed, you may shift too many bits"),
Some(span),
None,
Vec::new(),
@ -160,16 +154,18 @@ fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: Num
SignedOne => get_shift_left(val as i8, bits, span),
SignedTwo => get_shift_left(val as i16, bits, span),
SignedFour => get_shift_left(val as i32, bits, span),
SignedEight => get_shift_left(val as i64, bits, span),
SignedEight => get_shift_left(val, bits, span),
}
}
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value,
other => Value::Error {
error: ShellError::UnsupportedInput(
format!(
"Only integer values are supported, input type: {:?}",
other.get_type()
),
other.span().unwrap_or(head),
error: ShellError::OnlySupportsThisInputType(
"integer".into(),
other.get_type().to_string(),
head,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}

View File

@ -3,7 +3,7 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value,
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
};
use num_traits::CheckedShr;
use std::fmt::Display;
@ -18,6 +18,8 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("bits shr")
.input_output_types(vec![(Type::Int, Type::Int)])
.vectorizes_over_list(true)
.required("bits", SyntaxShape::Int, "number of bits to shift right")
.switch(
"signed",
@ -47,7 +49,7 @@ impl Command for SubCommand {
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
) -> Result<PipelineData, ShellError> {
let head = call.head;
let bits: usize = call.req(engine_state, stack, 0)?;
let signed = call.has_flag("signed");
@ -58,11 +60,16 @@ impl Command for SubCommand {
if let Some(val) = number_bytes {
return Err(ShellError::UnsupportedInput(
"Only 1, 2, 4, 8, or 'auto' bytes are supported as word sizes".to_string(),
"value originates from here".to_string(),
head,
val.span,
));
}
}
// This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) {
return Err(ShellError::PipelineEmpty(head));
}
input.map(
move |value| operate(value, bits, head, signed, bytes_len),
engine_state.ctrlc.clone(),
@ -74,10 +81,7 @@ impl Command for SubCommand {
Example {
description: "Shift right a number with 2 bits",
example: "8 | bits shr 2",
result: Some(Value::Int {
val: 2,
span: Span::test_data(),
}),
result: Some(Value::test_int(2)),
},
Example {
description: "Shift right a list of numbers",
@ -104,8 +108,7 @@ where
error: ShellError::GenericError(
"Shift right result beyond the range of 64 bit signed number".to_string(),
format!(
"{} of the specified number of bytes shift right {} bits exceed limit",
val, bits
"{val} of the specified number of bytes shift right {bits} bits exceed limit"
),
Some(span),
None,
@ -117,10 +120,7 @@ where
None => Value::Error {
error: ShellError::GenericError(
"Shift right failed".to_string(),
format!(
"{} shift right {} bits failed, you may shift too many bits",
val, bits
),
format!("{val} shift right {bits} bits failed, you may shift too many bits"),
Some(span),
None,
Vec::new(),
@ -144,16 +144,18 @@ fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: Num
SignedOne => get_shift_right(val as i8, bits, span),
SignedTwo => get_shift_right(val as i16, bits, span),
SignedFour => get_shift_right(val as i32, bits, span),
SignedEight => get_shift_right(val as i64, bits, span),
SignedEight => get_shift_right(val, bits, span),
}
}
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value,
other => Value::Error {
error: ShellError::UnsupportedInput(
format!(
"Only integer values are supported, input type: {:?}",
other.get_type()
),
other.span().unwrap_or(head),
error: ShellError::OnlySupportsThisInputType(
"integer".into(),
other.get_type().to_string(),
head,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}

View File

@ -2,7 +2,7 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
#[derive(Clone)]
@ -15,6 +15,8 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("bits xor")
.input_output_types(vec![(Type::Int, Type::Int)])
.vectorizes_over_list(true)
.required(
"target",
SyntaxShape::Int,
@ -37,10 +39,13 @@ impl Command for SubCommand {
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
) -> Result<PipelineData, ShellError> {
let head = call.head;
let target: i64 = call.req(engine_state, stack, 0)?;
// This doesn't match explicit nulls
if matches!(input, PipelineData::Empty) {
return Err(ShellError::PipelineEmpty(head));
}
input.map(
move |value| operate(value, target, head),
engine_state.ctrlc.clone(),
@ -52,10 +57,7 @@ impl Command for SubCommand {
Example {
description: "Apply bits xor to two numbers",
example: "2 | bits xor 2",
result: Some(Value::Int {
val: 0,
span: Span::test_data(),
}),
result: Some(Value::test_int(0)),
},
Example {
description: "Apply logical xor to a list of numbers",
@ -75,13 +77,15 @@ fn operate(value: Value, target: i64, head: Span) -> Value {
val: val ^ target,
span,
},
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => value,
other => Value::Error {
error: ShellError::UnsupportedInput(
format!(
"Only integer values are supported, input type: {:?}",
other.get_type()
),
other.span().unwrap_or(head),
error: ShellError::OnlySupportsThisInputType(
"integer".into(),
other.get_type().to_string(),
head,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}

View File

@ -1,21 +1,21 @@
use super::{operate, BytesArgument};
use crate::input_handler::{operate, CmdArgument};
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::ast::CellPath;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::Category;
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value};
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value};
struct Arguments {
added_data: Vec<u8>,
index: Option<usize>,
end: bool,
column_paths: Option<Vec<CellPath>>,
cell_paths: Option<Vec<CellPath>>,
}
impl BytesArgument for Arguments {
fn take_column_paths(&mut self) -> Option<Vec<CellPath>> {
self.column_paths.take()
impl CmdArgument for Arguments {
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
self.cell_paths.take()
}
}
@ -30,6 +30,8 @@ impl Command for BytesAdd {
fn signature(&self) -> Signature {
Signature::build("bytes add")
.input_output_types(vec![(Type::Binary, Type::Binary)])
.vectorizes_over_list(true)
.required("data", SyntaxShape::Binary, "the binary to add")
.named(
"index",
@ -41,7 +43,7 @@ impl Command for BytesAdd {
.rest(
"rest",
SyntaxShape::CellPath,
"optionally matches prefix of text by column paths",
"for a data structure input, add bytes to the data at the given cell paths",
)
.category(Category::Bytes)
}
@ -62,12 +64,8 @@ impl Command for BytesAdd {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let added_data: Vec<u8> = call.req(engine_state, stack, 0)?;
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
let column_paths = if column_paths.is_empty() {
None
} else {
Some(column_paths)
};
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
let index: Option<usize> = call.get_flag(engine_state, stack, "index")?;
let end = call.has_flag("end");
@ -75,7 +73,7 @@ impl Command for BytesAdd {
added_data,
index,
end,
column_paths,
cell_paths,
};
operate(add, arg, input, call.head, engine_state.ctrlc.clone())
}
@ -118,7 +116,27 @@ impl Command for BytesAdd {
}
}
fn add(input: &[u8], args: &Arguments, span: Span) -> Value {
fn add(val: &Value, args: &Arguments, span: Span) -> Value {
match val {
Value::Binary {
val,
span: val_span,
} => add_impl(val, args, *val_span),
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => val.clone(),
other => Value::Error {
error: ShellError::OnlySupportsThisInputType(
"integer".into(),
other.get_type().to_string(),
span,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}
}
fn add_impl(input: &[u8], args: &Arguments, span: Span) -> Value {
match args.index {
None => {
if args.end {

View File

@ -1,10 +1,10 @@
use super::{operate, BytesArgument};
use crate::input_handler::{operate, CmdArgument};
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::ast::CellPath;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use std::cmp::Ordering;
@ -15,12 +15,12 @@ struct Arguments {
start: isize,
end: isize,
arg_span: Span,
column_paths: Option<Vec<CellPath>>,
cell_paths: Option<Vec<CellPath>>,
}
impl BytesArgument for Arguments {
fn take_column_paths(&mut self) -> Option<Vec<CellPath>> {
self.column_paths.take()
impl CmdArgument for Arguments {
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
self.cell_paths.take()
}
}
@ -30,7 +30,9 @@ fn parse_range(range: Value, head: Span) -> Result<(isize, isize, Span), ShellEr
Value::List { mut vals, span } => {
if vals.len() != 2 {
return Err(ShellError::UnsupportedInput(
"More than two indices given".to_string(),
"More than two indices in range".to_string(),
"value originates from here".to_string(),
head,
span,
));
} else {
@ -38,10 +40,14 @@ fn parse_range(range: Value, head: Span) -> Result<(isize, isize, Span), ShellEr
let end = match end {
Value::Int { val, .. } => val.to_string(),
Value::String { val, .. } => val,
// Explicitly propagate errors instead of dropping them.
Value::Error { error } => return Err(error),
other => {
return Err(ShellError::UnsupportedInput(
"could not perform subbytes. Expecting a string or int".to_string(),
other.span().unwrap_or(head),
"Only string or list<int> ranges are supported".into(),
format!("input type: {:?}", other.get_type()),
head,
other.expect_span(),
))
}
};
@ -49,10 +55,14 @@ fn parse_range(range: Value, head: Span) -> Result<(isize, isize, Span), ShellEr
let start = match start {
Value::Int { val, .. } => val.to_string(),
Value::String { val, .. } => val,
// Explicitly propagate errors instead of dropping them.
Value::Error { error } => return Err(error),
other => {
return Err(ShellError::UnsupportedInput(
"could not perform subbytes. Expecting a string or int".to_string(),
other.span().unwrap_or(head),
"Only string or list<int> ranges are supported".into(),
format!("input type: {:?}", other.get_type()),
head,
other.expect_span(),
))
}
};
@ -60,21 +70,27 @@ fn parse_range(range: Value, head: Span) -> Result<(isize, isize, Span), ShellEr
}
}
Value::String { val, span } => {
let splitted_result = val.split_once(',');
match splitted_result {
let split_result = val.split_once(',');
match split_result {
Some((start, end)) => (start.to_string(), end.to_string(), span),
None => {
return Err(ShellError::UnsupportedInput(
"could not perform subbytes".to_string(),
"with this range".to_string(),
head,
span,
))
}
}
}
// Explicitly propagate errors instead of dropping them.
Value::Error { error } => return Err(error),
other => {
return Err(ShellError::UnsupportedInput(
"could not perform subbytes".to_string(),
other.span().unwrap_or(head),
"with this range".to_string(),
head,
other.expect_span(),
))
}
};
@ -82,28 +98,26 @@ fn parse_range(range: Value, head: Span) -> Result<(isize, isize, Span), ShellEr
let start: isize = if start.is_empty() || start == "_" {
0
} else {
match start.trim().parse() {
Ok(s) => s,
Err(_) => {
return Err(ShellError::UnsupportedInput(
"could not perform subbytes".to_string(),
span,
))
}
}
start.trim().parse().map_err(|_| {
ShellError::UnsupportedInput(
"could not perform subbytes".to_string(),
"with this range".to_string(),
head,
span,
)
})?
};
let end: isize = if end.is_empty() || end == "_" {
isize::max_value()
} else {
match end.trim().parse() {
Ok(s) => s,
Err(_) => {
return Err(ShellError::UnsupportedInput(
"could not perform subbytes".to_string(),
span,
))
}
}
end.trim().parse().map_err(|_| {
ShellError::UnsupportedInput(
"could not perform subbytes".to_string(),
"with this range".to_string(),
head,
span,
)
})?
};
Ok((start, end, span))
}
@ -115,11 +129,13 @@ impl Command for BytesAt {
fn signature(&self) -> Signature {
Signature::build("bytes at")
.input_output_types(vec![(Type::Binary, Type::Binary)])
.vectorizes_over_list(true)
.required("range", SyntaxShape::Any, "the indexes to get bytes")
.rest(
"rest",
SyntaxShape::CellPath,
"optionally get bytes by column paths",
"for a data structure input, get bytes from data at the given cell paths",
)
.category(Category::Bytes)
}
@ -141,17 +157,13 @@ impl Command for BytesAt {
) -> Result<PipelineData, ShellError> {
let range: Value = call.req(engine_state, stack, 0)?;
let (start, end, arg_span) = parse_range(range, call.head)?;
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
let column_paths = if column_paths.is_empty() {
None
} else {
Some(column_paths)
};
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
let arg = Arguments {
start,
end,
arg_span,
column_paths,
cell_paths,
};
operate(at, arg, input, call.head, engine_state.ctrlc.clone())
}
@ -228,7 +240,27 @@ impl Command for BytesAt {
}
}
fn at(input: &[u8], arg: &Arguments, span: Span) -> Value {
fn at(val: &Value, args: &Arguments, span: Span) -> Value {
match val {
Value::Binary {
val,
span: val_span,
} => at_impl(val, args, *val_span),
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => val.clone(),
other => Value::Error {
error: ShellError::OnlySupportsThisInputType(
"integer".into(),
other.get_type().to_string(),
span,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}
}
fn at_impl(input: &[u8], arg: &Arguments, span: Span) -> Value {
let len: isize = input.len() as isize;
let start: isize = if arg.start < 0 {
@ -246,7 +278,7 @@ fn at(input: &[u8], arg: &Arguments, span: Span) -> Value {
match start.cmp(&end) {
Ordering::Equal => Value::Binary { val: vec![], span },
Ordering::Greater => Value::Error {
error: ShellError::UnsupportedInput(
error: ShellError::TypeMismatch(
"End must be greater than or equal to Start".to_string(),
arg.arg_span,
),

View File

@ -3,7 +3,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
Value,
Type, Value,
};
#[derive(Clone)]
@ -24,6 +24,7 @@ impl Command for BytesBuild {
fn signature(&self) -> nu_protocol::Signature {
Signature::build("bytes build")
.input_output_types(vec![(Type::Nothing, Type::Binary)])
.rest("rest", SyntaxShape::Any, "list of bytes")
.category(Category::Bytes)
}
@ -45,16 +46,18 @@ impl Command for BytesBuild {
stack: &mut Stack,
call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
) -> Result<PipelineData, ShellError> {
let mut output = vec![];
for expr in call.positional_iter() {
let val = eval_expression(engine_state, stack, expr)?;
match val {
Value::Binary { mut val, .. } => output.append(&mut val),
// Explicitly propagate errors instead of dropping them.
Value::Error { error } => return Err(error),
other => {
return Err(ShellError::UnsupportedInput(
"only support expression which yields to binary data".to_string(),
other.span().unwrap_or(call.head),
return Err(ShellError::TypeMismatch(
"only binary data arguments are supported".to_string(),
other.expect_span(),
))
}
}

View File

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

View File

@ -3,7 +3,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
Value,
Type, Value,
};
#[derive(Clone, Copy)]
@ -16,6 +16,7 @@ impl Command for BytesCollect {
fn signature(&self) -> Signature {
Signature::build("bytes collect")
.input_output_types(vec![(Type::List(Box::new(Type::Binary)), Type::Binary)])
.optional(
"separator",
SyntaxShape::Binary,
@ -53,14 +54,16 @@ impl Command for BytesCollect {
output_binary.append(&mut work_sep)
}
}
// Explicitly propagate errors instead of dropping them.
Value::Error { error } => return Err(error),
other => {
return Err(ShellError::UnsupportedInput(
format!(
"The element type is {}, this command only works with bytes.",
other.get_type()
),
other.span().unwrap_or(call.head),
))
return Err(ShellError::OnlySupportsThisInputType(
"integer".into(),
other.get_type().to_string(),
call.head,
// This line requires the Value::Error match above.
other.expect_span(),
));
}
}
}

View File

@ -1,19 +1,19 @@
use super::{operate, BytesArgument};
use crate::input_handler::{operate, CmdArgument};
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::ast::CellPath;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::Category;
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value};
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value};
struct Arguments {
pattern: Vec<u8>,
column_paths: Option<Vec<CellPath>>,
cell_paths: Option<Vec<CellPath>>,
}
impl BytesArgument for Arguments {
fn take_column_paths(&mut self) -> Option<Vec<CellPath>> {
self.column_paths.take()
impl CmdArgument for Arguments {
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
self.cell_paths.take()
}
}
@ -28,11 +28,12 @@ impl Command for BytesEndsWith {
fn signature(&self) -> Signature {
Signature::build("bytes ends-with")
.input_output_types(vec![(Type::Binary, Type::Bool)])
.required("pattern", SyntaxShape::Binary, "the pattern to match")
.rest(
"rest",
SyntaxShape::CellPath,
"optionally matches prefix of text by column paths",
"for a data structure input, check if bytes at the given cell paths end with the pattern",
)
.category(Category::Bytes)
}
@ -53,15 +54,11 @@ impl Command for BytesEndsWith {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let pattern: Vec<u8> = call.req(engine_state, stack, 0)?;
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
let column_paths = if column_paths.is_empty() {
None
} else {
Some(column_paths)
};
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
let arg = Arguments {
pattern,
column_paths,
cell_paths,
};
operate(ends_with, arg, input, call.head, engine_state.ctrlc.clone())
}
@ -71,35 +68,39 @@ impl Command for BytesEndsWith {
Example {
description: "Checks if binary ends with `0x[AA]`",
example: "0x[1F FF AA AA] | bytes ends-with 0x[AA]",
result: Some(Value::Bool {
val: true,
span: Span::test_data(),
}),
result: Some(Value::test_bool(true)),
},
Example {
description: "Checks if binary ends with `0x[FF AA AA]`",
example: "0x[1F FF AA AA] | bytes ends-with 0x[FF AA AA]",
result: Some(Value::Bool {
val: true,
span: Span::test_data(),
}),
result: Some(Value::test_bool(true)),
},
Example {
description: "Checks if binary ends with `0x[11]`",
example: "0x[1F FF AA AA] | bytes ends-with 0x[11]",
result: Some(Value::Bool {
val: false,
span: Span::test_data(),
}),
result: Some(Value::test_bool(false)),
},
]
}
}
fn ends_with(input: &[u8], Arguments { pattern, .. }: &Arguments, span: Span) -> Value {
Value::Bool {
val: input.ends_with(pattern),
span,
fn ends_with(val: &Value, args: &Arguments, span: Span) -> Value {
match val {
Value::Binary {
val,
span: val_span,
} => Value::boolean(val.ends_with(&args.pattern), *val_span),
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => val.clone(),
other => Value::Error {
error: ShellError::OnlySupportsThisInputType(
"binary".into(),
other.get_type().to_string(),
span,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}
}

View File

@ -1,21 +1,21 @@
use super::{operate, BytesArgument};
use crate::input_handler::{operate, CmdArgument};
use nu_engine::CallExt;
use nu_protocol::ast::{Call, CellPath};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
struct Arguments {
pattern: Vec<u8>,
end: bool,
all: bool,
column_paths: Option<Vec<CellPath>>,
cell_paths: Option<Vec<CellPath>>,
}
impl BytesArgument for Arguments {
fn take_column_paths(&mut self) -> Option<Vec<CellPath>> {
self.column_paths.take()
impl CmdArgument for Arguments {
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
self.cell_paths.take()
}
}
@ -29,6 +29,10 @@ impl Command for BytesIndexOf {
fn signature(&self) -> Signature {
Signature::build("bytes index-of")
.input_output_types(vec![
(Type::Binary, Type::Int),
(Type::Binary, Type::List(Box::new(Type::Int))),
])
.required(
"pattern",
SyntaxShape::Binary,
@ -37,7 +41,7 @@ impl Command for BytesIndexOf {
.rest(
"rest",
SyntaxShape::CellPath,
"optionally returns index of pattern in string by column paths",
"for a data structure input, find the indexes at the given cell paths",
)
.switch("all", "returns all matched index", Some('a'))
.switch("end", "search from the end of the binary", Some('e'))
@ -60,17 +64,13 @@ impl Command for BytesIndexOf {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let pattern: Vec<u8> = call.req(engine_state, stack, 0)?;
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
let column_paths = if column_paths.is_empty() {
None
} else {
Some(column_paths)
};
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
let arg = Arguments {
pattern,
end: call.has_flag("end"),
all: call.has_flag("all"),
column_paths,
cell_paths,
};
operate(index_of, arg, input, call.head, engine_state.ctrlc.clone())
}
@ -126,7 +126,27 @@ impl Command for BytesIndexOf {
}
}
fn index_of(input: &[u8], arg: &Arguments, span: Span) -> Value {
fn index_of(val: &Value, args: &Arguments, span: Span) -> Value {
match val {
Value::Binary {
val,
span: val_span,
} => index_of_impl(val, args, *val_span),
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => val.clone(),
other => Value::Error {
error: ShellError::OnlySupportsThisInputType(
"binary".into(),
other.get_type().to_string(),
span,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}
}
fn index_of_impl(input: &[u8], arg: &Arguments, span: Span) -> Value {
if arg.all {
search_all_index(input, &arg.pattern, arg.end, span)
} else {

View File

@ -1,24 +1,14 @@
use super::{operate, BytesArgument};
use crate::input_handler::{operate, CellPathOnlyArgs};
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::ast::CellPath;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::Category;
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value};
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value};
#[derive(Clone)]
pub struct BytesLen;
struct Arguments {
column_paths: Option<Vec<CellPath>>,
}
impl BytesArgument for Arguments {
fn take_column_paths(&mut self) -> Option<Vec<CellPath>> {
self.column_paths.take()
}
}
impl Command for BytesLen {
fn name(&self) -> &str {
"bytes length"
@ -26,10 +16,12 @@ impl Command for BytesLen {
fn signature(&self) -> Signature {
Signature::build("bytes length")
.input_output_types(vec![(Type::Binary, Type::Int)])
.vectorizes_over_list(true)
.rest(
"rest",
SyntaxShape::CellPath,
"optionally find length of binary by column paths",
"for a data structure input, find the length of data at the given cell paths",
)
.category(Category::Bytes)
}
@ -49,13 +41,8 @@ impl Command for BytesLen {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
let column_paths = if column_paths.is_empty() {
None
} else {
Some(column_paths)
};
let arg = Arguments { column_paths };
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
let arg = CellPathOnlyArgs::from(cell_paths);
operate(length, arg, input, call.head, engine_state.ctrlc.clone())
}
@ -78,10 +65,23 @@ impl Command for BytesLen {
}
}
fn length(input: &[u8], _arg: &Arguments, span: Span) -> Value {
Value::Int {
val: input.len() as i64,
span,
fn length(val: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
match val {
Value::Binary {
val,
span: val_span,
} => Value::int(val.len() as i64, *val_span),
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => val.clone(),
other => Value::Error {
error: ShellError::OnlySupportsThisInputType(
"binary".into(),
other.get_type().to_string(),
span,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}
}

View File

@ -11,11 +11,6 @@ mod replace;
mod reverse;
mod starts_with;
use nu_protocol::ast::CellPath;
use nu_protocol::{PipelineData, ShellError, Span, Value};
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
pub use add::BytesAdd;
pub use at::BytesAt;
pub use build_::BytesBuild;
@ -28,71 +23,3 @@ pub use remove::BytesRemove;
pub use replace::BytesReplace;
pub use reverse::BytesReverse;
pub use starts_with::BytesStartsWith;
trait BytesArgument {
fn take_column_paths(&mut self) -> Option<Vec<CellPath>>;
}
/// map input pipeline data, for each elements, if it's Binary, invoke relative `cmd` with `arg`.
fn operate<C, A>(
cmd: C,
mut arg: A,
input: PipelineData,
span: Span,
ctrlc: Option<Arc<AtomicBool>>,
) -> Result<PipelineData, ShellError>
where
A: BytesArgument + Send + Sync + 'static,
C: Fn(&[u8], &A, Span) -> Value + Send + Sync + 'static + Clone + Copy,
{
match arg.take_column_paths() {
None => input.map(
move |v| match v {
Value::Binary {
val,
span: val_span,
} => cmd(&val, &arg, val_span),
other => Value::Error {
error: ShellError::UnsupportedInput(
format!(
"Input's type is {}. This command only works with bytes.",
other.get_type()
),
span,
),
},
},
ctrlc,
),
Some(column_paths) => {
let arg = Arc::new(arg);
input.map(
move |mut v| {
for path in &column_paths {
let opt = arg.clone();
let r = v.update_cell_path(
&path.members,
Box::new(move |old| {
match old {
Value::Binary {val, span: val_span} => cmd(val, &opt, *val_span),
other => Value::Error {
error: ShellError::UnsupportedInput(
format!(
"Input's type is {}. This command only works with bytes.",
other.get_type()
),
span,
),
}}}),
);
if let Err(error) = r {
return Value::Error { error };
}
}
v
},
ctrlc,
)
}
}
}

View File

@ -1,21 +1,22 @@
use super::{operate, BytesArgument};
use crate::input_handler::{operate, CmdArgument};
use nu_engine::CallExt;
use nu_protocol::{
ast::{Call, CellPath},
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value,
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type,
Value,
};
struct Arguments {
pattern: Vec<u8>,
end: bool,
column_paths: Option<Vec<CellPath>>,
cell_paths: Option<Vec<CellPath>>,
all: bool,
}
impl BytesArgument for Arguments {
fn take_column_paths(&mut self) -> Option<Vec<CellPath>> {
self.column_paths.take()
impl CmdArgument for Arguments {
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
self.cell_paths.take()
}
}
@ -29,11 +30,12 @@ impl Command for BytesRemove {
fn signature(&self) -> Signature {
Signature::build("bytes remove")
.input_output_types(vec![(Type::Binary, Type::Binary)])
.required("pattern", SyntaxShape::Binary, "the pattern to find")
.rest(
"rest",
SyntaxShape::CellPath,
"optionally remove bytes by column paths",
"for a data structure input, remove bytes from data at the given cell paths",
)
.switch("end", "remove from end of binary", Some('e'))
.switch("all", "remove occurrences of finding binary", Some('a'))
@ -55,15 +57,11 @@ impl Command for BytesRemove {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
let column_paths = if column_paths.is_empty() {
None
} else {
Some(column_paths)
};
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
let pattern_to_remove = call.req::<Spanned<Vec<u8>>>(engine_state, stack, 0)?;
if pattern_to_remove.item.is_empty() {
return Err(ShellError::UnsupportedInput(
return Err(ShellError::TypeMismatch(
"the pattern to remove cannot be empty".to_string(),
pattern_to_remove.span,
));
@ -73,7 +71,7 @@ impl Command for BytesRemove {
let arg = Arguments {
pattern: pattern_to_remove,
end: call.has_flag("end"),
column_paths,
cell_paths,
all: call.has_flag("all"),
};
@ -135,7 +133,27 @@ impl Command for BytesRemove {
}
}
fn remove(input: &[u8], arg: &Arguments, span: Span) -> Value {
fn remove(val: &Value, args: &Arguments, span: Span) -> Value {
match val {
Value::Binary {
val,
span: val_span,
} => remove_impl(val, args, *val_span),
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => val.clone(),
other => Value::Error {
error: ShellError::OnlySupportsThisInputType(
"binary".into(),
other.get_type().to_string(),
span,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}
}
fn remove_impl(input: &[u8], arg: &Arguments, span: Span) -> Value {
let mut result = vec![];
let remove_all = arg.all;
let input_len = input.len();
@ -143,7 +161,7 @@ fn remove(input: &[u8], arg: &Arguments, span: Span) -> Value {
// Note:
// remove_all from start and end will generate the same result.
// so we'll put `remove_all` relative logic into else clouse.
// so we'll put `remove_all` relative logic into else clause.
if arg.end && !remove_all {
let (mut left, mut right) = (
input.len() as isize - arg.pattern.len() as isize,
@ -154,7 +172,7 @@ fn remove(input: &[u8], arg: &Arguments, span: Span) -> Value {
left -= 1;
right -= 1;
}
// append the remaining thing to result, this can be happeneed when
// append the remaining thing to result, this can be happening when
// we have something to remove and remove_all is False.
let mut remain = input[..left as usize].iter().copied().rev().collect();
result.append(&mut remain);
@ -175,7 +193,7 @@ fn remove(input: &[u8], arg: &Arguments, span: Span) -> Value {
right += 1;
}
}
// append the remaing thing to result, this can happened when
// append the remaining thing to result, this can happened when
// we have something to remove and remove_all is False.
let mut remain = input[left..].to_vec();
result.append(&mut remain);

View File

@ -1,21 +1,22 @@
use super::{operate, BytesArgument};
use crate::input_handler::{operate, CmdArgument};
use nu_engine::CallExt;
use nu_protocol::{
ast::{Call, CellPath},
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value,
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type,
Value,
};
struct Arguments {
find: Vec<u8>,
replace: Vec<u8>,
column_paths: Option<Vec<CellPath>>,
cell_paths: Option<Vec<CellPath>>,
all: bool,
}
impl BytesArgument for Arguments {
fn take_column_paths(&mut self) -> Option<Vec<CellPath>> {
self.column_paths.take()
impl CmdArgument for Arguments {
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
self.cell_paths.take()
}
}
@ -29,12 +30,13 @@ impl Command for BytesReplace {
fn signature(&self) -> Signature {
Signature::build("bytes replace")
.input_output_types(vec![(Type::Binary, Type::Binary)])
.required("find", SyntaxShape::Binary, "the pattern to find")
.required("replace", SyntaxShape::Binary, "the replacement pattern")
.rest(
"rest",
SyntaxShape::CellPath,
"optionally find and replace text by column paths",
"for a data structure input, replace bytes in data at the given cell paths",
)
.switch("all", "replace all occurrences of find binary", Some('a'))
.category(Category::Bytes)
@ -55,15 +57,11 @@ impl Command for BytesReplace {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 2)?;
let column_paths = if column_paths.is_empty() {
None
} else {
Some(column_paths)
};
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 2)?;
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
let find = call.req::<Spanned<Vec<u8>>>(engine_state, stack, 0)?;
if find.item.is_empty() {
return Err(ShellError::UnsupportedInput(
return Err(ShellError::TypeMismatch(
"the pattern to find cannot be empty".to_string(),
find.span,
));
@ -72,7 +70,7 @@ impl Command for BytesReplace {
let arg = Arguments {
find: find.item,
replace: call.req::<Vec<u8>>(engine_state, stack, 1)?,
column_paths,
cell_paths,
all: call.has_flag("all"),
};
@ -126,7 +124,27 @@ impl Command for BytesReplace {
}
}
fn replace(input: &[u8], arg: &Arguments, span: Span) -> Value {
fn replace(val: &Value, args: &Arguments, span: Span) -> Value {
match val {
Value::Binary {
val,
span: val_span,
} => replace_impl(val, args, *val_span),
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => val.clone(),
other => Value::Error {
error: ShellError::OnlySupportsThisInputType(
"binary".into(),
other.get_type().to_string(),
span,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}
}
fn replace_impl(input: &[u8], arg: &Arguments, span: Span) -> Value {
let mut replaced = vec![];
let replace_all = arg.all;

View File

@ -1,20 +1,10 @@
use super::{operate, BytesArgument};
use crate::input_handler::{operate, CellPathOnlyArgs};
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::ast::CellPath;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::Category;
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value};
struct Arguments {
column_paths: Option<Vec<CellPath>>,
}
impl BytesArgument for Arguments {
fn take_column_paths(&mut self) -> Option<Vec<CellPath>> {
self.column_paths.take()
}
}
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value};
#[derive(Clone)]
@ -27,16 +17,17 @@ impl Command for BytesReverse {
fn signature(&self) -> Signature {
Signature::build("bytes reverse")
.input_output_types(vec![(Type::Binary, Type::Binary)])
.rest(
"rest",
SyntaxShape::CellPath,
"optionally matches prefix of text by column paths",
"for a data structure input, reverse data at the given cell paths",
)
.category(Category::Bytes)
}
fn usage(&self) -> &str {
"Reverse every bytes in the pipeline"
"Reverse the bytes in the pipeline"
}
fn search_terms(&self) -> Vec<&str> {
@ -50,13 +41,8 @@ impl Command for BytesReverse {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
let column_paths = if column_paths.is_empty() {
None
} else {
Some(column_paths)
};
let arg = Arguments { column_paths };
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
let arg = CellPathOnlyArgs::from(cell_paths);
operate(reverse, arg, input, call.head, engine_state.ctrlc.clone())
}
@ -82,12 +68,30 @@ impl Command for BytesReverse {
}
}
fn reverse(input: &[u8], _args: &Arguments, span: Span) -> Value {
let mut reversed_input = input.to_vec();
reversed_input.reverse();
Value::Binary {
val: reversed_input,
span,
fn reverse(val: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
match val {
Value::Binary {
val,
span: val_span,
} => {
let mut reversed_input = val.to_vec();
reversed_input.reverse();
Value::Binary {
val: reversed_input,
span: *val_span,
}
}
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => val.clone(),
other => Value::Error {
error: ShellError::OnlySupportsThisInputType(
"binary".into(),
other.get_type().to_string(),
span,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}
}

View File

@ -1,19 +1,19 @@
use super::{operate, BytesArgument};
use crate::input_handler::{operate, CmdArgument};
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::ast::CellPath;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::Category;
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value};
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value};
struct Arguments {
pattern: Vec<u8>,
column_paths: Option<Vec<CellPath>>,
cell_paths: Option<Vec<CellPath>>,
}
impl BytesArgument for Arguments {
fn take_column_paths(&mut self) -> Option<Vec<CellPath>> {
self.column_paths.take()
impl CmdArgument for Arguments {
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
self.cell_paths.take()
}
}
@ -28,11 +28,12 @@ impl Command for BytesStartsWith {
fn signature(&self) -> Signature {
Signature::build("bytes starts-with")
.input_output_types(vec![(Type::Binary, Type::Bool)])
.required("pattern", SyntaxShape::Binary, "the pattern to match")
.rest(
"rest",
SyntaxShape::CellPath,
"optionally matches prefix of text by column paths",
"for a data structure input, check if bytes at the given cell paths start with the pattern",
)
.category(Category::Bytes)
}
@ -53,15 +54,11 @@ impl Command for BytesStartsWith {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let pattern: Vec<u8> = call.req(engine_state, stack, 0)?;
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
let column_paths = if column_paths.is_empty() {
None
} else {
Some(column_paths)
};
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
let arg = Arguments {
pattern,
column_paths,
cell_paths,
};
operate(
starts_with,
@ -77,35 +74,39 @@ impl Command for BytesStartsWith {
Example {
description: "Checks if binary starts with `0x[1F FF AA]`",
example: "0x[1F FF AA AA] | bytes starts-with 0x[1F FF AA]",
result: Some(Value::Bool {
val: true,
span: Span::test_data(),
}),
result: Some(Value::test_bool(true)),
},
Example {
description: "Checks if binary starts with `0x[1F]`",
example: "0x[1F FF AA AA] | bytes starts-with 0x[1F]",
result: Some(Value::Bool {
val: true,
span: Span::test_data(),
}),
result: Some(Value::test_bool(true)),
},
Example {
description: "Checks if binary starts with `0x[1F]`",
example: "0x[1F FF AA AA] | bytes starts-with 0x[11]",
result: Some(Value::Bool {
val: false,
span: Span::test_data(),
}),
result: Some(Value::test_bool(false)),
},
]
}
}
fn starts_with(input: &[u8], Arguments { pattern, .. }: &Arguments, span: Span) -> Value {
Value::Bool {
val: input.starts_with(pattern),
span,
fn starts_with(val: &Value, args: &Arguments, span: Span) -> Value {
match val {
Value::Binary {
val,
span: val_span,
} => Value::boolean(val.starts_with(&args.pattern), *val_span),
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => val.clone(),
other => Value::Error {
error: ShellError::OnlySupportsThisInputType(
"binary".into(),
other.get_type().to_string(),
span,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}
}

View File

@ -13,7 +13,7 @@ use std::hash::{Hash, Hasher};
/// ```text
/// assert_eq!(HashableValue::Bool {val: true, span: Span{start: 0, end: 1}}, HashableValue::Bool {val: true, span: Span{start: 90, end: 1000}})
/// ```
#[derive(Eq, Debug)]
#[derive(Eq, Debug, Ord, PartialOrd)]
pub enum HashableValue {
Bool {
val: bool,
@ -53,7 +53,7 @@ impl Default for HashableValue {
fn default() -> Self {
HashableValue::Bool {
val: false,
span: Span { start: 0, end: 0 },
span: Span::unknown(),
}
}
}
@ -78,13 +78,14 @@ impl HashableValue {
Value::String { val, span } => Ok(HashableValue::String { val, span }),
Value::Binary { val, span } => Ok(HashableValue::Binary { val, span }),
_ => {
let input_span = value.span().unwrap_or(span);
Err(ShellError::UnsupportedInput(
format!("input value {value:?} is not hashable"),
input_span,
))
}
// Explicitly propagate errors instead of dropping them.
Value::Error { error } => Err(error),
_ => Err(ShellError::UnsupportedInput(
"input value is not hashable".into(),
format!("input type: {:?}", value.get_type()),
span,
value.expect_span(),
)),
}
}
@ -214,7 +215,7 @@ mod test {
];
for (val, expect_hashable_val) in values.into_iter() {
assert_eq!(
HashableValue::from_value(val, Span { start: 0, end: 0 }).unwrap(),
HashableValue::from_value(val, Span::unknown()).unwrap(),
expect_hashable_val
);
}
@ -228,7 +229,7 @@ mod test {
vals: vec![Value::Bool { val: true, span }],
span,
},
Value::Block {
Value::Closure {
val: 0,
captures: HashMap::new(),
span,
@ -245,7 +246,7 @@ mod test {
},
];
for v in values {
assert!(HashableValue::from_value(v, Span { start: 0, end: 0 }).is_err())
assert!(HashableValue::from_value(v, Span::unknown()).is_err())
}
}
@ -266,7 +267,7 @@ mod test {
for val in values.into_iter() {
let expected_val = val.clone();
assert_eq!(
HashableValue::from_value(val, Span { start: 0, end: 0 })
HashableValue::from_value(val, Span::unknown())
.unwrap()
.into_value(),
expected_val
@ -279,14 +280,11 @@ mod test {
assert_eq!(
HashableValue::Bool {
val: true,
span: Span { start: 0, end: 1 }
span: Span::new(0, 1)
},
HashableValue::Bool {
val: true,
span: Span {
start: 90,
end: 1000
}
span: Span::new(90, 1000)
}
)
}
@ -299,7 +297,7 @@ mod test {
assert!(set.contains(&HashableValue::Bool { val: true, span }));
// hashable value doesn't care about span.
let diff_span = Span { start: 1, end: 2 };
let diff_span = Span::new(1, 2);
set.insert(HashableValue::Bool {
val: true,
span: diff_span,

View File

@ -1,10 +1,11 @@
use super::hashable_value::HashableValue;
use itertools::Itertools;
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape,
Value,
Type, Value,
};
use std::collections::HashMap;
use std::iter;
@ -24,6 +25,7 @@ impl Command for Histogram {
fn signature(&self) -> Signature {
Signature::build("histogram")
.input_output_types(vec![(Type::List(Box::new(Type::Any)), Type::Table(vec![])),])
.optional("column-name", SyntaxShape::String, "column name to calc frequency, no need to provide if input is just a list")
.optional("frequency-column-name", SyntaxShape::String, "histogram's frequency column, default to be frequency column output")
.named("percentage-type", SyntaxShape::String, "percentage calculate method, can be 'normalize' or 'relative', in 'normalize', defaults to be 'normalize'", Some('t'))
@ -36,24 +38,49 @@ impl Command for Histogram {
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "Get a histogram for the types of files",
description: "Compute a histogram of file types",
example: "ls | histogram type",
result: None,
},
Example {
description:
"Get a histogram for the types of files, with frequency column named freq",
"Compute a histogram for the types of files, with frequency column named freq",
example: "ls | histogram type freq",
result: None,
},
Example {
description: "Get a histogram for a list of numbers",
example: "echo [1 2 3 1 1 1 2 2 1 1] | histogram",
result: None,
description: "Compute a histogram for a list of numbers",
example: "[1 2 1] | histogram",
result: Some(Value::List {
vals: vec![Value::Record {
cols: vec!["value".to_string(), "count".to_string(), "quantile".to_string(), "percentage".to_string(), "frequency".to_string()],
vals: vec![
Value::test_int(1),
Value::test_int(2),
Value::test_float(0.6666666666666666),
Value::test_string("66.67%"),
Value::test_string("******************************************************************"),
],
span: Span::test_data(),
},
Value::Record {
cols: vec!["value".to_string(), "count".to_string(), "quantile".to_string(), "percentage".to_string(), "frequency".to_string()],
vals: vec![
Value::test_int(2),
Value::test_int(1),
Value::test_float(0.3333333333333333),
Value::test_string("33.33%"),
Value::test_string("*********************************"),
],
span: Span::test_data(),
}],
span: Span::test_data(),
}
),
},
Example {
description: "Get a histogram for a list of numbers, and percentage is based on the maximum value",
example: "echo [1 2 3 1 1 1 2 2 1 1] | histogram --percentage-type relative",
description: "Compute a histogram for a list of numbers, and percentage is based on the maximum value",
example: "[1 2 3 1 1 1 2 2 1 1] | histogram --percentage-type relative",
result: None,
}
]
@ -71,12 +98,11 @@ impl Command for Histogram {
let frequency_name_arg = call.opt::<Spanned<String>>(engine_state, stack, 1)?;
let frequency_column_name = match frequency_name_arg {
Some(inner) => {
let span = inner.span;
if ["value", "count", "quantile", "percentage"].contains(&inner.item.as_str()) {
return Err(ShellError::UnsupportedInput(
return Err(ShellError::TypeMismatch(
"frequency-column-name can't be 'value', 'count' or 'percentage'"
.to_string(),
span,
inner.span,
));
}
inner.item
@ -92,7 +118,7 @@ impl Command for Histogram {
"normalize" => PercentageCalcMethod::Normalize,
"relative" => PercentageCalcMethod::Relative,
_ => {
return Err(ShellError::UnsupportedInput(
return Err(ShellError::TypeMismatch(
"calc method can only be 'normalize' or 'relative'".to_string(),
inner.span,
))
@ -103,16 +129,15 @@ impl Command for Histogram {
let span = call.head;
let data_as_value = input.into_value(span);
// `input` is not a list, here we can return an error.
match data_as_value.as_list() {
Ok(list_value) => run_histogram(
list_value.to_vec(),
column_name,
frequency_column_name,
calc_method,
span,
),
Err(e) => Err(e),
}
run_histogram(
data_as_value.as_list()?.to_vec(),
column_name,
frequency_column_name,
calc_method,
span,
// Note that as_list() filters out Value::Error here.
data_as_value.expect_span(),
)
}
}
@ -122,6 +147,7 @@ fn run_histogram(
freq_column: String,
calc_method: PercentageCalcMethod,
head_span: Span,
list_span: Span,
) -> Result<PipelineData, ShellError> {
let mut inputs = vec![];
// convert from inputs to hashable values.
@ -130,14 +156,24 @@ fn run_histogram(
// some invalid input scenario needs to handle:
// Expect input is a list of hashable value, if one value is not hashable, throw out error.
for v in values {
let current_span = v.span().unwrap_or(head_span);
inputs.push(HashableValue::from_value(v, head_span).map_err(|_| {
ShellError::UnsupportedInput(
"--column-name is not provided, can only support a list of simple value."
.to_string(),
current_span,
)
})?);
match v {
// Propagate existing errors.
Value::Error { error } => return Err(error),
_ => {
let t = v.get_type();
let span = v.expect_span();
inputs.push(HashableValue::from_value(v, head_span).map_err(|_| {
ShellError::UnsupportedInput(
"Since --column-name was not provided, only lists of hashable values are supported.".to_string(),
format!(
"input type: {t:?}"
),
head_span,
span,
)
})?)
}
}
}
}
Some(ref col) => {
@ -159,14 +195,17 @@ fn run_histogram(
}
}
}
// Propagate existing errors.
Value::Error { error } => return Err(error),
_ => continue,
}
}
if inputs.is_empty() {
return Err(ShellError::UnsupportedInput(
format!("expect input is table, and inputs doesn't contain any value which has {col_name} column"),
return Err(ShellError::CantFindColumn(
col_name.clone(),
head_span,
list_span,
));
}
}
@ -213,7 +252,7 @@ fn histogram_impl(
freq_column.to_string(),
];
const MAX_FREQ_COUNT: f64 = 100.0;
for (val, count) in counter.into_iter() {
for (val, count) in counter.into_iter().sorted() {
let quantile = match calc_method {
PercentageCalcMethod::Normalize => count as f64 / total_cnt as f64,
PercentageCalcMethod::Relative => count as f64 / max_cnt as f64,
@ -222,25 +261,33 @@ fn histogram_impl(
let percentage = format!("{:.2}%", quantile * 100_f64);
let freq = "*".repeat((MAX_FREQ_COUNT * quantile).floor() as usize);
result.push(Value::Record {
cols: result_cols.clone(),
vals: vec![
val.into_value(),
Value::Int { val: count, span },
Value::Float {
val: quantile,
span,
},
Value::String {
val: percentage,
span,
},
Value::String { val: freq, span },
],
span,
});
result.push((
count, // attach count first for easily sorting.
Value::Record {
cols: result_cols.clone(),
vals: vec![
val.into_value(),
Value::Int { val: count, span },
Value::Float {
val: quantile,
span,
},
Value::String {
val: percentage,
span,
},
Value::String { val: freq, span },
],
span,
},
));
}
Value::List { vals: result, span }.into_pipeline_data()
result.sort_by(|a, b| b.0.cmp(&a.0));
Value::List {
vals: result.into_iter().map(|x| x.1).collect(),
span,
}
.into_pipeline_data()
}
#[cfg(test)]

View File

@ -0,0 +1,269 @@
use crate::input_handler::{operate, CmdArgument};
use nu_engine::CallExt;
use nu_protocol::{
ast::{Call, CellPath},
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
use print_positions::print_positions;
#[derive(Clone)]
pub struct Fill;
struct Arguments {
width: usize,
alignment: FillAlignment,
character: String,
cell_paths: Option<Vec<CellPath>>,
}
impl CmdArgument for Arguments {
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
self.cell_paths.take()
}
}
#[derive(Clone, Copy)]
enum FillAlignment {
Left,
Right,
Middle,
MiddleRight,
}
impl Command for Fill {
fn name(&self) -> &str {
"fill"
}
fn usage(&self) -> &str {
"Fill and Align"
}
fn signature(&self) -> nu_protocol::Signature {
Signature::build("fill")
.input_output_types(vec![
(Type::Int, Type::String),
(Type::Float, Type::String),
(Type::String, Type::String),
(Type::Filesize, Type::String),
])
.vectorizes_over_list(true)
.named(
"width",
SyntaxShape::Int,
"The width of the output. Defaults to 1",
Some('w'),
)
.named(
"alignment",
SyntaxShape::String,
"The alignment of the output. Defaults to Left (Left(l), Right(r), Center(c/m), MiddleRight(cr/mr))",
Some('a'),
)
.named(
"character",
SyntaxShape::String,
"The character to fill with. Defaults to ' ' (space)",
Some('c'),
)
.category(Category::Conversions)
}
fn search_terms(&self) -> Vec<&str> {
vec!["display", "render", "format", "pad", "align"]
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description:
"Fill a string on the left side to a width of 15 with the character '─'",
example: "'nushell' | fill -a l -c '─' -w 15",
result: Some(Value::String {
val: "nushell────────".into(),
span: Span::test_data(),
}),
},
Example {
description:
"Fill a string on the right side to a width of 15 with the character '─'",
example: "'nushell' | fill -a r -c '─' -w 15",
result: Some(Value::String {
val: "────────nushell".into(),
span: Span::test_data(),
}),
},
Example {
description: "Fill a string on both sides to a width of 15 with the character '─'",
example: "'nushell' | fill -a m -c '─' -w 15",
result: Some(Value::String {
val: "────nushell────".into(),
span: Span::test_data(),
}),
},
Example {
description:
"Fill a number on the left side to a width of 5 with the character '0'",
example: "1 | fill --alignment right --character 0 --width 5",
result: Some(Value::String {
val: "00001".into(),
span: Span::test_data(),
}),
},
Example {
description: "Fill a number on both sides to a width of 5 with the character '0'",
example: "1.1 | fill --alignment center --character 0 --width 5",
result: Some(Value::String {
val: "01.10".into(),
span: Span::test_data(),
}),
},
Example {
description:
"Fill a filesize on the left side to a width of 5 with the character '0'",
example: "1kib | fill --alignment middle --character 0 --width 10",
result: Some(Value::String {
val: "0001024000".into(),
span: Span::test_data(),
}),
},
]
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
fill(engine_state, stack, call, input)
}
}
fn fill(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let width_arg: Option<usize> = call.get_flag(engine_state, stack, "width")?;
let alignment_arg: Option<String> = call.get_flag(engine_state, stack, "alignment")?;
let character_arg: Option<String> = call.get_flag(engine_state, stack, "character")?;
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
let alignment = if let Some(arg) = alignment_arg {
match arg.to_lowercase().as_str() {
"l" | "left" => FillAlignment::Left,
"r" | "right" => FillAlignment::Right,
"c" | "center" | "m" | "middle" => FillAlignment::Middle,
"cr" | "centerright" | "mr" | "middleright" => FillAlignment::MiddleRight,
_ => FillAlignment::Left,
}
} else {
FillAlignment::Left
};
let width = if let Some(arg) = width_arg { arg } else { 1 };
let character = if let Some(arg) = character_arg {
arg
} else {
" ".to_string()
};
let arg = Arguments {
width,
alignment,
character,
cell_paths,
};
operate(action, arg, input, call.head, engine_state.ctrlc.clone())
}
fn action(input: &Value, args: &Arguments, span: Span) -> Value {
match input {
Value::Int { val, .. } => fill_int(*val, args, span),
Value::Filesize { val, .. } => fill_int(*val, args, span),
Value::Float { val, .. } => fill_float(*val, args, span),
Value::String { val, .. } => fill_string(val, args, span),
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => input.clone(),
other => Value::Error {
error: ShellError::OnlySupportsThisInputType(
"int, filesize, float, string".into(),
other.get_type().to_string(),
span,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}
}
fn fill_float(num: f64, args: &Arguments, span: Span) -> Value {
let s = num.to_string();
let out_str = pad(&s, args.width, &args.character, args.alignment, false);
Value::String { val: out_str, span }
}
fn fill_int(num: i64, args: &Arguments, span: Span) -> Value {
let s = num.to_string();
let out_str = pad(&s, args.width, &args.character, args.alignment, false);
Value::String { val: out_str, span }
}
fn fill_string(s: &str, args: &Arguments, span: Span) -> Value {
let out_str = pad(s, args.width, &args.character, args.alignment, false);
Value::String { val: out_str, span }
}
fn pad(s: &str, width: usize, pad_char: &str, alignment: FillAlignment, truncate: bool) -> String {
// Attribution: Most of this function was taken from https://github.com/ogham/rust-pad and tweaked. Thank you!
// Use width instead of len for graphical display
let cols = print_positions(s).count();
if cols >= width {
if truncate {
return s[..width].to_string();
} else {
return s.to_string();
}
}
let diff = width - cols;
let (left_pad, right_pad) = match alignment {
FillAlignment::Left => (0, diff),
FillAlignment::Right => (diff, 0),
FillAlignment::Middle => (diff / 2, diff - diff / 2),
FillAlignment::MiddleRight => (diff - diff / 2, diff / 2),
};
let mut new_str = String::new();
for _ in 0..left_pad {
new_str.push_str(pad_char)
}
new_str.push_str(s);
for _ in 0..right_pad {
new_str.push_str(pad_char)
}
new_str
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_examples() {
use crate::test_examples;
test_examples(Fill {})
}
}

View File

@ -1,8 +1,9 @@
use crate::input_handler::{operate, CellPathOnlyArgs};
use nu_engine::CallExt;
use nu_protocol::{
ast::{Call, CellPath},
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Value,
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
};
#[derive(Clone)]
@ -18,7 +19,9 @@ impl Command for Fmt {
}
fn signature(&self) -> nu_protocol::Signature {
Signature::build("fmt").category(Category::Conversions)
Signature::build("fmt")
.input_output_types(vec![(Type::Number, Type::Record(vec![]))])
.category(Category::Conversions)
}
fn search_terms(&self) -> Vec<&str> {
@ -41,38 +44,14 @@ impl Command for Fmt {
"upperhex".into(),
],
vals: vec![
Value::String {
val: "0b101010".to_string(),
span: Span::test_data(),
},
Value::String {
val: "42".to_string(),
span: Span::test_data(),
},
Value::String {
val: "42".to_string(),
span: Span::test_data(),
},
Value::String {
val: "4.2e1".to_string(),
span: Span::test_data(),
},
Value::String {
val: "0x2a".to_string(),
span: Span::test_data(),
},
Value::String {
val: "0o52".to_string(),
span: Span::test_data(),
},
Value::String {
val: "4.2E1".to_string(),
span: Span::test_data(),
},
Value::String {
val: "0x2A".to_string(),
span: Span::test_data(),
},
Value::test_string("0b101010"),
Value::test_string("42"),
Value::test_string("42"),
Value::test_string("4.2e1"),
Value::test_string("0x2a"),
Value::test_string("0o52"),
Value::test_string("4.2E1"),
Value::test_string("0x2A"),
],
span: Span::test_data(),
}),
@ -85,7 +64,7 @@ impl Command for Fmt {
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
) -> Result<PipelineData, ShellError> {
fmt(engine_state, stack, call, input)
}
}
@ -95,39 +74,25 @@ fn fmt(
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let head = call.head;
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
input.map(
move |v| {
if column_paths.is_empty() {
action(&v, head)
} else {
let mut ret = v;
for path in &column_paths {
let r =
ret.update_cell_path(&path.members, Box::new(move |old| action(old, head)));
if let Err(error) = r {
return Value::Error { error };
}
}
ret
}
},
engine_state.ctrlc.clone(),
)
) -> Result<PipelineData, ShellError> {
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
let args = CellPathOnlyArgs::from(cell_paths);
operate(action, args, input, call.head, engine_state.ctrlc.clone())
}
pub fn action(input: &Value, span: Span) -> Value {
fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
match input {
Value::Int { val, .. } => fmt_it(*val, span),
Value::Filesize { val, .. } => fmt_it(*val, span),
_ => Value::Error {
error: ShellError::UnsupportedInput(
format!("unsupported input type: {:?}", input.get_type()),
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => input.clone(),
other => Value::Error {
error: ShellError::OnlySupportsThisInputType(
"integer or filesize".into(),
other.get_type().to_string(),
span,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}
@ -138,31 +103,31 @@ fn fmt_it(num: i64, span: Span) -> Value {
let mut vals = vec![];
cols.push("binary".into());
vals.push(Value::string(format!("{:#b}", num), span));
vals.push(Value::string(format!("{num:#b}"), span));
cols.push("debug".into());
vals.push(Value::string(format!("{:#?}", num), span));
vals.push(Value::string(format!("{num:#?}"), span));
cols.push("display".into());
vals.push(Value::string(format!("{}", num), span));
vals.push(Value::string(format!("{num}"), span));
cols.push("lowerexp".into());
vals.push(Value::string(format!("{:#e}", num), span));
vals.push(Value::string(format!("{num:#e}"), span));
cols.push("lowerhex".into());
vals.push(Value::string(format!("{:#x}", num), span));
vals.push(Value::string(format!("{num:#x}"), span));
cols.push("octal".into());
vals.push(Value::string(format!("{:#o}", num), span));
vals.push(Value::string(format!("{num:#o}"), span));
// cols.push("pointer".into());
// vals.push(Value::string(format!("{:#p}", &num), span));
cols.push("upperexp".into());
vals.push(Value::string(format!("{:#E}", num), span));
vals.push(Value::string(format!("{num:#E}"), span));
cols.push("upperhex".into());
vals.push(Value::string(format!("{:#X}", num), span));
vals.push(Value::string(format!("{num:#X}"), span));
Value::Record { cols, vals, span }
}

View File

@ -1,9 +1,10 @@
use crate::input_handler::{operate, CellPathOnlyArgs};
use nu_engine::CallExt;
use nu_protocol::{
ast::{Call, CellPath},
engine::{Command, EngineState, Stack},
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
Value,
Type, Value,
};
#[derive(Clone)]
@ -16,10 +17,20 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("into binary")
.input_output_types(vec![
(Type::Binary, Type::Binary),
(Type::Int, Type::Binary),
(Type::Number, Type::Binary),
(Type::String, Type::Binary),
(Type::Bool, Type::Binary),
(Type::Filesize, Type::Binary),
(Type::Date, Type::Binary),
])
.allow_variants_without_examples(true) // TODO: supply exhaustive examples
.rest(
"rest",
SyntaxShape::CellPath,
"column paths to convert to binary (for table input)",
"for a data structure input, convert data at the given cell paths",
)
.category(Category::Conversions)
}
@ -38,7 +49,7 @@ impl Command for SubCommand {
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
) -> Result<PipelineData, ShellError> {
into_binary(engine_state, stack, call, input)
}
@ -98,9 +109,9 @@ fn into_binary(
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
) -> Result<PipelineData, ShellError> {
let head = call.head;
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
match input {
PipelineData::ExternalStream { stdout: None, .. } => Ok(Value::Binary {
@ -120,27 +131,10 @@ fn into_binary(
}
.into_pipeline_data())
}
_ => input.map(
move |v| {
if column_paths.is_empty() {
action(&v, head)
} else {
let mut ret = v;
for path in &column_paths {
let r = ret.update_cell_path(
&path.members,
Box::new(move |old| action(old, head)),
);
if let Err(error) = r {
return Value::Error { error };
}
}
ret
}
},
engine_state.ctrlc.clone(),
),
_ => {
let arg = CellPathOnlyArgs::from(cell_paths);
operate(action, arg, input, call.head, engine_state.ctrlc.clone())
}
}
}
@ -160,7 +154,7 @@ fn float_to_endian(n: f64) -> Vec<u8> {
}
}
pub fn action(input: &Value, span: Span) -> Value {
pub fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
match input {
Value::Binary { .. } => input.clone(),
Value::Int { val, .. } => Value::Binary {
@ -180,16 +174,27 @@ pub fn action(input: &Value, span: Span) -> Value {
span,
},
Value::Bool { val, .. } => Value::Binary {
val: int_to_endian(if *val { 1i64 } else { 0 }),
val: int_to_endian(i64::from(*val)),
span,
},
Value::Duration { val, .. } => Value::Binary {
val: int_to_endian(*val),
span,
},
Value::Date { val, .. } => Value::Binary {
val: val.format("%c").to_string().as_bytes().to_vec(),
span,
},
_ => Value::Error {
error: ShellError::UnsupportedInput("'into binary' for unsupported type".into(), span),
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => input.clone(),
other => Value::Error {
error: ShellError::OnlySupportsThisInputType(
"integer, float, filesize, string, date, duration, binary or bool".into(),
other.get_type().to_string(),
span,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}
}

View File

@ -1,8 +1,9 @@
use crate::input_handler::{operate, CellPathOnlyArgs};
use nu_engine::CallExt;
use nu_protocol::{
ast::{Call, CellPath},
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
#[derive(Clone)]
@ -15,10 +16,17 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("into bool")
.input_output_types(vec![
(Type::Int, Type::Bool),
(Type::Number, Type::Bool),
(Type::String, Type::Bool),
(Type::Bool, Type::Bool),
(Type::List(Box::new(Type::Any)), Type::Table(vec![])),
])
.rest(
"rest",
SyntaxShape::CellPath,
"column paths to convert to boolean (for table input)",
"for a data structure input, convert data at the given cell paths",
)
.category(Category::Conversions)
}
@ -37,7 +45,7 @@ impl Command for SubCommand {
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
) -> Result<PipelineData, ShellError> {
into_bool(engine_state, stack, call, input)
}
@ -46,7 +54,7 @@ impl Command for SubCommand {
vec![
Example {
description: "Convert value to boolean in table",
example: "echo [[value]; ['false'] ['1'] [0] [1.0] [true]] | into bool value",
example: "[[value]; ['false'] ['1'] [0] [1.0] [true]] | into bool value",
result: Some(Value::List {
vals: vec![
Value::Record {
@ -88,6 +96,11 @@ impl Command for SubCommand {
example: "1 | into bool",
result: Some(Value::boolean(true, span)),
},
Example {
description: "convert decimal to boolean",
example: "0.3 | into bool",
result: Some(Value::boolean(true, span)),
},
Example {
description: "convert decimal string to boolean",
example: "'0.0' | into bool",
@ -108,28 +121,9 @@ fn into_bool(
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let head = call.head;
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
input.map(
move |v| {
if column_paths.is_empty() {
action(&v, head)
} else {
let mut ret = v;
for path in &column_paths {
let r =
ret.update_cell_path(&path.members, Box::new(move |old| action(old, head)));
if let Err(error) = r {
return Value::Error { error };
}
}
ret
}
},
engine_state.ctrlc.clone(),
)
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
let args = CellPathOnlyArgs::from(cell_paths);
operate(action, args, input, call.head, engine_state.ctrlc.clone())
}
fn string_to_boolean(s: &str, span: Span) -> Result<bool, ShellError> {
@ -154,7 +148,7 @@ fn string_to_boolean(s: &str, span: Span) -> Result<bool, ShellError> {
}
}
fn action(input: &Value, span: Span) -> Value {
fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
match input {
Value::Bool { .. } => input.clone(),
Value::Int { val, .. } => Value::Bool {
@ -169,10 +163,15 @@ fn action(input: &Value, span: Span) -> Value {
Ok(val) => Value::Bool { val, span },
Err(error) => Value::Error { error },
},
_ => Value::Error {
error: ShellError::UnsupportedInput(
"'into bool' does not support this input".into(),
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => input.clone(),
other => Value::Error {
error: ShellError::OnlySupportsThisInputType(
"bool, integer, float or string".into(),
other.get_type().to_string(),
span,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}

View File

@ -2,7 +2,7 @@ use nu_engine::get_full_help;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, IntoPipelineData, PipelineData, Signature, Value,
Category, IntoPipelineData, PipelineData, ShellError, Signature, Type, Value,
};
#[derive(Clone)]
@ -14,36 +14,36 @@ impl Command for Into {
}
fn signature(&self) -> Signature {
Signature::build("into").category(Category::Conversions)
Signature::build("into")
.category(Category::Conversions)
.input_output_types(vec![(Type::Nothing, Type::String)])
}
fn usage(&self) -> &str {
"Commands to convert data from one type to another."
}
fn extra_usage(&self) -> &str {
"You must use one of the following subcommands. Using this command as-is will only produce this help message."
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
) -> Result<PipelineData, ShellError> {
Ok(Value::String {
val: get_full_help(&Into.signature(), &[], engine_state, stack),
val: get_full_help(
&Into.signature(),
&[],
engine_state,
stack,
self.is_parser_keyword(),
),
span: call.head,
}
.into_pipeline_data())
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_examples() {
use crate::test_examples;
test_examples(Into {})
}
}

View File

@ -1,18 +1,25 @@
use crate::input_handler::{operate, CmdArgument};
use crate::{generate_strftime_list, parse_date_from_string};
use chrono::{DateTime, FixedOffset, Local, TimeZone, Utc};
use chrono::{DateTime, FixedOffset, Local, LocalResult, TimeZone, Utc};
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::ast::CellPath;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value,
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Spanned,
SyntaxShape, Type, Value,
};
struct Arguments {
timezone: Option<Spanned<String>>,
offset: Option<Spanned<i64>>,
format: Option<String>,
column_paths: Vec<CellPath>,
zone_options: Option<Spanned<Zone>>,
format_options: Option<DatetimeFormat>,
cell_paths: Option<Vec<CellPath>>,
}
impl CmdArgument for Arguments {
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
self.cell_paths.take()
}
}
// In case it may be confused with chrono::TimeZone
@ -57,7 +64,11 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("into datetime")
.named(
.input_output_types(vec![
(Type::Int, Type::Date),
(Type::String, Type::Date),
])
.named(
"timezone",
SyntaxShape::String,
"Specify timezone if the input is a Unix timestamp. Valid options: 'UTC' ('u') or 'LOCAL' ('l')",
@ -83,7 +94,7 @@ impl Command for SubCommand {
.rest(
"rest",
SyntaxShape::CellPath,
"optionally convert text into datetime by column paths",
"for a data structure input, convert data at the given cell paths",
)
.category(Category::Conversions)
}
@ -95,7 +106,36 @@ impl Command for SubCommand {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
operate(engine_state, stack, call, input)
if call.has_flag("list") {
Ok(generate_strftime_list(call.head, true).into_pipeline_data())
} else {
let cell_paths = call.rest(engine_state, stack, 0)?;
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
// if zone-offset is specified, then zone will be neglected
let timezone = call.get_flag::<Spanned<String>>(engine_state, stack, "timezone")?;
let zone_options =
match &call.get_flag::<Spanned<i64>>(engine_state, stack, "offset")? {
Some(zone_offset) => Some(Spanned {
item: Zone::new(zone_offset.item),
span: zone_offset.span,
}),
None => timezone.as_ref().map(|zone| Spanned {
item: Zone::from_string(zone.item.clone()),
span: zone.span,
}),
};
let format_options = call
.get_flag::<String>(engine_state, stack, "format")?
.as_ref()
.map(|fmt| DatetimeFormat(fmt.to_string()));
let args = Arguments {
format_options,
zone_options,
cell_paths,
};
operate(action, args, input, call.head, engine_state.ctrlc.clone())
}
}
fn usage(&self) -> &str {
@ -107,38 +147,41 @@ impl Command for SubCommand {
}
fn examples(&self) -> Vec<Example> {
let example_result_1 = |secs: i64, nsecs: u32| match Utc.timestamp_opt(secs, nsecs) {
LocalResult::Single(dt) => Some(Value::Date {
val: dt.into(),
span: Span::test_data(),
}),
_ => panic!("datetime: help example is invalid"),
};
let example_result_2 = |millis: i64| match Utc.timestamp_millis_opt(millis) {
LocalResult::Single(dt) => Some(Value::Date {
val: dt.into(),
span: Span::test_data(),
}),
_ => panic!("datetime: help example is invalid"),
};
vec![
Example {
description: "Convert to datetime",
example: "'27.02.2021 1:55 pm +0000' | into datetime",
result: Some(Value::Date {
val: Utc.timestamp(1614434100, 0).into(),
span: Span::test_data(),
}),
result: example_result_1(1614434100,0)
},
Example {
description: "Convert to datetime",
example: "'2021-02-27T13:55:40+00:00' | into datetime",
result: Some(Value::Date {
val: Utc.timestamp(1614434140, 0).into(),
span: Span::test_data(),
}),
result: example_result_1(1614434140, 0)
},
Example {
description: "Convert to datetime using a custom format",
example: "'20210227_135540+0000' | into datetime -f '%Y%m%d_%H%M%S%z'",
result: Some(Value::Date {
val: Utc.timestamp(1614434140, 0).into(),
span: Span::test_data(),
}),
result: example_result_1(1614434140, 0)
},
Example {
description: "Convert timestamp (no larger than 8e+12) to a UTC datetime",
example: "1614434140 | into datetime",
result: Some(Value::Date {
val: Utc.timestamp(1614434140, 0).into(),
span: Span::test_data(),
}),
result: example_result_1(1614434140, 0)
},
Example {
description:
@ -148,12 +191,9 @@ impl Command for SubCommand {
},
Example {
description:
"Convert timestamps like the sqlite history t",
"Convert a millisecond-precise timestamp",
example: "1656165681720 | into datetime",
result: Some(Value::Date {
val: Utc.timestamp_millis(1656165681720).into(),
span: Span::test_data(),
}),
result: example_result_2(1656165681720)
},
]
}
@ -162,81 +202,23 @@ impl Command for SubCommand {
#[derive(Clone)]
struct DatetimeFormat(String);
fn operate(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let head = call.head;
let options = Arguments {
timezone: call.get_flag(engine_state, stack, "timezone")?,
offset: call.get_flag(engine_state, stack, "offset")?,
format: call.get_flag(engine_state, stack, "format")?,
column_paths: call.rest(engine_state, stack, 0)?,
};
// if zone-offset is specified, then zone will be neglected
let zone_options = match &options.offset {
Some(zone_offset) => Some(Spanned {
item: Zone::new(zone_offset.item),
span: zone_offset.span,
}),
None => options.timezone.as_ref().map(|zone| Spanned {
item: Zone::from_string(zone.item.clone()),
span: zone.span,
}),
};
let list_flag = call.has_flag("list");
let format_options = options
.format
.as_ref()
.map(|fmt| DatetimeFormat(fmt.to_string()));
input.map(
move |v| {
if options.column_paths.is_empty() && !list_flag {
action(&v, &zone_options, &format_options, head)
} else if list_flag {
generate_strftime_list(head, true)
} else {
let mut ret = v;
for path in &options.column_paths {
let zone_options = zone_options.clone();
let format_options = format_options.clone();
let r = ret.update_cell_path(
&path.members,
Box::new(move |old| action(old, &zone_options, &format_options, head)),
);
if let Err(error) = r {
return Value::Error { error };
}
}
ret
}
},
engine_state.ctrlc.clone(),
)
}
fn action(
input: &Value,
timezone: &Option<Spanned<Zone>>,
dateformat: &Option<DatetimeFormat>,
head: Span,
) -> Value {
fn action(input: &Value, args: &Arguments, head: Span) -> Value {
let timezone = &args.zone_options;
let dateformat = &args.format_options;
// Check to see if input looks like a Unix timestamp (i.e. can it be parsed to an int?)
let timestamp = match input {
Value::Int { val, .. } => Ok(*val),
Value::String { val, .. } => val.parse::<i64>(),
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => return input.clone(),
other => {
return Value::Error {
error: ShellError::UnsupportedInput(
format!("Expected string or int, got {} instead", other.get_type()),
error: ShellError::OnlySupportsThisInputType(
"string and integer".into(),
other.get_type().to_string(),
head,
// This line requires the Value::Error match above.
other.expect_span(),
),
};
}
@ -249,54 +231,68 @@ fn action(
if ts.abs() > TIMESTAMP_BOUND {
return Value::Error {
error: ShellError::UnsupportedInput(
"Given timestamp is out of range, it should between -8e+12 and 8e+12"
.to_string(),
"timestamp is out of range; it should between -8e+12 and 8e+12".to_string(),
format!("timestamp is {ts:?}"),
head,
// Again, can safely unwrap this from here on
input.expect_span(),
),
};
}
macro_rules! match_datetime {
($expr:expr) => {
match $expr {
LocalResult::Single(dt) => Value::Date {
val: dt.into(),
span: head,
},
_ => {
return Value::Error {
error: ShellError::UnsupportedInput(
"The given local datetime representation is invalid.".into(),
format!("timestamp is {:?}", ts),
head,
head,
),
};
}
}
};
}
return match timezone {
// default to UTC
None => {
// be able to convert chrono::Utc::now()
let dt = match ts.to_string().len() {
x if x > 13 => Utc.timestamp_nanos(ts).into(),
x if x > 10 => Utc.timestamp_millis(ts).into(),
_ => Utc.timestamp(ts, 0).into(),
};
Value::Date {
val: dt,
span: head,
match ts.to_string().len() {
x if x > 13 => Value::Date {
val: Utc.timestamp_nanos(ts).into(),
span: head,
},
x if x > 10 => match_datetime!(Utc.timestamp_millis_opt(ts)),
_ => match_datetime!(Utc.timestamp_opt(ts, 0)),
}
}
Some(Spanned { item, span }) => match item {
Zone::Utc => Value::Date {
val: Utc.timestamp(ts, 0).into(),
span: head,
Zone::Utc => match_datetime!(Utc.timestamp_opt(ts, 0)),
Zone::Local => match_datetime!(Local.timestamp_opt(ts, 0)),
Zone::East(i) => match FixedOffset::east_opt((*i as i32) * HOUR) {
Some(eastoffset) => match_datetime!(eastoffset.timestamp_opt(ts, 0)),
None => Value::Error {
error: ShellError::DatetimeParseError(input.debug_value(), *span),
},
},
Zone::Local => Value::Date {
val: Local.timestamp(ts, 0).into(),
span: head,
Zone::West(i) => match FixedOffset::west_opt((*i as i32) * HOUR) {
Some(westoffset) => match_datetime!(westoffset.timestamp_opt(ts, 0)),
None => Value::Error {
error: ShellError::DatetimeParseError(input.debug_value(), *span),
},
},
Zone::East(i) => {
let eastoffset = FixedOffset::east((*i as i32) * HOUR);
Value::Date {
val: eastoffset.timestamp(ts, 0),
span: head,
}
}
Zone::West(i) => {
let westoffset = FixedOffset::west((*i as i32) * HOUR);
Value::Date {
val: westoffset.timestamp(ts, 0),
span: head,
}
}
Zone::Error => Value::Error {
error: ShellError::UnsupportedInput(
"Cannot convert given timezone or offset to timestamp".to_string(),
// This is an argument error, not an input error
error: ShellError::TypeMismatch(
"Invalid timezone or offset".to_string(),
*span,
),
},
@ -333,10 +329,15 @@ fn action(
},
}
}
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => input.clone(),
other => Value::Error {
error: ShellError::UnsupportedInput(
format!("Expected string, got {} instead", other.get_type()),
error: ShellError::OnlySupportsThisInputType(
"string".into(),
other.get_type().to_string(),
head,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}
@ -359,7 +360,12 @@ mod tests {
fn takes_a_date_format() {
let date_str = Value::test_string("16.11.1984 8:00 am +0000");
let fmt_options = Some(DatetimeFormat("%d.%m.%Y %H:%M %P %z".to_string()));
let actual = action(&date_str, &None, &fmt_options, Span::test_data());
let args = Arguments {
zone_options: None,
format_options: fmt_options,
cell_paths: None,
};
let actual = action(&date_str, &args, Span::test_data());
let expected = Value::Date {
val: DateTime::parse_from_str("16.11.1984 8:00 am +0000", "%d.%m.%Y %H:%M %P %z")
.unwrap(),
@ -371,7 +377,12 @@ mod tests {
#[test]
fn takes_iso8601_date_format() {
let date_str = Value::test_string("2020-08-04T16:39:18+00:00");
let actual = action(&date_str, &None, &None, Span::test_data());
let args = Arguments {
zone_options: None,
format_options: None,
cell_paths: None,
};
let actual = action(&date_str, &args, Span::test_data());
let expected = Value::Date {
val: DateTime::parse_from_str("2020-08-04T16:39:18+00:00", "%Y-%m-%dT%H:%M:%S%z")
.unwrap(),
@ -387,7 +398,12 @@ mod tests {
item: Zone::East(8),
span: Span::test_data(),
});
let actual = action(&date_str, &timezone_option, &None, Span::test_data());
let args = Arguments {
zone_options: timezone_option,
format_options: None,
cell_paths: None,
};
let actual = action(&date_str, &args, Span::test_data());
let expected = Value::Date {
val: DateTime::parse_from_str("2021-02-27 21:55:40 +08:00", "%Y-%m-%d %H:%M:%S %z")
.unwrap(),
@ -404,7 +420,12 @@ mod tests {
item: Zone::East(8),
span: Span::test_data(),
});
let actual = action(&date_int, &timezone_option, &None, Span::test_data());
let args = Arguments {
zone_options: timezone_option,
format_options: None,
cell_paths: None,
};
let actual = action(&date_int, &args, Span::test_data());
let expected = Value::Date {
val: DateTime::parse_from_str("2021-02-27 21:55:40 +08:00", "%Y-%m-%d %H:%M:%S %z")
.unwrap(),
@ -421,9 +442,14 @@ mod tests {
item: Zone::Local,
span: Span::test_data(),
});
let actual = action(&date_str, &timezone_option, &None, Span::test_data());
let args = Arguments {
zone_options: timezone_option,
format_options: None,
cell_paths: None,
};
let actual = action(&date_str, &args, Span::test_data());
let expected = Value::Date {
val: Local.timestamp(1614434140, 0).into(),
val: Local.timestamp_opt(1614434140, 0).unwrap().into(),
span: Span::test_data(),
};
@ -433,11 +459,15 @@ mod tests {
#[test]
fn takes_timestamp_without_timezone() {
let date_str = Value::test_string("1614434140");
let timezone_option = None;
let actual = action(&date_str, &timezone_option, &None, Span::test_data());
let args = Arguments {
zone_options: None,
format_options: None,
cell_paths: None,
};
let actual = action(&date_str, &args, Span::test_data());
let expected = Value::Date {
val: Utc.timestamp(1614434140, 0).into(),
val: Utc.timestamp_opt(1614434140, 0).unwrap().into(),
span: Span::test_data(),
};
@ -451,7 +481,12 @@ mod tests {
item: Zone::Utc,
span: Span::test_data(),
});
let actual = action(&date_str, &timezone_option, &None, Span::test_data());
let args = Arguments {
zone_options: timezone_option,
format_options: None,
cell_paths: None,
};
let actual = action(&date_str, &args, Span::test_data());
assert_eq!(actual.get_type(), Error);
}
@ -460,7 +495,12 @@ mod tests {
fn communicates_parsing_error_given_an_invalid_datetimelike_string() {
let date_str = Value::test_string("16.11.1984 8:00 am Oops0000");
let fmt_options = Some(DatetimeFormat("%d.%m.%Y %H:%M %P %z".to_string()));
let actual = action(&date_str, &None, &fmt_options, Span::test_data());
let args = Arguments {
zone_options: None,
format_options: fmt_options,
cell_paths: None,
};
let actual = action(&date_str, &args, Span::test_data());
assert_eq!(actual.get_type(), Error);
}

View File

@ -1,8 +1,9 @@
use crate::input_handler::{operate, CellPathOnlyArgs};
use nu_engine::CallExt;
use nu_protocol::{
ast::{Call, CellPath},
engine::{Command, EngineState, Stack},
Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
#[derive(Clone)]
@ -14,11 +15,16 @@ impl Command for SubCommand {
}
fn signature(&self) -> Signature {
Signature::build("into decimal").rest(
"rest",
SyntaxShape::CellPath,
"optionally convert text into decimal by column paths",
)
Signature::build("into decimal")
.input_output_types(vec![
(Type::String, Type::Number),
(Type::Bool, Type::Number),
])
.rest(
"rest",
SyntaxShape::CellPath,
"for a data structure input, convert data at the given cell paths",
)
}
fn usage(&self) -> &str {
@ -35,8 +41,10 @@ impl Command for SubCommand {
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
operate(engine_state, stack, call, input)
) -> Result<PipelineData, ShellError> {
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
let args = CellPathOnlyArgs::from(cell_paths);
operate(action, args, input, call.head, engine_state.ctrlc.clone())
}
fn examples(&self) -> Vec<Example> {
@ -72,43 +80,13 @@ impl Command for SubCommand {
}
}
fn operate(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let head = call.head;
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
input.map(
move |v| {
if column_paths.is_empty() {
action(&v, head)
} else {
let mut ret = v;
for path in &column_paths {
let r =
ret.update_cell_path(&path.members, Box::new(move |old| action(old, head)));
if let Err(error) = r {
return Value::Error { error };
}
}
ret
}
},
engine_state.ctrlc.clone(),
)
}
fn action(input: &Value, head: Span) -> Value {
fn action(input: &Value, _args: &CellPathOnlyArgs, head: Span) -> Value {
match input {
Value::String { val: s, span } => {
let other = s.trim();
match other.parse::<f64>() {
Ok(x) => Value::Float { val: x, span: head },
Ok(x) => Value::float(x, head),
Err(reason) => Value::Error {
error: ShellError::CantConvert(
"float".to_string(),
@ -119,10 +97,7 @@ fn action(input: &Value, head: Span) -> Value {
},
}
}
Value::Int { val: v, span } => Value::Float {
val: *v as f64,
span: *span,
},
Value::Int { val: v, span } => Value::float(*v as f64, *span),
Value::Bool { val: b, span } => Value::Float {
val: match b {
true => 1.0,
@ -130,18 +105,17 @@ fn action(input: &Value, head: Span) -> Value {
},
span: *span,
},
other => {
let span = other.span();
match span {
Ok(s) => {
let got = format!("Expected a string, got {} instead", other.get_type());
Value::Error {
error: ShellError::UnsupportedInput(got, s),
}
}
Err(e) => Value::Error { error: e },
}
}
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => input.clone(),
other => Value::Error {
error: ShellError::OnlySupportsThisInputType(
"string, integer or bool".into(),
other.get_type().to_string(),
head,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}
}
@ -163,7 +137,7 @@ mod tests {
let word = Value::test_string("3.1415");
let expected = Value::test_float(3.1415);
let actual = action(&word, Span::test_data());
let actual = action(&word, &CellPathOnlyArgs::from(vec![]), Span::test_data());
assert_eq!(actual, expected);
}
@ -171,7 +145,11 @@ mod tests {
fn communicates_parsing_error_given_an_invalid_decimallike_string() {
let decimal_str = Value::test_string("11.6anra");
let actual = action(&decimal_str, Span::test_data());
let actual = action(
&decimal_str,
&CellPathOnlyArgs::from(vec![]),
Span::test_data(),
);
assert_eq!(actual.get_type(), Error);
}
@ -180,7 +158,11 @@ mod tests {
fn int_to_decimal() {
let decimal_str = Value::test_int(10);
let expected = Value::test_float(10.0);
let actual = action(&decimal_str, Span::test_data());
let actual = action(
&decimal_str,
&CellPathOnlyArgs::from(vec![]),
Span::test_data(),
);
assert_eq!(actual, expected);
}

View File

@ -3,7 +3,7 @@ use nu_parser::parse_duration_bytes;
use nu_protocol::{
ast::{Call, CellPath, Expr},
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Unit,
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Unit,
Value,
};
@ -17,6 +17,13 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("into duration")
.input_output_types(vec![
(Type::String, Type::Duration),
(Type::Duration, Type::Duration),
// TODO: --convert option should be implemented as `format duration`
(Type::String, Type::String),
(Type::Duration, Type::String),
])
.named(
"convert",
SyntaxShape::String,
@ -26,7 +33,7 @@ impl Command for SubCommand {
.rest(
"rest",
SyntaxShape::CellPath,
"column paths to convert to duration (for table input)",
"for a data structure input, convert data at the given cell paths",
)
.category(Category::Conversions)
}
@ -36,7 +43,7 @@ impl Command for SubCommand {
}
fn extra_usage(&self) -> &str {
"into duration does not take leap years into account and every month is calculated with 30 days"
"This command does not take leap years into account, and every month is assumed to have 30 days."
}
fn search_terms(&self) -> Vec<&str> {
@ -49,7 +56,7 @@ impl Command for SubCommand {
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
) -> Result<PipelineData, ShellError> {
into_duration(engine_state, stack, call, input)
}
@ -58,7 +65,8 @@ impl Command for SubCommand {
vec![
Example {
description: "Convert string to duration in table",
example: "echo [[value]; ['1sec'] ['2min'] ['3hr'] ['4day'] ['5wk']] | into duration value",
example:
"[[value]; ['1sec'] ['2min'] ['3hr'] ['4day'] ['5wk']] | into duration value",
result: Some(Value::List {
vals: vec![
Value::Record {
@ -121,11 +129,19 @@ impl Command for SubCommand {
span,
}),
},
Example {
description: "Convert duration to duration",
example: "420sec | into duration",
result: Some(Value::Duration {
val: 7 * 60 * 1000 * 1000 * 1000,
span,
}),
},
Example {
description: "Convert duration to the requested duration as a string",
example: "420sec | into duration --convert min",
example: "420sec | into duration --convert ms",
result: Some(Value::String {
val: "7 min".to_string(),
val: "420000 ms".to_string(),
span,
}),
},
@ -452,9 +468,11 @@ fn action(
}
} else {
Value::Error {
error: ShellError::UnsupportedInput(
"'into duration' does not support this string input".into(),
error: ShellError::CantConvert(
"string".into(),
"duration".into(),
span,
None,
),
}
}
@ -465,10 +483,15 @@ fn action(
}
}
}
_ => Value::Error {
error: ShellError::UnsupportedInput(
"'into duration' does not support this input".into(),
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => input.clone(),
other => Value::Error {
error: ShellError::OnlySupportsThisInputType(
"string or duration".into(),
other.get_type().to_string(),
span,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}
@ -487,7 +510,7 @@ mod test {
#[test]
fn turns_ns_to_duration() {
let span = Span::test_data();
let span = Span::new(0, 2);
let word = Value::test_string("3ns");
let expected = Value::Duration { val: 3, span };
let convert_duration = None;
@ -498,7 +521,7 @@ mod test {
#[test]
fn turns_us_to_duration() {
let span = Span::test_data();
let span = Span::new(0, 2);
let word = Value::test_string("4us");
let expected = Value::Duration {
val: 4 * 1000,
@ -512,7 +535,7 @@ mod test {
#[test]
fn turns_ms_to_duration() {
let span = Span::test_data();
let span = Span::new(0, 2);
let word = Value::test_string("5ms");
let expected = Value::Duration {
val: 5 * 1000 * 1000,
@ -526,7 +549,7 @@ mod test {
#[test]
fn turns_sec_to_duration() {
let span = Span::test_data();
let span = Span::new(0, 3);
let word = Value::test_string("1sec");
let expected = Value::Duration {
val: 1000 * 1000 * 1000,
@ -540,7 +563,7 @@ mod test {
#[test]
fn turns_min_to_duration() {
let span = Span::test_data();
let span = Span::new(0, 3);
let word = Value::test_string("7min");
let expected = Value::Duration {
val: 7 * 60 * 1000 * 1000 * 1000,
@ -554,7 +577,7 @@ mod test {
#[test]
fn turns_hr_to_duration() {
let span = Span::test_data();
let span = Span::new(0, 3);
let word = Value::test_string("42hr");
let expected = Value::Duration {
val: 42 * 60 * 60 * 1000 * 1000 * 1000,
@ -568,7 +591,7 @@ mod test {
#[test]
fn turns_day_to_duration() {
let span = Span::test_data();
let span = Span::new(0, 5);
let word = Value::test_string("123day");
let expected = Value::Duration {
val: 123 * 24 * 60 * 60 * 1000 * 1000 * 1000,
@ -582,7 +605,7 @@ mod test {
#[test]
fn turns_wk_to_duration() {
let span = Span::test_data();
let span = Span::new(0, 2);
let word = Value::test_string("3wk");
let expected = Value::Duration {
val: 3 * 7 * 24 * 60 * 60 * 1000 * 1000 * 1000,

View File

@ -1,8 +1,9 @@
use crate::input_handler::{operate, CellPathOnlyArgs};
use nu_engine::CallExt;
use nu_protocol::{
ast::{Call, CellPath},
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
#[derive(Clone)]
@ -15,10 +16,16 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("into filesize")
.input_output_types(vec![
(Type::Int, Type::Filesize),
(Type::Number, Type::Filesize),
(Type::String, Type::Filesize),
(Type::Filesize, Type::Filesize),
])
.rest(
"rest",
SyntaxShape::CellPath,
"column paths to convert to filesize (for table input)",
"for a data structure input, convert data at the given cell paths",
)
.category(Category::Conversions)
}
@ -37,8 +44,10 @@ impl Command for SubCommand {
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
into_filesize(engine_state, stack, call, input)
) -> Result<PipelineData, ShellError> {
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
let args = CellPathOnlyArgs::from(cell_paths);
operate(action, args, input, call.head, engine_state.ctrlc.clone())
}
fn examples(&self) -> Vec<Example> {
@ -84,37 +93,7 @@ impl Command for SubCommand {
}
}
fn into_filesize(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let head = call.head;
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
input.map(
move |v| {
if column_paths.is_empty() {
action(&v, head)
} else {
let mut ret = v;
for path in &column_paths {
let r =
ret.update_cell_path(&path.members, Box::new(move |old| action(old, head)));
if let Err(error) = r {
return Value::Error { error };
}
}
ret
}
},
engine_state.ctrlc.clone(),
)
}
pub fn action(input: &Value, span: Span) -> Value {
pub fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
if let Ok(value_span) = input.span() {
match input {
Value::Filesize { .. } => input.clone(),
@ -137,20 +116,18 @@ pub fn action(input: &Value, span: Span) -> Value {
val: 0,
span: value_span,
},
_ => Value::Error {
error: ShellError::UnsupportedInput(
"'into filesize' for unsupported type".into(),
other => Value::Error {
error: ShellError::OnlySupportsThisInputType(
"string and integer".into(),
other.get_type().to_string(),
span,
value_span,
),
},
}
} else {
Value::Error {
error: ShellError::UnsupportedInput(
"'into filesize' for unsupported type".into(),
span,
),
}
// Propagate existing errors
input.clone()
}
}
fn int_from_string(a_string: &str, span: Span) -> Result<i64, ShellError> {

View File

@ -1,16 +1,23 @@
use crate::input_handler::{operate, CmdArgument};
use nu_engine::CallExt;
use nu_protocol::{
ast::{Call, CellPath},
engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
struct Arguments {
radix: Option<Value>,
column_paths: Vec<CellPath>,
radix: u32,
cell_paths: Option<Vec<CellPath>>,
little_endian: bool,
}
impl CmdArgument for Arguments {
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
self.cell_paths.take()
}
}
#[derive(Clone)]
pub struct SubCommand;
@ -21,12 +28,22 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("into int")
.input_output_types(vec![
(Type::String, Type::Int),
(Type::Number, Type::Int),
(Type::Bool, Type::Int),
// Unix timestamp in seconds
(Type::Date, Type::Int),
// TODO: Users should do this by dividing a Filesize by a Filesize explicitly
(Type::Filesize, Type::Int),
])
.vectorizes_over_list(true)
.named("radix", SyntaxShape::Number, "radix of integer", Some('r'))
.switch("little-endian", "use little-endian byte decoding", None)
.rest(
"rest",
SyntaxShape::CellPath,
"column paths to convert to int (for table input)",
"for a data structure input, convert data at the given cell paths",
)
.category(Category::Conversions)
}
@ -45,15 +62,37 @@ impl Command for SubCommand {
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
into_int(engine_state, stack, call, input)
) -> Result<PipelineData, ShellError> {
let cell_paths = call.rest(engine_state, stack, 0)?;
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
let radix = call.get_flag::<Value>(engine_state, stack, "radix")?;
let radix: u32 = match radix {
Some(Value::Int { val, span }) => {
if !(2..=36).contains(&val) {
return Err(ShellError::TypeMismatch(
"Radix must lie in the range [2, 36]".to_string(),
span,
));
}
val as u32
}
Some(_) => 10,
None => 10,
};
let args = Arguments {
radix,
little_endian: call.has_flag("little-endian"),
cell_paths,
};
operate(action, args, input, call.head, engine_state.ctrlc.clone())
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "Convert string to integer in table",
example: "echo [[num]; ['-5'] [4] [1.5]] | into int num",
example: "[[num]; ['-5'] [4] [1.5]] | into int num",
result: None,
},
Example {
@ -74,10 +113,7 @@ impl Command for SubCommand {
Example {
description: "Convert file size to integer",
example: "4KB | into int",
result: Some(Value::Int {
val: 4000,
span: Span::test_data(),
}),
result: Some(Value::test_int(4000)),
},
Example {
description: "Convert bool to integer",
@ -121,59 +157,9 @@ impl Command for SubCommand {
}
}
fn into_int(
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let head = call.head;
let options = Arguments {
radix: call.get_flag(engine_state, stack, "radix")?,
little_endian: call.has_flag("little-endian"),
column_paths: call.rest(engine_state, stack, 0)?,
};
let radix: u32 = match options.radix {
Some(Value::Int { val, .. }) => val as u32,
Some(_) => 10,
None => 10,
};
if let Some(val) = &options.radix {
if !(2..=36).contains(&radix) {
return Err(ShellError::UnsupportedInput(
"Radix must lie in the range [2, 36]".to_string(),
val.span()?,
));
}
}
input.map(
move |v| {
if options.column_paths.is_empty() {
action(&v, head, radix, options.little_endian)
} else {
let mut ret = v;
for path in &options.column_paths {
let r = ret.update_cell_path(
&path.members,
Box::new(move |old| action(old, head, radix, options.little_endian)),
);
if let Err(error) = r {
return Value::Error { error };
}
}
ret
}
},
engine_state.ctrlc.clone(),
)
}
pub fn action(input: &Value, span: Span, radix: u32, little_endian: bool) -> Value {
fn action(input: &Value, args: &Arguments, span: Span) -> Value {
let radix = args.radix;
let little_endian = args.little_endian;
match input {
Value::Int { val: _, .. } => {
if radix == 10 {
@ -201,9 +187,11 @@ pub fn action(input: &Value, span: Span, radix: u32, little_endian: bool) -> Val
Ok(v) => v,
_ => {
return Value::Error {
error: ShellError::UnsupportedInput(
"Could not convert float to integer".to_string(),
error: ShellError::CantConvert(
"float".to_string(),
"integer".to_string(),
span,
None,
),
}
}
@ -233,6 +221,7 @@ pub fn action(input: &Value, span: Span, radix: u32, little_endian: bool) -> Val
val: val.timestamp(),
span,
},
Value::Duration { val, .. } => Value::Int { val: *val, span },
Value::Binary { val, span } => {
use byteorder::{BigEndian, ByteOrder, LittleEndian};
@ -244,26 +233,25 @@ pub fn action(input: &Value, span: Span, radix: u32, little_endian: bool) -> Val
}
val.resize(8, 0);
Value::Int {
val: LittleEndian::read_i64(&val),
span: *span,
}
Value::int(LittleEndian::read_i64(&val), *span)
} else {
while val.len() < 8 {
val.insert(0, 0);
}
val.resize(8, 0);
Value::Int {
val: BigEndian::read_i64(&val),
span: *span,
}
Value::int(BigEndian::read_i64(&val), *span)
}
}
_ => Value::Error {
error: ShellError::UnsupportedInput(
format!("'into int' for unsupported type '{}'", input.get_type()),
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => input.clone(),
other => Value::Error {
error: ShellError::OnlySupportsThisInputType(
"integer, float, filesize, date, string, binary, duration or bool".into(),
other.get_type().to_string(),
span,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
}
@ -280,13 +268,13 @@ fn convert_int(input: &Value, head: Span, radix: u32) -> Value {
// octal
{
match int_from_string(val, head) {
Ok(x) => return Value::Int { val: x, span: head },
Ok(x) => return Value::int(x, head),
Err(e) => return Value::Error { error: e },
}
} else if val.starts_with("00") {
// It's a padded string
match i64::from_str_radix(val, radix) {
Ok(n) => return Value::Int { val: n, span: head },
Ok(n) => return Value::int(n, head),
Err(e) => {
return Value::Error {
error: ShellError::CantConvert(
@ -301,17 +289,22 @@ fn convert_int(input: &Value, head: Span, radix: u32) -> Value {
}
val.to_string()
}
_ => {
// Propagate errors by explicitly matching them before the final case.
Value::Error { .. } => return input.clone(),
other => {
return Value::Error {
error: ShellError::UnsupportedInput(
"only strings or integers are supported".to_string(),
error: ShellError::OnlySupportsThisInputType(
"string and integer".into(),
other.get_type().to_string(),
head,
// This line requires the Value::Error match above.
other.expect_span(),
),
}
};
}
};
match i64::from_str_radix(i.trim(), radix) {
Ok(n) => Value::Int { val: n, span: head },
Ok(n) => Value::int(n, head),
Err(_reason) => Value::Error {
error: ShellError::CantConvert("string".to_string(), "int".to_string(), head, None),
},
@ -374,8 +367,7 @@ fn int_from_string(a_string: &str, span: Span) -> Result<i64, ShellError> {
"string".to_string(),
span,
Some(format!(
r#"string "{}" does not represent a valid integer"#,
trimmed
r#"string "{trimmed}" does not represent a valid integer"#
)),
)),
},
@ -401,21 +393,45 @@ mod test {
let word = Value::test_string("10");
let expected = Value::test_int(10);
let actual = action(&word, Span::test_data(), 10, false);
let actual = action(
&word,
&Arguments {
radix: 10,
cell_paths: None,
little_endian: false,
},
Span::test_data(),
);
assert_eq!(actual, expected);
}
#[test]
fn turns_binary_to_integer() {
let s = Value::test_string("0b101");
let actual = action(&s, Span::test_data(), 10, false);
let actual = action(
&s,
&Arguments {
radix: 10,
cell_paths: None,
little_endian: false,
},
Span::test_data(),
);
assert_eq!(actual, Value::test_int(5));
}
#[test]
fn turns_hex_to_integer() {
let s = Value::test_string("0xFF");
let actual = action(&s, Span::test_data(), 16, false);
let actual = action(
&s,
&Arguments {
radix: 16,
cell_paths: None,
little_endian: false,
},
Span::test_data(),
);
assert_eq!(actual, Value::test_int(255));
}
@ -423,7 +439,15 @@ mod test {
fn communicates_parsing_error_given_an_invalid_integerlike_string() {
let integer_str = Value::test_string("36anra");
let actual = action(&integer_str, Span::test_data(), 10, false);
let actual = action(
&integer_str,
&Arguments {
radix: 10,
cell_paths: None,
little_endian: false,
},
Span::test_data(),
);
assert_eq!(actual.get_type(), Error)
}

View File

@ -6,6 +6,7 @@ mod decimal;
mod duration;
mod filesize;
mod int;
mod record;
mod string;
pub use self::bool::SubCommand as IntoBool;
@ -16,4 +17,5 @@ pub use datetime::SubCommand as IntoDatetime;
pub use decimal::SubCommand as IntoDecimal;
pub use duration::SubCommand as IntoDuration;
pub use int::SubCommand as IntoInt;
pub use record::SubCommand as IntoRecord;
pub use string::SubCommand as IntoString;

View File

@ -0,0 +1,295 @@
use chrono::{DateTime, Datelike, FixedOffset, Timelike};
use nu_protocol::format_duration_as_timeperiod;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Type, Value,
};
#[derive(Clone)]
pub struct SubCommand;
impl Command for SubCommand {
fn name(&self) -> &str {
"into record"
}
fn signature(&self) -> Signature {
Signature::build("into record")
.input_output_types(vec![
(Type::Date, Type::Record(vec![])),
(Type::Duration, Type::Record(vec![])),
(Type::List(Box::new(Type::Any)), Type::Record(vec![])),
(Type::Range, Type::Record(vec![])),
(Type::Record(vec![]), Type::Record(vec![])),
(Type::Table(vec![]), Type::Record(vec![])),
])
.category(Category::Conversions)
}
fn usage(&self) -> &str {
"Convert value to record"
}
fn search_terms(&self) -> Vec<&str> {
vec!["convert"]
}
fn run(
&self,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
into_record(engine_state, call, input)
}
fn examples(&self) -> Vec<Example> {
let span = Span::test_data();
vec![
Example {
description: "Convert from one row table to record",
example: "[[value]; [false]] | into record",
result: Some(Value::Record {
cols: vec!["value".to_string()],
vals: vec![Value::boolean(false, span)],
span,
}),
},
Example {
description: "Convert from list to record",
example: "[1 2 3] | into record",
result: Some(Value::Record {
cols: vec!["0".to_string(), "1".to_string(), "2".to_string()],
vals: vec![
Value::Int { val: 1, span },
Value::Int { val: 2, span },
Value::Int { val: 3, span },
],
span,
}),
},
Example {
description: "Convert from range to record",
example: "0..2 | into record",
result: Some(Value::Record {
cols: vec!["0".to_string(), "1".to_string(), "2".to_string()],
vals: vec![
Value::Int { val: 0, span },
Value::Int { val: 1, span },
Value::Int { val: 2, span },
],
span,
}),
},
Example {
description: "convert duration to record",
example: "-500day | into record",
result: Some(Value::Record {
cols: vec![
"year".into(),
"month".into(),
"week".into(),
"day".into(),
"sign".into(),
],
vals: vec![
Value::Int { val: 1, span },
Value::Int { val: 4, span },
Value::Int { val: 2, span },
Value::Int { val: 1, span },
Value::String {
val: "-".into(),
span,
},
],
span,
}),
},
Example {
description: "convert record to record",
example: "{a: 1, b: 2} | into record",
result: Some(Value::Record {
cols: vec!["a".to_string(), "b".to_string()],
vals: vec![Value::Int { val: 1, span }, Value::Int { val: 2, span }],
span,
}),
},
Example {
description: "convert date to record",
example: "2020-04-12T22:10:57+02:00 | into record",
result: Some(Value::Record {
cols: vec![
"year".into(),
"month".into(),
"day".into(),
"hour".into(),
"minute".into(),
"second".into(),
"timezone".into(),
],
vals: vec![
Value::Int { val: 2020, span },
Value::Int { val: 4, span },
Value::Int { val: 12, span },
Value::Int { val: 22, span },
Value::Int { val: 10, span },
Value::Int { val: 57, span },
Value::String {
val: "+02:00".to_string(),
span,
},
],
span,
}),
},
]
}
}
fn into_record(
engine_state: &EngineState,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let input = input.into_value(call.head);
let input_type = input.get_type();
let res = match input {
Value::Date { val, span } => parse_date_into_record(Ok(val), span),
Value::Duration { val, span } => parse_duration_into_record(val, span),
Value::List { mut vals, span } => match input_type {
Type::Table(..) if vals.len() == 1 => vals.pop().expect("already checked 1 item"),
_ => {
let mut cols = vec![];
let mut values = vec![];
for (idx, val) in vals.into_iter().enumerate() {
cols.push(format!("{idx}"));
values.push(val);
}
Value::Record {
cols,
vals: values,
span,
}
}
},
Value::Range { val, span } => {
let mut cols = vec![];
let mut vals = vec![];
for (idx, val) in val.into_range_iter(engine_state.ctrlc.clone())?.enumerate() {
cols.push(format!("{idx}"));
vals.push(val);
}
Value::Record { cols, vals, span }
}
Value::Record { cols, vals, span } => Value::Record { cols, vals, span },
Value::Error { .. } => input,
other => Value::Error {
error: ShellError::OnlySupportsThisInputType(
"string".into(),
other.get_type().to_string(),
call.head,
// This line requires the Value::Error match above.
other.expect_span(),
),
},
};
Ok(res.into_pipeline_data())
}
fn parse_date_into_record(date: Result<DateTime<FixedOffset>, Value>, span: Span) -> Value {
let cols = vec![
"year".into(),
"month".into(),
"day".into(),
"hour".into(),
"minute".into(),
"second".into(),
"timezone".into(),
];
match date {
Ok(x) => {
let vals = vec![
Value::Int {
val: x.year() as i64,
span,
},
Value::Int {
val: x.month() as i64,
span,
},
Value::Int {
val: x.day() as i64,
span,
},
Value::Int {
val: x.hour() as i64,
span,
},
Value::Int {
val: x.minute() as i64,
span,
},
Value::Int {
val: x.second() as i64,
span,
},
Value::String {
val: x.offset().to_string(),
span,
},
];
Value::Record { cols, vals, span }
}
Err(e) => e,
}
}
fn parse_duration_into_record(duration: i64, span: Span) -> Value {
let (sign, periods) = format_duration_as_timeperiod(duration);
let mut cols = vec![];
let mut vals = vec![];
for p in periods {
let num_with_unit = p.to_text().to_string();
let split = num_with_unit.split(' ').collect::<Vec<&str>>();
cols.push(match split[1] {
"ns" => "nanosecond".into(),
"µs" => "microsecond".into(),
"ms" => "millisecond".into(),
"sec" => "second".into(),
"min" => "minute".into(),
"hr" => "hour".into(),
"day" => "day".into(),
"wk" => "week".into(),
"month" => "month".into(),
"yr" => "year".into(),
_ => "unknown".into(),
});
vals.push(Value::Int {
val: split[0].parse::<i64>().unwrap_or(0),
span,
});
}
cols.push("sign".into());
vals.push(Value::String {
val: if sign == -1 { "-".into() } else { "+".into() },
span,
});
Value::Record { cols, vals, span }
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_examples() {
use crate::test_examples;
test_examples(SubCommand {})
}
}

View File

@ -1,13 +1,27 @@
use crate::input_handler::{operate, CmdArgument};
use nu_engine::CallExt;
use nu_protocol::{
ast::{Call, CellPath},
engine::{Command, EngineState, Stack},
into_code, Category, Config, Example, IntoPipelineData, PipelineData, ShellError, Signature,
Span, SyntaxShape, Value,
Span, SyntaxShape, Type, Value,
};
use nu_utils::get_system_locale;
use num_format::ToFormattedString;
struct Arguments {
decimals_value: Option<i64>,
decimals: bool,
cell_paths: Option<Vec<CellPath>>,
config: Config,
}
impl CmdArgument for Arguments {
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
self.cell_paths.take()
}
}
#[derive(Clone)]
pub struct SubCommand;
@ -18,11 +32,20 @@ impl Command for SubCommand {
fn signature(&self) -> Signature {
Signature::build("into string")
// FIXME - need to support column paths
.input_output_types(vec![
(Type::Binary, Type::String),
(Type::Int, Type::String),
(Type::Number, Type::String),
(Type::String, Type::String),
(Type::Bool, Type::String),
(Type::Filesize, Type::String),
(Type::Date, Type::String),
])
.allow_variants_without_examples(true) // https://github.com/nushell/nushell/issues/7032
.rest(
"rest",
SyntaxShape::CellPath,
"column paths to convert to string (for table input)",
"for a data structure input, convert data at the given cell paths",
)
.named(
"decimals",
@ -47,7 +70,7 @@ impl Command for SubCommand {
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
) -> Result<PipelineData, ShellError> {
string_helper(engine_state, stack, call, input)
}
@ -56,34 +79,22 @@ impl Command for SubCommand {
Example {
description: "convert integer to string and append three decimal places",
example: "5 | into string -d 3",
result: Some(Value::String {
val: "5.000".to_string(),
span: Span::test_data(),
}),
result: Some(Value::test_string("5.000")),
},
Example {
description: "convert decimal to string and round to nearest integer",
example: "1.7 | into string -d 0",
result: Some(Value::String {
val: "2".to_string(),
span: Span::test_data(),
}),
result: Some(Value::test_string("2")),
},
Example {
description: "convert decimal to string",
example: "1.7 | into string -d 1",
result: Some(Value::String {
val: "1.7".to_string(),
span: Span::test_data(),
}),
result: Some(Value::test_string("1.7")),
},
Example {
description: "convert decimal to string and limit to 2 decimals",
example: "1.734 | into string -d 2",
result: Some(Value::String {
val: "1.73".to_string(),
span: Span::test_data(),
}),
result: Some(Value::test_string("1.73")),
},
Example {
description: "try to convert decimal to string and provide negative decimal points",
@ -100,32 +111,24 @@ impl Command for SubCommand {
Example {
description: "convert decimal to string",
example: "4.3 | into string",
result: Some(Value::String {
val: "4.3".to_string(),
span: Span::test_data(),
}),
result: Some(Value::test_string("4.3")),
},
Example {
description: "convert string to string",
example: "'1234' | into string",
result: Some(Value::String {
val: "1234".to_string(),
span: Span::test_data(),
}),
result: Some(Value::test_string("1234")),
},
Example {
description: "convert boolean to string",
example: "true | into string",
result: Some(Value::String {
val: "true".to_string(),
span: Span::test_data(),
}),
},
Example {
description: "convert date to string",
example: "date now | into string",
result: None,
result: Some(Value::test_string("true")),
},
// TODO: This should work but does not; see https://github.com/nushell/nushell/issues/7032
// Example {
// description: "convert date to string",
// example: "'2020-10-10 10:00:00 +02:00' | into datetime | into string",
// result: Some(Value::test_string("Sat Oct 10 10:00:00 2020")),
// },
Example {
description: "convert filepath to string",
example: "ls Cargo.toml | get name | into string",
@ -133,8 +136,8 @@ impl Command for SubCommand {
},
Example {
description: "convert filesize to string",
example: "ls Cargo.toml | get size | into string",
result: None,
example: "1KiB | into string",
result: Some(Value::test_string("1,024 B")),
},
]
}
@ -145,21 +148,27 @@ fn string_helper(
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, ShellError> {
) -> Result<PipelineData, ShellError> {
let decimals = call.has_flag("decimals");
let head = call.head;
let decimals_value: Option<i64> = call.get_flag(engine_state, stack, "decimals")?;
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
let config = engine_state.get_config().clone();
if let Some(decimal_val) = decimals_value {
if decimals && decimal_val.is_negative() {
return Err(ShellError::UnsupportedInput(
return Err(ShellError::TypeMismatch(
"Cannot accept negative integers for decimals arguments".to_string(),
head,
));
}
}
let cell_paths = call.rest(engine_state, stack, 0)?;
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
let config = engine_state.get_config().clone();
let args = Arguments {
decimals_value,
decimals,
cell_paths,
config,
};
match input {
PipelineData::ExternalStream { stdout: None, .. } => Ok(Value::String {
@ -179,52 +188,25 @@ fn string_helper(
}
.into_pipeline_data())
}
_ => input.map(
move |v| {
if column_paths.is_empty() {
action(&v, head, decimals, decimals_value, false, &config)
} else {
let mut ret = v;
for path in &column_paths {
let config = config.clone();
let r = ret.update_cell_path(
&path.members,
Box::new(move |old| {
action(old, head, decimals, decimals_value, false, &config)
}),
);
if let Err(error) = r {
return Value::Error { error };
}
}
ret
}
},
engine_state.ctrlc.clone(),
),
_ => operate(action, args, input, head, engine_state.ctrlc.clone()),
}
}
pub fn action(
input: &Value,
span: Span,
decimals: bool,
digits: Option<i64>,
group_digits: bool,
config: &Config,
) -> Value {
fn action(input: &Value, args: &Arguments, span: Span) -> Value {
let decimals = args.decimals;
let digits = args.decimals_value;
let config = &args.config;
match input {
Value::Int { val, .. } => {
let decimal_value = digits.unwrap_or(0) as usize;
let res = format_int(*val, group_digits, decimal_value);
let res = format_int(*val, false, decimal_value);
Value::String { val: res, span }
}
Value::Float { val, .. } => {
if decimals {
let decimal_value = digits.unwrap_or(2) as usize;
Value::String {
val: format!("{:.*}", decimal_value, val),
val: format!("{val:.decimal_value$}"),
span,
}
} else {
@ -252,12 +234,7 @@ pub fn action(
span,
},
Value::Error { error } => Value::String {
val: {
match into_code(error) {
Some(code) => code,
None => "".to_string(),
}
},
val: into_code(error).unwrap_or_default(),
span,
},
Value::Nothing { .. } => Value::String {
@ -269,9 +246,11 @@ pub fn action(
vals: _,
span: _,
} => Value::Error {
error: ShellError::UnsupportedInput(
"Cannot convert Record into string".to_string(),
error: ShellError::CantConvert(
"record".into(),
"string".into(),
span,
Some("try using the `to nuon` command".into()),
),
},
Value::Binary { .. } => Value::Error {

View File

@ -1,5 +1,7 @@
mod fill;
mod fmt;
pub(crate) mod into;
pub use fill::Fill;
pub use fmt::Fmt;
pub use into::*;

View File

@ -1,6 +1,8 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, Signature, SyntaxShape};
use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
};
#[derive(Clone)]
pub struct Alias;
@ -16,6 +18,7 @@ impl Command for Alias {
fn signature(&self) -> nu_protocol::Signature {
Signature::build("alias")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.required("name", SyntaxShape::String, "name of the alias")
.required(
"initial_value",
@ -42,17 +45,24 @@ impl Command for Alias {
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
Ok(PipelineData::new(call.head))
) -> Result<PipelineData, ShellError> {
Ok(PipelineData::empty())
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Alias ll to ls -l",
example: "alias ll = ls -l",
result: None,
}]
vec![
Example {
description: "Alias ll to ls -l",
example: "alias ll = ls -l",
result: Some(Value::nothing(Span::test_data())),
},
Example {
description: "Make an alias that makes a list of all custom commands",
example: "alias customs = ($nu.scope.commands | where is_custom | get command)",
result: Some(Value::nothing(Span::test_data())),
},
]
}
}

View File

@ -0,0 +1,49 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Type};
#[derive(Clone)]
pub struct Break;
impl Command for Break {
fn name(&self) -> &str {
"break"
}
fn usage(&self) -> &str {
"Break a loop"
}
fn signature(&self) -> nu_protocol::Signature {
Signature::build("break")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.category(Category::Core)
}
fn extra_usage(&self) -> &str {
r#"This command is a parser keyword. For details, check:
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
}
fn run(
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
Err(ShellError::Break(call.head))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Break out of a loop",
example: r#"loop { break }"#,
result: None,
}]
}
}

View File

@ -4,7 +4,7 @@ use nu_protocol::engine::ReplOperation;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::Category;
use nu_protocol::IntoPipelineData;
use nu_protocol::{PipelineData, ShellError, Signature, SyntaxShape, Value};
use nu_protocol::{PipelineData, ShellError, Signature, SyntaxShape, Type, Value};
#[derive(Clone)]
pub struct Commandline;
@ -16,6 +16,7 @@ impl Command for Commandline {
fn signature(&self) -> Signature {
Signature::build("commandline")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.switch(
"append",
"appends the string to the end of the buffer",

View File

@ -0,0 +1,104 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type};
#[derive(Clone)]
pub struct Const;
impl Command for Const {
fn name(&self) -> &str {
"const"
}
fn usage(&self) -> &str {
"Create a parse-time constant."
}
fn signature(&self) -> nu_protocol::Signature {
Signature::build("const")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.allow_variants_without_examples(true)
.required("const_name", SyntaxShape::VarWithOptType, "constant name")
.required(
"initial_value",
SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::Expression)),
"equals sign followed by constant value",
)
.category(Category::Core)
}
fn extra_usage(&self) -> &str {
r#"This command is a parser keyword. For details, check:
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
}
fn search_terms(&self) -> Vec<&str> {
vec!["set", "let"]
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let var_id = call
.positional_nth(0)
.expect("checked through parser")
.as_var()
.expect("internal error: missing variable");
if let Some(constval) = engine_state.find_constant(var_id, &[]) {
// Instead of creating a second copy of the value in the stack, we could change
// stack.get_var() to check engine_state.find_constant().
stack.add_var(var_id, constval.clone());
Ok(PipelineData::empty())
} else {
Err(ShellError::NushellFailedSpanned(
"Missing Constant".to_string(),
"constant not added by the parser".to_string(),
call.head,
))
}
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "Create a new parse-time constant.",
example: "const x = 10",
result: None,
},
Example {
description: "Create a composite constant value",
example: "const x = { a: 10, b: 20 }",
result: None,
},
]
}
}
#[cfg(test)]
mod test {
use nu_protocol::engine::CommandType;
use super::*;
#[test]
fn test_examples() {
use crate::test_examples;
test_examples(Const {})
}
#[test]
fn test_command_type() {
assert!(matches!(Const.command_type(), CommandType::Keyword));
}
}

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