mirror of
https://github.com/nushell/nushell.git
synced 2025-07-01 07:00:37 +02:00
Compare commits
140 Commits
Author | SHA1 | Date | |
---|---|---|---|
a6f62e05ae | |||
f8939de14f | |||
01ade02ac1 | |||
39d93b536a | |||
32f67557af | |||
f05eed8e8d | |||
f0a265dbee | |||
bc7736bc99 | |||
19d732f313 | |||
a9a82de5c4 | |||
9074015d1c | |||
2b77544e58 | |||
5ee74b6ab5 | |||
3a04bd9154 | |||
2c176a7f14 | |||
026e18399e | |||
bbf0b45c59 | |||
5bd7300cd5 | |||
ffb5051f6c | |||
ce4ea16c08 | |||
48c94c75fc | |||
73d3708006 | |||
bbea7da669 | |||
7f39609d9a | |||
a14e9e0a2e | |||
3e14dc3eb8 | |||
ba6d8ad261 | |||
2a08865851 | |||
0a3bfe7f73 | |||
451a9c64d3 | |||
88d79c84cd | |||
abcb0877e2 | |||
9e1e2a4320 | |||
d53b0a99d0 | |||
1fb4f9e455 | |||
6e9b6f22c9 | |||
e90b099622 | |||
84c10de864 | |||
d618b60d9e | |||
c761f7f844 | |||
7b89fab327 | |||
eddff46155 | |||
baa50ec9b2 | |||
513186c390 | |||
0c37463bfa | |||
94fc33bbee | |||
ce378a68a6 | |||
fa40740e77 | |||
762fdb98ac | |||
5f795b1aec | |||
6811700b90 | |||
248aca7a44 | |||
17abbdf6e0 | |||
40eca52ed5 | |||
7907dda8f7 | |||
8501024546 | |||
21d30d1e4d | |||
eeaa65c8af | |||
6754b8534e | |||
2ffff959fc | |||
fed4233db4 | |||
2f47263380 | |||
4d5386635e | |||
872eb2c3df | |||
e62a77a885 | |||
9bca63ebef | |||
ae54dc862c | |||
5e951b2be9 | |||
f78d57a703 | |||
f021be623e | |||
b6189879e3 | |||
c7c6445b03 | |||
535aec0648 | |||
664dd291eb | |||
a9216deaa4 | |||
99caad7d60 | |||
7486850357 | |||
bb06661d24 | |||
6a374182a7 | |||
f433b3102f | |||
456e2a8ee3 | |||
1ee3bf784c | |||
54394fe9af | |||
7a728340de | |||
5f1e8a6af8 | |||
e566a073dc | |||
9a4dad6ca1 | |||
eca9f461da | |||
08aaa9494c | |||
352f913c39 | |||
aeeb5dd405 | |||
278bf7ffa9 | |||
b15c824932 | |||
5ad3bfa31b | |||
e5145358eb | |||
3a20fbfe94 | |||
dac32557cd | |||
fedd879b2e | |||
a46c21cffb | |||
6cdfee3573 | |||
af79eb2943 | |||
e9d4730099 | |||
844f541719 | |||
d28f728787 | |||
f35808cb89 | |||
7d6b23ee2f | |||
e68ae4c8d1 | |||
faad6ca355 | |||
c77c1bd297 | |||
5b4b4446b7 | |||
93f20b406e | |||
02318cf3a7 | |||
35fc387505 | |||
fd4ba0443d | |||
b943cbedff | |||
3fd1a26ec0 | |||
3f2c76df28 | |||
7d3312e96e | |||
c59d9dc306 | |||
1f06f8405c | |||
38f454d5ab | |||
487f1a97ea | |||
0f05475e2e | |||
cc805f3f01 | |||
5ac5b90aed | |||
3d73287ea4 | |||
7ebdced256 | |||
ad12018199 | |||
27dcc3ecc3 | |||
e25a795cf6 | |||
16c15e83a3 | |||
cea67cb30b | |||
1e3e034021 | |||
8da27a1a09 | |||
030e749fe7 | |||
a785e64bc9 | |||
d4eeef4bd1 | |||
c8a07d477f | |||
af82eeca72 | |||
3d698b74d8 |
0
.typos.toml → .github/.typos.toml
vendored
0
.typos.toml → .github/.typos.toml
vendored
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
@ -25,7 +25,7 @@ Make sure you've run and fixed any issues with these commands:
|
||||
|
||||
- `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes)
|
||||
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to check that you're using the standard code style
|
||||
- `cargo test --workspace` to check that all tests pass
|
||||
- `cargo test --workspace` to check that all tests pass (on Windows make sure to [enable developer mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
|
||||
- `cargo run -- -c "use std testing; testing run-tests --path crates/nu-std"` to run the tests for the standard library
|
||||
|
||||
> **Note**
|
||||
|
25
.github/workflows/audit.yml
vendored
Normal file
25
.github/workflows/audit.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
name: Security audit
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '**/Cargo.toml'
|
||||
- '**/Cargo.lock'
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
CARGO_TERM_COLOR: always
|
||||
CLICOLOR: 1
|
||||
|
||||
jobs:
|
||||
security_audit:
|
||||
runs-on: ubuntu-latest
|
||||
# Prevent sudden announcement of a new advisory from failing ci:
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: rustsec/audit-check@v1.4.1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
14
.github/workflows/ci.yml
vendored
14
.github/workflows/ci.yml
vendored
@ -7,7 +7,7 @@ on:
|
||||
name: continuous-integration
|
||||
|
||||
env:
|
||||
NUSHELL_CARGO_TARGET: ci
|
||||
NUSHELL_CARGO_PROFILE: ci
|
||||
NU_LOG_LEVEL: DEBUG
|
||||
CLIPPY_OPTIONS: "-D warnings -D clippy::unwrap_used"
|
||||
|
||||
@ -37,7 +37,7 @@ jobs:
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Rust toolchain and cache
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.5.0
|
||||
@ -49,6 +49,10 @@ jobs:
|
||||
|
||||
- name: Clippy
|
||||
run: cargo clippy --workspace ${{ matrix.flags }} --exclude nu_plugin_* -- $CLIPPY_OPTIONS
|
||||
|
||||
# In tests we don't have to deny unwrap
|
||||
- name: Clippy of tests
|
||||
run: cargo clippy --tests --workspace ${{ matrix.flags }} --exclude nu_plugin_* -- -D warnings
|
||||
|
||||
tests:
|
||||
strategy:
|
||||
@ -76,7 +80,7 @@ jobs:
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Rust toolchain and cache
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.5.0
|
||||
@ -97,7 +101,7 @@ jobs:
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Rust toolchain and cache
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.5.0
|
||||
@ -132,7 +136,7 @@ jobs:
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Rust toolchain and cache
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.5.0
|
||||
|
27
.github/workflows/nightly-build.yml
vendored
27
.github/workflows/nightly-build.yml
vendored
@ -13,7 +13,7 @@ on:
|
||||
- nightly # Just for test purpose only with the nightly repo
|
||||
# This schedule will run only from the default branch
|
||||
schedule:
|
||||
- cron: '15 1 * * *' # run at 01:15 AM UTC
|
||||
- cron: '15 0 * * *' # run at 00:15 AM UTC
|
||||
|
||||
defaults:
|
||||
run:
|
||||
@ -27,7 +27,7 @@ jobs:
|
||||
# if: github.repository == 'nushell/nightly'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
if: github.repository == 'nushell/nightly'
|
||||
with:
|
||||
ref: main
|
||||
@ -36,10 +36,10 @@ jobs:
|
||||
token: ${{ secrets.WORKFLOW_TOKEN }}
|
||||
|
||||
- name: Setup Nushell
|
||||
uses: hustcer/setup-nu@v3
|
||||
uses: hustcer/setup-nu@v3.6
|
||||
if: github.repository == 'nushell/nightly'
|
||||
with:
|
||||
version: 0.81.0
|
||||
version: 0.84.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@ -53,14 +53,13 @@ jobs:
|
||||
# We can't push if no user name and email are configured
|
||||
git config user.name 'hustcer'
|
||||
git config user.email 'hustcer@outlook.com'
|
||||
git fetch origin main
|
||||
git pull origin main
|
||||
git remote add src https://github.com/nushell/nushell.git
|
||||
git fetch src main
|
||||
# git pull --rebase src main
|
||||
# All the changes will be overwritten by the upstream main branch
|
||||
git reset --hard src/main
|
||||
git push origin main -f
|
||||
let sha_short = (git rev-parse --short src/main | str trim | str substring 0..7)
|
||||
let sha_short = (git rev-parse --short origin/main | str trim | str substring 0..7)
|
||||
let tag_name = $'nightly-($sha_short)'
|
||||
if (git ls-remote --tags origin $tag_name | is-empty) {
|
||||
git tag -a $tag_name -m $'Nightly build from ($sha_short)'
|
||||
@ -126,7 +125,7 @@ jobs:
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: main
|
||||
|
||||
@ -140,9 +139,9 @@ jobs:
|
||||
rustflags: ''
|
||||
|
||||
- name: Setup Nushell
|
||||
uses: hustcer/setup-nu@v3
|
||||
uses: hustcer/setup-nu@v3.6
|
||||
with:
|
||||
version: 0.81.0
|
||||
version: 0.84.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@ -176,7 +175,7 @@ jobs:
|
||||
# REF: https://github.com/marketplace/actions/gh-release
|
||||
# Create a release only in nushell/nightly repo
|
||||
- name: Publish Archive
|
||||
uses: softprops/action-gh-release@v0.1.13
|
||||
uses: softprops/action-gh-release@v0.1.15
|
||||
if: ${{ startsWith(github.repository, 'nushell/nightly') }}
|
||||
with:
|
||||
draft: false
|
||||
@ -200,14 +199,14 @@ jobs:
|
||||
- name: Waiting for Release
|
||||
run: sleep 1800
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: main
|
||||
|
||||
- name: Setup Nushell
|
||||
uses: hustcer/setup-nu@v3
|
||||
uses: hustcer/setup-nu@v3.6
|
||||
with:
|
||||
version: 0.81.0
|
||||
version: 0.84.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
12
.github/workflows/release-pkg.nu
vendored
12
.github/workflows/release-pkg.nu
vendored
@ -172,18 +172,22 @@ if $os in [$USE_UBUNTU, 'macos-latest'] {
|
||||
cp -r $'($dist)/*' target/release/
|
||||
cargo install cargo-wix --version 0.3.4
|
||||
cargo wix --no-build --nocapture --package nu --output $wixRelease
|
||||
print $'archive: ---> ($wixRelease)';
|
||||
echo $"archive=($wixRelease)" | save --append $env.GITHUB_OUTPUT
|
||||
# Workaround for https://github.com/softprops/action-gh-release/issues/280
|
||||
let archive = ($wixRelease | str replace -a '\' '/')
|
||||
print $'archive: ---> ($archive)';
|
||||
echo $"archive=($archive)" | save --append $env.GITHUB_OUTPUT
|
||||
|
||||
} else {
|
||||
|
||||
print $'(char nl)(ansi g)Archive contents:(ansi reset)'; hr-line; ls
|
||||
let archive = $'($dist)/($releaseStem).zip'
|
||||
7z a $archive *
|
||||
print $'archive: ---> ($archive)';
|
||||
let pkg = (ls -f $archive | get name)
|
||||
if not ($pkg | is-empty) {
|
||||
echo $"archive=($pkg | get 0)" | save --append $env.GITHUB_OUTPUT
|
||||
# Workaround for https://github.com/softprops/action-gh-release/issues/280
|
||||
let archive = ($pkg | get 0 | str replace -a '\' '/')
|
||||
print $'archive: ---> ($archive)'
|
||||
echo $"archive=($archive)" | save --append $env.GITHUB_OUTPUT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
@ -72,7 +72,7 @@ jobs:
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Update Rust Toolchain Target
|
||||
run: |
|
||||
@ -84,9 +84,9 @@ jobs:
|
||||
rustflags: ''
|
||||
|
||||
- name: Setup Nushell
|
||||
uses: hustcer/setup-nu@v3
|
||||
uses: hustcer/setup-nu@v3.6
|
||||
with:
|
||||
version: 0.81.0
|
||||
version: 0.84.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@ -102,7 +102,7 @@ jobs:
|
||||
|
||||
# REF: https://github.com/marketplace/actions/gh-release
|
||||
- name: Publish Archive
|
||||
uses: softprops/action-gh-release@v0.1.13
|
||||
uses: softprops/action-gh-release@v0.1.15
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||
with:
|
||||
draft: true
|
||||
|
6
.github/workflows/typos.yml
vendored
6
.github/workflows/typos.yml
vendored
@ -7,7 +7,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Actions Repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Check spelling
|
||||
uses: crate-ci/typos@master
|
||||
uses: crate-ci/typos@v1.16.11
|
||||
with:
|
||||
config: ./.github/.typos.toml
|
||||
|
705
Cargo.lock
generated
705
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
60
Cargo.toml
60
Cargo.toml
@ -11,7 +11,7 @@ license = "MIT"
|
||||
name = "nu"
|
||||
repository = "https://github.com/nushell/nushell"
|
||||
rust-version = "1.60"
|
||||
version = "0.84.0"
|
||||
version = "0.85.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -46,34 +46,34 @@ members = [
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
nu-cli = { path = "./crates/nu-cli", version = "0.84.0" }
|
||||
nu-color-config = { path = "./crates/nu-color-config", version = "0.84.0" }
|
||||
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.84.0" }
|
||||
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.84.0" }
|
||||
nu-cmd-dataframe = { path = "./crates/nu-cmd-dataframe", version = "0.84.0", features = ["dataframe"], optional = true }
|
||||
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.84.0", optional = true }
|
||||
nu-command = { path = "./crates/nu-command", version = "0.84.0" }
|
||||
nu-engine = { path = "./crates/nu-engine", version = "0.84.0" }
|
||||
nu-explore = { path = "./crates/nu-explore", version = "0.84.0" }
|
||||
nu-json = { path = "./crates/nu-json", version = "0.84.0" }
|
||||
nu-parser = { path = "./crates/nu-parser", version = "0.84.0" }
|
||||
nu-path = { path = "./crates/nu-path", version = "0.84.0" }
|
||||
nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.84.0" }
|
||||
nu-pretty-hex = { path = "./crates/nu-pretty-hex", version = "0.84.0" }
|
||||
nu-protocol = { path = "./crates/nu-protocol", version = "0.84.0" }
|
||||
nu-system = { path = "./crates/nu-system", version = "0.84.0" }
|
||||
nu-table = { path = "./crates/nu-table", version = "0.84.0" }
|
||||
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.84.0" }
|
||||
nu-std = { path = "./crates/nu-std", version = "0.84.0" }
|
||||
nu-utils = { path = "./crates/nu-utils", version = "0.84.0" }
|
||||
nu-cli = { path = "./crates/nu-cli", version = "0.85.0" }
|
||||
nu-color-config = { path = "./crates/nu-color-config", version = "0.85.0" }
|
||||
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.85.0" }
|
||||
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.85.0" }
|
||||
nu-cmd-dataframe = { path = "./crates/nu-cmd-dataframe", version = "0.85.0", features = ["dataframe"], optional = true }
|
||||
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.85.0", optional = true }
|
||||
nu-command = { path = "./crates/nu-command", version = "0.85.0" }
|
||||
nu-engine = { path = "./crates/nu-engine", version = "0.85.0" }
|
||||
nu-explore = { path = "./crates/nu-explore", version = "0.85.0" }
|
||||
nu-json = { path = "./crates/nu-json", version = "0.85.0" }
|
||||
nu-parser = { path = "./crates/nu-parser", version = "0.85.0" }
|
||||
nu-path = { path = "./crates/nu-path", version = "0.85.0" }
|
||||
nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.85.0" }
|
||||
nu-pretty-hex = { path = "./crates/nu-pretty-hex", version = "0.85.0" }
|
||||
nu-protocol = { path = "./crates/nu-protocol", version = "0.85.0" }
|
||||
nu-system = { path = "./crates/nu-system", version = "0.85.0" }
|
||||
nu-table = { path = "./crates/nu-table", version = "0.85.0" }
|
||||
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.85.0" }
|
||||
nu-std = { path = "./crates/nu-std", version = "0.85.0" }
|
||||
nu-utils = { path = "./crates/nu-utils", version = "0.85.0" }
|
||||
nu-ansi-term = "0.49.0"
|
||||
reedline = { version = "0.23.0", features = ["bashisms", "sqlite"]}
|
||||
reedline = { version = "0.24.0", features = ["bashisms", "sqlite"] }
|
||||
|
||||
crossterm = "0.26"
|
||||
crossterm = "0.27"
|
||||
ctrlc = "3.4"
|
||||
log = "0.4"
|
||||
miette = { version = "5.10", features = ["fancy-no-backtrace"] }
|
||||
mimalloc = { version = "0.1.37", default-features = false, optional = true}
|
||||
mimalloc = { version = "0.1.37", default-features = false, optional = true }
|
||||
serde_json = "1.0"
|
||||
simplelog = "0.12"
|
||||
time = "0.3"
|
||||
@ -87,22 +87,21 @@ signal-hook = { version = "0.3", default-features = false }
|
||||
winresource = "0.1"
|
||||
|
||||
[target.'cfg(target_family = "unix")'.dependencies]
|
||||
nix = { version = "0.26", default-features = false, features = [
|
||||
nix = { version = "0.27", default-features = false, features = [
|
||||
"signal",
|
||||
"process",
|
||||
"fs",
|
||||
"term",
|
||||
] }
|
||||
is-terminal = "0.4.8"
|
||||
|
||||
[dev-dependencies]
|
||||
nu-test-support = { path = "./crates/nu-test-support", version = "0.84.0" }
|
||||
nu-test-support = { path = "./crates/nu-test-support", version = "0.85.0" }
|
||||
assert_cmd = "2.0"
|
||||
criterion = "0.5"
|
||||
pretty_assertions = "1.4"
|
||||
rstest = { version = "0.18", default-features = false }
|
||||
serial_test = "2.0"
|
||||
tempfile = "3.7"
|
||||
tempfile = "3.8"
|
||||
|
||||
[features]
|
||||
plugin = [
|
||||
@ -113,12 +112,13 @@ plugin = [
|
||||
"nu-protocol/plugin",
|
||||
"nu-engine/plugin",
|
||||
]
|
||||
default = ["plugin", "which-support", "trash-support", "sqlite"]
|
||||
default = ["plugin", "which-support", "trash-support", "sqlite", "mimalloc"]
|
||||
stable = ["default"]
|
||||
wasi = ["nu-cmd-lang/wasi"]
|
||||
# NOTE: individual features are also passed to `nu-cmd-lang` that uses them to generate the feature matrix in the `version` command
|
||||
|
||||
# Enable to statically link OpenSSL; otherwise the system version will be used. Not enabled by default because it takes a while to build
|
||||
# Enable to statically link OpenSSL (perl is required, to build OpenSSL https://docs.rs/openssl/latest/openssl/);
|
||||
# otherwise the system version will be used. Not enabled by default because it takes a while to build
|
||||
static-link-openssl = ["dep:openssl", "nu-cmd-lang/static-link-openssl"]
|
||||
|
||||
mimalloc = ["nu-cmd-lang/mimalloc", "dep:mimalloc"]
|
||||
|
@ -7,7 +7,6 @@
|
||||
[](https://twitter.com/nu_shell)
|
||||
[](https://github.com/nushell/nushell/graphs/commit-activity)
|
||||
[](https://github.com/nushell/nushell/graphs/contributors)
|
||||
[](https://codecov.io/gh/nushell/nushell)
|
||||
|
||||
A new type of shell.
|
||||
|
||||
@ -220,13 +219,14 @@ Please submit an issue or PR to be added to this list.
|
||||
- [virtualenv](https://github.com/pypa/virtualenv)
|
||||
- [atuin](https://github.com/ellie/atuin)
|
||||
- [clap](https://github.com/clap-rs/clap/tree/master/clap_complete_nushell)
|
||||
- [Dorothy](http://github.com/bevry/dorothy)
|
||||
|
||||
## Contributing
|
||||
|
||||
See [Contributing](CONTRIBUTING.md) for details. Thanks to all the people who already contributed!
|
||||
|
||||
<a href="https://github.com/nushell/nushell/graphs/contributors">
|
||||
<img src="https://contributors-img.web.app/image?repo=nushell/nushell&max=500" />
|
||||
<img src="https://contributors-img.web.app/image?repo=nushell/nushell&max=600" />
|
||||
</a>
|
||||
|
||||
## License
|
||||
|
@ -114,15 +114,13 @@ fn eval_benchmarks(c: &mut Criterion) {
|
||||
|
||||
// generate a new table data with `row_cnt` rows, `col_cnt` columns.
|
||||
fn encoding_test_data(row_cnt: usize, col_cnt: usize) -> Value {
|
||||
let columns: Vec<String> = (0..col_cnt).map(|x| format!("col_{x}")).collect();
|
||||
let vals: Vec<Value> = (0..col_cnt as i64).map(Value::test_int).collect();
|
||||
|
||||
Value::List {
|
||||
vals: (0..row_cnt)
|
||||
.map(|_| Value::test_record(columns.clone(), vals.clone()))
|
||||
let record = Value::test_record(
|
||||
(0..col_cnt)
|
||||
.map(|x| (format!("col_{x}"), Value::test_int(x as i64)))
|
||||
.collect(),
|
||||
span: Span::test_data(),
|
||||
}
|
||||
);
|
||||
|
||||
Value::list(vec![record; row_cnt], Span::test_data())
|
||||
}
|
||||
|
||||
fn encoding_benchmarks(c: &mut Criterion) {
|
||||
|
17
codecov.yml
17
codecov.yml
@ -1,17 +0,0 @@
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
target: 55%
|
||||
threshold: 2%
|
||||
patch:
|
||||
default:
|
||||
informational: true
|
||||
|
||||
comment:
|
||||
layout: reach, diff, files
|
||||
behavior: default
|
||||
require_base: yes
|
||||
require_head: yes
|
||||
after_n_builds: 1 # Disabled windows else: 2
|
||||
|
@ -5,34 +5,33 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cli"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cli"
|
||||
version = "0.84.0"
|
||||
version = "0.85.0"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dev-dependencies]
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.84.0" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.84.0" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.85.0" }
|
||||
nu-command = { path = "../nu-command", version = "0.85.0" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.85.0" }
|
||||
rstest = { version = "0.18.1", default-features = false }
|
||||
|
||||
[dependencies]
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.84.0" }
|
||||
nu-command = { path = "../nu-command", version = "0.84.0" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.84.0" }
|
||||
nu-path = { path = "../nu-path", version = "0.84.0" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.84.0" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.84.0" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.84.0" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.84.0" }
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.85.0" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.85.0" }
|
||||
nu-path = { path = "../nu-path", version = "0.85.0" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.85.0" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.85.0" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.85.0" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.85.0" }
|
||||
nu-ansi-term = "0.49.0"
|
||||
reedline = { version = "0.23.0", features = ["bashisms", "sqlite"]}
|
||||
reedline = { version = "0.24.0", features = ["bashisms", "sqlite"] }
|
||||
|
||||
chrono = { default-features = false, features = ["std"], version = "0.4" }
|
||||
crossterm = "0.26"
|
||||
crossterm = "0.27"
|
||||
fancy-regex = "0.11"
|
||||
fuzzy-matcher = "0.3"
|
||||
is_executable = "1.0"
|
||||
is-terminal = "0.4.8"
|
||||
log = "0.4"
|
||||
miette = { version = "5.10", features = ["fancy-no-backtrace"] }
|
||||
once_cell = "1.18"
|
||||
|
@ -1,9 +1,9 @@
|
||||
use nu_engine::CallExt;
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::Category;
|
||||
use nu_protocol::IntoPipelineData;
|
||||
use nu_protocol::{PipelineData, ShellError, Signature, SyntaxShape, Type, Value};
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
|
||||
};
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -25,6 +25,11 @@ impl Command for Commandline {
|
||||
"Set or get the current cursor position",
|
||||
Some('c'),
|
||||
)
|
||||
.switch(
|
||||
"cursor-end",
|
||||
"Set the current cursor position to the end of the buffer",
|
||||
Some('e'),
|
||||
)
|
||||
.switch(
|
||||
"append",
|
||||
"appends the string to the end of the buffer",
|
||||
@ -84,7 +89,7 @@ impl Command for Commandline {
|
||||
return Err(ShellError::CantConvert {
|
||||
to_type: "int".to_string(),
|
||||
from_type: "string".to_string(),
|
||||
span: cmd.span()?,
|
||||
span: cmd.span(),
|
||||
help: Some(format!(
|
||||
r#"string "{cmd_str}" does not represent a valid integer"#
|
||||
)),
|
||||
@ -102,27 +107,22 @@ impl Command for Commandline {
|
||||
repl.buffer = cmd.as_string()?;
|
||||
repl.cursor_pos = repl.buffer.len();
|
||||
}
|
||||
Ok(Value::Nothing { span: call.head }.into_pipeline_data())
|
||||
Ok(Value::nothing(call.head).into_pipeline_data())
|
||||
} else {
|
||||
let repl = engine_state.repl_state.lock().expect("repl state mutex");
|
||||
if call.has_flag("cursor") {
|
||||
let mut repl = engine_state.repl_state.lock().expect("repl state mutex");
|
||||
if call.has_flag("cursor-end") {
|
||||
repl.cursor_pos = repl.buffer.graphemes(true).count();
|
||||
Ok(Value::nothing(call.head).into_pipeline_data())
|
||||
} else if call.has_flag("cursor") {
|
||||
let char_pos = repl
|
||||
.buffer
|
||||
.grapheme_indices(true)
|
||||
.chain(std::iter::once((repl.buffer.len(), "")))
|
||||
.position(|(i, _c)| i == repl.cursor_pos)
|
||||
.expect("Cursor position isn't on a grapheme boundary");
|
||||
Ok(Value::String {
|
||||
val: char_pos.to_string(),
|
||||
span: call.head,
|
||||
}
|
||||
.into_pipeline_data())
|
||||
Ok(Value::string(char_pos.to_string(), call.head).into_pipeline_data())
|
||||
} else {
|
||||
Ok(Value::String {
|
||||
val: repl.buffer.to_string(),
|
||||
span: call.head,
|
||||
}
|
||||
.into_pipeline_data())
|
||||
Ok(Value::string(repl.buffer.to_string(), call.head).into_pipeline_data())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
Category, Example, HistoryFileFormat, IntoInterruptiblePipelineData, PipelineData, ShellError,
|
||||
Signature, Span, Type, Value,
|
||||
record, Category, Example, HistoryFileFormat, IntoInterruptiblePipelineData, PipelineData,
|
||||
ShellError, Signature, Span, Type, Value,
|
||||
};
|
||||
use reedline::{
|
||||
FileBackedHistory, History as ReedlineHistory, HistoryItem, SearchDirection, SearchQuery,
|
||||
@ -70,12 +70,14 @@ impl Command for History {
|
||||
} else {
|
||||
let history_reader: Option<Box<dyn ReedlineHistory>> =
|
||||
match engine_state.config.history_file_format {
|
||||
HistoryFileFormat::Sqlite => SqliteBackedHistory::with_file(history_path)
|
||||
.map(|inner| {
|
||||
let boxed: Box<dyn ReedlineHistory> = Box::new(inner);
|
||||
boxed
|
||||
})
|
||||
.ok(),
|
||||
HistoryFileFormat::Sqlite => {
|
||||
SqliteBackedHistory::with_file(history_path, None, None)
|
||||
.map(|inner| {
|
||||
let boxed: Box<dyn ReedlineHistory> = Box::new(inner);
|
||||
boxed
|
||||
})
|
||||
.ok()
|
||||
}
|
||||
|
||||
HistoryFileFormat::PlainText => FileBackedHistory::with_file(
|
||||
engine_state.config.max_history_size as usize,
|
||||
@ -95,20 +97,15 @@ impl Command for History {
|
||||
.ok()
|
||||
})
|
||||
.map(move |entries| {
|
||||
entries
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(move |(idx, entry)| Value::Record {
|
||||
cols: vec!["command".to_string(), "index".to_string()],
|
||||
vals: vec![
|
||||
Value::String {
|
||||
val: entry.command_line,
|
||||
span: head,
|
||||
},
|
||||
Value::int(idx as i64, head),
|
||||
],
|
||||
span: head,
|
||||
})
|
||||
entries.into_iter().enumerate().map(move |(idx, entry)| {
|
||||
Value::record(
|
||||
record! {
|
||||
"command" => Value::string(entry.command_line, head),
|
||||
"index" => Value::int(idx as i64, head),
|
||||
},
|
||||
head,
|
||||
)
|
||||
})
|
||||
})
|
||||
.ok_or(ShellError::FileNotFound(head))?
|
||||
.into_pipeline_data(ctrlc)),
|
||||
@ -144,7 +141,7 @@ impl Command for History {
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
example: "history | wrap cmd | where cmd =~ cargo",
|
||||
example: "history | where command =~ cargo | get command",
|
||||
description: "Search all the commands from history that contains 'cargo'",
|
||||
result: None,
|
||||
},
|
||||
@ -156,8 +153,8 @@ fn create_history_record(idx: usize, entry: HistoryItem, long: bool, head: Span)
|
||||
//1. Format all the values
|
||||
//2. Create a record of either short or long columns and values
|
||||
|
||||
let item_id_value = Value::Int {
|
||||
val: match entry.id {
|
||||
let item_id_value = Value::int(
|
||||
match entry.id {
|
||||
Some(id) => {
|
||||
let ids = id.to_string();
|
||||
match ids.parse::<i64>() {
|
||||
@ -167,21 +164,18 @@ fn create_history_record(idx: usize, entry: HistoryItem, long: bool, head: Span)
|
||||
}
|
||||
None => 0i64,
|
||||
},
|
||||
span: head,
|
||||
};
|
||||
let start_timestamp_value = Value::String {
|
||||
val: match entry.start_timestamp {
|
||||
head,
|
||||
);
|
||||
let start_timestamp_value = Value::string(
|
||||
match entry.start_timestamp {
|
||||
Some(time) => time.to_string(),
|
||||
None => "".into(),
|
||||
},
|
||||
span: head,
|
||||
};
|
||||
let command_value = Value::String {
|
||||
val: entry.command_line,
|
||||
span: head,
|
||||
};
|
||||
let session_id_value = Value::Int {
|
||||
val: match entry.session_id {
|
||||
head,
|
||||
);
|
||||
let command_value = Value::string(entry.command_line, head);
|
||||
let session_id_value = Value::int(
|
||||
match entry.session_id {
|
||||
Some(sid) => {
|
||||
let sids = sid.to_string();
|
||||
match sids.parse::<i64>() {
|
||||
@ -191,74 +185,56 @@ fn create_history_record(idx: usize, entry: HistoryItem, long: bool, head: Span)
|
||||
}
|
||||
None => 0i64,
|
||||
},
|
||||
span: head,
|
||||
};
|
||||
let hostname_value = Value::String {
|
||||
val: match entry.hostname {
|
||||
head,
|
||||
);
|
||||
let hostname_value = Value::string(
|
||||
match entry.hostname {
|
||||
Some(host) => host,
|
||||
None => "".into(),
|
||||
},
|
||||
span: head,
|
||||
};
|
||||
let cwd_value = Value::String {
|
||||
val: match entry.cwd {
|
||||
head,
|
||||
);
|
||||
let cwd_value = Value::string(
|
||||
match entry.cwd {
|
||||
Some(cwd) => cwd,
|
||||
None => "".into(),
|
||||
},
|
||||
span: head,
|
||||
};
|
||||
let duration_value = Value::Duration {
|
||||
val: match entry.duration {
|
||||
head,
|
||||
);
|
||||
let duration_value = Value::duration(
|
||||
match entry.duration {
|
||||
Some(d) => d.as_nanos().try_into().unwrap_or(0),
|
||||
None => 0,
|
||||
},
|
||||
span: head,
|
||||
};
|
||||
head,
|
||||
);
|
||||
let exit_status_value = Value::int(entry.exit_status.unwrap_or(0), head);
|
||||
let index_value = Value::int(idx as i64, head);
|
||||
if long {
|
||||
Value::Record {
|
||||
cols: vec![
|
||||
"item_id".into(),
|
||||
"start_timestamp".into(),
|
||||
"command".to_string(),
|
||||
"session_id".into(),
|
||||
"hostname".into(),
|
||||
"cwd".into(),
|
||||
"duration".into(),
|
||||
"exit_status".into(),
|
||||
"idx".to_string(),
|
||||
],
|
||||
vals: vec![
|
||||
item_id_value,
|
||||
start_timestamp_value,
|
||||
command_value,
|
||||
session_id_value,
|
||||
hostname_value,
|
||||
cwd_value,
|
||||
duration_value,
|
||||
exit_status_value,
|
||||
index_value,
|
||||
],
|
||||
span: head,
|
||||
}
|
||||
Value::record(
|
||||
record! {
|
||||
"item_id" => item_id_value,
|
||||
"start_timestamp" => start_timestamp_value,
|
||||
"command" => command_value,
|
||||
"session_id" => session_id_value,
|
||||
"hostname" => hostname_value,
|
||||
"cwd" => cwd_value,
|
||||
"duration" => duration_value,
|
||||
"exit_status" => exit_status_value,
|
||||
"idx" => index_value,
|
||||
},
|
||||
head,
|
||||
)
|
||||
} else {
|
||||
Value::Record {
|
||||
cols: vec![
|
||||
"start_timestamp".into(),
|
||||
"command".to_string(),
|
||||
"cwd".into(),
|
||||
"duration".into(),
|
||||
"exit_status".into(),
|
||||
],
|
||||
vals: vec![
|
||||
start_timestamp_value,
|
||||
command_value,
|
||||
cwd_value,
|
||||
duration_value,
|
||||
exit_status_value,
|
||||
],
|
||||
span: head,
|
||||
}
|
||||
Value::record(
|
||||
record! {
|
||||
"start_timestamp" => start_timestamp_value,
|
||||
"command" => command_value,
|
||||
"cwd" => cwd_value,
|
||||
"duration" => duration_value,
|
||||
"exit_status" => exit_status_value,
|
||||
},
|
||||
head,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,10 @@ impl Command for Keybindings {
|
||||
}
|
||||
|
||||
fn extra_usage(&self) -> &str {
|
||||
"You must use one of the following subcommands. Using this command as-is will only produce this help message."
|
||||
r#"You must use one of the following subcommands. Using this command as-is will only produce this help message.
|
||||
|
||||
For more information on input and keybindings, check:
|
||||
https://www.nushell.sh/book/line_editor.html"#
|
||||
}
|
||||
|
||||
fn search_terms(&self) -> Vec<&str> {
|
||||
@ -38,16 +41,16 @@ impl Command for Keybindings {
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
Ok(Value::String {
|
||||
val: get_full_help(
|
||||
Ok(Value::string(
|
||||
get_full_help(
|
||||
&Keybindings.signature(),
|
||||
&Keybindings.examples(),
|
||||
engine_state,
|
||||
stack,
|
||||
self.is_parser_keyword(),
|
||||
),
|
||||
span: call.head,
|
||||
}
|
||||
call.head,
|
||||
)
|
||||
.into_pipeline_data())
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Type, Value,
|
||||
record, Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Type, Value,
|
||||
};
|
||||
use reedline::get_reedline_default_keybindings;
|
||||
|
||||
@ -41,43 +41,18 @@ impl Command for KeybindingsDefault {
|
||||
let records = get_reedline_default_keybindings()
|
||||
.into_iter()
|
||||
.map(|(mode, modifier, code, event)| {
|
||||
let mode = Value::String {
|
||||
val: mode,
|
||||
span: call.head,
|
||||
};
|
||||
|
||||
let modifier = Value::String {
|
||||
val: modifier,
|
||||
span: call.head,
|
||||
};
|
||||
|
||||
let code = Value::String {
|
||||
val: code,
|
||||
span: call.head,
|
||||
};
|
||||
|
||||
let event = Value::String {
|
||||
val: event,
|
||||
span: call.head,
|
||||
};
|
||||
|
||||
Value::Record {
|
||||
cols: vec![
|
||||
"mode".to_string(),
|
||||
"modifier".to_string(),
|
||||
"code".to_string(),
|
||||
"event".to_string(),
|
||||
],
|
||||
vals: vec![mode, modifier, code, event],
|
||||
span: call.head,
|
||||
}
|
||||
Value::record(
|
||||
record! {
|
||||
"mode" => Value::string(mode, call.head),
|
||||
"modifier" => Value::string(modifier, call.head),
|
||||
"code" => Value::string(code, call.head),
|
||||
"event" => Value::string(event, call.head),
|
||||
},
|
||||
call.head,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(Value::List {
|
||||
vals: records,
|
||||
span: call.head,
|
||||
}
|
||||
.into_pipeline_data())
|
||||
Ok(Value::list(records, call.head).into_pipeline_data())
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Type, Value,
|
||||
record, Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Type,
|
||||
Value,
|
||||
};
|
||||
use reedline::{
|
||||
get_reedline_edit_commands, get_reedline_keybinding_modifiers, get_reedline_keycodes,
|
||||
@ -70,11 +71,7 @@ impl Command for KeybindingsList {
|
||||
.collect()
|
||||
};
|
||||
|
||||
Ok(Value::List {
|
||||
vals: records,
|
||||
span: call.head,
|
||||
}
|
||||
.into_pipeline_data())
|
||||
Ok(Value::list(records, call.head).into_pipeline_data())
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,15 +93,13 @@ fn get_records(entry_type: &str, span: Span) -> Vec<Value> {
|
||||
}
|
||||
|
||||
fn convert_to_record(edit: &str, entry_type: &str, span: Span) -> Value {
|
||||
let entry_type = Value::string(entry_type, span);
|
||||
|
||||
let name = Value::string(edit, span);
|
||||
|
||||
Value::Record {
|
||||
cols: vec!["type".to_string(), "name".to_string()],
|
||||
vals: vec![entry_type, name],
|
||||
Value::record(
|
||||
record! {
|
||||
"type" => Value::string(entry_type, span),
|
||||
"name" => Value::string(edit, span),
|
||||
},
|
||||
span,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// Helper to sort a vec and return a vec
|
||||
|
@ -3,7 +3,8 @@ use crossterm::{event::Event, event::KeyCode, event::KeyEvent, terminal};
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Type, Value,
|
||||
record, Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Type,
|
||||
Value,
|
||||
};
|
||||
use std::io::{stdout, Write};
|
||||
|
||||
@ -19,6 +20,10 @@ impl Command for KeybindingsListen {
|
||||
"Get input from the user."
|
||||
}
|
||||
|
||||
fn extra_usage(&self) -> &str {
|
||||
"This is an internal debugging tool. For better output, try `input listen --types [key]`"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name())
|
||||
.category(Category::Platform)
|
||||
@ -78,9 +83,8 @@ pub fn print_events(engine_state: &EngineState) -> Result<Value, ShellError> {
|
||||
let v = print_events_helper(event)?;
|
||||
// Print out the record
|
||||
let o = match v {
|
||||
Value::Record { cols, vals, .. } => cols
|
||||
Value::Record { val, .. } => val
|
||||
.iter()
|
||||
.zip(vals.iter())
|
||||
.map(|(x, y)| format!("{}: {}", x, y.into_string("", config)))
|
||||
.collect::<Vec<String>>()
|
||||
.join(", "),
|
||||
@ -111,54 +115,29 @@ fn print_events_helper(event: Event) -> Result<Value, ShellError> {
|
||||
{
|
||||
match code {
|
||||
KeyCode::Char(c) => {
|
||||
let record = Value::Record {
|
||||
cols: vec![
|
||||
"char".into(),
|
||||
"code".into(),
|
||||
"modifier".into(),
|
||||
"flags".into(),
|
||||
"kind".into(),
|
||||
"state".into(),
|
||||
],
|
||||
vals: vec![
|
||||
Value::string(format!("{c}"), Span::unknown()),
|
||||
Value::string(format!("{:#08x}", u32::from(c)), Span::unknown()),
|
||||
Value::string(format!("{modifiers:?}"), Span::unknown()),
|
||||
Value::string(format!("{modifiers:#08b}"), Span::unknown()),
|
||||
Value::string(format!("{kind:?}"), Span::unknown()),
|
||||
Value::string(format!("{state:?}"), Span::unknown()),
|
||||
],
|
||||
span: Span::unknown(),
|
||||
let record = record! {
|
||||
"char" => Value::string(format!("{c}"), Span::unknown()),
|
||||
"code" => Value::string(format!("{:#08x}", u32::from(c)), Span::unknown()),
|
||||
"modifier" => Value::string(format!("{modifiers:?}"), Span::unknown()),
|
||||
"flags" => Value::string(format!("{modifiers:#08b}"), Span::unknown()),
|
||||
"kind" => Value::string(format!("{kind:?}"), Span::unknown()),
|
||||
"state" => Value::string(format!("{state:?}"), Span::unknown()),
|
||||
};
|
||||
Ok(record)
|
||||
Ok(Value::record(record, Span::unknown()))
|
||||
}
|
||||
_ => {
|
||||
let record = Value::Record {
|
||||
cols: vec![
|
||||
"code".into(),
|
||||
"modifier".into(),
|
||||
"flags".into(),
|
||||
"kind".into(),
|
||||
"state".into(),
|
||||
],
|
||||
vals: vec![
|
||||
Value::string(format!("{code:?}"), Span::unknown()),
|
||||
Value::string(format!("{modifiers:?}"), Span::unknown()),
|
||||
Value::string(format!("{modifiers:#08b}"), Span::unknown()),
|
||||
Value::string(format!("{kind:?}"), Span::unknown()),
|
||||
Value::string(format!("{state:?}"), Span::unknown()),
|
||||
],
|
||||
span: Span::unknown(),
|
||||
let record = record! {
|
||||
"code" => Value::string(format!("{code:?}"), Span::unknown()),
|
||||
"modifier" => Value::string(format!("{modifiers:?}"), Span::unknown()),
|
||||
"flags" => Value::string(format!("{modifiers:#08b}"), Span::unknown()),
|
||||
"kind" => Value::string(format!("{kind:?}"), Span::unknown()),
|
||||
"state" => Value::string(format!("{state:?}"), Span::unknown()),
|
||||
};
|
||||
Ok(record)
|
||||
Ok(Value::record(record, Span::unknown()))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let record = Value::Record {
|
||||
cols: vec!["event".into()],
|
||||
vals: vec![Value::string(format!("{event:?}"), Span::unknown())],
|
||||
span: Span::unknown(),
|
||||
};
|
||||
Ok(record)
|
||||
let record = record! { "event" => Value::string(format!("{event:?}"), Span::unknown()) };
|
||||
Ok(Value::record(record, Span::unknown()))
|
||||
}
|
||||
}
|
||||
|
@ -263,7 +263,7 @@ mod command_completions_tests {
|
||||
(" hello sud", 1),
|
||||
];
|
||||
for (idx, ele) in commands.iter().enumerate() {
|
||||
let index = find_non_whitespace_index(&Vec::from(ele.0.as_bytes()), 0);
|
||||
let index = find_non_whitespace_index(ele.0.as_bytes(), 0);
|
||||
assert_eq!(index, ele.1, "Failed on index {}", idx);
|
||||
}
|
||||
}
|
||||
|
@ -74,13 +74,13 @@ impl NuCompleter {
|
||||
if let Some(var_id) = pos_arg.var_id {
|
||||
callee_stack.add_var(
|
||||
var_id,
|
||||
Value::List {
|
||||
vals: spans
|
||||
Value::list(
|
||||
spans
|
||||
.iter()
|
||||
.map(|it| Value::string(it, Span::unknown()))
|
||||
.collect(),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
Span::unknown(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -97,7 +97,7 @@ impl NuCompleter {
|
||||
match result {
|
||||
Ok(pd) => {
|
||||
let value = pd.into_value(span);
|
||||
if let Value::List { vals, span: _ } = value {
|
||||
if let Value::List { vals, .. } = value {
|
||||
let result =
|
||||
map_value_completions(vals.iter(), Span::new(span.start, span.end), offset);
|
||||
|
||||
@ -136,7 +136,7 @@ impl NuCompleter {
|
||||
for (flat_idx, flat) in flattened.iter().enumerate() {
|
||||
let is_passthrough_command = spans
|
||||
.first()
|
||||
.filter(|content| *content == &String::from("sudo"))
|
||||
.filter(|content| content.as_str() == "sudo")
|
||||
.is_some();
|
||||
// Read the current spam to string
|
||||
let current_span = working_set.get_span_contents(flat.0).to_vec();
|
||||
@ -454,7 +454,7 @@ pub fn map_value_completions<'a>(
|
||||
}
|
||||
|
||||
// Match for record values
|
||||
if let Ok((cols, vals)) = x.as_record() {
|
||||
if let Ok(record) = x.as_record() {
|
||||
let mut suggestion = Suggestion {
|
||||
value: String::from(""), // Initialize with empty string
|
||||
description: None,
|
||||
@ -467,7 +467,7 @@ pub fn map_value_completions<'a>(
|
||||
};
|
||||
|
||||
// Iterate the cols looking for `value` and `description`
|
||||
cols.iter().zip(vals).for_each(|it| {
|
||||
record.iter().for_each(|it| {
|
||||
// Match `value` column
|
||||
if it.0 == "value" {
|
||||
// Convert the value to string
|
||||
|
@ -63,7 +63,12 @@ impl Completer for DirectoryCompletion {
|
||||
|
||||
match self.get_sort_by() {
|
||||
SortBy::Ascending => {
|
||||
sorted_items.sort_by(|a, b| a.value.cmp(&b.value));
|
||||
sorted_items.sort_by(|a, b| {
|
||||
// Ignore trailing slashes in folder names when sorting
|
||||
a.value
|
||||
.trim_end_matches(SEP)
|
||||
.cmp(b.value.trim_end_matches(SEP))
|
||||
});
|
||||
}
|
||||
SortBy::LevenshteinDistance => {
|
||||
sorted_items.sort_by(|a, b| {
|
||||
|
@ -60,7 +60,12 @@ impl Completer for FileCompletion {
|
||||
|
||||
match self.get_sort_by() {
|
||||
SortBy::Ascending => {
|
||||
sorted_items.sort_by(|a, b| a.value.cmp(&b.value));
|
||||
sorted_items.sort_by(|a, b| {
|
||||
// Ignore trailing slashes in folder names when sorting
|
||||
a.value
|
||||
.trim_end_matches(SEP)
|
||||
.cmp(b.value.trim_end_matches(SEP))
|
||||
});
|
||||
}
|
||||
SortBy::LevenshteinDistance => {
|
||||
sorted_items.sort_by(|a, b| {
|
||||
|
@ -235,13 +235,9 @@ fn nested_suggestions(
|
||||
let value = recursive_value(val, sublevels);
|
||||
|
||||
match value {
|
||||
Value::Record {
|
||||
cols,
|
||||
vals: _,
|
||||
span: _,
|
||||
} => {
|
||||
Value::Record { val, .. } => {
|
||||
// Add all the columns as completion
|
||||
for item in cols {
|
||||
for item in val.cols {
|
||||
output.push(Suggestion {
|
||||
value: item,
|
||||
description: None,
|
||||
@ -267,7 +263,7 @@ fn nested_suggestions(
|
||||
|
||||
output
|
||||
}
|
||||
Value::List { vals, span: _ } => {
|
||||
Value::List { vals, .. } => {
|
||||
for column_name in get_columns(vals.as_slice()) {
|
||||
output.push(Suggestion {
|
||||
value: column_name,
|
||||
@ -288,13 +284,10 @@ fn nested_suggestions(
|
||||
fn recursive_value(val: Value, sublevels: Vec<Vec<u8>>) -> Value {
|
||||
// Go to next sublevel
|
||||
if let Some(next_sublevel) = sublevels.clone().into_iter().next() {
|
||||
let span = val.span();
|
||||
match val {
|
||||
Value::Record {
|
||||
cols,
|
||||
vals,
|
||||
span: _,
|
||||
} => {
|
||||
for item in cols.into_iter().zip(vals) {
|
||||
Value::Record { val, .. } => {
|
||||
for item in val {
|
||||
// Check if index matches with sublevel
|
||||
if item.0.as_bytes().to_vec() == next_sublevel {
|
||||
// If matches try to fetch recursively the next
|
||||
@ -303,11 +296,9 @@ fn recursive_value(val: Value, sublevels: Vec<Vec<u8>>) -> Value {
|
||||
}
|
||||
|
||||
// Current sublevel value not found
|
||||
return Value::Nothing {
|
||||
span: Span::unknown(),
|
||||
};
|
||||
return Value::nothing(span);
|
||||
}
|
||||
Value::LazyRecord { val, span: _ } => {
|
||||
Value::LazyRecord { val, .. } => {
|
||||
for col in val.column_names() {
|
||||
if col.as_bytes().to_vec() == next_sublevel {
|
||||
return recursive_value(
|
||||
@ -318,15 +309,13 @@ fn recursive_value(val: Value, sublevels: Vec<Vec<u8>>) -> Value {
|
||||
}
|
||||
|
||||
// Current sublevel value not found
|
||||
return Value::Nothing {
|
||||
span: Span::unknown(),
|
||||
};
|
||||
return Value::nothing(span);
|
||||
}
|
||||
Value::List { vals, span } => {
|
||||
Value::List { vals, .. } => {
|
||||
for col in get_columns(vals.as_slice()) {
|
||||
if col.as_bytes().to_vec() == next_sublevel {
|
||||
return recursive_value(
|
||||
Value::List { vals, span }
|
||||
Value::list(vals, span)
|
||||
.get_data_by_key(&col)
|
||||
.unwrap_or_default(),
|
||||
sublevels.into_iter().skip(1).collect(),
|
||||
@ -335,9 +324,7 @@ fn recursive_value(val: Value, sublevels: Vec<Vec<u8>>) -> Value {
|
||||
}
|
||||
|
||||
// Current sublevel value not found
|
||||
return Value::Nothing {
|
||||
span: Span::unknown(),
|
||||
};
|
||||
return Value::nothing(span);
|
||||
}
|
||||
_ => return val,
|
||||
}
|
||||
|
@ -107,13 +107,17 @@ pub fn evaluate_file(
|
||||
trace!("parsing file: {}", file_path_str);
|
||||
let block = parse(&mut working_set, Some(file_path_str), &file, false);
|
||||
|
||||
if let Some(err) = working_set.parse_errors.first() {
|
||||
report_error(&working_set, err);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
for block in &mut working_set.delta.blocks {
|
||||
if block.signature.name == "main" {
|
||||
block.signature.name = source_filename.to_string_lossy().to_string();
|
||||
} else if block.signature.name.starts_with("main ") {
|
||||
block.signature.name = source_filename.to_string_lossy().to_string()
|
||||
+ " "
|
||||
+ &String::from_utf8_lossy(&block.signature.name.as_bytes()[5..]);
|
||||
block.signature.name =
|
||||
source_filename.to_string_lossy().to_string() + " " + &block.signature.name[5..];
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,7 +189,7 @@ pub(crate) fn print_table_or_error(
|
||||
// Change the engine_state config to use the passed in configuration
|
||||
engine_state.set_config(config);
|
||||
|
||||
if let PipelineData::Value(Value::Error { error }, ..) = &pipeline_data {
|
||||
if let PipelineData::Value(Value::Error { error, .. }, ..) = &pipeline_data {
|
||||
let working_set = StateWorkingSet::new(engine_state);
|
||||
report_error(&working_set, &**error);
|
||||
std::process::exit(1);
|
||||
@ -232,7 +236,7 @@ pub(crate) fn print_table_or_error(
|
||||
|
||||
fn print_or_exit(pipeline_data: PipelineData, engine_state: &mut EngineState, config: &Config) {
|
||||
for item in pipeline_data {
|
||||
if let Value::Error { error } = item {
|
||||
if let Value::Error { error, .. } = item {
|
||||
let working_set = StateWorkingSet::new(engine_state);
|
||||
|
||||
report_error(&working_set, &*error);
|
||||
|
@ -48,14 +48,9 @@ impl Command for NuHighlight {
|
||||
Ok(line) => {
|
||||
let highlights = highlighter.highlight(&line, line.len());
|
||||
|
||||
Value::String {
|
||||
val: highlights.render_simple(),
|
||||
span: head,
|
||||
}
|
||||
Value::string(highlights.render_simple(), head)
|
||||
}
|
||||
Err(err) => Value::Error {
|
||||
error: Box::new(err),
|
||||
},
|
||||
Err(err) => Value::error(err, head),
|
||||
},
|
||||
ctrlc,
|
||||
)
|
||||
|
@ -7,7 +7,8 @@ use nu_parser::parse;
|
||||
use nu_protocol::{
|
||||
create_menus,
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
extract_value, Config, ParsedKeybinding, ParsedMenu, PipelineData, ShellError, Span, Value,
|
||||
extract_value, Config, ParsedKeybinding, ParsedMenu, PipelineData, Record, ShellError, Span,
|
||||
Value,
|
||||
};
|
||||
use reedline::{
|
||||
default_emacs_keybindings, default_vi_insert_keybindings, default_vi_normal_keybindings,
|
||||
@ -130,8 +131,9 @@ fn add_menu(
|
||||
stack: &Stack,
|
||||
config: &Config,
|
||||
) -> Result<Reedline, ShellError> {
|
||||
if let Value::Record { cols, vals, span } = &menu.menu_type {
|
||||
let layout = extract_value("layout", cols, vals, *span)?.into_string("", config);
|
||||
let span = menu.menu_type.span();
|
||||
if let Value::Record { val, .. } = &menu.menu_type {
|
||||
let layout = extract_value("layout", val, span)?.into_string("", config);
|
||||
|
||||
match layout.as_str() {
|
||||
"columnar" => add_columnar_menu(line_editor, menu, engine_state, stack, config),
|
||||
@ -140,22 +142,22 @@ fn add_menu(
|
||||
_ => Err(ShellError::UnsupportedConfigValue(
|
||||
"columnar, list or description".to_string(),
|
||||
menu.menu_type.into_abbreviated_string(config),
|
||||
menu.menu_type.span()?,
|
||||
menu.menu_type.span(),
|
||||
)),
|
||||
}
|
||||
} else {
|
||||
Err(ShellError::UnsupportedConfigValue(
|
||||
"only record type".to_string(),
|
||||
menu.menu_type.into_abbreviated_string(config),
|
||||
menu.menu_type.span()?,
|
||||
menu.menu_type.span(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! add_style {
|
||||
// first arm match add!(1,2), add!(2,3) etc
|
||||
($name:expr, $cols: expr, $vals:expr, $span:expr, $config: expr, $menu:expr, $f:expr) => {
|
||||
$menu = match extract_value($name, $cols, $vals, *$span) {
|
||||
($name:expr, $record: expr, $span:expr, $config: expr, $menu:expr, $f:expr) => {
|
||||
$menu = match extract_value($name, $record, $span) {
|
||||
Ok(text) => {
|
||||
let style = match text {
|
||||
Value::String { val, .. } => lookup_ansi_color_style(&val),
|
||||
@ -177,11 +179,12 @@ pub(crate) fn add_columnar_menu(
|
||||
stack: &Stack,
|
||||
config: &Config,
|
||||
) -> Result<Reedline, ShellError> {
|
||||
let span = menu.menu_type.span();
|
||||
let name = menu.name.into_string("", config);
|
||||
let mut columnar_menu = ColumnarMenu::default().with_name(&name);
|
||||
|
||||
if let Value::Record { cols, vals, span } = &menu.menu_type {
|
||||
columnar_menu = match extract_value("columns", cols, vals, *span) {
|
||||
if let Value::Record { val, .. } = &menu.menu_type {
|
||||
columnar_menu = match extract_value("columns", val, span) {
|
||||
Ok(columns) => {
|
||||
let columns = columns.as_int()?;
|
||||
columnar_menu.with_columns(columns as u16)
|
||||
@ -189,7 +192,7 @@ pub(crate) fn add_columnar_menu(
|
||||
Err(_) => columnar_menu,
|
||||
};
|
||||
|
||||
columnar_menu = match extract_value("col_width", cols, vals, *span) {
|
||||
columnar_menu = match extract_value("col_width", val, span) {
|
||||
Ok(col_width) => {
|
||||
let col_width = col_width.as_int()?;
|
||||
columnar_menu.with_column_width(Some(col_width as usize))
|
||||
@ -197,7 +200,7 @@ pub(crate) fn add_columnar_menu(
|
||||
Err(_) => columnar_menu.with_column_width(None),
|
||||
};
|
||||
|
||||
columnar_menu = match extract_value("col_padding", cols, vals, *span) {
|
||||
columnar_menu = match extract_value("col_padding", val, span) {
|
||||
Ok(col_padding) => {
|
||||
let col_padding = col_padding.as_int()?;
|
||||
columnar_menu.with_column_padding(col_padding as usize)
|
||||
@ -206,11 +209,11 @@ pub(crate) fn add_columnar_menu(
|
||||
};
|
||||
}
|
||||
|
||||
if let Value::Record { cols, vals, span } = &menu.style {
|
||||
let span = menu.style.span();
|
||||
if let Value::Record { val, .. } = &menu.style {
|
||||
add_style!(
|
||||
"text",
|
||||
cols,
|
||||
vals,
|
||||
val,
|
||||
span,
|
||||
config,
|
||||
columnar_menu,
|
||||
@ -218,8 +221,7 @@ pub(crate) fn add_columnar_menu(
|
||||
);
|
||||
add_style!(
|
||||
"selected_text",
|
||||
cols,
|
||||
vals,
|
||||
val,
|
||||
span,
|
||||
config,
|
||||
columnar_menu,
|
||||
@ -227,8 +229,7 @@ pub(crate) fn add_columnar_menu(
|
||||
);
|
||||
add_style!(
|
||||
"description_text",
|
||||
cols,
|
||||
vals,
|
||||
val,
|
||||
span,
|
||||
config,
|
||||
columnar_menu,
|
||||
@ -242,18 +243,15 @@ pub(crate) fn add_columnar_menu(
|
||||
let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
|
||||
columnar_menu = columnar_menu.with_only_buffer_difference(only_buffer_difference);
|
||||
|
||||
let span = menu.source.span();
|
||||
match &menu.source {
|
||||
Value::Nothing { .. } => {
|
||||
Ok(line_editor.with_menu(ReedlineMenu::EngineCompleter(Box::new(columnar_menu))))
|
||||
}
|
||||
Value::Closure {
|
||||
val,
|
||||
captures,
|
||||
span,
|
||||
} => {
|
||||
Value::Closure { val, captures, .. } => {
|
||||
let menu_completer = NuMenuCompleter::new(
|
||||
*val,
|
||||
*span,
|
||||
span,
|
||||
stack.captures_to_stack(captures),
|
||||
engine_state,
|
||||
only_buffer_difference,
|
||||
@ -266,7 +264,7 @@ pub(crate) fn add_columnar_menu(
|
||||
_ => Err(ShellError::UnsupportedConfigValue(
|
||||
"block or omitted value".to_string(),
|
||||
menu.source.into_abbreviated_string(config),
|
||||
menu.source.span()?,
|
||||
span,
|
||||
)),
|
||||
}
|
||||
}
|
||||
@ -282,8 +280,9 @@ pub(crate) fn add_list_menu(
|
||||
let name = menu.name.into_string("", config);
|
||||
let mut list_menu = ListMenu::default().with_name(&name);
|
||||
|
||||
if let Value::Record { cols, vals, span } = &menu.menu_type {
|
||||
list_menu = match extract_value("page_size", cols, vals, *span) {
|
||||
let span = menu.menu_type.span();
|
||||
if let Value::Record { val, .. } = &menu.menu_type {
|
||||
list_menu = match extract_value("page_size", val, span) {
|
||||
Ok(page_size) => {
|
||||
let page_size = page_size.as_int()?;
|
||||
list_menu.with_page_size(page_size as usize)
|
||||
@ -292,11 +291,11 @@ pub(crate) fn add_list_menu(
|
||||
};
|
||||
}
|
||||
|
||||
if let Value::Record { cols, vals, span } = &menu.style {
|
||||
let span = menu.style.span();
|
||||
if let Value::Record { val, .. } = &menu.style {
|
||||
add_style!(
|
||||
"text",
|
||||
cols,
|
||||
vals,
|
||||
val,
|
||||
span,
|
||||
config,
|
||||
list_menu,
|
||||
@ -304,8 +303,7 @@ pub(crate) fn add_list_menu(
|
||||
);
|
||||
add_style!(
|
||||
"selected_text",
|
||||
cols,
|
||||
vals,
|
||||
val,
|
||||
span,
|
||||
config,
|
||||
list_menu,
|
||||
@ -313,8 +311,7 @@ pub(crate) fn add_list_menu(
|
||||
);
|
||||
add_style!(
|
||||
"description_text",
|
||||
cols,
|
||||
vals,
|
||||
val,
|
||||
span,
|
||||
config,
|
||||
list_menu,
|
||||
@ -328,18 +325,15 @@ pub(crate) fn add_list_menu(
|
||||
let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
|
||||
list_menu = list_menu.with_only_buffer_difference(only_buffer_difference);
|
||||
|
||||
let span = menu.source.span();
|
||||
match &menu.source {
|
||||
Value::Nothing { .. } => {
|
||||
Ok(line_editor.with_menu(ReedlineMenu::HistoryMenu(Box::new(list_menu))))
|
||||
}
|
||||
Value::Closure {
|
||||
val,
|
||||
captures,
|
||||
span,
|
||||
} => {
|
||||
Value::Closure { val, captures, .. } => {
|
||||
let menu_completer = NuMenuCompleter::new(
|
||||
*val,
|
||||
*span,
|
||||
span,
|
||||
stack.captures_to_stack(captures),
|
||||
engine_state,
|
||||
only_buffer_difference,
|
||||
@ -352,7 +346,7 @@ pub(crate) fn add_list_menu(
|
||||
_ => Err(ShellError::UnsupportedConfigValue(
|
||||
"block or omitted value".to_string(),
|
||||
menu.source.into_abbreviated_string(config),
|
||||
menu.source.span()?,
|
||||
menu.source.span(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
@ -368,8 +362,9 @@ pub(crate) fn add_description_menu(
|
||||
let name = menu.name.into_string("", config);
|
||||
let mut description_menu = DescriptionMenu::default().with_name(&name);
|
||||
|
||||
if let Value::Record { cols, vals, span } = &menu.menu_type {
|
||||
description_menu = match extract_value("columns", cols, vals, *span) {
|
||||
let span = menu.menu_type.span();
|
||||
if let Value::Record { val, .. } = &menu.menu_type {
|
||||
description_menu = match extract_value("columns", val, span) {
|
||||
Ok(columns) => {
|
||||
let columns = columns.as_int()?;
|
||||
description_menu.with_columns(columns as u16)
|
||||
@ -377,7 +372,7 @@ pub(crate) fn add_description_menu(
|
||||
Err(_) => description_menu,
|
||||
};
|
||||
|
||||
description_menu = match extract_value("col_width", cols, vals, *span) {
|
||||
description_menu = match extract_value("col_width", val, span) {
|
||||
Ok(col_width) => {
|
||||
let col_width = col_width.as_int()?;
|
||||
description_menu.with_column_width(Some(col_width as usize))
|
||||
@ -385,7 +380,7 @@ pub(crate) fn add_description_menu(
|
||||
Err(_) => description_menu.with_column_width(None),
|
||||
};
|
||||
|
||||
description_menu = match extract_value("col_padding", cols, vals, *span) {
|
||||
description_menu = match extract_value("col_padding", val, span) {
|
||||
Ok(col_padding) => {
|
||||
let col_padding = col_padding.as_int()?;
|
||||
description_menu.with_column_padding(col_padding as usize)
|
||||
@ -393,7 +388,7 @@ pub(crate) fn add_description_menu(
|
||||
Err(_) => description_menu,
|
||||
};
|
||||
|
||||
description_menu = match extract_value("selection_rows", cols, vals, *span) {
|
||||
description_menu = match extract_value("selection_rows", val, span) {
|
||||
Ok(selection_rows) => {
|
||||
let selection_rows = selection_rows.as_int()?;
|
||||
description_menu.with_selection_rows(selection_rows as u16)
|
||||
@ -401,7 +396,7 @@ pub(crate) fn add_description_menu(
|
||||
Err(_) => description_menu,
|
||||
};
|
||||
|
||||
description_menu = match extract_value("description_rows", cols, vals, *span) {
|
||||
description_menu = match extract_value("description_rows", val, span) {
|
||||
Ok(description_rows) => {
|
||||
let description_rows = description_rows.as_int()?;
|
||||
description_menu.with_description_rows(description_rows as usize)
|
||||
@ -410,11 +405,11 @@ pub(crate) fn add_description_menu(
|
||||
};
|
||||
}
|
||||
|
||||
if let Value::Record { cols, vals, span } = &menu.style {
|
||||
let span = menu.style.span();
|
||||
if let Value::Record { val, .. } = &menu.style {
|
||||
add_style!(
|
||||
"text",
|
||||
cols,
|
||||
vals,
|
||||
val,
|
||||
span,
|
||||
config,
|
||||
description_menu,
|
||||
@ -422,8 +417,7 @@ pub(crate) fn add_description_menu(
|
||||
);
|
||||
add_style!(
|
||||
"selected_text",
|
||||
cols,
|
||||
vals,
|
||||
val,
|
||||
span,
|
||||
config,
|
||||
description_menu,
|
||||
@ -431,8 +425,7 @@ pub(crate) fn add_description_menu(
|
||||
);
|
||||
add_style!(
|
||||
"description_text",
|
||||
cols,
|
||||
vals,
|
||||
val,
|
||||
span,
|
||||
config,
|
||||
description_menu,
|
||||
@ -446,6 +439,7 @@ pub(crate) fn add_description_menu(
|
||||
let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
|
||||
description_menu = description_menu.with_only_buffer_difference(only_buffer_difference);
|
||||
|
||||
let span = menu.source.span();
|
||||
match &menu.source {
|
||||
Value::Nothing { .. } => {
|
||||
let completer = Box::new(NuHelpCompleter::new(engine_state));
|
||||
@ -454,14 +448,10 @@ pub(crate) fn add_description_menu(
|
||||
completer,
|
||||
}))
|
||||
}
|
||||
Value::Closure {
|
||||
val,
|
||||
captures,
|
||||
span,
|
||||
} => {
|
||||
Value::Closure { val, captures, .. } => {
|
||||
let menu_completer = NuMenuCompleter::new(
|
||||
*val,
|
||||
*span,
|
||||
span,
|
||||
stack.captures_to_stack(captures),
|
||||
engine_state,
|
||||
only_buffer_difference,
|
||||
@ -474,7 +464,7 @@ pub(crate) fn add_description_menu(
|
||||
_ => Err(ShellError::UnsupportedConfigValue(
|
||||
"closure or omitted value".to_string(),
|
||||
menu.source.into_abbreviated_string(config),
|
||||
menu.source.span()?,
|
||||
menu.source.span(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
@ -486,6 +476,7 @@ fn add_menu_keybindings(keybindings: &mut Keybindings) {
|
||||
KeyCode::Tab,
|
||||
ReedlineEvent::UntilFound(vec![
|
||||
ReedlineEvent::Menu("completion_menu".to_string()),
|
||||
ReedlineEvent::MenuNext,
|
||||
ReedlineEvent::Edit(vec![EditCommand::Complete]),
|
||||
]),
|
||||
);
|
||||
@ -583,15 +574,16 @@ fn add_keybinding(
|
||||
insert_keybindings: &mut Keybindings,
|
||||
normal_keybindings: &mut Keybindings,
|
||||
) -> Result<(), ShellError> {
|
||||
let span = mode.span();
|
||||
match &mode {
|
||||
Value::String { val, span } => match val.as_str() {
|
||||
Value::String { val, .. } => match val.as_str() {
|
||||
"emacs" => add_parsed_keybinding(emacs_keybindings, keybinding, config),
|
||||
"vi_insert" => add_parsed_keybinding(insert_keybindings, keybinding, config),
|
||||
"vi_normal" => add_parsed_keybinding(normal_keybindings, keybinding, config),
|
||||
m => Err(ShellError::UnsupportedConfigValue(
|
||||
"emacs, vi_insert or vi_normal".to_string(),
|
||||
m.to_string(),
|
||||
*span,
|
||||
span,
|
||||
)),
|
||||
},
|
||||
Value::List { vals, .. } => {
|
||||
@ -611,7 +603,7 @@ fn add_keybinding(
|
||||
v => Err(ShellError::UnsupportedConfigValue(
|
||||
"string or list of strings".to_string(),
|
||||
v.into_abbreviated_string(config),
|
||||
v.span()?,
|
||||
v.span(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
@ -641,7 +633,7 @@ fn add_parsed_keybinding(
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"CONTROL, SHIFT, ALT or NONE".to_string(),
|
||||
keybinding.modifier.into_abbreviated_string(config),
|
||||
keybinding.modifier.span()?,
|
||||
keybinding.modifier.span(),
|
||||
))
|
||||
}
|
||||
};
|
||||
@ -665,7 +657,7 @@ fn add_parsed_keybinding(
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"char_<CHAR: unicode codepoint>".to_string(),
|
||||
c.to_string(),
|
||||
keybinding.keycode.span()?,
|
||||
keybinding.keycode.span(),
|
||||
));
|
||||
};
|
||||
|
||||
@ -692,7 +684,7 @@ fn add_parsed_keybinding(
|
||||
.ok_or(ShellError::UnsupportedConfigValue(
|
||||
"(f1|f2|...|f20)".to_string(),
|
||||
format!("unknown function key: {c}"),
|
||||
keybinding.keycode.span()?,
|
||||
keybinding.keycode.span(),
|
||||
))?;
|
||||
KeyCode::F(fn_num)
|
||||
}
|
||||
@ -702,7 +694,7 @@ fn add_parsed_keybinding(
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"crossterm KeyCode".to_string(),
|
||||
keybinding.keycode.into_abbreviated_string(config),
|
||||
keybinding.keycode.span()?,
|
||||
keybinding.keycode.span(),
|
||||
))
|
||||
}
|
||||
};
|
||||
@ -722,68 +714,61 @@ enum EventType<'config> {
|
||||
}
|
||||
|
||||
impl<'config> EventType<'config> {
|
||||
fn try_from_columns(
|
||||
cols: &'config [String],
|
||||
vals: &'config [Value],
|
||||
span: Span,
|
||||
) -> Result<Self, ShellError> {
|
||||
extract_value("send", cols, vals, span)
|
||||
fn try_from_record(record: &'config Record, span: Span) -> Result<Self, ShellError> {
|
||||
extract_value("send", record, span)
|
||||
.map(Self::Send)
|
||||
.or_else(|_| extract_value("edit", cols, vals, span).map(Self::Edit))
|
||||
.or_else(|_| extract_value("until", cols, vals, span).map(Self::Until))
|
||||
.or_else(|_| extract_value("edit", record, span).map(Self::Edit))
|
||||
.or_else(|_| extract_value("until", record, span).map(Self::Until))
|
||||
.map_err(|_| ShellError::MissingConfigValue("send, edit or until".to_string(), span))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_event(value: &Value, config: &Config) -> Result<Option<ReedlineEvent>, ShellError> {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::Record { cols, vals, span } => {
|
||||
match EventType::try_from_columns(cols, vals, *span)? {
|
||||
EventType::Send(value) => event_from_record(
|
||||
Value::Record { val: record, .. } => match EventType::try_from_record(record, span)? {
|
||||
EventType::Send(value) => event_from_record(
|
||||
value.into_string("", config).to_lowercase().as_str(),
|
||||
record,
|
||||
config,
|
||||
span,
|
||||
)
|
||||
.map(Some),
|
||||
EventType::Edit(value) => {
|
||||
let edit = edit_from_record(
|
||||
value.into_string("", config).to_lowercase().as_str(),
|
||||
cols,
|
||||
vals,
|
||||
record,
|
||||
config,
|
||||
*span,
|
||||
)
|
||||
.map(Some),
|
||||
EventType::Edit(value) => {
|
||||
let edit = edit_from_record(
|
||||
value.into_string("", config).to_lowercase().as_str(),
|
||||
cols,
|
||||
vals,
|
||||
config,
|
||||
*span,
|
||||
)?;
|
||||
Ok(Some(ReedlineEvent::Edit(vec![edit])))
|
||||
}
|
||||
EventType::Until(value) => match value {
|
||||
Value::List { vals, .. } => {
|
||||
let events = vals
|
||||
.iter()
|
||||
.map(|value| match parse_event(value, config) {
|
||||
Ok(inner) => match inner {
|
||||
None => Err(ShellError::UnsupportedConfigValue(
|
||||
"List containing valid events".to_string(),
|
||||
"Nothing value (null)".to_string(),
|
||||
value.span()?,
|
||||
)),
|
||||
Some(event) => Ok(event),
|
||||
},
|
||||
Err(e) => Err(e),
|
||||
})
|
||||
.collect::<Result<Vec<ReedlineEvent>, ShellError>>()?;
|
||||
|
||||
Ok(Some(ReedlineEvent::UntilFound(events)))
|
||||
}
|
||||
v => Err(ShellError::UnsupportedConfigValue(
|
||||
"list of events".to_string(),
|
||||
v.into_abbreviated_string(config),
|
||||
v.span()?,
|
||||
)),
|
||||
},
|
||||
span,
|
||||
)?;
|
||||
Ok(Some(ReedlineEvent::Edit(vec![edit])))
|
||||
}
|
||||
}
|
||||
EventType::Until(value) => match value {
|
||||
Value::List { vals, .. } => {
|
||||
let events = vals
|
||||
.iter()
|
||||
.map(|value| match parse_event(value, config) {
|
||||
Ok(inner) => match inner {
|
||||
None => Err(ShellError::UnsupportedConfigValue(
|
||||
"List containing valid events".to_string(),
|
||||
"Nothing value (null)".to_string(),
|
||||
value.span(),
|
||||
)),
|
||||
Some(event) => Ok(event),
|
||||
},
|
||||
Err(e) => Err(e),
|
||||
})
|
||||
.collect::<Result<Vec<ReedlineEvent>, ShellError>>()?;
|
||||
|
||||
Ok(Some(ReedlineEvent::UntilFound(events)))
|
||||
}
|
||||
v => Err(ShellError::UnsupportedConfigValue(
|
||||
"list of events".to_string(),
|
||||
v.into_abbreviated_string(config),
|
||||
v.span(),
|
||||
)),
|
||||
},
|
||||
},
|
||||
Value::List { vals, .. } => {
|
||||
let events = vals
|
||||
.iter()
|
||||
@ -792,7 +777,7 @@ fn parse_event(value: &Value, config: &Config) -> Result<Option<ReedlineEvent>,
|
||||
None => Err(ShellError::UnsupportedConfigValue(
|
||||
"List containing valid events".to_string(),
|
||||
"Nothing value (null)".to_string(),
|
||||
value.span()?,
|
||||
value.span(),
|
||||
)),
|
||||
Some(event) => Ok(event),
|
||||
},
|
||||
@ -806,15 +791,14 @@ fn parse_event(value: &Value, config: &Config) -> Result<Option<ReedlineEvent>,
|
||||
v => Err(ShellError::UnsupportedConfigValue(
|
||||
"record or list of records, null to unbind key".to_string(),
|
||||
v.into_abbreviated_string(config),
|
||||
v.span()?,
|
||||
v.span(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn event_from_record(
|
||||
name: &str,
|
||||
cols: &[String],
|
||||
vals: &[Value],
|
||||
record: &Record,
|
||||
config: &Config,
|
||||
span: Span,
|
||||
) -> Result<ReedlineEvent, ShellError> {
|
||||
@ -848,11 +832,11 @@ fn event_from_record(
|
||||
"menupageprevious" => ReedlineEvent::MenuPagePrevious,
|
||||
"openeditor" => ReedlineEvent::OpenEditor,
|
||||
"menu" => {
|
||||
let menu = extract_value("name", cols, vals, span)?;
|
||||
let menu = extract_value("name", record, span)?;
|
||||
ReedlineEvent::Menu(menu.into_string("", config))
|
||||
}
|
||||
"executehostcommand" => {
|
||||
let cmd = extract_value("cmd", cols, vals, span)?;
|
||||
let cmd = extract_value("cmd", record, span)?;
|
||||
ReedlineEvent::ExecuteHostCommand(cmd.into_string("", config))
|
||||
}
|
||||
v => {
|
||||
@ -869,8 +853,7 @@ fn event_from_record(
|
||||
|
||||
fn edit_from_record(
|
||||
name: &str,
|
||||
cols: &[String],
|
||||
vals: &[Value],
|
||||
record: &Record,
|
||||
config: &Config,
|
||||
span: Span,
|
||||
) -> Result<EditCommand, ShellError> {
|
||||
@ -889,16 +872,16 @@ fn edit_from_record(
|
||||
"movewordrightstart" => EditCommand::MoveWordRightStart,
|
||||
"movebigwordrightstart" => EditCommand::MoveBigWordRightStart,
|
||||
"movetoposition" => {
|
||||
let value = extract_value("value", cols, vals, span)?;
|
||||
let value = extract_value("value", record, span)?;
|
||||
EditCommand::MoveToPosition(value.as_int()? as usize)
|
||||
}
|
||||
"insertchar" => {
|
||||
let value = extract_value("value", cols, vals, span)?;
|
||||
let value = extract_value("value", record, span)?;
|
||||
let char = extract_char(value, config)?;
|
||||
EditCommand::InsertChar(char)
|
||||
}
|
||||
"insertstring" => {
|
||||
let value = extract_value("value", cols, vals, span)?;
|
||||
let value = extract_value("value", record, span)?;
|
||||
EditCommand::InsertString(value.into_string("", config))
|
||||
}
|
||||
"insertnewline" => EditCommand::InsertNewline,
|
||||
@ -930,42 +913,42 @@ fn edit_from_record(
|
||||
"undo" => EditCommand::Undo,
|
||||
"redo" => EditCommand::Redo,
|
||||
"cutrightuntil" => {
|
||||
let value = extract_value("value", cols, vals, span)?;
|
||||
let value = extract_value("value", record, span)?;
|
||||
let char = extract_char(value, config)?;
|
||||
EditCommand::CutRightUntil(char)
|
||||
}
|
||||
"cutrightbefore" => {
|
||||
let value = extract_value("value", cols, vals, span)?;
|
||||
let value = extract_value("value", record, span)?;
|
||||
let char = extract_char(value, config)?;
|
||||
EditCommand::CutRightBefore(char)
|
||||
}
|
||||
"moverightuntil" => {
|
||||
let value = extract_value("value", cols, vals, span)?;
|
||||
let value = extract_value("value", record, span)?;
|
||||
let char = extract_char(value, config)?;
|
||||
EditCommand::MoveRightUntil(char)
|
||||
}
|
||||
"moverightbefore" => {
|
||||
let value = extract_value("value", cols, vals, span)?;
|
||||
let value = extract_value("value", record, span)?;
|
||||
let char = extract_char(value, config)?;
|
||||
EditCommand::MoveRightBefore(char)
|
||||
}
|
||||
"cutleftuntil" => {
|
||||
let value = extract_value("value", cols, vals, span)?;
|
||||
let value = extract_value("value", record, span)?;
|
||||
let char = extract_char(value, config)?;
|
||||
EditCommand::CutLeftUntil(char)
|
||||
}
|
||||
"cutleftbefore" => {
|
||||
let value = extract_value("value", cols, vals, span)?;
|
||||
let value = extract_value("value", record, span)?;
|
||||
let char = extract_char(value, config)?;
|
||||
EditCommand::CutLeftBefore(char)
|
||||
}
|
||||
"moveleftuntil" => {
|
||||
let value = extract_value("value", cols, vals, span)?;
|
||||
let value = extract_value("value", record, span)?;
|
||||
let char = extract_char(value, config)?;
|
||||
EditCommand::MoveLeftUntil(char)
|
||||
}
|
||||
"moveleftbefore" => {
|
||||
let value = extract_value("value", cols, vals, span)?;
|
||||
let value = extract_value("value", record, span)?;
|
||||
let char = extract_char(value, config)?;
|
||||
EditCommand::MoveLeftBefore(char)
|
||||
}
|
||||
@ -983,7 +966,7 @@ fn edit_from_record(
|
||||
}
|
||||
|
||||
fn extract_char(value: &Value, config: &Config) -> Result<char, ShellError> {
|
||||
let span = value.span()?;
|
||||
let span = value.span();
|
||||
value
|
||||
.into_string("", config)
|
||||
.chars()
|
||||
@ -999,16 +982,13 @@ mod test {
|
||||
fn test_send_event() {
|
||||
let cols = vec!["send".to_string()];
|
||||
let vals = vec![Value::test_string("Enter")];
|
||||
let event = Record { vals, cols };
|
||||
|
||||
let span = Span::test_data();
|
||||
let b = EventType::try_from_columns(&cols, &vals, span).unwrap();
|
||||
let b = EventType::try_from_record(&event, span).unwrap();
|
||||
assert!(matches!(b, EventType::Send(_)));
|
||||
|
||||
let event = Value::Record {
|
||||
vals,
|
||||
cols,
|
||||
span: Span::test_data(),
|
||||
};
|
||||
let event = Value::test_record(event);
|
||||
let config = Config::default();
|
||||
|
||||
let parsed_event = parse_event(&event, &config).unwrap();
|
||||
@ -1019,16 +999,13 @@ mod test {
|
||||
fn test_edit_event() {
|
||||
let cols = vec!["edit".to_string()];
|
||||
let vals = vec![Value::test_string("Clear")];
|
||||
let event = Record { vals, cols };
|
||||
|
||||
let span = Span::test_data();
|
||||
let b = EventType::try_from_columns(&cols, &vals, span).unwrap();
|
||||
let b = EventType::try_from_record(&event, span).unwrap();
|
||||
assert!(matches!(b, EventType::Edit(_)));
|
||||
|
||||
let event = Value::Record {
|
||||
vals,
|
||||
cols,
|
||||
span: Span::test_data(),
|
||||
};
|
||||
let event = Value::test_record(event);
|
||||
let config = Config::default();
|
||||
|
||||
let parsed_event = parse_event(&event, &config).unwrap();
|
||||
@ -1045,16 +1022,13 @@ mod test {
|
||||
Value::test_string("Menu"),
|
||||
Value::test_string("history_menu"),
|
||||
];
|
||||
let event = Record { vals, cols };
|
||||
|
||||
let span = Span::test_data();
|
||||
let b = EventType::try_from_columns(&cols, &vals, span).unwrap();
|
||||
let b = EventType::try_from_record(&event, span).unwrap();
|
||||
assert!(matches!(b, EventType::Send(_)));
|
||||
|
||||
let event = Value::Record {
|
||||
vals,
|
||||
cols,
|
||||
span: Span::test_data(),
|
||||
};
|
||||
let event = Value::test_record(event);
|
||||
let config = Config::default();
|
||||
|
||||
let parsed_event = parse_event(&event, &config).unwrap();
|
||||
@ -1073,38 +1047,27 @@ mod test {
|
||||
Value::test_string("history_menu"),
|
||||
];
|
||||
|
||||
let menu_event = Value::Record {
|
||||
cols,
|
||||
vals,
|
||||
span: Span::test_data(),
|
||||
};
|
||||
let menu_event = Value::test_record(Record { cols, vals });
|
||||
|
||||
// Enter event
|
||||
let cols = vec!["send".to_string()];
|
||||
let vals = vec![Value::test_string("Enter")];
|
||||
|
||||
let enter_event = Value::Record {
|
||||
cols,
|
||||
vals,
|
||||
span: Span::test_data(),
|
||||
};
|
||||
let enter_event = Value::test_record(Record { cols, vals });
|
||||
|
||||
// Until event
|
||||
let cols = vec!["until".to_string()];
|
||||
let vals = vec![Value::List {
|
||||
vals: vec![menu_event, enter_event],
|
||||
span: Span::test_data(),
|
||||
}];
|
||||
let vals = vec![Value::list(
|
||||
vec![menu_event, enter_event],
|
||||
Span::test_data(),
|
||||
)];
|
||||
let event = Record { cols, vals };
|
||||
|
||||
let span = Span::test_data();
|
||||
let b = EventType::try_from_columns(&cols, &vals, span).unwrap();
|
||||
let b = EventType::try_from_record(&event, span).unwrap();
|
||||
assert!(matches!(b, EventType::Until(_)));
|
||||
|
||||
let event = Value::Record {
|
||||
cols,
|
||||
vals,
|
||||
span: Span::test_data(),
|
||||
};
|
||||
let event = Value::test_record(event);
|
||||
let config = Config::default();
|
||||
|
||||
let parsed_event = parse_event(&event, &config).unwrap();
|
||||
@ -1126,27 +1089,16 @@ mod test {
|
||||
Value::test_string("history_menu"),
|
||||
];
|
||||
|
||||
let menu_event = Value::Record {
|
||||
cols,
|
||||
vals,
|
||||
span: Span::test_data(),
|
||||
};
|
||||
let menu_event = Value::test_record(Record { cols, vals });
|
||||
|
||||
// Enter event
|
||||
let cols = vec!["send".to_string()];
|
||||
let vals = vec![Value::test_string("Enter")];
|
||||
|
||||
let enter_event = Value::Record {
|
||||
cols,
|
||||
vals,
|
||||
span: Span::test_data(),
|
||||
};
|
||||
let enter_event = Value::test_record(Record { cols, vals });
|
||||
|
||||
// Multiple event
|
||||
let event = Value::List {
|
||||
vals: vec![menu_event, enter_event],
|
||||
span: Span::test_data(),
|
||||
};
|
||||
let event = Value::list(vec![menu_event, enter_event], Span::test_data());
|
||||
|
||||
let config = Config::default();
|
||||
let parsed_event = parse_event(&event, &config).unwrap();
|
||||
@ -1163,9 +1115,10 @@ mod test {
|
||||
fn test_error() {
|
||||
let cols = vec!["not_exist".to_string()];
|
||||
let vals = vec![Value::test_string("Enter")];
|
||||
let event = Record { cols, vals };
|
||||
|
||||
let span = Span::test_data();
|
||||
let b = EventType::try_from_columns(&cols, &vals, span);
|
||||
let b = EventType::try_from_record(&event, span);
|
||||
assert!(matches!(b, Err(ShellError::MissingConfigValue(_, _))));
|
||||
}
|
||||
}
|
||||
|
@ -6,19 +6,19 @@ use crate::{
|
||||
NuHighlighter, NuValidator, NushellPrompt,
|
||||
};
|
||||
use crossterm::cursor::SetCursorStyle;
|
||||
use is_terminal::IsTerminal;
|
||||
use log::{trace, warn};
|
||||
use miette::{ErrReport, IntoDiagnostic, Result};
|
||||
use nu_cmd_base::hook::eval_hook;
|
||||
use nu_cmd_base::util::get_guaranteed_cwd;
|
||||
use nu_color_config::StyleComputer;
|
||||
use nu_command::hook::eval_hook;
|
||||
use nu_engine::convert_env_values;
|
||||
use nu_parser::{lex, parse, trim_quotes_str};
|
||||
use nu_protocol::{
|
||||
config::NuCursorShape,
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
eval_const::create_nu_constant,
|
||||
report_error, report_error_new, HistoryFileFormat, PipelineData, ShellError, Span, Spanned,
|
||||
Value,
|
||||
Value, NU_VARIABLE_ID,
|
||||
};
|
||||
use nu_utils::utils::perf;
|
||||
use reedline::{
|
||||
@ -26,7 +26,7 @@ use reedline::{
|
||||
SqliteBackedHistory, Vi,
|
||||
};
|
||||
use std::{
|
||||
io::{self, Write},
|
||||
io::{self, IsTerminal, Write},
|
||||
path::Path,
|
||||
sync::atomic::Ordering,
|
||||
time::Instant,
|
||||
@ -51,7 +51,7 @@ pub fn evaluate_repl(
|
||||
load_std_lib: Option<Spanned<String>>,
|
||||
entire_start_time: Instant,
|
||||
) -> Result<()> {
|
||||
use nu_command::hook;
|
||||
use nu_cmd_base::hook;
|
||||
use reedline::Signal;
|
||||
let use_color = engine_state.get_config().use_ansi_coloring;
|
||||
|
||||
@ -165,6 +165,10 @@ pub fn evaluate_repl(
|
||||
|
||||
engine_state.set_startup_time(entire_start_time.elapsed().as_nanos() as i64);
|
||||
|
||||
// Regenerate the $nu constant to contain the startup time and any other potential updates
|
||||
let nu_const = create_nu_constant(engine_state, Span::unknown())?;
|
||||
engine_state.set_variable_const_val(NU_VARIABLE_ID, nu_const);
|
||||
|
||||
if load_std_lib.is_none() && engine_state.get_config().show_banner {
|
||||
eval_source(
|
||||
engine_state,
|
||||
@ -231,13 +235,15 @@ pub fn evaluate_repl(
|
||||
|
||||
// Find the configured cursor shapes for each mode
|
||||
let cursor_config = CursorConfig {
|
||||
vi_insert: Some(map_nucursorshape_to_cursorshape(
|
||||
config.cursor_shape_vi_insert,
|
||||
)),
|
||||
vi_normal: Some(map_nucursorshape_to_cursorshape(
|
||||
config.cursor_shape_vi_normal,
|
||||
)),
|
||||
emacs: Some(map_nucursorshape_to_cursorshape(config.cursor_shape_emacs)),
|
||||
vi_insert: config
|
||||
.cursor_shape_vi_insert
|
||||
.map(map_nucursorshape_to_cursorshape),
|
||||
vi_normal: config
|
||||
.cursor_shape_vi_normal
|
||||
.map(map_nucursorshape_to_cursorshape),
|
||||
emacs: config
|
||||
.cursor_shape_emacs
|
||||
.map(map_nucursorshape_to_cursorshape),
|
||||
};
|
||||
perf(
|
||||
"get config/cursor config",
|
||||
@ -391,7 +397,7 @@ pub fn evaluate_repl(
|
||||
// Right before we start our prompt and take input from the user,
|
||||
// fire the "pre_prompt" hook
|
||||
if let Some(hook) = config.hooks.pre_prompt.clone() {
|
||||
if let Err(err) = eval_hook(engine_state, stack, None, vec![], &hook) {
|
||||
if let Err(err) = eval_hook(engine_state, stack, None, vec![], &hook, "pre_prompt") {
|
||||
report_error_new(engine_state, &err);
|
||||
}
|
||||
}
|
||||
@ -466,7 +472,9 @@ pub fn evaluate_repl(
|
||||
repl.buffer = s.to_string();
|
||||
drop(repl);
|
||||
|
||||
if let Err(err) = eval_hook(engine_state, stack, None, vec![], &hook) {
|
||||
if let Err(err) =
|
||||
eval_hook(engine_state, stack, None, vec![], &hook, "pre_execution")
|
||||
{
|
||||
report_error_new(engine_state, &err);
|
||||
}
|
||||
}
|
||||
@ -508,24 +516,12 @@ pub fn evaluate_repl(
|
||||
(path.to_string_lossy().to_string(), tokens.0[0].span)
|
||||
};
|
||||
|
||||
stack.add_env_var(
|
||||
"OLDPWD".into(),
|
||||
Value::String {
|
||||
val: cwd.clone(),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
);
|
||||
stack.add_env_var("OLDPWD".into(), Value::string(cwd.clone(), Span::unknown()));
|
||||
|
||||
//FIXME: this only changes the current scope, but instead this environment variable
|
||||
//should probably be a block that loads the information from the state in the overlay
|
||||
stack.add_env_var(
|
||||
"PWD".into(),
|
||||
Value::String {
|
||||
val: path.clone(),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
);
|
||||
let cwd = Value::String { val: cwd, span };
|
||||
stack.add_env_var("PWD".into(), Value::string(path.clone(), Span::unknown()));
|
||||
let cwd = Value::string(cwd, span);
|
||||
|
||||
let shells = stack.get_env_var(engine_state, "NUSHELL_SHELLS");
|
||||
let mut shells = if let Some(v) = shells {
|
||||
@ -550,15 +546,12 @@ pub fn evaluate_repl(
|
||||
0
|
||||
};
|
||||
|
||||
shells[current_shell] = Value::String { val: path, span };
|
||||
shells[current_shell] = Value::string(path, span);
|
||||
|
||||
stack.add_env_var("NUSHELL_SHELLS".into(), Value::List { vals: shells, span });
|
||||
stack.add_env_var("NUSHELL_SHELLS".into(), Value::list(shells, span));
|
||||
stack.add_env_var(
|
||||
"NUSHELL_LAST_SHELL".into(),
|
||||
Value::Int {
|
||||
val: last_shell as i64,
|
||||
span,
|
||||
},
|
||||
Value::int(last_shell as i64, span),
|
||||
);
|
||||
} else if !s.trim().is_empty() {
|
||||
trace!("eval source: {}", s);
|
||||
@ -601,10 +594,7 @@ pub fn evaluate_repl(
|
||||
|
||||
stack.add_env_var(
|
||||
"CMD_DURATION_MS".into(),
|
||||
Value::String {
|
||||
val: format!("{}", cmd_duration.as_millis()),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
Value::string(format!("{}", cmd_duration.as_millis()), Span::unknown()),
|
||||
);
|
||||
|
||||
if history_supports_meta && !s.is_empty() && line_editor.has_last_command_context()
|
||||
@ -740,9 +730,14 @@ fn update_line_editor_history(
|
||||
)
|
||||
.into_diagnostic()?,
|
||||
),
|
||||
HistoryFileFormat::Sqlite => {
|
||||
Box::new(SqliteBackedHistory::with_file(history_path.to_path_buf()).into_diagnostic()?)
|
||||
}
|
||||
HistoryFileFormat::Sqlite => Box::new(
|
||||
SqliteBackedHistory::with_file(
|
||||
history_path.to_path_buf(),
|
||||
history_session_id,
|
||||
Some(chrono::Utc::now()),
|
||||
)
|
||||
.into_diagnostic()?,
|
||||
),
|
||||
};
|
||||
let line_editor = line_editor
|
||||
.with_history_session_id(history_session_id)
|
||||
|
@ -144,7 +144,7 @@ impl Highlighter for NuHighlighter {
|
||||
fn split_span_by_highlight_positions(
|
||||
line: &str,
|
||||
span: Span,
|
||||
highlight_positions: &Vec<usize>,
|
||||
highlight_positions: &[usize],
|
||||
global_span_offset: usize,
|
||||
) -> Vec<(Span, bool)> {
|
||||
let mut start = span.start;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use nu_command::hook::eval_hook;
|
||||
use nu_cmd_base::hook::eval_hook;
|
||||
use nu_engine::{eval_block, eval_block_with_early_return};
|
||||
use nu_parser::{escape_quote_string, lex, parse, unescape_unquote_string, Token, TokenContents};
|
||||
use nu_protocol::engine::StateWorkingSet;
|
||||
@ -185,10 +185,7 @@ fn gather_env_vars(
|
||||
continue;
|
||||
}
|
||||
|
||||
Value::String {
|
||||
val: bytes,
|
||||
span: *span,
|
||||
}
|
||||
Value::string(bytes, *span)
|
||||
} else {
|
||||
report_capture_error(
|
||||
engine_state,
|
||||
@ -257,7 +254,14 @@ pub fn eval_source(
|
||||
{
|
||||
result = print_if_stream(stream, stderr_stream, false, exit_code);
|
||||
} else if let Some(hook) = config.hooks.display_output.clone() {
|
||||
match eval_hook(engine_state, stack, Some(pipeline_data), vec![], &hook) {
|
||||
match eval_hook(
|
||||
engine_state,
|
||||
stack,
|
||||
Some(pipeline_data),
|
||||
vec![],
|
||||
&hook,
|
||||
"display_output",
|
||||
) {
|
||||
Err(err) => {
|
||||
result = Err(err);
|
||||
}
|
||||
|
@ -4,7 +4,8 @@ use nu_engine::eval_block;
|
||||
use nu_parser::parse;
|
||||
use nu_protocol::{
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
PipelineData, ShellError, Span, Value,
|
||||
eval_const::create_nu_constant,
|
||||
PipelineData, ShellError, Span, Value, NU_VARIABLE_ID,
|
||||
};
|
||||
use nu_test_support::fs;
|
||||
use reedline::Suggestion;
|
||||
@ -28,39 +29,41 @@ pub fn new_engine() -> (PathBuf, String, EngineState, Stack) {
|
||||
// Create a new engine with default context
|
||||
let mut engine_state = create_default_context();
|
||||
|
||||
// Add $nu
|
||||
let nu_const =
|
||||
create_nu_constant(&engine_state, Span::test_data()).expect("Failed creating $nu");
|
||||
engine_state.set_variable_const_val(NU_VARIABLE_ID, nu_const);
|
||||
|
||||
// New stack
|
||||
let mut stack = Stack::new();
|
||||
|
||||
// Add pwd as env var
|
||||
stack.add_env_var(
|
||||
"PWD".to_string(),
|
||||
Value::String {
|
||||
val: dir_str.clone(),
|
||||
span: nu_protocol::Span::new(0, dir_str.len()),
|
||||
},
|
||||
Value::string(dir_str.clone(), nu_protocol::Span::new(0, dir_str.len())),
|
||||
);
|
||||
stack.add_env_var(
|
||||
"TEST".to_string(),
|
||||
Value::String {
|
||||
val: "NUSHELL".to_string(),
|
||||
span: nu_protocol::Span::new(0, dir_str.len()),
|
||||
},
|
||||
Value::string(
|
||||
"NUSHELL".to_string(),
|
||||
nu_protocol::Span::new(0, dir_str.len()),
|
||||
),
|
||||
);
|
||||
#[cfg(windows)]
|
||||
stack.add_env_var(
|
||||
"Path".to_string(),
|
||||
Value::String {
|
||||
val: "c:\\some\\path;c:\\some\\other\\path".to_string(),
|
||||
span: nu_protocol::Span::new(0, dir_str.len()),
|
||||
},
|
||||
Value::string(
|
||||
"c:\\some\\path;c:\\some\\other\\path".to_string(),
|
||||
nu_protocol::Span::new(0, dir_str.len()),
|
||||
),
|
||||
);
|
||||
#[cfg(not(windows))]
|
||||
stack.add_env_var(
|
||||
"PATH".to_string(),
|
||||
Value::String {
|
||||
val: "/some/path:/some/other/path".to_string(),
|
||||
span: nu_protocol::Span::new(0, dir_str.len()),
|
||||
},
|
||||
Value::string(
|
||||
"/some/path:/some/other/path".to_string(),
|
||||
nu_protocol::Span::new(0, dir_str.len()),
|
||||
),
|
||||
);
|
||||
|
||||
// Merge environment into the permanent state
|
||||
@ -89,17 +92,14 @@ pub fn new_quote_engine() -> (PathBuf, String, EngineState, Stack) {
|
||||
// Add pwd as env var
|
||||
stack.add_env_var(
|
||||
"PWD".to_string(),
|
||||
Value::String {
|
||||
val: dir_str.clone(),
|
||||
span: nu_protocol::Span::new(0, dir_str.len()),
|
||||
},
|
||||
Value::string(dir_str.clone(), nu_protocol::Span::new(0, dir_str.len())),
|
||||
);
|
||||
stack.add_env_var(
|
||||
"TEST".to_string(),
|
||||
Value::String {
|
||||
val: "NUSHELL".to_string(),
|
||||
span: nu_protocol::Span::new(0, dir_str.len()),
|
||||
},
|
||||
Value::string(
|
||||
"NUSHELL".to_string(),
|
||||
nu_protocol::Span::new(0, dir_str.len()),
|
||||
),
|
||||
);
|
||||
|
||||
// Merge environment into the permanent state
|
||||
@ -162,12 +162,7 @@ pub fn merge_input(
|
||||
engine_state,
|
||||
stack,
|
||||
&block,
|
||||
PipelineData::Value(
|
||||
Value::Nothing {
|
||||
span: Span::unknown(),
|
||||
},
|
||||
None
|
||||
),
|
||||
PipelineData::Value(Value::nothing(Span::unknown(),), None),
|
||||
false,
|
||||
false
|
||||
)
|
||||
|
@ -5,12 +5,14 @@ edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cmd-base"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-base"
|
||||
version = "0.84.0"
|
||||
version = "0.85.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.84.0" }
|
||||
nu-path = { path = "../nu-path", version = "0.84.0" }
|
||||
nu-protocol = { version = "0.84.0", path = "../nu-protocol" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.85.0" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.85.0" }
|
||||
nu-path = { path = "../nu-path", version = "0.85.0" }
|
||||
nu-protocol = { version = "0.85.0", path = "../nu-protocol" }
|
||||
indexmap = { version = "2.0" }
|
||||
miette = { version = "5.10", features = ["fancy-no-backtrace"] }
|
||||
|
@ -6,7 +6,7 @@ pub fn merge_descriptors(values: &[Value]) -> Vec<String> {
|
||||
let mut seen: IndexSet<String> = indexset! {};
|
||||
for value in values {
|
||||
let data_descriptors = match value {
|
||||
Value::Record { cols, .. } => cols.to_owned(),
|
||||
Value::Record { val, .. } => val.cols.clone(),
|
||||
_ => vec!["".to_string()],
|
||||
};
|
||||
for desc in data_descriptors {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::util::get_guaranteed_cwd;
|
||||
use miette::Result;
|
||||
use nu_cmd_base::util::get_guaranteed_cwd;
|
||||
use nu_engine::{eval_block, eval_block_with_early_return};
|
||||
use nu_parser::parse;
|
||||
use nu_protocol::ast::PathMember;
|
||||
@ -14,12 +14,8 @@ pub fn eval_env_change_hook(
|
||||
) -> Result<(), ShellError> {
|
||||
if let Some(hook) = env_change_hook {
|
||||
match hook {
|
||||
Value::Record {
|
||||
cols: env_names,
|
||||
vals: hook_values,
|
||||
..
|
||||
} => {
|
||||
for (env_name, hook_value) in env_names.iter().zip(hook_values.iter()) {
|
||||
Value::Record { val, .. } => {
|
||||
for (env_name, hook_value) in &val {
|
||||
let before = engine_state
|
||||
.previous_env_vars
|
||||
.get(env_name)
|
||||
@ -37,6 +33,7 @@ pub fn eval_env_change_hook(
|
||||
None,
|
||||
vec![("$before".into(), before), ("$after".into(), after.clone())],
|
||||
hook_value,
|
||||
"env_change",
|
||||
)?;
|
||||
|
||||
engine_state
|
||||
@ -48,7 +45,7 @@ pub fn eval_env_change_hook(
|
||||
x => {
|
||||
return Err(ShellError::TypeMismatch {
|
||||
err_message: "record for the 'env_change' hook".to_string(),
|
||||
span: x.span()?,
|
||||
span: x.span(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -63,8 +60,9 @@ pub fn eval_hook(
|
||||
input: Option<PipelineData>,
|
||||
arguments: Vec<(String, Value)>,
|
||||
value: &Value,
|
||||
hook_name: &str,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let value_span = value.span()?;
|
||||
let value_span = value.span();
|
||||
|
||||
// Hooks can optionally be a record in this form:
|
||||
// {
|
||||
@ -86,8 +84,9 @@ pub fn eval_hook(
|
||||
optional: false,
|
||||
};
|
||||
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::String { val, span } => {
|
||||
Value::String { val, .. } => {
|
||||
let (block, delta, vars) = {
|
||||
let mut working_set = StateWorkingSet::new(engine_state);
|
||||
|
||||
@ -96,22 +95,26 @@ pub fn eval_hook(
|
||||
for (name, val) in arguments {
|
||||
let var_id = working_set.add_variable(
|
||||
name.as_bytes().to_vec(),
|
||||
val.span()?,
|
||||
val.span(),
|
||||
Type::Any,
|
||||
false,
|
||||
);
|
||||
|
||||
vars.push((var_id, val));
|
||||
}
|
||||
|
||||
let output = parse(&mut working_set, Some("hook"), val.as_bytes(), false);
|
||||
let output = parse(
|
||||
&mut working_set,
|
||||
Some(&format!("{hook_name} hook")),
|
||||
val.as_bytes(),
|
||||
false,
|
||||
);
|
||||
if let Some(err) = working_set.parse_errors.first() {
|
||||
report_error(&working_set, err);
|
||||
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"valid source code".into(),
|
||||
"source code with syntax errors".into(),
|
||||
*span,
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
@ -148,68 +151,67 @@ pub fn eval_hook(
|
||||
}
|
||||
Value::List { vals, .. } => {
|
||||
for val in vals {
|
||||
eval_hook(engine_state, stack, None, arguments.clone(), val)?;
|
||||
eval_hook(
|
||||
engine_state,
|
||||
stack,
|
||||
None,
|
||||
arguments.clone(),
|
||||
val,
|
||||
&format!("{hook_name} list, recursive"),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
Value::Record { .. } => {
|
||||
let do_run_hook =
|
||||
if let Ok(condition) = value.clone().follow_cell_path(&[condition_path], false) {
|
||||
match condition {
|
||||
Value::Block {
|
||||
val: block_id,
|
||||
span: block_span,
|
||||
..
|
||||
}
|
||||
| Value::Closure {
|
||||
val: block_id,
|
||||
span: block_span,
|
||||
..
|
||||
} => {
|
||||
match run_hook_block(
|
||||
engine_state,
|
||||
stack,
|
||||
block_id,
|
||||
None,
|
||||
arguments.clone(),
|
||||
block_span,
|
||||
) {
|
||||
Ok(pipeline_data) => {
|
||||
if let PipelineData::Value(Value::Bool { val, .. }, ..) =
|
||||
pipeline_data
|
||||
{
|
||||
val
|
||||
} else {
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"boolean output".to_string(),
|
||||
"other PipelineData variant".to_string(),
|
||||
block_span,
|
||||
));
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
return Err(err);
|
||||
let do_run_hook = if let Ok(condition) =
|
||||
value.clone().follow_cell_path(&[condition_path], false)
|
||||
{
|
||||
let other_span = condition.span();
|
||||
match condition {
|
||||
Value::Block { val: block_id, .. } | Value::Closure { val: block_id, .. } => {
|
||||
match run_hook_block(
|
||||
engine_state,
|
||||
stack,
|
||||
block_id,
|
||||
None,
|
||||
arguments.clone(),
|
||||
other_span,
|
||||
) {
|
||||
Ok(pipeline_data) => {
|
||||
if let PipelineData::Value(Value::Bool { val, .. }, ..) =
|
||||
pipeline_data
|
||||
{
|
||||
val
|
||||
} else {
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"boolean output".to_string(),
|
||||
"other PipelineData variant".to_string(),
|
||||
other_span,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
other => {
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"block".to_string(),
|
||||
format!("{}", other.get_type()),
|
||||
other.span()?,
|
||||
));
|
||||
Err(err) => {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// always run the hook
|
||||
true
|
||||
};
|
||||
other => {
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"block".to_string(),
|
||||
format!("{}", other.get_type()),
|
||||
other_span,
|
||||
));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// always run the hook
|
||||
true
|
||||
};
|
||||
|
||||
if do_run_hook {
|
||||
match value.clone().follow_cell_path(&[code_path], false)? {
|
||||
Value::String {
|
||||
val,
|
||||
span: source_span,
|
||||
} => {
|
||||
let follow = value.clone().follow_cell_path(&[code_path], false)?;
|
||||
let source_span = follow.span();
|
||||
match follow {
|
||||
Value::String { val, .. } => {
|
||||
let (block, delta, vars) = {
|
||||
let mut working_set = StateWorkingSet::new(engine_state);
|
||||
|
||||
@ -218,16 +220,19 @@ pub fn eval_hook(
|
||||
for (name, val) in arguments {
|
||||
let var_id = working_set.add_variable(
|
||||
name.as_bytes().to_vec(),
|
||||
val.span()?,
|
||||
val.span(),
|
||||
Type::Any,
|
||||
false,
|
||||
);
|
||||
|
||||
vars.push((var_id, val));
|
||||
}
|
||||
|
||||
let output =
|
||||
parse(&mut working_set, Some("hook"), val.as_bytes(), false);
|
||||
let output = parse(
|
||||
&mut working_set,
|
||||
Some(&format!("{hook_name} hook")),
|
||||
val.as_bytes(),
|
||||
false,
|
||||
);
|
||||
if let Some(err) = working_set.parse_errors.first() {
|
||||
report_error(&working_set, err);
|
||||
|
||||
@ -265,77 +270,47 @@ pub fn eval_hook(
|
||||
stack.remove_var(*var_id);
|
||||
}
|
||||
}
|
||||
Value::Block {
|
||||
val: block_id,
|
||||
span: block_span,
|
||||
..
|
||||
} => {
|
||||
Value::Block { val: block_id, .. } => {
|
||||
run_hook_block(
|
||||
engine_state,
|
||||
stack,
|
||||
block_id,
|
||||
input,
|
||||
arguments,
|
||||
block_span,
|
||||
source_span,
|
||||
)?;
|
||||
}
|
||||
Value::Closure {
|
||||
val: block_id,
|
||||
span: block_span,
|
||||
..
|
||||
} => {
|
||||
Value::Closure { val: block_id, .. } => {
|
||||
run_hook_block(
|
||||
engine_state,
|
||||
stack,
|
||||
block_id,
|
||||
input,
|
||||
arguments,
|
||||
block_span,
|
||||
source_span,
|
||||
)?;
|
||||
}
|
||||
other => {
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"block or string".to_string(),
|
||||
format!("{}", other.get_type()),
|
||||
other.span()?,
|
||||
source_span,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Value::Block {
|
||||
val: block_id,
|
||||
span: block_span,
|
||||
..
|
||||
} => {
|
||||
output = run_hook_block(
|
||||
engine_state,
|
||||
stack,
|
||||
*block_id,
|
||||
input,
|
||||
arguments,
|
||||
*block_span,
|
||||
)?;
|
||||
Value::Block { val: block_id, .. } => {
|
||||
output = run_hook_block(engine_state, stack, *block_id, input, arguments, span)?;
|
||||
}
|
||||
Value::Closure {
|
||||
val: block_id,
|
||||
span: block_span,
|
||||
..
|
||||
} => {
|
||||
output = run_hook_block(
|
||||
engine_state,
|
||||
stack,
|
||||
*block_id,
|
||||
input,
|
||||
arguments,
|
||||
*block_span,
|
||||
)?;
|
||||
Value::Closure { val: block_id, .. } => {
|
||||
output = run_hook_block(engine_state, stack, *block_id, input, arguments, span)?;
|
||||
}
|
||||
other => {
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"string, block, record, or list of commands".into(),
|
||||
format!("{}", other.get_type()),
|
||||
other.span()?,
|
||||
other.span(),
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -378,7 +353,7 @@ fn run_hook_block(
|
||||
let pipeline_data =
|
||||
eval_block_with_early_return(engine_state, &mut callee_stack, block, input, false, false)?;
|
||||
|
||||
if let PipelineData::Value(Value::Error { error }, _) = pipeline_data {
|
||||
if let PipelineData::Value(Value::Error { error, .. }, _) = pipeline_data {
|
||||
return Err(*error);
|
||||
}
|
||||
|
@ -76,9 +76,7 @@ where
|
||||
}),
|
||||
);
|
||||
if let Err(error) = r {
|
||||
return Value::Error {
|
||||
error: Box::new(error),
|
||||
};
|
||||
return Value::error(error, span);
|
||||
}
|
||||
}
|
||||
v
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub mod formats;
|
||||
pub mod hook;
|
||||
pub mod input_handler;
|
||||
pub mod util;
|
||||
|
@ -5,7 +5,7 @@ edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cmd-dataframe"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-dataframe"
|
||||
version = "0.84.0"
|
||||
version = "0.85.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -13,9 +13,9 @@ version = "0.84.0"
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.84.0" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.84.0" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.84.0" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.85.0" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.85.0" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.85.0" }
|
||||
|
||||
# Potential dependencies for extras
|
||||
chrono = { version = "0.4", features = ["std", "unstable-locales"], default-features = false }
|
||||
@ -23,8 +23,8 @@ fancy-regex = "0.11"
|
||||
indexmap = { version = "2.0" }
|
||||
num = { version = "0.4", optional = true }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
sqlparser = { version = "0.34", features = ["serde"], optional = true }
|
||||
polars-io = { version = "0.30.0", features = ["avro"] }
|
||||
sqlparser = { version = "0.36.1", optional = true }
|
||||
polars-io = { version = "0.32", features = ["avro"], optional = true }
|
||||
|
||||
[dependencies.polars]
|
||||
features = [
|
||||
@ -51,15 +51,15 @@ features = [
|
||||
"serde",
|
||||
"serde-lazy",
|
||||
"strings",
|
||||
"to_dummies"
|
||||
"to_dummies",
|
||||
]
|
||||
optional = true
|
||||
version = "0.30.0"
|
||||
version = "0.32"
|
||||
|
||||
[features]
|
||||
dataframe = ["num", "polars", "sqlparser"]
|
||||
dataframe = ["num", "polars", "polars-io", "sqlparser"]
|
||||
default = []
|
||||
|
||||
[dev-dependencies]
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.84.0" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.84.0" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.85.0" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.85.0" }
|
||||
|
@ -27,10 +27,10 @@ impl Command for ColumnsDF {
|
||||
vec![Example {
|
||||
description: "Dataframe columns",
|
||||
example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr columns",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_string("a"), Value::test_string("b")],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_string("a"), Value::test_string("b")],
|
||||
Span::test_data(),
|
||||
)),
|
||||
}]
|
||||
}
|
||||
|
||||
@ -60,10 +60,7 @@ fn command(
|
||||
.map(|v| Value::string(*v, call.head))
|
||||
.collect();
|
||||
|
||||
let names = Value::List {
|
||||
vals: names,
|
||||
span: call.head,
|
||||
};
|
||||
let names = Value::list(names, call.head);
|
||||
|
||||
Ok(PipelineData::Value(names, None))
|
||||
}
|
||||
|
@ -79,10 +79,7 @@ fn command(
|
||||
.dtype();
|
||||
|
||||
let dtype_str = dtype.to_string();
|
||||
dtypes.push(Value::String {
|
||||
val: dtype_str,
|
||||
span: call.head,
|
||||
});
|
||||
dtypes.push(Value::string(dtype_str, call.head));
|
||||
|
||||
Value::string(*v, call.head)
|
||||
})
|
||||
|
@ -20,6 +20,7 @@ impl Command for Dummies {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name())
|
||||
.switch("drop-first", "Drop first row", Some('d'))
|
||||
.input_output_type(
|
||||
Type::Custom("dataframe".into()),
|
||||
Type::Custom("dataframe".into()),
|
||||
@ -115,10 +116,11 @@ fn command(
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let drop_first: bool = call.has_flag("drop-first");
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
|
||||
df.as_ref()
|
||||
.to_dummies(None)
|
||||
.to_dummies(None, drop_first)
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error calculating dummies".into(),
|
||||
|
@ -92,7 +92,7 @@ fn command_eager(
|
||||
df: NuDataFrame,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let mask_value: Value = call.req(engine_state, stack, 0)?;
|
||||
let mask_span = mask_value.span()?;
|
||||
let mask_span = mask_value.span();
|
||||
|
||||
if NuExpression::can_downcast(&mask_value) {
|
||||
let expression = NuExpression::try_from_value(mask_value)?;
|
||||
|
@ -1,7 +1,7 @@
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Value,
|
||||
record, Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Value,
|
||||
};
|
||||
|
||||
use crate::dataframe::values::NuDataFrame;
|
||||
@ -55,34 +55,18 @@ impl Command for ListDF {
|
||||
NuDataFrame::try_from_value(value).ok().map(|df| (name, df))
|
||||
})
|
||||
.map(|(name, df)| {
|
||||
let name = Value::String {
|
||||
val: name,
|
||||
span: call.head,
|
||||
};
|
||||
|
||||
let columns = Value::int(df.as_ref().width() as i64, call.head);
|
||||
|
||||
let rows = Value::int(df.as_ref().height() as i64, call.head);
|
||||
|
||||
let cols = vec![
|
||||
"name".to_string(),
|
||||
"columns".to_string(),
|
||||
"rows".to_string(),
|
||||
];
|
||||
let vals = vec![name, columns, rows];
|
||||
|
||||
Value::Record {
|
||||
cols,
|
||||
vals,
|
||||
span: call.head,
|
||||
}
|
||||
Value::record(
|
||||
record! {
|
||||
"name" => Value::string(name, call.head),
|
||||
"columns" => Value::int(df.as_ref().width() as i64, call.head),
|
||||
"rows" => Value::int(df.as_ref().height() as i64, call.head),
|
||||
},
|
||||
call.head,
|
||||
)
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
|
||||
let list = Value::List {
|
||||
vals,
|
||||
span: call.head,
|
||||
};
|
||||
let list = Value::list(vals, call.head);
|
||||
|
||||
Ok(list.into_pipeline_data())
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ fn command(
|
||||
match type_id {
|
||||
Some((e, msg, blamed)) => match e.as_str() {
|
||||
"csv" | "tsv" => from_csv(engine_state, stack, call),
|
||||
"parquet" => from_parquet(engine_state, stack, call),
|
||||
"parquet" | "parq" => from_parquet(engine_state, stack, call),
|
||||
"ipc" | "arrow" => from_ipc(engine_state, stack, call),
|
||||
"json" => from_json(engine_state, stack, call),
|
||||
"jsonl" => from_jsonl(engine_state, stack, call),
|
||||
|
@ -88,10 +88,7 @@ fn command(
|
||||
let lazy = NuLazyFrame::new(false, df_sql);
|
||||
|
||||
let eager = lazy.collect(call.head)?;
|
||||
let value = Value::CustomValue {
|
||||
val: Box::new(eager),
|
||||
span: call.head,
|
||||
};
|
||||
let value = Value::custom_value(Box::new(eager), call.head);
|
||||
|
||||
Ok(PipelineData::Value(value, None))
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ fn command_lazy(
|
||||
let value: Value = call.req(engine_state, stack, 1)?;
|
||||
return Err(ShellError::IncompatibleParametersSingle {
|
||||
msg: "New name list has different size to column list".into(),
|
||||
span: value.span()?,
|
||||
span: value.span(),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,7 @@ pub fn parse_sql_expr(expr: &SqlExpr) -> Result<Expr> {
|
||||
})
|
||||
}
|
||||
|
||||
fn apply_window_spec(expr: Expr, window_type: &Option<WindowType>) -> Result<Expr> {
|
||||
fn apply_window_spec(expr: Expr, window_type: Option<&WindowType>) -> Result<Expr> {
|
||||
Ok(match &window_type {
|
||||
Some(wtype) => match wtype {
|
||||
WindowType::WindowSpec(window_spec) => {
|
||||
@ -168,13 +168,13 @@ fn parse_sql_function(sql_function: &SQLFunction) -> Result<Expr> {
|
||||
sql_function.distinct,
|
||||
) {
|
||||
("sum", [FunctionArgExpr::Expr(expr)], false) => {
|
||||
apply_window_spec(parse_sql_expr(expr)?, &sql_function.over)?.sum()
|
||||
apply_window_spec(parse_sql_expr(expr)?, sql_function.over.as_ref())?.sum()
|
||||
}
|
||||
("count", [FunctionArgExpr::Expr(expr)], false) => {
|
||||
apply_window_spec(parse_sql_expr(expr)?, &sql_function.over)?.count()
|
||||
apply_window_spec(parse_sql_expr(expr)?, sql_function.over.as_ref())?.count()
|
||||
}
|
||||
("count", [FunctionArgExpr::Expr(expr)], true) => {
|
||||
apply_window_spec(parse_sql_expr(expr)?, &sql_function.over)?.n_unique()
|
||||
apply_window_spec(parse_sql_expr(expr)?, sql_function.over.as_ref())?.n_unique()
|
||||
}
|
||||
// Special case for wildcard args to count function.
|
||||
("count", [FunctionArgExpr::Wildcard], false) => lit(1i32).count(),
|
||||
|
@ -120,30 +120,31 @@ fn command(
|
||||
let quantiles = quantiles.map(|values| {
|
||||
values
|
||||
.iter()
|
||||
.map(|value| match value {
|
||||
Value::Float { val, span } => {
|
||||
if (&0.0..=&1.0).contains(&val) {
|
||||
Ok(*val)
|
||||
} else {
|
||||
Err(ShellError::GenericError(
|
||||
"Incorrect value for quantile".to_string(),
|
||||
"value should be between 0 and 1".to_string(),
|
||||
Some(*span),
|
||||
None,
|
||||
Vec::new(),
|
||||
))
|
||||
.map(|value| {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::Float { val, .. } => {
|
||||
if (&0.0..=&1.0).contains(&val) {
|
||||
Ok(*val)
|
||||
} else {
|
||||
Err(ShellError::GenericError(
|
||||
"Incorrect value for quantile".to_string(),
|
||||
"value should be between 0 and 1".to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => match value.span() {
|
||||
Ok(span) => Err(ShellError::GenericError(
|
||||
Value::Error { error, .. } => Err(*error.clone()),
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Incorrect value for quantile".to_string(),
|
||||
"value should be a float".to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
Err(e) => Err(e),
|
||||
},
|
||||
}
|
||||
})
|
||||
.collect::<Result<Vec<f64>, ShellError>>()
|
||||
});
|
||||
|
@ -93,7 +93,7 @@ fn command(
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let index_value: Value = call.req(engine_state, stack, 0)?;
|
||||
let index_span = index_value.span()?;
|
||||
let index_span = index_value.span();
|
||||
let index = NuDataFrame::try_from_value(index_value)?.as_series(index_span)?;
|
||||
|
||||
let casted = match index.dtype() {
|
||||
|
@ -78,16 +78,10 @@ fn command(
|
||||
)
|
||||
})?;
|
||||
|
||||
let file_value = Value::String {
|
||||
val: format!("saved {:?}", &file_name.item),
|
||||
span: file_name.span,
|
||||
};
|
||||
let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span);
|
||||
|
||||
Ok(PipelineData::Value(
|
||||
Value::List {
|
||||
vals: vec![file_value],
|
||||
span: call.head,
|
||||
},
|
||||
Value::list(vec![file_value], call.head),
|
||||
None,
|
||||
))
|
||||
}
|
||||
|
@ -108,16 +108,10 @@ fn command(
|
||||
)
|
||||
})?;
|
||||
|
||||
let file_value = Value::String {
|
||||
val: format!("saved {:?}", &file_name.item),
|
||||
span: file_name.span,
|
||||
};
|
||||
let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span);
|
||||
|
||||
Ok(PipelineData::Value(
|
||||
Value::List {
|
||||
vals: vec![file_value],
|
||||
span: call.head,
|
||||
},
|
||||
Value::list(vec![file_value], call.head),
|
||||
None,
|
||||
))
|
||||
}
|
||||
|
@ -124,16 +124,10 @@ fn command(
|
||||
)
|
||||
})?;
|
||||
|
||||
let file_value = Value::String {
|
||||
val: format!("saved {:?}", &file_name.item),
|
||||
span: file_name.span,
|
||||
};
|
||||
let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span);
|
||||
|
||||
Ok(PipelineData::Value(
|
||||
Value::List {
|
||||
vals: vec![file_value],
|
||||
span: call.head,
|
||||
},
|
||||
Value::list(vec![file_value], call.head),
|
||||
None,
|
||||
))
|
||||
}
|
||||
|
@ -81,16 +81,10 @@ fn command(
|
||||
)
|
||||
})?;
|
||||
|
||||
let file_value = Value::String {
|
||||
val: format!("saved {:?}", &file_name.item),
|
||||
span: file_name.span,
|
||||
};
|
||||
let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span);
|
||||
|
||||
Ok(PipelineData::Value(
|
||||
Value::List {
|
||||
vals: vec![file_value],
|
||||
span: call.head,
|
||||
},
|
||||
Value::list(vec![file_value], call.head),
|
||||
None,
|
||||
))
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use nu_engine::CallExt;
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
|
||||
Category, Example, PipelineData, Record, ShellError, Signature, Span, SyntaxShape, Type, Value,
|
||||
};
|
||||
|
||||
use crate::dataframe::values::NuExpression;
|
||||
@ -40,47 +40,37 @@ impl Command for ToNu {
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
let cols = vec!["index".into(), "a".into(), "b".into()];
|
||||
let rec_1 = Value::Record {
|
||||
let rec_1 = Value::test_record(Record {
|
||||
cols: cols.clone(),
|
||||
vals: vec![Value::test_int(0), Value::test_int(1), Value::test_int(2)],
|
||||
span: Span::test_data(),
|
||||
};
|
||||
let rec_2 = Value::Record {
|
||||
});
|
||||
let rec_2 = Value::test_record(Record {
|
||||
cols: cols.clone(),
|
||||
vals: vec![Value::test_int(1), Value::test_int(3), Value::test_int(4)],
|
||||
span: Span::test_data(),
|
||||
};
|
||||
let rec_3 = Value::Record {
|
||||
});
|
||||
let rec_3 = Value::test_record(Record {
|
||||
cols,
|
||||
vals: vec![Value::test_int(2), Value::test_int(3), Value::test_int(4)],
|
||||
span: Span::test_data(),
|
||||
};
|
||||
});
|
||||
|
||||
vec![
|
||||
Example {
|
||||
description: "Shows head rows from dataframe",
|
||||
example: "[[a b]; [1 2] [3 4]] | dfr into-df | dfr into-nu",
|
||||
result: Some(Value::List {
|
||||
vals: vec![rec_1, rec_2],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(vec![rec_1, rec_2], Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Shows tail rows from dataframe",
|
||||
example: "[[a b]; [1 2] [5 6] [3 4]] | dfr into-df | dfr into-nu -t -n 1",
|
||||
result: Some(Value::List {
|
||||
vals: vec![rec_3],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(vec![rec_3], Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Convert a col expression into a nushell value",
|
||||
example: "dfr col a | dfr into-nu",
|
||||
result: Some(Value::Record {
|
||||
result: Some(Value::test_record(Record {
|
||||
cols: vec!["expr".into(), "value".into()],
|
||||
vals: vec![Value::test_string("column"), Value::test_string("a")],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
})),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -123,16 +113,13 @@ fn dataframe_command(
|
||||
}
|
||||
};
|
||||
|
||||
let value = Value::List {
|
||||
vals: values,
|
||||
span: call.head,
|
||||
};
|
||||
let value = Value::list(values, call.head);
|
||||
|
||||
Ok(PipelineData::Value(value, None))
|
||||
}
|
||||
fn expression_command(call: &Call, input: Value) -> Result<PipelineData, ShellError> {
|
||||
let expr = NuExpression::try_from_value(input)?;
|
||||
let value = expr.to_value(call.head);
|
||||
let value = expr.to_value(call.head)?;
|
||||
|
||||
Ok(PipelineData::Value(value, None))
|
||||
}
|
||||
|
@ -78,16 +78,10 @@ fn command(
|
||||
)
|
||||
})?;
|
||||
|
||||
let file_value = Value::String {
|
||||
val: format!("saved {:?}", &file_name.item),
|
||||
span: file_name.span,
|
||||
};
|
||||
let file_value = Value::string(format!("saved {:?}", &file_name.item), file_name.span);
|
||||
|
||||
Ok(PipelineData::Value(
|
||||
Value::List {
|
||||
vals: vec![file_value],
|
||||
span: call.head,
|
||||
},
|
||||
Value::list(vec![file_value], call.head),
|
||||
None,
|
||||
))
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ impl Command for WithColumn {
|
||||
Err(ShellError::CantConvert {
|
||||
to_type: "lazy or eager dataframe".into(),
|
||||
from_type: value.get_type().to_string(),
|
||||
span: value.span()?,
|
||||
span: value.span(),
|
||||
help: None,
|
||||
})
|
||||
}
|
||||
@ -128,14 +128,11 @@ fn command_eager(
|
||||
mut df: NuDataFrame,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let new_column: Value = call.req(engine_state, stack, 0)?;
|
||||
let column_span = new_column.span()?;
|
||||
let column_span = new_column.span();
|
||||
|
||||
if NuExpression::can_downcast(&new_column) {
|
||||
let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
|
||||
let value = Value::List {
|
||||
vals,
|
||||
span: call.head,
|
||||
};
|
||||
let value = Value::list(vals, call.head);
|
||||
let expressions = NuExpression::extract_exprs(value)?;
|
||||
let lazy = NuLazyFrame::new(true, df.lazy().with_columns(&expressions));
|
||||
|
||||
@ -179,10 +176,7 @@ fn command_lazy(
|
||||
lazy: NuLazyFrame,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
|
||||
let value = Value::List {
|
||||
vals,
|
||||
span: call.head,
|
||||
};
|
||||
let value = Value::list(vals, call.head);
|
||||
let expressions = NuExpression::extract_exprs(value)?;
|
||||
|
||||
let lazy: NuLazyFrame = lazy.into_polars().with_columns(&expressions).into();
|
||||
|
@ -4,7 +4,7 @@ use nu_engine::CallExt;
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
|
||||
Category, Example, PipelineData, Record, ShellError, Signature, SyntaxShape, Type, Value,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -41,20 +41,18 @@ impl Command for ExprAlias {
|
||||
let cols = vec!["expr".into(), "value".into()];
|
||||
let expr = Value::test_string("column");
|
||||
let value = Value::test_string("a");
|
||||
let expr = Value::Record {
|
||||
let expr = Value::test_record(Record {
|
||||
cols,
|
||||
vals: vec![expr, value],
|
||||
span: Span::test_data(),
|
||||
};
|
||||
});
|
||||
|
||||
let cols = vec!["expr".into(), "alias".into()];
|
||||
let value = Value::test_string("new_a");
|
||||
|
||||
let record = Value::Record {
|
||||
let record = Value::test_record(Record {
|
||||
cols,
|
||||
vals: vec![expr, value],
|
||||
span: Span::test_data(),
|
||||
};
|
||||
});
|
||||
|
||||
Some(record)
|
||||
},
|
||||
|
@ -3,7 +3,7 @@ use nu_engine::CallExt;
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
|
||||
Category, Example, PipelineData, Record, ShellError, Signature, SyntaxShape, Type, Value,
|
||||
};
|
||||
use polars::prelude::col;
|
||||
|
||||
@ -34,11 +34,10 @@ impl Command for ExprCol {
|
||||
vec![Example {
|
||||
description: "Creates a named column expression and converts it to a nu object",
|
||||
example: "dfr col a | dfr into-nu",
|
||||
result: Some(Value::Record {
|
||||
result: Some(Value::test_record(Record {
|
||||
cols: vec!["expr".into(), "value".into()],
|
||||
vals: vec![Value::test_string("column"), Value::test_string("a")],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
})),
|
||||
}]
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ use nu_engine::CallExt;
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
|
||||
Category, Example, PipelineData, Record, ShellError, Signature, SyntaxShape, Type, Value,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -33,11 +33,10 @@ impl Command for ExprLit {
|
||||
vec![Example {
|
||||
description: "Created a literal expression and converts it to a nu object",
|
||||
example: "dfr lit 2 | dfr into-nu",
|
||||
result: Some(Value::Record {
|
||||
result: Some(Value::test_record(Record {
|
||||
cols: vec!["expr".into(), "value".into()],
|
||||
vals: vec![Value::test_string("literal"), Value::test_string("2")],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
})),
|
||||
}]
|
||||
}
|
||||
|
||||
|
@ -95,10 +95,8 @@ impl Command for ExprOtherwise {
|
||||
|
||||
let value = input.into_value(call.head);
|
||||
let complete: NuExpression = match NuWhen::try_from_value(value)? {
|
||||
NuWhen::WhenThen(when_then) => when_then
|
||||
.otherwise(otherwise_predicate.into_polars())
|
||||
.into(),
|
||||
NuWhen::WhenThenThen(when_then_then) => when_then_then
|
||||
NuWhen::Then(then) => then.otherwise(otherwise_predicate.into_polars()).into(),
|
||||
NuWhen::ChainedThen(chained_when) => chained_when
|
||||
.otherwise(otherwise_predicate.into_polars())
|
||||
.into(),
|
||||
};
|
||||
|
@ -110,11 +110,11 @@ impl Command for ExprWhen {
|
||||
.then(then_predicate.into_polars())
|
||||
.into(),
|
||||
v => match NuWhen::try_from_value(v)? {
|
||||
NuWhen::WhenThen(when_then) => when_then
|
||||
NuWhen::Then(when_then) => when_then
|
||||
.when(when_predicate.into_polars())
|
||||
.then(then_predicate.into_polars())
|
||||
.into(),
|
||||
NuWhen::WhenThenThen(when_then_then) => when_then_then
|
||||
NuWhen::ChainedThen(when_then_then) => when_then_then
|
||||
.when(when_predicate.into_polars())
|
||||
.then(then_predicate.into_polars())
|
||||
.into(),
|
||||
|
@ -114,10 +114,7 @@ impl Command for LazyAggregate {
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
|
||||
let value = Value::List {
|
||||
vals,
|
||||
span: call.head,
|
||||
};
|
||||
let value = Value::list(vals, call.head);
|
||||
let expressions = NuExpression::extract_exprs(value)?;
|
||||
|
||||
let group_by = NuLazyGroupBy::try_from_pipeline(input, call.head)?;
|
||||
@ -172,7 +169,6 @@ fn get_col_name(expr: &Expr) -> Option<String> {
|
||||
},
|
||||
Expr::Filter { input: expr, .. }
|
||||
| Expr::Slice { input: expr, .. }
|
||||
| Expr::Cache { input: expr, .. }
|
||||
| Expr::Cast { expr, .. }
|
||||
| Expr::Sort { expr, .. }
|
||||
| Expr::Take { expr, .. }
|
||||
@ -192,7 +188,8 @@ fn get_col_name(expr: &Expr) -> Option<String> {
|
||||
| Expr::Wildcard
|
||||
| Expr::RenameAlias { .. }
|
||||
| Expr::Count
|
||||
| Expr::Nth(_) => None,
|
||||
| Expr::Nth(_)
|
||||
| Expr::Selector(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,10 +58,7 @@ impl Command for LazyCollect {
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?;
|
||||
let eager = lazy.collect(call.head)?;
|
||||
let value = Value::CustomValue {
|
||||
val: Box::new(eager),
|
||||
span: call.head,
|
||||
};
|
||||
let value = Value::custom_value(Box::new(eager), call.head);
|
||||
|
||||
Ok(PipelineData::Value(value, None))
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ impl Command for LazyFillNA {
|
||||
None,
|
||||
))
|
||||
} else {
|
||||
let val_span = value.span()?;
|
||||
let val_span = value.span();
|
||||
let frame = NuDataFrame::try_from_value(value)?;
|
||||
let columns = frame.columns(val_span)?;
|
||||
let dataframe = columns
|
||||
@ -102,18 +102,21 @@ impl Command for LazyFillNA {
|
||||
let column_name = column.name().to_string();
|
||||
let values = column
|
||||
.into_iter()
|
||||
.map(|value| match value {
|
||||
Value::Float { val, .. } => {
|
||||
if val.is_nan() {
|
||||
fill.clone()
|
||||
} else {
|
||||
value
|
||||
.map(|value| {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::Float { val, .. } => {
|
||||
if val.is_nan() {
|
||||
fill.clone()
|
||||
} else {
|
||||
value
|
||||
}
|
||||
}
|
||||
Value::List { vals, .. } => {
|
||||
NuDataFrame::fill_list_nan(vals, span, fill.clone())
|
||||
}
|
||||
_ => value,
|
||||
}
|
||||
Value::List { vals, span } => {
|
||||
NuDataFrame::fill_list_nan(vals, span, fill.clone())
|
||||
}
|
||||
_ => value,
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
Column::new(column_name, values)
|
||||
|
@ -113,10 +113,7 @@ impl Command for ToLazyGroupBy {
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
|
||||
let value = Value::List {
|
||||
vals,
|
||||
span: call.head,
|
||||
};
|
||||
let value = Value::list(vals, call.head);
|
||||
let expressions = NuExpression::extract_exprs(value)?;
|
||||
|
||||
if expressions
|
||||
@ -126,7 +123,7 @@ impl Command for ToLazyGroupBy {
|
||||
let value: Value = call.req(engine_state, stack, 0)?;
|
||||
return Err(ShellError::IncompatibleParametersSingle {
|
||||
msg: "Expected only Col expressions".into(),
|
||||
span: value.span()?,
|
||||
span: value.span(),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -199,7 +199,7 @@ impl Command for LazyJoin {
|
||||
let right_on: Value = call.req(engine_state, stack, 2)?;
|
||||
return Err(ShellError::IncompatibleParametersSingle {
|
||||
msg: "The right column list has a different size to the left column list".into(),
|
||||
span: right_on.span()?,
|
||||
span: right_on.span(),
|
||||
});
|
||||
}
|
||||
|
||||
@ -209,7 +209,7 @@ impl Command for LazyJoin {
|
||||
let value: Value = call.req(engine_state, stack, *index)?;
|
||||
return Err(ShellError::IncompatibleParametersSingle {
|
||||
msg: "Expected only a string, col expressions or list of strings".into(),
|
||||
span: value.span()?,
|
||||
span: value.span(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -55,10 +55,7 @@ impl Command for LazySelect {
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
|
||||
let value = Value::List {
|
||||
vals,
|
||||
span: call.head,
|
||||
};
|
||||
let value = Value::list(vals, call.head);
|
||||
let expressions = NuExpression::extract_exprs(value)?;
|
||||
|
||||
let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?;
|
||||
|
@ -37,6 +37,7 @@ impl Command for LazySortBy {
|
||||
"nulls are shown last in the dataframe",
|
||||
Some('n'),
|
||||
)
|
||||
.switch("maintain-order", "Maintains order during sort", Some('m'))
|
||||
.input_output_type(
|
||||
Type::Custom("dataframe".into()),
|
||||
Type::Custom("dataframe".into()),
|
||||
@ -104,12 +105,10 @@ impl Command for LazySortBy {
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
|
||||
let value = Value::List {
|
||||
vals,
|
||||
span: call.head,
|
||||
};
|
||||
let value = Value::list(vals, call.head);
|
||||
let expressions = NuExpression::extract_exprs(value)?;
|
||||
let nulls_last = call.has_flag("nulls-last");
|
||||
let maintain_order = call.has_flag("maintain-order");
|
||||
|
||||
let reverse: Option<Vec<bool>> = call.get_flag(engine_state, stack, "reverse")?;
|
||||
let reverse = match reverse {
|
||||
@ -118,7 +117,7 @@ impl Command for LazySortBy {
|
||||
let span = call
|
||||
.get_flag::<Value>(engine_state, stack, "reverse")?
|
||||
.expect("already checked and it exists")
|
||||
.span()?;
|
||||
.span();
|
||||
return Err(ShellError::GenericError(
|
||||
"Incorrect list size".into(),
|
||||
"Size doesn't match expression list".into(),
|
||||
@ -137,7 +136,7 @@ impl Command for LazySortBy {
|
||||
let lazy = NuLazyFrame::new(
|
||||
lazy.from_eager,
|
||||
lazy.into_polars()
|
||||
.sort_by_exprs(&expressions, reverse, nulls_last),
|
||||
.sort_by_exprs(&expressions, reverse, nulls_last, maintain_order),
|
||||
);
|
||||
|
||||
Ok(PipelineData::Value(
|
||||
|
@ -41,10 +41,7 @@ impl Command for ToLazyFrame {
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let df = NuDataFrame::try_from_iter(input.into_iter())?;
|
||||
let lazy = NuLazyFrame::from_dataframe(df);
|
||||
let value = Value::CustomValue {
|
||||
val: Box::new(lazy),
|
||||
span: call.head,
|
||||
};
|
||||
let value = Value::custom_value(Box::new(lazy), call.head);
|
||||
|
||||
Ok(PipelineData::Value(value, None))
|
||||
}
|
||||
|
@ -56,22 +56,22 @@ impl Command for AsDateTime {
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"datetime".to_string(),
|
||||
vec![
|
||||
Value::Date {
|
||||
val: DateTime::parse_from_str(
|
||||
Value::date(
|
||||
DateTime::parse_from_str(
|
||||
"2021-12-30 00:00:00 +0000",
|
||||
"%Y-%m-%d %H:%M:%S %z",
|
||||
)
|
||||
.expect("date calculation should not fail in test"),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::Date {
|
||||
val: DateTime::parse_from_str(
|
||||
Span::test_data(),
|
||||
),
|
||||
Value::date(
|
||||
DateTime::parse_from_str(
|
||||
"2021-12-31 00:00:00 +0000",
|
||||
"%Y-%m-%d %H:%M:%S %z",
|
||||
)
|
||||
.expect("date calculation should not fail in test"),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Span::test_data(),
|
||||
),
|
||||
],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
@ -85,22 +85,22 @@ impl Command for AsDateTime {
|
||||
NuDataFrame::try_from_columns(vec![Column::new(
|
||||
"datetime".to_string(),
|
||||
vec![
|
||||
Value::Date {
|
||||
val: DateTime::parse_from_str(
|
||||
Value::date(
|
||||
DateTime::parse_from_str(
|
||||
"2021-12-30 00:00:00.123456789 +0000",
|
||||
"%Y-%m-%d %H:%M:%S.%9f %z",
|
||||
)
|
||||
.expect("date calculation should not fail in test"),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::Date {
|
||||
val: DateTime::parse_from_str(
|
||||
Span::test_data(),
|
||||
),
|
||||
Value::date(
|
||||
DateTime::parse_from_str(
|
||||
"2021-12-31 00:00:00.123456789 +0000",
|
||||
"%Y-%m-%d %H:%M:%S.%9f %z",
|
||||
)
|
||||
.expect("date calculation should not fail in test"),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Span::test_data(),
|
||||
),
|
||||
],
|
||||
)])
|
||||
.expect("simple df for test should not fail")
|
||||
@ -143,7 +143,13 @@ fn command(
|
||||
})?;
|
||||
|
||||
let res = if not_exact {
|
||||
casted.as_datetime_not_exact(Some(format.as_str()), TimeUnit::Nanoseconds, None)
|
||||
casted.as_datetime_not_exact(
|
||||
Some(format.as_str()),
|
||||
TimeUnit::Nanoseconds,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
casted.as_datetime(
|
||||
Some(format.as_str()),
|
||||
@ -151,6 +157,7 @@ fn command(
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -27,6 +27,11 @@ impl Command for ArgSort {
|
||||
Signature::build(self.name())
|
||||
.switch("reverse", "reverse order", Some('r'))
|
||||
.switch("nulls-last", "nulls ordered last", Some('n'))
|
||||
.switch(
|
||||
"maintain-order",
|
||||
"maintain order on sorted items",
|
||||
Some('m'),
|
||||
)
|
||||
.input_output_type(
|
||||
Type::Custom("dataframe".into()),
|
||||
Type::Custom("dataframe".into()),
|
||||
@ -98,6 +103,7 @@ fn command(
|
||||
descending: call.has_flag("reverse"),
|
||||
nulls_last: call.has_flag("nulls-last"),
|
||||
multithreaded: true,
|
||||
maintain_order: call.has_flag("maintain-order"),
|
||||
};
|
||||
|
||||
let mut res = df
|
||||
|
@ -98,7 +98,12 @@ fn command(
|
||||
let value = NuDataFrame::dataframe_into_value(res, call.head);
|
||||
Ok(PipelineData::Value(value, None))
|
||||
}
|
||||
_ => todo!(),
|
||||
_ => Err(ShellError::UnsupportedInput(
|
||||
"Expected the dataframe to have a column".to_string(),
|
||||
"".to_string(),
|
||||
call.head,
|
||||
call.head,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,7 +82,7 @@ fn command(
|
||||
let indices_value: Value = call
|
||||
.get_flag(engine_state, stack, "indices")?
|
||||
.expect("required named value");
|
||||
let indices_span = indices_value.span()?;
|
||||
let indices_span = indices_value.span();
|
||||
let indices = NuDataFrame::try_from_value(indices_value)?.as_series(indices_span)?;
|
||||
|
||||
let casted = match indices.dtype() {
|
||||
@ -123,8 +123,9 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
let span = value.span();
|
||||
let res = match value {
|
||||
Value::Int { val, span } => {
|
||||
Value::Int { val, .. } => {
|
||||
let chunked = series.i64().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to i64".into(),
|
||||
@ -147,7 +148,7 @@ fn command(
|
||||
|
||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||
}
|
||||
Value::Float { val, span } => {
|
||||
Value::Float { val, .. } => {
|
||||
let chunked = series.f64().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to f64".into(),
|
||||
@ -170,7 +171,7 @@ fn command(
|
||||
|
||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||
}
|
||||
Value::String { val, span } => {
|
||||
Value::String { val, .. } => {
|
||||
let chunked = series.utf8().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to string".into(),
|
||||
@ -204,7 +205,7 @@ fn command(
|
||||
"this value cannot be set in a series of type '{}'",
|
||||
series.dtype()
|
||||
),
|
||||
Some(value.span()?),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
|
@ -74,7 +74,7 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
|
||||
let other_value: Value = call.req(engine_state, stack, 0)?;
|
||||
let other_span = other_value.span()?;
|
||||
let other_span = other_value.span();
|
||||
let other_df = NuDataFrame::try_from_value(other_value)?;
|
||||
let other = other_df.as_series(other_span)?;
|
||||
|
||||
|
@ -81,7 +81,7 @@ fn command(
|
||||
let mask_value: Value = call
|
||||
.get_flag(engine_state, stack, "mask")?
|
||||
.expect("required named value");
|
||||
let mask_span = mask_value.span()?;
|
||||
let mask_span = mask_value.span();
|
||||
let mask = NuDataFrame::try_from_value(mask_value)?.as_series(mask_span)?;
|
||||
|
||||
let bool_mask = match mask.dtype() {
|
||||
@ -105,9 +105,9 @@ fn command(
|
||||
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
let series = df.as_series(call.head)?;
|
||||
|
||||
let span = value.span();
|
||||
let res = match value {
|
||||
Value::Int { val, span } => {
|
||||
Value::Int { val, .. } => {
|
||||
let chunked = series.i64().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to i64".into(),
|
||||
@ -130,7 +130,7 @@ fn command(
|
||||
|
||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||
}
|
||||
Value::Float { val, span } => {
|
||||
Value::Float { val, .. } => {
|
||||
let chunked = series.f64().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to f64".into(),
|
||||
@ -153,7 +153,7 @@ fn command(
|
||||
|
||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||
}
|
||||
Value::String { val, span } => {
|
||||
Value::String { val, .. } => {
|
||||
let chunked = series.utf8().map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error casting to string".into(),
|
||||
@ -185,7 +185,7 @@ fn command(
|
||||
"this value cannot be set in a series of type '{}'",
|
||||
series.dtype()
|
||||
),
|
||||
Some(value.span()?),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
|
@ -149,6 +149,7 @@ fn command(
|
||||
closed_window: None,
|
||||
tu: None,
|
||||
tz: None,
|
||||
fn_params: None,
|
||||
};
|
||||
let res = match roll_type {
|
||||
RollType::Max => series.rolling_max(rolling_opts),
|
||||
|
@ -74,7 +74,7 @@ fn command(
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
|
||||
let other: Value = call.req(engine_state, stack, 0)?;
|
||||
let other_span = other.span()?;
|
||||
let other_span = other.span();
|
||||
let other_df = NuDataFrame::try_from_value(other)?;
|
||||
|
||||
let other_series = other_df.as_series(other_span)?;
|
||||
|
@ -9,7 +9,7 @@ pub fn extract_strings(value: Value) -> Result<Vec<String>, ShellError> {
|
||||
(Err(_), Ok(cols)) => Ok(cols),
|
||||
_ => Err(ShellError::IncompatibleParametersSingle {
|
||||
msg: "Expected a string or list of strings".into(),
|
||||
span: value.span()?,
|
||||
span: value.span(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ pub(super) fn between_dataframes(
|
||||
right: &Value,
|
||||
rhs: &NuDataFrame,
|
||||
) -> Result<Value, ShellError> {
|
||||
let operation_span = span(&[left.span()?, right.span()?]);
|
||||
let operation_span = span(&[left.span(), right.span()]);
|
||||
match operator.item {
|
||||
Operator::Math(Math::Plus) => match lhs.append_df(rhs, Axis::Row, operation_span) {
|
||||
Ok(df) => Ok(df.into_value(operation_span)),
|
||||
@ -26,9 +26,9 @@ pub(super) fn between_dataframes(
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span()?,
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span()?,
|
||||
rhs_span: right.span(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -40,7 +40,7 @@ pub(super) fn compute_between_series(
|
||||
right: &Value,
|
||||
rhs: &Series,
|
||||
) -> Result<Value, ShellError> {
|
||||
let operation_span = span(&[left.span()?, right.span()?]);
|
||||
let operation_span = span(&[left.span(), right.span()]);
|
||||
match operator.item {
|
||||
Operator::Math(Math::Plus) => {
|
||||
let mut res = lhs + rhs;
|
||||
@ -71,7 +71,7 @@ pub(super) fn compute_between_series(
|
||||
Err(e) => Err(ShellError::GenericError(
|
||||
"Division error".into(),
|
||||
e.to_string(),
|
||||
Some(right.span()?),
|
||||
Some(right.span()),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
@ -79,32 +79,32 @@ pub(super) fn compute_between_series(
|
||||
}
|
||||
Operator::Comparison(Comparison::Equal) => {
|
||||
let name = format!("eq_{}_{}", lhs.name(), rhs.name());
|
||||
let res = compare_series(lhs, rhs, name.as_str(), right.span().ok(), Series::equal)?;
|
||||
let res = compare_series(lhs, rhs, name.as_str(), right.span(), Series::equal)?;
|
||||
NuDataFrame::series_to_value(res, operation_span)
|
||||
}
|
||||
Operator::Comparison(Comparison::NotEqual) => {
|
||||
let name = format!("neq_{}_{}", lhs.name(), rhs.name());
|
||||
let res = compare_series(lhs, rhs, name.as_str(), right.span().ok(), Series::equal)?;
|
||||
let res = compare_series(lhs, rhs, name.as_str(), right.span(), Series::equal)?;
|
||||
NuDataFrame::series_to_value(res, operation_span)
|
||||
}
|
||||
Operator::Comparison(Comparison::LessThan) => {
|
||||
let name = format!("lt_{}_{}", lhs.name(), rhs.name());
|
||||
let res = compare_series(lhs, rhs, name.as_str(), right.span().ok(), Series::equal)?;
|
||||
let res = compare_series(lhs, rhs, name.as_str(), right.span(), Series::equal)?;
|
||||
NuDataFrame::series_to_value(res, operation_span)
|
||||
}
|
||||
Operator::Comparison(Comparison::LessThanOrEqual) => {
|
||||
let name = format!("lte_{}_{}", lhs.name(), rhs.name());
|
||||
let res = compare_series(lhs, rhs, name.as_str(), right.span().ok(), Series::equal)?;
|
||||
let res = compare_series(lhs, rhs, name.as_str(), right.span(), Series::equal)?;
|
||||
NuDataFrame::series_to_value(res, operation_span)
|
||||
}
|
||||
Operator::Comparison(Comparison::GreaterThan) => {
|
||||
let name = format!("gt_{}_{}", lhs.name(), rhs.name());
|
||||
let res = compare_series(lhs, rhs, name.as_str(), right.span().ok(), Series::equal)?;
|
||||
let res = compare_series(lhs, rhs, name.as_str(), right.span(), Series::equal)?;
|
||||
NuDataFrame::series_to_value(res, operation_span)
|
||||
}
|
||||
Operator::Comparison(Comparison::GreaterThanOrEqual) => {
|
||||
let name = format!("gte_{}_{}", lhs.name(), rhs.name());
|
||||
let res = compare_series(lhs, rhs, name.as_str(), right.span().ok(), Series::equal)?;
|
||||
let res = compare_series(lhs, rhs, name.as_str(), right.span(), Series::equal)?;
|
||||
NuDataFrame::series_to_value(res, operation_span)
|
||||
}
|
||||
Operator::Boolean(Boolean::And) => match lhs.dtype() {
|
||||
@ -122,7 +122,7 @@ pub(super) fn compute_between_series(
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Incompatible types".into(),
|
||||
"unable to cast to boolean".into(),
|
||||
Some(right.span()?),
|
||||
Some(right.span()),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
@ -151,7 +151,7 @@ pub(super) fn compute_between_series(
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Incompatible types".into(),
|
||||
"unable to cast to boolean".into(),
|
||||
Some(right.span()?),
|
||||
Some(right.span()),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
@ -168,9 +168,9 @@ pub(super) fn compute_between_series(
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span()?,
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span()?,
|
||||
rhs_span: right.span(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -179,7 +179,7 @@ fn compare_series<'s, F>(
|
||||
lhs: &'s Series,
|
||||
rhs: &'s Series,
|
||||
name: &'s str,
|
||||
span: Option<Span>,
|
||||
span: Span,
|
||||
f: F,
|
||||
) -> Result<Series, ShellError>
|
||||
where
|
||||
@ -190,7 +190,7 @@ where
|
||||
ShellError::GenericError(
|
||||
"Equality error".into(),
|
||||
e.to_string(),
|
||||
span,
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
@ -211,13 +211,13 @@ pub(super) fn compute_series_single_value(
|
||||
return Err(ShellError::OperatorMismatch {
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span()?,
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span()?,
|
||||
rhs_span: right.span(),
|
||||
});
|
||||
}
|
||||
|
||||
let lhs_span = left.span()?;
|
||||
let lhs_span = left.span();
|
||||
let lhs = lhs.as_series(lhs_span)?;
|
||||
|
||||
match operator.item {
|
||||
@ -226,15 +226,15 @@ pub(super) fn compute_series_single_value(
|
||||
compute_series_i64(&lhs, *val, <ChunkedArray<Int64Type>>::add, lhs_span)
|
||||
}
|
||||
Value::Float { val, .. } => {
|
||||
compute_series_decimal(&lhs, *val, <ChunkedArray<Float64Type>>::add, lhs_span)
|
||||
compute_series_float(&lhs, *val, <ChunkedArray<Float64Type>>::add, lhs_span)
|
||||
}
|
||||
Value::String { val, .. } => add_string_to_series(&lhs, val, lhs_span),
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span()?,
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span()?,
|
||||
rhs_span: right.span(),
|
||||
}),
|
||||
},
|
||||
Operator::Math(Math::Minus) => match &right {
|
||||
@ -242,14 +242,14 @@ pub(super) fn compute_series_single_value(
|
||||
compute_series_i64(&lhs, *val, <ChunkedArray<Int64Type>>::sub, lhs_span)
|
||||
}
|
||||
Value::Float { val, .. } => {
|
||||
compute_series_decimal(&lhs, *val, <ChunkedArray<Float64Type>>::sub, lhs_span)
|
||||
compute_series_float(&lhs, *val, <ChunkedArray<Float64Type>>::sub, lhs_span)
|
||||
}
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span()?,
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span()?,
|
||||
rhs_span: right.span(),
|
||||
}),
|
||||
},
|
||||
Operator::Math(Math::Multiply) => match &right {
|
||||
@ -257,43 +257,46 @@ pub(super) fn compute_series_single_value(
|
||||
compute_series_i64(&lhs, *val, <ChunkedArray<Int64Type>>::mul, lhs_span)
|
||||
}
|
||||
Value::Float { val, .. } => {
|
||||
compute_series_decimal(&lhs, *val, <ChunkedArray<Float64Type>>::mul, lhs_span)
|
||||
compute_series_float(&lhs, *val, <ChunkedArray<Float64Type>>::mul, lhs_span)
|
||||
}
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span()?,
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span()?,
|
||||
rhs_span: right.span(),
|
||||
}),
|
||||
},
|
||||
Operator::Math(Math::Divide) => match &right {
|
||||
Value::Int { val, span } => {
|
||||
if *val == 0 {
|
||||
Err(ShellError::DivisionByZero { span: *span })
|
||||
} else {
|
||||
compute_series_i64(&lhs, *val, <ChunkedArray<Int64Type>>::div, lhs_span)
|
||||
Operator::Math(Math::Divide) => {
|
||||
let span = right.span();
|
||||
match &right {
|
||||
Value::Int { val, .. } => {
|
||||
if *val == 0 {
|
||||
Err(ShellError::DivisionByZero { span })
|
||||
} else {
|
||||
compute_series_i64(&lhs, *val, <ChunkedArray<Int64Type>>::div, lhs_span)
|
||||
}
|
||||
}
|
||||
}
|
||||
Value::Float { val, span } => {
|
||||
if val.is_zero() {
|
||||
Err(ShellError::DivisionByZero { span: *span })
|
||||
} else {
|
||||
compute_series_decimal(&lhs, *val, <ChunkedArray<Float64Type>>::div, lhs_span)
|
||||
Value::Float { val, .. } => {
|
||||
if val.is_zero() {
|
||||
Err(ShellError::DivisionByZero { span })
|
||||
} else {
|
||||
compute_series_float(&lhs, *val, <ChunkedArray<Float64Type>>::div, lhs_span)
|
||||
}
|
||||
}
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span(),
|
||||
}),
|
||||
}
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span()?,
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span()?,
|
||||
}),
|
||||
},
|
||||
}
|
||||
Operator::Comparison(Comparison::Equal) => match &right {
|
||||
Value::Int { val, .. } => compare_series_i64(&lhs, *val, ChunkedArray::equal, lhs_span),
|
||||
Value::Float { val, .. } => {
|
||||
compare_series_decimal(&lhs, *val, ChunkedArray::equal, lhs_span)
|
||||
compare_series_float(&lhs, *val, ChunkedArray::equal, lhs_span)
|
||||
}
|
||||
Value::String { val, .. } => {
|
||||
let equal_pattern = format!("^{}$", fancy_regex::escape(val));
|
||||
@ -305,9 +308,9 @@ pub(super) fn compute_series_single_value(
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span()?,
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span()?,
|
||||
rhs_span: right.span(),
|
||||
}),
|
||||
},
|
||||
Operator::Comparison(Comparison::NotEqual) => match &right {
|
||||
@ -315,7 +318,7 @@ pub(super) fn compute_series_single_value(
|
||||
compare_series_i64(&lhs, *val, ChunkedArray::not_equal, lhs_span)
|
||||
}
|
||||
Value::Float { val, .. } => {
|
||||
compare_series_decimal(&lhs, *val, ChunkedArray::not_equal, lhs_span)
|
||||
compare_series_float(&lhs, *val, ChunkedArray::not_equal, lhs_span)
|
||||
}
|
||||
Value::Date { val, .. } => compare_series_i64(
|
||||
&lhs,
|
||||
@ -326,15 +329,15 @@ pub(super) fn compute_series_single_value(
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span()?,
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span()?,
|
||||
rhs_span: right.span(),
|
||||
}),
|
||||
},
|
||||
Operator::Comparison(Comparison::LessThan) => match &right {
|
||||
Value::Int { val, .. } => compare_series_i64(&lhs, *val, ChunkedArray::lt, lhs_span),
|
||||
Value::Float { val, .. } => {
|
||||
compare_series_decimal(&lhs, *val, ChunkedArray::lt, lhs_span)
|
||||
compare_series_float(&lhs, *val, ChunkedArray::lt, lhs_span)
|
||||
}
|
||||
Value::Date { val, .. } => {
|
||||
compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::lt, lhs_span)
|
||||
@ -342,15 +345,15 @@ pub(super) fn compute_series_single_value(
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span()?,
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span()?,
|
||||
rhs_span: right.span(),
|
||||
}),
|
||||
},
|
||||
Operator::Comparison(Comparison::LessThanOrEqual) => match &right {
|
||||
Value::Int { val, .. } => compare_series_i64(&lhs, *val, ChunkedArray::lt_eq, lhs_span),
|
||||
Value::Float { val, .. } => {
|
||||
compare_series_decimal(&lhs, *val, ChunkedArray::lt_eq, lhs_span)
|
||||
compare_series_float(&lhs, *val, ChunkedArray::lt_eq, lhs_span)
|
||||
}
|
||||
Value::Date { val, .. } => {
|
||||
compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::lt_eq, lhs_span)
|
||||
@ -358,15 +361,15 @@ pub(super) fn compute_series_single_value(
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span()?,
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span()?,
|
||||
rhs_span: right.span(),
|
||||
}),
|
||||
},
|
||||
Operator::Comparison(Comparison::GreaterThan) => match &right {
|
||||
Value::Int { val, .. } => compare_series_i64(&lhs, *val, ChunkedArray::gt, lhs_span),
|
||||
Value::Float { val, .. } => {
|
||||
compare_series_decimal(&lhs, *val, ChunkedArray::gt, lhs_span)
|
||||
compare_series_float(&lhs, *val, ChunkedArray::gt, lhs_span)
|
||||
}
|
||||
Value::Date { val, .. } => {
|
||||
compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::gt, lhs_span)
|
||||
@ -374,15 +377,15 @@ pub(super) fn compute_series_single_value(
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span()?,
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span()?,
|
||||
rhs_span: right.span(),
|
||||
}),
|
||||
},
|
||||
Operator::Comparison(Comparison::GreaterThanOrEqual) => match &right {
|
||||
Value::Int { val, .. } => compare_series_i64(&lhs, *val, ChunkedArray::gt_eq, lhs_span),
|
||||
Value::Float { val, .. } => {
|
||||
compare_series_decimal(&lhs, *val, ChunkedArray::gt_eq, lhs_span)
|
||||
compare_series_float(&lhs, *val, ChunkedArray::gt_eq, lhs_span)
|
||||
}
|
||||
Value::Date { val, .. } => {
|
||||
compare_series_i64(&lhs, val.timestamp_millis(), ChunkedArray::gt_eq, lhs_span)
|
||||
@ -390,9 +393,9 @@ pub(super) fn compute_series_single_value(
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span()?,
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span()?,
|
||||
rhs_span: right.span(),
|
||||
}),
|
||||
},
|
||||
// TODO: update this to do a regex match instead of a simple contains?
|
||||
@ -401,9 +404,9 @@ pub(super) fn compute_series_single_value(
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span()?,
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span()?,
|
||||
rhs_span: right.span(),
|
||||
}),
|
||||
},
|
||||
Operator::Comparison(Comparison::StartsWith) => match &right {
|
||||
@ -414,9 +417,9 @@ pub(super) fn compute_series_single_value(
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span()?,
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span()?,
|
||||
rhs_span: right.span(),
|
||||
}),
|
||||
},
|
||||
Operator::Comparison(Comparison::EndsWith) => match &right {
|
||||
@ -427,17 +430,17 @@ pub(super) fn compute_series_single_value(
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span()?,
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span()?,
|
||||
rhs_span: right.span(),
|
||||
}),
|
||||
},
|
||||
_ => Err(ShellError::OperatorMismatch {
|
||||
op_span: operator.span,
|
||||
lhs_ty: left.get_type().to_string(),
|
||||
lhs_span: left.span()?,
|
||||
lhs_span: left.span(),
|
||||
rhs_ty: right.get_type().to_string(),
|
||||
rhs_span: right.span()?,
|
||||
rhs_span: right.span(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -506,12 +509,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_series_decimal<F>(
|
||||
series: &Series,
|
||||
val: f64,
|
||||
f: F,
|
||||
span: Span,
|
||||
) -> Result<Value, ShellError>
|
||||
fn compute_series_float<F>(series: &Series, val: f64, f: F, span: Span) -> Result<Value, ShellError>
|
||||
where
|
||||
F: Fn(ChunkedArray<Float64Type>, f64) -> ChunkedArray<Float64Type>,
|
||||
{
|
||||
@ -540,7 +538,7 @@ where
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Incorrect type".into(),
|
||||
format!(
|
||||
"Series of type {} can not be used for operations with a decimal value",
|
||||
"Series of type {} can not be used for operations with a float value",
|
||||
series.dtype()
|
||||
),
|
||||
Some(span),
|
||||
@ -660,12 +658,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn compare_series_decimal<F>(
|
||||
series: &Series,
|
||||
val: f64,
|
||||
f: F,
|
||||
span: Span,
|
||||
) -> Result<Value, ShellError>
|
||||
fn compare_series_float<F>(series: &Series, val: f64, f: F, span: Span) -> Result<Value, ShellError>
|
||||
where
|
||||
F: Fn(&ChunkedArray<Float64Type>, f64) -> ChunkedArray<BooleanType>,
|
||||
{
|
||||
@ -694,7 +687,7 @@ where
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Incorrect type".into(),
|
||||
format!(
|
||||
"Series of type {} can not be used for operations with a decimal value",
|
||||
"Series of type {} can not be used for operations with a float value",
|
||||
series.dtype()
|
||||
),
|
||||
Some(span),
|
||||
|
@ -2,7 +2,7 @@ use super::{DataFrameValue, NuDataFrame};
|
||||
|
||||
use chrono::{DateTime, FixedOffset, NaiveDateTime};
|
||||
use indexmap::map::{Entry, IndexMap};
|
||||
use nu_protocol::{ShellError, Span, Value};
|
||||
use nu_protocol::{Record, ShellError, Span, Value};
|
||||
use polars::chunked_array::builder::AnonymousOwnedListBuilder;
|
||||
use polars::chunked_array::object::builder::ObjectChunkedBuilder;
|
||||
use polars::chunked_array::ChunkedArray;
|
||||
@ -128,36 +128,21 @@ pub fn create_column(
|
||||
// Adds a separator to the vector of values using the column names from the
|
||||
// dataframe to create the Values Row
|
||||
pub fn add_separator(values: &mut Vec<Value>, df: &DataFrame, span: Span) {
|
||||
let mut cols = vec![];
|
||||
let mut vals = vec![];
|
||||
let mut record = Record::new();
|
||||
|
||||
cols.push("index".to_string());
|
||||
vals.push(Value::String {
|
||||
val: "...".into(),
|
||||
span,
|
||||
});
|
||||
record.push("index", Value::string("...", span));
|
||||
|
||||
for name in df.get_column_names() {
|
||||
cols.push(name.to_string());
|
||||
vals.push(Value::String {
|
||||
val: "...".into(),
|
||||
span,
|
||||
})
|
||||
record.push(name, Value::string("...", span))
|
||||
}
|
||||
|
||||
let extra_record = Value::Record { cols, vals, span };
|
||||
|
||||
values.push(extra_record);
|
||||
values.push(Value::record(record, span));
|
||||
}
|
||||
|
||||
// Inserting the values found in a Value::List
|
||||
pub fn insert_record(
|
||||
column_values: &mut ColumnMap,
|
||||
cols: &[String],
|
||||
values: &[Value],
|
||||
) -> Result<(), ShellError> {
|
||||
for (col, value) in cols.iter().zip(values.iter()) {
|
||||
insert_value(value.clone(), col.clone(), column_values)?;
|
||||
// Inserting the values found in a Value::List or Value::Record
|
||||
pub fn insert_record(column_values: &mut ColumnMap, record: Record) -> Result<(), ShellError> {
|
||||
for (col, value) in record {
|
||||
insert_value(value, col, column_values)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -284,7 +269,7 @@ pub fn from_parsed_columns(column_values: ColumnMap) -> Result<NuDataFrame, Shel
|
||||
InputType::Date => {
|
||||
let it = column.values.iter().map(|v| {
|
||||
if let Value::Date { val, .. } = &v {
|
||||
Some(val.timestamp_nanos())
|
||||
Some(val.timestamp_nanos_opt().unwrap_or_default())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -428,7 +413,7 @@ fn input_type_list_to_series(
|
||||
|
||||
let it = v.as_list()?.iter().map(|v| {
|
||||
if let Value::Date { val, .. } = &v {
|
||||
Some(val.timestamp_nanos())
|
||||
Some(val.timestamp_nanos_opt().unwrap_or_default())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -436,7 +421,17 @@ fn input_type_list_to_series(
|
||||
let dt_chunked = ChunkedArray::<Int64Type>::from_iter_options(&list_name, it)
|
||||
.into_datetime(TimeUnit::Nanoseconds, None);
|
||||
|
||||
builder.append_series(&dt_chunked.into_series());
|
||||
builder
|
||||
.append_series(&dt_chunked.into_series())
|
||||
.map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error appending to series".into(),
|
||||
"".to_string(),
|
||||
None,
|
||||
Some(e.to_string()),
|
||||
Vec::new(),
|
||||
)
|
||||
})?
|
||||
}
|
||||
let res = builder.finish();
|
||||
Ok(res.into_series())
|
||||
@ -457,7 +452,7 @@ fn series_to_values(
|
||||
) -> Result<Vec<Value>, ShellError> {
|
||||
match series.dtype() {
|
||||
DataType::Null => {
|
||||
let it = std::iter::repeat(Value::Nothing { span });
|
||||
let it = std::iter::repeat(Value::nothing(span));
|
||||
let values = if let Some(size) = maybe_size {
|
||||
Either::Left(it.take(size))
|
||||
} else {
|
||||
@ -485,11 +480,8 @@ fn series_to_values(
|
||||
Either::Right(it)
|
||||
}
|
||||
.map(|v| match v {
|
||||
Some(a) => Value::Int {
|
||||
val: a as i64,
|
||||
span,
|
||||
},
|
||||
None => Value::Nothing { span },
|
||||
Some(a) => Value::int(a as i64, span),
|
||||
None => Value::nothing(span),
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
|
||||
@ -513,11 +505,8 @@ fn series_to_values(
|
||||
Either::Right(it)
|
||||
}
|
||||
.map(|v| match v {
|
||||
Some(a) => Value::Int {
|
||||
val: a as i64,
|
||||
span,
|
||||
},
|
||||
None => Value::Nothing { span },
|
||||
Some(a) => Value::int(a as i64, span),
|
||||
None => Value::nothing(span),
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
|
||||
@ -541,11 +530,8 @@ fn series_to_values(
|
||||
Either::Right(it)
|
||||
}
|
||||
.map(|v| match v {
|
||||
Some(a) => Value::Int {
|
||||
val: a as i64,
|
||||
span,
|
||||
},
|
||||
None => Value::Nothing { span },
|
||||
Some(a) => Value::int(a as i64, span),
|
||||
None => Value::nothing(span),
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
|
||||
@ -569,11 +555,8 @@ fn series_to_values(
|
||||
Either::Right(it)
|
||||
}
|
||||
.map(|v| match v {
|
||||
Some(a) => Value::Int {
|
||||
val: a as i64,
|
||||
span,
|
||||
},
|
||||
None => Value::Nothing { span },
|
||||
Some(a) => Value::int(a as i64, span),
|
||||
None => Value::nothing(span),
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
|
||||
@ -597,11 +580,8 @@ fn series_to_values(
|
||||
Either::Right(it)
|
||||
}
|
||||
.map(|v| match v {
|
||||
Some(a) => Value::Int {
|
||||
val: a as i64,
|
||||
span,
|
||||
},
|
||||
None => Value::Nothing { span },
|
||||
Some(a) => Value::int(a as i64, span),
|
||||
None => Value::nothing(span),
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
|
||||
@ -625,11 +605,8 @@ fn series_to_values(
|
||||
Either::Right(it)
|
||||
}
|
||||
.map(|v| match v {
|
||||
Some(a) => Value::Int {
|
||||
val: a as i64,
|
||||
span,
|
||||
},
|
||||
None => Value::Nothing { span },
|
||||
Some(a) => Value::int(a as i64, span),
|
||||
None => Value::nothing(span),
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
|
||||
@ -653,11 +630,8 @@ fn series_to_values(
|
||||
Either::Right(it)
|
||||
}
|
||||
.map(|v| match v {
|
||||
Some(a) => Value::Int {
|
||||
val: a as i64,
|
||||
span,
|
||||
},
|
||||
None => Value::Nothing { span },
|
||||
Some(a) => Value::int(a as i64, span),
|
||||
None => Value::nothing(span),
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
|
||||
@ -681,8 +655,8 @@ fn series_to_values(
|
||||
Either::Right(it)
|
||||
}
|
||||
.map(|v| match v {
|
||||
Some(a) => Value::Int { val: a, span },
|
||||
None => Value::Nothing { span },
|
||||
Some(a) => Value::int(a, span),
|
||||
None => Value::nothing(span),
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
|
||||
@ -706,11 +680,8 @@ fn series_to_values(
|
||||
Either::Right(it)
|
||||
}
|
||||
.map(|v| match v {
|
||||
Some(a) => Value::Float {
|
||||
val: a as f64,
|
||||
span,
|
||||
},
|
||||
None => Value::Nothing { span },
|
||||
Some(a) => Value::float(a as f64, span),
|
||||
None => Value::nothing(span),
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
|
||||
@ -734,8 +705,8 @@ fn series_to_values(
|
||||
Either::Right(it)
|
||||
}
|
||||
.map(|v| match v {
|
||||
Some(a) => Value::Float { val: a, span },
|
||||
None => Value::Nothing { span },
|
||||
Some(a) => Value::float(a, span),
|
||||
None => Value::nothing(span),
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
|
||||
@ -759,8 +730,8 @@ fn series_to_values(
|
||||
Either::Right(it)
|
||||
}
|
||||
.map(|v| match v {
|
||||
Some(a) => Value::Bool { val: a, span },
|
||||
None => Value::Nothing { span },
|
||||
Some(a) => Value::bool(a, span),
|
||||
None => Value::nothing(span),
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
|
||||
@ -784,11 +755,8 @@ fn series_to_values(
|
||||
Either::Right(it)
|
||||
}
|
||||
.map(|v| match v {
|
||||
Some(a) => Value::String {
|
||||
val: a.into(),
|
||||
span,
|
||||
},
|
||||
None => Value::Nothing { span },
|
||||
Some(a) => Value::string(a.to_string(), span),
|
||||
None => Value::nothing(span),
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
|
||||
@ -817,7 +785,7 @@ fn series_to_values(
|
||||
}
|
||||
.map(|v| match v {
|
||||
Some(a) => a.get_value(),
|
||||
None => Value::Nothing { span },
|
||||
None => Value::nothing(span),
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
|
||||
@ -855,10 +823,7 @@ fn series_to_values(
|
||||
}
|
||||
})
|
||||
.unwrap_or(vec![]);
|
||||
Value::List {
|
||||
vals: sublist,
|
||||
span,
|
||||
}
|
||||
Value::list(sublist, span)
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
Ok(values)
|
||||
@ -889,40 +854,40 @@ fn series_to_values(
|
||||
let naive_datetime = match NaiveDateTime::from_timestamp_opt(seconds, 0) {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
return Value::Error {
|
||||
error: Box::new(ShellError::UnsupportedInput(
|
||||
return Value::error(
|
||||
ShellError::UnsupportedInput(
|
||||
"The given local datetime representation is invalid."
|
||||
.to_string(),
|
||||
format!("timestamp is {a:?}"),
|
||||
span,
|
||||
Span::unknown(),
|
||||
)),
|
||||
}
|
||||
),
|
||||
span,
|
||||
)
|
||||
}
|
||||
};
|
||||
// Zero length offset
|
||||
let offset = match FixedOffset::east_opt(0) {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
return Value::Error {
|
||||
error: Box::new(ShellError::UnsupportedInput(
|
||||
return Value::error(
|
||||
ShellError::UnsupportedInput(
|
||||
"The given local datetime representation is invalid."
|
||||
.to_string(),
|
||||
format!("timestamp is {a:?}"),
|
||||
span,
|
||||
Span::unknown(),
|
||||
)),
|
||||
}
|
||||
),
|
||||
span,
|
||||
)
|
||||
}
|
||||
};
|
||||
let datetime = DateTime::<FixedOffset>::from_utc(naive_datetime, offset);
|
||||
let datetime =
|
||||
DateTime::<FixedOffset>::from_naive_utc_and_offset(naive_datetime, offset);
|
||||
|
||||
Value::Date {
|
||||
val: datetime,
|
||||
span,
|
||||
}
|
||||
Value::date(datetime, span)
|
||||
}
|
||||
None => Value::Nothing { span },
|
||||
None => Value::nothing(span),
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
|
||||
@ -957,40 +922,40 @@ fn series_to_values(
|
||||
let naive_datetime = match NaiveDateTime::from_timestamp_opt(seconds, 0) {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
return Value::Error {
|
||||
error: Box::new(ShellError::UnsupportedInput(
|
||||
return Value::error(
|
||||
ShellError::UnsupportedInput(
|
||||
"The given local datetime representation is invalid."
|
||||
.to_string(),
|
||||
format!("timestamp is {a:?}"),
|
||||
span,
|
||||
Span::unknown(),
|
||||
)),
|
||||
}
|
||||
),
|
||||
span,
|
||||
)
|
||||
}
|
||||
};
|
||||
// Zero length offset
|
||||
let offset = match FixedOffset::east_opt(0) {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
return Value::Error {
|
||||
error: Box::new(ShellError::UnsupportedInput(
|
||||
return Value::error(
|
||||
ShellError::UnsupportedInput(
|
||||
"The given local datetime representation is invalid."
|
||||
.to_string(),
|
||||
format!("timestamp is {a:?}"),
|
||||
span,
|
||||
Span::unknown(),
|
||||
)),
|
||||
}
|
||||
),
|
||||
span,
|
||||
)
|
||||
}
|
||||
};
|
||||
let datetime = DateTime::<FixedOffset>::from_utc(naive_datetime, offset);
|
||||
let datetime =
|
||||
DateTime::<FixedOffset>::from_naive_utc_and_offset(naive_datetime, offset);
|
||||
|
||||
Value::Date {
|
||||
val: datetime,
|
||||
span,
|
||||
}
|
||||
Value::date(datetime, span)
|
||||
}
|
||||
None => Value::Nothing { span },
|
||||
None => Value::nothing(span),
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
|
||||
@ -1014,11 +979,8 @@ fn series_to_values(
|
||||
Either::Right(it)
|
||||
}
|
||||
.map(|v| match v {
|
||||
Some(nanoseconds) => Value::Duration {
|
||||
val: nanoseconds,
|
||||
span,
|
||||
},
|
||||
None => Value::Nothing { span },
|
||||
Some(nanoseconds) => Value::duration(nanoseconds, span),
|
||||
None => Value::nothing(span),
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
|
||||
@ -1042,20 +1004,14 @@ mod tests {
|
||||
#[test]
|
||||
fn test_parsed_column_string_list() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let values = vec![
|
||||
Value::List {
|
||||
vals: vec![Value::String {
|
||||
val: "bar".to_string(),
|
||||
span: Span::test_data(),
|
||||
}],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::List {
|
||||
vals: vec![Value::String {
|
||||
val: "baz".to_string(),
|
||||
span: Span::test_data(),
|
||||
}],
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::list(
|
||||
vec![Value::string("bar".to_string(), Span::test_data())],
|
||||
Span::test_data(),
|
||||
),
|
||||
Value::list(
|
||||
vec![Value::string("baz".to_string(), Span::test_data())],
|
||||
Span::test_data(),
|
||||
),
|
||||
];
|
||||
let column = Column {
|
||||
name: "foo".to_string(),
|
||||
|
@ -17,10 +17,7 @@ impl CustomValue for NuDataFrame {
|
||||
from_lazy: false,
|
||||
};
|
||||
|
||||
Value::CustomValue {
|
||||
val: Box::new(cloned),
|
||||
span,
|
||||
}
|
||||
Value::custom_value(Box::new(cloned), span)
|
||||
}
|
||||
|
||||
fn value_string(&self) -> String {
|
||||
@ -30,7 +27,7 @@ impl CustomValue for NuDataFrame {
|
||||
fn to_base_value(&self, span: Span) -> Result<Value, ShellError> {
|
||||
let vals = self.print(span)?;
|
||||
|
||||
Ok(Value::List { vals, span })
|
||||
Ok(Value::list(vals, span))
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
|
@ -7,7 +7,7 @@ pub use conversion::{Column, ColumnMap};
|
||||
pub use operations::Axis;
|
||||
|
||||
use indexmap::map::IndexMap;
|
||||
use nu_protocol::{did_you_mean, PipelineData, ShellError, Span, Value};
|
||||
use nu_protocol::{did_you_mean, PipelineData, Record, ShellError, Span, Value};
|
||||
use polars::prelude::{DataFrame, DataType, IntoLazy, LazyFrame, PolarsObject, Series};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{cmp::Ordering, fmt::Display, hash::Hasher};
|
||||
@ -38,9 +38,7 @@ impl Display for DataFrameValue {
|
||||
|
||||
impl Default for DataFrameValue {
|
||||
fn default() -> Self {
|
||||
Self(Value::Nothing {
|
||||
span: Span::unknown(),
|
||||
})
|
||||
Self(Value::nothing(Span::unknown()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,24 +109,15 @@ impl NuDataFrame {
|
||||
}
|
||||
|
||||
pub fn dataframe_into_value(dataframe: DataFrame, span: Span) -> Value {
|
||||
Value::CustomValue {
|
||||
val: Box::new(Self::new(false, dataframe)),
|
||||
span,
|
||||
}
|
||||
Value::custom_value(Box::new(Self::new(false, dataframe)), span)
|
||||
}
|
||||
|
||||
pub fn into_value(self, span: Span) -> Value {
|
||||
if self.from_lazy {
|
||||
let lazy = NuLazyFrame::from_dataframe(self);
|
||||
Value::CustomValue {
|
||||
val: Box::new(lazy),
|
||||
span,
|
||||
}
|
||||
Value::custom_value(Box::new(lazy), span)
|
||||
} else {
|
||||
Value::CustomValue {
|
||||
val: Box::new(self),
|
||||
span,
|
||||
}
|
||||
Value::custom_value(Box::new(self), span)
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,10 +151,10 @@ impl NuDataFrame {
|
||||
.map(|i| format!("{i}"))
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
conversion::insert_record(&mut column_values, &cols, &vals)?
|
||||
conversion::insert_record(&mut column_values, Record { cols, vals })?
|
||||
}
|
||||
Value::Record { cols, vals, .. } => {
|
||||
conversion::insert_record(&mut column_values, &cols, &vals)?
|
||||
Value::Record { val: record, .. } => {
|
||||
conversion::insert_record(&mut column_values, record)?
|
||||
}
|
||||
_ => {
|
||||
let key = "0".to_string();
|
||||
@ -207,16 +196,19 @@ impl NuDataFrame {
|
||||
pub fn fill_list_nan(list: Vec<Value>, list_span: Span, fill: Value) -> Value {
|
||||
let newlist = list
|
||||
.into_iter()
|
||||
.map(|value| match value {
|
||||
Value::Float { val, .. } => {
|
||||
if val.is_nan() {
|
||||
fill.clone()
|
||||
} else {
|
||||
value
|
||||
.map(|value| {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::Float { val, .. } => {
|
||||
if val.is_nan() {
|
||||
fill.clone()
|
||||
} else {
|
||||
value
|
||||
}
|
||||
}
|
||||
Value::List { vals, .. } => Self::fill_list_nan(vals, span, fill.clone()),
|
||||
_ => value,
|
||||
}
|
||||
Value::List { vals, span } => Self::fill_list_nan(vals, span, fill.clone()),
|
||||
_ => value,
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
Value::list(newlist, list_span)
|
||||
@ -235,7 +227,7 @@ impl NuDataFrame {
|
||||
if Self::can_downcast(&value) {
|
||||
Ok(Self::get_df(value)?)
|
||||
} else if NuLazyFrame::can_downcast(&value) {
|
||||
let span = value.span()?;
|
||||
let span = value.span();
|
||||
let lazy = NuLazyFrame::try_from_value(value)?;
|
||||
let df = lazy.collect(span)?;
|
||||
Ok(df)
|
||||
@ -243,15 +235,16 @@ impl NuDataFrame {
|
||||
Err(ShellError::CantConvert {
|
||||
to_type: "lazy or eager dataframe".into(),
|
||||
from_type: value.get_type().to_string(),
|
||||
span: value.span()?,
|
||||
span: value.span(),
|
||||
help: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_df(value: Value) -> Result<Self, ShellError> {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::CustomValue { val, span } => match val.as_any().downcast_ref::<Self>() {
|
||||
Value::CustomValue { val, .. } => match val.as_any().downcast_ref::<Self>() {
|
||||
Some(df) => Ok(NuDataFrame {
|
||||
df: df.df.clone(),
|
||||
from_lazy: false,
|
||||
@ -266,7 +259,7 @@ impl NuDataFrame {
|
||||
x => Err(ShellError::CantConvert {
|
||||
to_type: "dataframe".into(),
|
||||
from_type: x.get_type().to_string(),
|
||||
span: x.span()?,
|
||||
span: x.span(),
|
||||
help: None,
|
||||
}),
|
||||
}
|
||||
@ -427,25 +420,15 @@ impl NuDataFrame {
|
||||
|
||||
let values = (0..size)
|
||||
.map(|i| {
|
||||
let mut cols = vec![];
|
||||
let mut vals = vec![];
|
||||
let mut record = Record::new();
|
||||
|
||||
cols.push("index".into());
|
||||
vals.push(Value::Int {
|
||||
val: (i + from_row) as i64,
|
||||
span,
|
||||
});
|
||||
record.push("index", Value::int((i + from_row) as i64, span));
|
||||
|
||||
for (name, col) in &mut iterators {
|
||||
cols.push(name.clone());
|
||||
|
||||
match col.next() {
|
||||
Some(v) => vals.push(v),
|
||||
None => vals.push(Value::Nothing { span }),
|
||||
};
|
||||
record.push(name.clone(), col.next().unwrap_or(Value::nothing(span)));
|
||||
}
|
||||
|
||||
Value::Record { cols, vals, span }
|
||||
Value::record(record, span)
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
|
||||
@ -476,12 +459,12 @@ impl NuDataFrame {
|
||||
.expect("already checked that dataframe is different than 0");
|
||||
|
||||
// if unable to sort, then unable to compare
|
||||
let lhs = match self.as_ref().sort(vec![*first_col], false) {
|
||||
let lhs = match self.as_ref().sort(vec![*first_col], false, false) {
|
||||
Ok(df) => df,
|
||||
Err(_) => return None,
|
||||
};
|
||||
|
||||
let rhs = match other.as_ref().sort(vec![*first_col], false) {
|
||||
let rhs = match other.as_ref().sort(vec![*first_col], false, false) {
|
||||
Ok(df) => df,
|
||||
Err(_) => return None,
|
||||
};
|
||||
|
@ -20,15 +20,13 @@ impl NuDataFrame {
|
||||
op_span: Span,
|
||||
right: &Value,
|
||||
) -> Result<Value, ShellError> {
|
||||
let rhs_span = right.span();
|
||||
match right {
|
||||
Value::CustomValue {
|
||||
val: rhs,
|
||||
span: rhs_span,
|
||||
} => {
|
||||
Value::CustomValue { val: rhs, .. } => {
|
||||
let rhs = rhs.as_any().downcast_ref::<NuDataFrame>().ok_or_else(|| {
|
||||
ShellError::DowncastNotPossible(
|
||||
"Unable to create dataframe".to_string(),
|
||||
*rhs_span,
|
||||
rhs_span,
|
||||
)
|
||||
})?;
|
||||
|
||||
@ -38,7 +36,7 @@ impl NuDataFrame {
|
||||
.as_series(lhs_span)
|
||||
.expect("Already checked that is a series");
|
||||
let rhs = &rhs
|
||||
.as_series(*rhs_span)
|
||||
.as_series(rhs_span)
|
||||
.expect("Already checked that is a series");
|
||||
|
||||
if lhs.dtype() != rhs.dtype() {
|
||||
@ -46,7 +44,7 @@ impl NuDataFrame {
|
||||
left_message: format!("datatype {}", lhs.dtype()),
|
||||
left_span: lhs_span,
|
||||
right_message: format!("datatype {}", lhs.dtype()),
|
||||
right_span: *rhs_span,
|
||||
right_span: rhs_span,
|
||||
});
|
||||
}
|
||||
|
||||
@ -55,7 +53,7 @@ impl NuDataFrame {
|
||||
left_message: format!("len {}", lhs.len()),
|
||||
left_span: lhs_span,
|
||||
right_message: format!("len {}", rhs.len()),
|
||||
right_span: *rhs_span,
|
||||
right_span: rhs_span,
|
||||
});
|
||||
}
|
||||
|
||||
@ -78,7 +76,7 @@ impl NuDataFrame {
|
||||
left_message: format!("rows {}", self.df.height()),
|
||||
left_span: lhs_span,
|
||||
right_message: format!("rows {}", rhs.df.height()),
|
||||
right_span: *rhs_span,
|
||||
right_span: rhs_span,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -20,10 +20,7 @@ impl CustomValue for NuExpression {
|
||||
fn clone_value(&self, span: nu_protocol::Span) -> Value {
|
||||
let cloned = NuExpression(self.0.clone());
|
||||
|
||||
Value::CustomValue {
|
||||
val: Box::new(cloned),
|
||||
span,
|
||||
}
|
||||
Value::custom_value(Box::new(cloned), span)
|
||||
}
|
||||
|
||||
fn value_string(&self) -> String {
|
||||
@ -31,7 +28,7 @@ impl CustomValue for NuExpression {
|
||||
}
|
||||
|
||||
fn to_base_value(&self, span: Span) -> Result<Value, ShellError> {
|
||||
Ok(self.to_value(span))
|
||||
self.to_value(span)
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
@ -56,31 +53,26 @@ fn compute_with_value(
|
||||
op: Span,
|
||||
right: &Value,
|
||||
) -> Result<Value, ShellError> {
|
||||
let rhs_span = right.span();
|
||||
match right {
|
||||
Value::CustomValue {
|
||||
val: rhs,
|
||||
span: rhs_span,
|
||||
} => {
|
||||
Value::CustomValue { val: rhs, .. } => {
|
||||
let rhs = rhs.as_any().downcast_ref::<NuExpression>().ok_or_else(|| {
|
||||
ShellError::DowncastNotPossible(
|
||||
"Unable to create expression".to_string(),
|
||||
*rhs_span,
|
||||
)
|
||||
ShellError::DowncastNotPossible("Unable to create expression".to_string(), rhs_span)
|
||||
})?;
|
||||
|
||||
match rhs.as_ref() {
|
||||
polars::prelude::Expr::Literal(..) => {
|
||||
with_operator(operator, left, rhs, lhs_span, right.span()?, op)
|
||||
with_operator(operator, left, rhs, lhs_span, right.span(), op)
|
||||
}
|
||||
_ => Err(ShellError::TypeMismatch {
|
||||
err_message: "Only literal expressions or number".into(),
|
||||
span: right.span()?,
|
||||
span: right.span(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let rhs = NuExpression::try_from_value(right.clone())?;
|
||||
with_operator(operator, left, &rhs, lhs_span, right.span()?, op)
|
||||
with_operator(operator, left, &rhs, lhs_span, right.span(), op)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
mod custom_value;
|
||||
|
||||
use nu_protocol::{PipelineData, ShellError, Span, Value};
|
||||
use nu_protocol::{record, PipelineData, ShellError, Span, Value};
|
||||
use polars::prelude::{col, AggExpr, Expr, Literal};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
@ -55,15 +55,13 @@ impl From<Expr> for NuExpression {
|
||||
|
||||
impl NuExpression {
|
||||
pub fn into_value(self, span: Span) -> Value {
|
||||
Value::CustomValue {
|
||||
val: Box::new(self),
|
||||
span,
|
||||
}
|
||||
Value::custom_value(Box::new(self), span)
|
||||
}
|
||||
|
||||
pub fn try_from_value(value: Value) -> Result<Self, ShellError> {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::CustomValue { val, span } => match val.as_any().downcast_ref::<Self>() {
|
||||
Value::CustomValue { val, .. } => match val.as_any().downcast_ref::<Self>() {
|
||||
Some(expr) => Ok(NuExpression(expr.0.clone())),
|
||||
None => Err(ShellError::CantConvert {
|
||||
to_type: "lazy expression".into(),
|
||||
@ -79,7 +77,7 @@ impl NuExpression {
|
||||
x => Err(ShellError::CantConvert {
|
||||
to_type: "lazy expression".into(),
|
||||
from_type: x.get_type().to_string(),
|
||||
span: x.span()?,
|
||||
span: x.span(),
|
||||
help: None,
|
||||
}),
|
||||
}
|
||||
@ -115,7 +113,7 @@ impl NuExpression {
|
||||
f(expr, other).into()
|
||||
}
|
||||
|
||||
pub fn to_value(&self, span: Span) -> Value {
|
||||
pub fn to_value(&self, span: Span) -> Result<Value, ShellError> {
|
||||
expr_to_value(self.as_ref(), span)
|
||||
}
|
||||
|
||||
@ -157,111 +155,66 @@ impl ExtractedExpr {
|
||||
x => Err(ShellError::CantConvert {
|
||||
to_type: "expression".into(),
|
||||
from_type: x.get_type().to_string(),
|
||||
span: x.span()?,
|
||||
span: x.span(),
|
||||
help: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expr_to_value(expr: &Expr, span: Span) -> Value {
|
||||
let cols = vec!["expr".to_string(), "value".to_string()];
|
||||
|
||||
pub fn expr_to_value(expr: &Expr, span: Span) -> Result<Value, ShellError> {
|
||||
match expr {
|
||||
Expr::Alias(expr, alias) => {
|
||||
let expr = expr_to_value(expr.as_ref(), span);
|
||||
let alias = Value::String {
|
||||
val: alias.as_ref().into(),
|
||||
span,
|
||||
};
|
||||
|
||||
let cols = vec!["expr".into(), "alias".into()];
|
||||
|
||||
Value::Record {
|
||||
cols,
|
||||
vals: vec![expr, alias],
|
||||
span,
|
||||
}
|
||||
}
|
||||
Expr::Column(name) => {
|
||||
let expr_type = Value::String {
|
||||
val: "column".to_string(),
|
||||
span,
|
||||
};
|
||||
let value = Value::String {
|
||||
val: name.to_string(),
|
||||
span,
|
||||
};
|
||||
|
||||
let vals = vec![expr_type, value];
|
||||
Value::Record { cols, vals, span }
|
||||
}
|
||||
Expr::Alias(expr, alias) => Ok(Value::record(
|
||||
record! {
|
||||
"expr" => expr_to_value(expr.as_ref(), span)?,
|
||||
"alias" => Value::string(alias.as_ref(), span),
|
||||
},
|
||||
span,
|
||||
)),
|
||||
Expr::Column(name) => Ok(Value::record(
|
||||
record! {
|
||||
"expr" => Value::string("column", span),
|
||||
"value" => Value::string(name.to_string(), span),
|
||||
},
|
||||
span,
|
||||
)),
|
||||
Expr::Columns(columns) => {
|
||||
let expr_type = Value::String {
|
||||
val: "columns".into(),
|
||||
let value = columns.iter().map(|col| Value::string(col, span)).collect();
|
||||
Ok(Value::record(
|
||||
record! {
|
||||
"expr" => Value::string("columns", span),
|
||||
"value" => Value::list(value, span),
|
||||
},
|
||||
span,
|
||||
};
|
||||
let value = Value::List {
|
||||
vals: columns
|
||||
.iter()
|
||||
.map(|col| Value::String {
|
||||
val: col.clone(),
|
||||
span,
|
||||
})
|
||||
.collect(),
|
||||
span,
|
||||
};
|
||||
|
||||
let vals = vec![expr_type, value];
|
||||
Value::Record { cols, vals, span }
|
||||
}
|
||||
Expr::Literal(literal) => {
|
||||
let expr_type = Value::String {
|
||||
val: "literal".into(),
|
||||
span,
|
||||
};
|
||||
let value = Value::String {
|
||||
val: format!("{literal:?}"),
|
||||
span,
|
||||
};
|
||||
|
||||
let vals = vec![expr_type, value];
|
||||
Value::Record { cols, vals, span }
|
||||
}
|
||||
Expr::BinaryExpr { left, op, right } => {
|
||||
let left_val = expr_to_value(left, span);
|
||||
let right_val = expr_to_value(right, span);
|
||||
|
||||
let operator = Value::String {
|
||||
val: format!("{op:?}"),
|
||||
span,
|
||||
};
|
||||
|
||||
let cols = vec!["left".into(), "op".into(), "right".into()];
|
||||
|
||||
Value::Record {
|
||||
cols,
|
||||
vals: vec![left_val, operator, right_val],
|
||||
span,
|
||||
}
|
||||
))
|
||||
}
|
||||
Expr::Literal(literal) => Ok(Value::record(
|
||||
record! {
|
||||
"expr" => Value::string("literal", span),
|
||||
"value" => Value::string(format!("{literal:?}"), span),
|
||||
},
|
||||
span,
|
||||
)),
|
||||
Expr::BinaryExpr { left, op, right } => Ok(Value::record(
|
||||
record! {
|
||||
"left" => expr_to_value(left, span)?,
|
||||
"op" => Value::string(format!("{op:?}"), span),
|
||||
"right" => expr_to_value(right, span)?,
|
||||
},
|
||||
span,
|
||||
)),
|
||||
Expr::Ternary {
|
||||
predicate,
|
||||
truthy,
|
||||
falsy,
|
||||
} => {
|
||||
let predicate = expr_to_value(predicate.as_ref(), span);
|
||||
let truthy = expr_to_value(truthy.as_ref(), span);
|
||||
let falsy = expr_to_value(falsy.as_ref(), span);
|
||||
|
||||
let cols = vec!["predicate".into(), "truthy".into(), "falsy".into()];
|
||||
|
||||
Value::Record {
|
||||
cols,
|
||||
vals: vec![predicate, truthy, falsy],
|
||||
span,
|
||||
}
|
||||
}
|
||||
} => Ok(Value::record(
|
||||
record! {
|
||||
"predicate" => expr_to_value(predicate.as_ref(), span)?,
|
||||
"truthy" => expr_to_value(truthy.as_ref(), span)?,
|
||||
"falsy" => expr_to_value(falsy.as_ref(), span)?,
|
||||
},
|
||||
span,
|
||||
)),
|
||||
Expr::Agg(agg_expr) => {
|
||||
let value = match agg_expr {
|
||||
AggExpr::Min { input: expr, .. }
|
||||
@ -281,311 +234,169 @@ pub fn expr_to_value(expr: &Expr, span: Span) -> Value {
|
||||
expr,
|
||||
quantile,
|
||||
interpol,
|
||||
} => {
|
||||
let expr = expr_to_value(expr.as_ref(), span);
|
||||
let quantile = expr_to_value(quantile.as_ref(), span);
|
||||
let interpol = Value::String {
|
||||
val: format!("{interpol:?}"),
|
||||
span,
|
||||
};
|
||||
|
||||
let cols = vec!["expr".into(), "quantile".into(), "interpol".into()];
|
||||
|
||||
Value::Record {
|
||||
cols,
|
||||
vals: vec![expr, quantile, interpol],
|
||||
span,
|
||||
}
|
||||
}
|
||||
} => Ok(Value::record(
|
||||
record! {
|
||||
"expr" => expr_to_value(expr.as_ref(), span)?,
|
||||
"quantile" => expr_to_value(quantile.as_ref(), span)?,
|
||||
"interpol" => Value::string(format!("{interpol:?}"), span),
|
||||
},
|
||||
span,
|
||||
)),
|
||||
};
|
||||
|
||||
let expr_type = Value::String {
|
||||
val: "agg".into(),
|
||||
Ok(Value::record(
|
||||
record! {
|
||||
"expr" => Value::string("agg", span),
|
||||
"value" => value?,
|
||||
},
|
||||
span,
|
||||
};
|
||||
|
||||
let vals = vec![expr_type, value];
|
||||
Value::Record { cols, vals, span }
|
||||
}
|
||||
Expr::Count => {
|
||||
let expr = Value::String {
|
||||
val: "count".into(),
|
||||
span,
|
||||
};
|
||||
let cols = vec!["expr".into()];
|
||||
|
||||
Value::Record {
|
||||
cols,
|
||||
vals: vec![expr],
|
||||
span,
|
||||
}
|
||||
}
|
||||
Expr::Wildcard => {
|
||||
let expr = Value::String {
|
||||
val: "wildcard".into(),
|
||||
span,
|
||||
};
|
||||
let cols = vec!["expr".into()];
|
||||
|
||||
Value::Record {
|
||||
cols,
|
||||
vals: vec![expr],
|
||||
span,
|
||||
}
|
||||
}
|
||||
Expr::Explode(expr) => {
|
||||
let expr = expr_to_value(expr.as_ref(), span);
|
||||
let cols = vec!["expr".into()];
|
||||
|
||||
Value::Record {
|
||||
cols,
|
||||
vals: vec![expr],
|
||||
span,
|
||||
}
|
||||
}
|
||||
Expr::KeepName(expr) => {
|
||||
let expr = expr_to_value(expr.as_ref(), span);
|
||||
let cols = vec!["expr".into()];
|
||||
|
||||
Value::Record {
|
||||
cols,
|
||||
vals: vec![expr],
|
||||
span,
|
||||
}
|
||||
}
|
||||
Expr::Nth(i) => {
|
||||
let expr = Value::int(*i, span);
|
||||
let cols = vec!["expr".into()];
|
||||
|
||||
Value::Record {
|
||||
cols,
|
||||
vals: vec![expr],
|
||||
span,
|
||||
}
|
||||
))
|
||||
}
|
||||
Expr::Count => Ok(Value::record(
|
||||
record! { "expr" => Value::string("count", span) },
|
||||
span,
|
||||
)),
|
||||
Expr::Wildcard => Ok(Value::record(
|
||||
record! { "expr" => Value::string("wildcard", span) },
|
||||
span,
|
||||
)),
|
||||
Expr::Explode(expr) => Ok(Value::record(
|
||||
record! { "expr" => expr_to_value(expr.as_ref(), span)? },
|
||||
span,
|
||||
)),
|
||||
Expr::KeepName(expr) => Ok(Value::record(
|
||||
record! { "expr" => expr_to_value(expr.as_ref(), span)? },
|
||||
span,
|
||||
)),
|
||||
Expr::Nth(i) => Ok(Value::record(
|
||||
record! { "expr" => Value::int(*i, span) },
|
||||
span,
|
||||
)),
|
||||
Expr::DtypeColumn(dtypes) => {
|
||||
let vals = dtypes
|
||||
.iter()
|
||||
.map(|d| Value::String {
|
||||
val: format!("{d}"),
|
||||
span,
|
||||
})
|
||||
.map(|d| Value::string(format!("{d}"), span))
|
||||
.collect();
|
||||
|
||||
Value::List { vals, span }
|
||||
}
|
||||
Expr::Sort { expr, options } => {
|
||||
let expr = expr_to_value(expr.as_ref(), span);
|
||||
let options = Value::String {
|
||||
val: format!("{options:?}"),
|
||||
span,
|
||||
};
|
||||
let cols = vec!["expr".into(), "options".into()];
|
||||
|
||||
Value::Record {
|
||||
cols,
|
||||
vals: vec![expr, options],
|
||||
span,
|
||||
}
|
||||
Ok(Value::list(vals, span))
|
||||
}
|
||||
Expr::Sort { expr, options } => Ok(Value::record(
|
||||
record! {
|
||||
"expr" => expr_to_value(expr.as_ref(), span)?,
|
||||
"options" => Value::string(format!("{options:?}"), span),
|
||||
},
|
||||
span,
|
||||
)),
|
||||
Expr::Cast {
|
||||
expr,
|
||||
data_type,
|
||||
strict,
|
||||
} => {
|
||||
let expr = expr_to_value(expr.as_ref(), span);
|
||||
let dtype = Value::String {
|
||||
val: format!("{data_type:?}"),
|
||||
span,
|
||||
};
|
||||
let strict = Value::Bool { val: *strict, span };
|
||||
|
||||
let cols = vec!["expr".into(), "dtype".into(), "strict".into()];
|
||||
|
||||
Value::Record {
|
||||
cols,
|
||||
vals: vec![expr, dtype, strict],
|
||||
span,
|
||||
}
|
||||
}
|
||||
Expr::Take { expr, idx } => {
|
||||
let expr = expr_to_value(expr.as_ref(), span);
|
||||
let idx = expr_to_value(idx.as_ref(), span);
|
||||
|
||||
let cols = vec!["expr".into(), "idx".into()];
|
||||
|
||||
Value::Record {
|
||||
cols,
|
||||
vals: vec![expr, idx],
|
||||
span,
|
||||
}
|
||||
}
|
||||
} => Ok(Value::record(
|
||||
record! {
|
||||
"expr" => expr_to_value(expr.as_ref(), span)?,
|
||||
"dtype" => Value::string(format!("{data_type:?}"), span),
|
||||
"strict" => Value::bool(*strict, span),
|
||||
},
|
||||
span,
|
||||
)),
|
||||
Expr::Take { expr, idx } => Ok(Value::record(
|
||||
record! {
|
||||
"expr" => expr_to_value(expr.as_ref(), span)?,
|
||||
"idx" => expr_to_value(idx.as_ref(), span)?,
|
||||
},
|
||||
span,
|
||||
)),
|
||||
Expr::SortBy {
|
||||
expr,
|
||||
by,
|
||||
descending,
|
||||
} => {
|
||||
let expr = expr_to_value(expr.as_ref(), span);
|
||||
let by: Vec<Value> = by.iter().map(|b| expr_to_value(b, span)).collect();
|
||||
let by = Value::List { vals: by, span };
|
||||
let by: Result<Vec<Value>, ShellError> =
|
||||
by.iter().map(|b| expr_to_value(b, span)).collect();
|
||||
let descending: Vec<Value> = descending.iter().map(|r| Value::bool(*r, span)).collect();
|
||||
|
||||
let descending: Vec<Value> = descending
|
||||
.iter()
|
||||
.map(|r| Value::Bool { val: *r, span })
|
||||
.collect();
|
||||
let descending = Value::List {
|
||||
vals: descending,
|
||||
Ok(Value::record(
|
||||
record! {
|
||||
"expr" => expr_to_value(expr.as_ref(), span)?,
|
||||
"by" => Value::list(by?, span),
|
||||
"descending" => Value::list(descending, span),
|
||||
},
|
||||
span,
|
||||
};
|
||||
|
||||
let cols = vec!["expr".into(), "by".into(), "descending".into()];
|
||||
|
||||
Value::Record {
|
||||
cols,
|
||||
vals: vec![expr, by, descending],
|
||||
span,
|
||||
}
|
||||
}
|
||||
Expr::Filter { input, by } => {
|
||||
let input = expr_to_value(input.as_ref(), span);
|
||||
let by = expr_to_value(by.as_ref(), span);
|
||||
|
||||
let cols = vec!["input".into(), "by".into()];
|
||||
|
||||
Value::Record {
|
||||
cols,
|
||||
vals: vec![input, by],
|
||||
span,
|
||||
}
|
||||
))
|
||||
}
|
||||
Expr::Filter { input, by } => Ok(Value::record(
|
||||
record! {
|
||||
"input" => expr_to_value(input.as_ref(), span)?,
|
||||
"by" => expr_to_value(by.as_ref(), span)?,
|
||||
},
|
||||
span,
|
||||
)),
|
||||
Expr::Slice {
|
||||
input,
|
||||
offset,
|
||||
length,
|
||||
} => {
|
||||
let input = expr_to_value(input.as_ref(), span);
|
||||
let offset = expr_to_value(offset.as_ref(), span);
|
||||
let length = expr_to_value(length.as_ref(), span);
|
||||
|
||||
let cols = vec!["input".into(), "offset".into(), "length".into()];
|
||||
|
||||
Value::Record {
|
||||
cols,
|
||||
vals: vec![input, offset, length],
|
||||
span,
|
||||
}
|
||||
}
|
||||
} => Ok(Value::record(
|
||||
record! {
|
||||
"input" => expr_to_value(input.as_ref(), span)?,
|
||||
"offset" => expr_to_value(offset.as_ref(), span)?,
|
||||
"length" => expr_to_value(length.as_ref(), span)?,
|
||||
},
|
||||
span,
|
||||
)),
|
||||
Expr::Exclude(expr, excluded) => {
|
||||
let expr = expr_to_value(expr.as_ref(), span);
|
||||
let excluded = excluded
|
||||
.iter()
|
||||
.map(|e| Value::String {
|
||||
val: format!("{e:?}"),
|
||||
span,
|
||||
})
|
||||
.map(|e| Value::string(format!("{e:?}"), span))
|
||||
.collect();
|
||||
let excluded = Value::List {
|
||||
vals: excluded,
|
||||
span,
|
||||
};
|
||||
|
||||
let cols = vec!["expr".into(), "excluded".into()];
|
||||
|
||||
Value::Record {
|
||||
cols,
|
||||
vals: vec![expr, excluded],
|
||||
Ok(Value::record(
|
||||
record! {
|
||||
"expr" => expr_to_value(expr.as_ref(), span)?,
|
||||
"excluded" => Value::list(excluded, span),
|
||||
},
|
||||
span,
|
||||
}
|
||||
}
|
||||
Expr::RenameAlias { expr, function } => {
|
||||
let expr = expr_to_value(expr.as_ref(), span);
|
||||
let function = Value::String {
|
||||
val: format!("{function:?}"),
|
||||
span,
|
||||
};
|
||||
|
||||
let cols = vec!["expr".into(), "function".into()];
|
||||
|
||||
Value::Record {
|
||||
cols,
|
||||
vals: vec![expr, function],
|
||||
span,
|
||||
}
|
||||
))
|
||||
}
|
||||
Expr::RenameAlias { expr, function } => Ok(Value::record(
|
||||
record! {
|
||||
"expr" => expr_to_value(expr.as_ref(), span)?,
|
||||
"function" => Value::string(format!("{function:?}"), span),
|
||||
},
|
||||
span,
|
||||
)),
|
||||
Expr::AnonymousFunction {
|
||||
input,
|
||||
function,
|
||||
output_type,
|
||||
options,
|
||||
} => {
|
||||
let input: Vec<Value> = input.iter().map(|e| expr_to_value(e, span)).collect();
|
||||
let input = Value::List { vals: input, span };
|
||||
|
||||
let function = Value::String {
|
||||
val: format!("{function:?}"),
|
||||
let input: Result<Vec<Value>, ShellError> =
|
||||
input.iter().map(|e| expr_to_value(e, span)).collect();
|
||||
Ok(Value::record(
|
||||
record! {
|
||||
"input" => Value::list(input?, span),
|
||||
"function" => Value::string(format!("{function:?}"), span),
|
||||
"output_type" => Value::string(format!("{output_type:?}"), span),
|
||||
"options" => Value::string(format!("{options:?}"), span),
|
||||
},
|
||||
span,
|
||||
};
|
||||
let output_type = Value::String {
|
||||
val: format!("{output_type:?}"),
|
||||
span,
|
||||
};
|
||||
let options = Value::String {
|
||||
val: format!("{options:?}"),
|
||||
span,
|
||||
};
|
||||
|
||||
let cols = vec![
|
||||
"input".into(),
|
||||
"function".into(),
|
||||
"output_type".into(),
|
||||
"options".into(),
|
||||
];
|
||||
|
||||
Value::Record {
|
||||
cols,
|
||||
vals: vec![input, function, output_type, options],
|
||||
span,
|
||||
}
|
||||
))
|
||||
}
|
||||
Expr::Function {
|
||||
input,
|
||||
function,
|
||||
options,
|
||||
} => {
|
||||
let input: Vec<Value> = input.iter().map(|e| expr_to_value(e, span)).collect();
|
||||
let input = Value::List { vals: input, span };
|
||||
|
||||
let function = Value::String {
|
||||
val: format!("{function:?}"),
|
||||
let input: Result<Vec<Value>, ShellError> =
|
||||
input.iter().map(|e| expr_to_value(e, span)).collect();
|
||||
Ok(Value::record(
|
||||
record! {
|
||||
"input" => Value::list(input?, span),
|
||||
"function" => Value::string(format!("{function:?}"), span),
|
||||
"options" => Value::string(format!("{options:?}"), span),
|
||||
},
|
||||
span,
|
||||
};
|
||||
let options = Value::String {
|
||||
val: format!("{options:?}"),
|
||||
span,
|
||||
};
|
||||
|
||||
let cols = vec!["input".into(), "function".into(), "options".into()];
|
||||
|
||||
Value::Record {
|
||||
cols,
|
||||
vals: vec![input, function, options],
|
||||
span,
|
||||
}
|
||||
}
|
||||
Expr::Cache { input, id } => {
|
||||
let input = expr_to_value(input.as_ref(), span);
|
||||
let id = Value::String {
|
||||
val: format!("{id:?}"),
|
||||
span,
|
||||
};
|
||||
|
||||
let cols = vec!["input".into(), "id".into()];
|
||||
|
||||
Value::Record {
|
||||
cols,
|
||||
vals: vec![input, id],
|
||||
span,
|
||||
}
|
||||
))
|
||||
}
|
||||
Expr::Window {
|
||||
function,
|
||||
@ -593,39 +404,34 @@ pub fn expr_to_value(expr: &Expr, span: Span) -> Value {
|
||||
order_by,
|
||||
options,
|
||||
} => {
|
||||
let function = expr_to_value(function, span);
|
||||
|
||||
let partition_by: Vec<Value> = partition_by
|
||||
let partition_by: Result<Vec<Value>, ShellError> = partition_by
|
||||
.iter()
|
||||
.map(|e| expr_to_value(e, span))
|
||||
.collect();
|
||||
let partition_by = Value::List {
|
||||
vals: partition_by,
|
||||
span,
|
||||
};
|
||||
|
||||
let order_by = order_by
|
||||
.as_ref()
|
||||
.map(|e| expr_to_value(e.as_ref(), span))
|
||||
.transpose()?
|
||||
.unwrap_or_else(|| Value::nothing(span));
|
||||
|
||||
let options = Value::String {
|
||||
val: format!("{options:?}"),
|
||||
Ok(Value::record(
|
||||
record! {
|
||||
"function" => expr_to_value(function, span)?,
|
||||
"partition_by" => Value::list(partition_by?, span),
|
||||
"order_by" => order_by,
|
||||
"options" => Value::string(format!("{options:?}"), span),
|
||||
},
|
||||
span,
|
||||
};
|
||||
|
||||
let cols = vec![
|
||||
"function".into(),
|
||||
"partition_by".into(),
|
||||
"order_by".into(),
|
||||
"options".into(),
|
||||
];
|
||||
|
||||
Value::Record {
|
||||
cols,
|
||||
vals: vec![function, partition_by, order_by, options],
|
||||
span,
|
||||
}
|
||||
))
|
||||
}
|
||||
// the parameter polars_plan::dsl::selector::Selector is not publicly exposed.
|
||||
// I am not sure what we can meaningfully do with this at this time.
|
||||
Expr::Selector(_) => Err(ShellError::UnsupportedInput(
|
||||
"Expressions of type Selector to Nu Values is not yet supported".to_string(),
|
||||
format!("Expression is {expr:?}"),
|
||||
span,
|
||||
Span::unknown(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::NuLazyFrame;
|
||||
use nu_protocol::{CustomValue, ShellError, Span, Value};
|
||||
use nu_protocol::{record, CustomValue, ShellError, Span, Value};
|
||||
|
||||
// CustomValue implementation for NuDataFrame
|
||||
impl CustomValue for NuLazyFrame {
|
||||
@ -18,10 +18,7 @@ impl CustomValue for NuLazyFrame {
|
||||
schema: self.schema.clone(),
|
||||
};
|
||||
|
||||
Value::CustomValue {
|
||||
val: Box::new(cloned),
|
||||
span,
|
||||
}
|
||||
Value::custom_value(Box::new(cloned), span)
|
||||
}
|
||||
|
||||
fn value_string(&self) -> String {
|
||||
@ -29,22 +26,18 @@ impl CustomValue for NuLazyFrame {
|
||||
}
|
||||
|
||||
fn to_base_value(&self, span: Span) -> Result<Value, ShellError> {
|
||||
let cols = vec!["plan".into(), "optimized_plan".into()];
|
||||
let vals = vec![
|
||||
Value::String {
|
||||
val: self.as_ref().describe_plan(),
|
||||
span,
|
||||
},
|
||||
Value::String {
|
||||
val: self
|
||||
.as_ref()
|
||||
.describe_optimized_plan()
|
||||
.unwrap_or_else(|_| "<NOT AVAILABLE>".to_string()),
|
||||
span,
|
||||
},
|
||||
];
|
||||
let optimized_plan = self
|
||||
.as_ref()
|
||||
.describe_optimized_plan()
|
||||
.unwrap_or_else(|_| "<NOT AVAILABLE>".to_string());
|
||||
|
||||
Ok(Value::Record { cols, vals, span })
|
||||
Ok(Value::record(
|
||||
record! {
|
||||
"plan" => Value::string(self.as_ref().describe_plan(), span),
|
||||
"optimized_plan" => Value::string(optimized_plan, span),
|
||||
},
|
||||
span,
|
||||
))
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
|
@ -90,15 +90,9 @@ impl NuLazyFrame {
|
||||
pub fn into_value(self, span: Span) -> Result<Value, ShellError> {
|
||||
if self.from_eager {
|
||||
let df = self.collect(span)?;
|
||||
Ok(Value::CustomValue {
|
||||
val: Box::new(df),
|
||||
span,
|
||||
})
|
||||
Ok(Value::custom_value(Box::new(df), span))
|
||||
} else {
|
||||
Ok(Value::CustomValue {
|
||||
val: Box::new(self),
|
||||
span,
|
||||
})
|
||||
Ok(Value::custom_value(Box::new(self), span))
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,7 +129,7 @@ impl NuLazyFrame {
|
||||
Err(ShellError::CantConvert {
|
||||
to_type: "lazy or eager dataframe".into(),
|
||||
from_type: value.get_type().to_string(),
|
||||
span: value.span()?,
|
||||
span: value.span(),
|
||||
help: None,
|
||||
})
|
||||
}
|
||||
@ -147,8 +141,9 @@ impl NuLazyFrame {
|
||||
}
|
||||
|
||||
pub fn get_lazy_df(value: Value) -> Result<Self, ShellError> {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::CustomValue { val, span } => match val.as_any().downcast_ref::<Self>() {
|
||||
Value::CustomValue { val, .. } => match val.as_any().downcast_ref::<Self>() {
|
||||
Some(expr) => Ok(Self {
|
||||
lazy: expr.lazy.clone(),
|
||||
from_eager: false,
|
||||
@ -164,7 +159,7 @@ impl NuLazyFrame {
|
||||
x => Err(ShellError::CantConvert {
|
||||
to_type: "lazy frame".into(),
|
||||
from_type: x.get_type().to_string(),
|
||||
span: x.span()?,
|
||||
span: x.span(),
|
||||
help: None,
|
||||
}),
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::NuLazyGroupBy;
|
||||
use nu_protocol::{CustomValue, ShellError, Span, Value};
|
||||
use nu_protocol::{record, CustomValue, ShellError, Span, Value};
|
||||
|
||||
// CustomValue implementation for NuDataFrame
|
||||
impl CustomValue for NuLazyGroupBy {
|
||||
@ -18,10 +18,7 @@ impl CustomValue for NuLazyGroupBy {
|
||||
from_eager: self.from_eager,
|
||||
};
|
||||
|
||||
Value::CustomValue {
|
||||
val: Box::new(cloned),
|
||||
span,
|
||||
}
|
||||
Value::custom_value(Box::new(cloned), span)
|
||||
}
|
||||
|
||||
fn value_string(&self) -> String {
|
||||
@ -29,13 +26,12 @@ impl CustomValue for NuLazyGroupBy {
|
||||
}
|
||||
|
||||
fn to_base_value(&self, span: Span) -> Result<Value, ShellError> {
|
||||
let cols = vec!["LazyGroupBy".into()];
|
||||
let vals = vec![Value::String {
|
||||
val: "apply aggregation to complete execution plan".into(),
|
||||
Ok(Value::record(
|
||||
record! {
|
||||
"LazyGroupBy" => Value::string("apply aggregation to complete execution plan", span)
|
||||
},
|
||||
span,
|
||||
}];
|
||||
|
||||
Ok(Value::Record { cols, vals, span })
|
||||
))
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
|
@ -74,10 +74,7 @@ impl From<LazyGroupBy> for NuLazyGroupBy {
|
||||
|
||||
impl NuLazyGroupBy {
|
||||
pub fn into_value(self, span: Span) -> Value {
|
||||
Value::CustomValue {
|
||||
val: Box::new(self),
|
||||
span,
|
||||
}
|
||||
Value::custom_value(Box::new(self), span)
|
||||
}
|
||||
|
||||
pub fn into_polars(self) -> LazyGroupBy {
|
||||
@ -85,26 +82,25 @@ impl NuLazyGroupBy {
|
||||
}
|
||||
|
||||
pub fn try_from_value(value: Value) -> Result<Self, ShellError> {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::CustomValue { val, span } => {
|
||||
match val.as_any().downcast_ref::<NuLazyGroupBy>() {
|
||||
Some(group) => Ok(Self {
|
||||
group_by: group.group_by.clone(),
|
||||
schema: group.schema.clone(),
|
||||
from_eager: group.from_eager,
|
||||
}),
|
||||
None => Err(ShellError::CantConvert {
|
||||
to_type: "lazy groupby".into(),
|
||||
from_type: "custom value".into(),
|
||||
span,
|
||||
help: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
Value::CustomValue { val, .. } => match val.as_any().downcast_ref::<NuLazyGroupBy>() {
|
||||
Some(group) => Ok(Self {
|
||||
group_by: group.group_by.clone(),
|
||||
schema: group.schema.clone(),
|
||||
from_eager: group.from_eager,
|
||||
}),
|
||||
None => Err(ShellError::CantConvert {
|
||||
to_type: "lazy groupby".into(),
|
||||
from_type: "custom value".into(),
|
||||
span,
|
||||
help: None,
|
||||
}),
|
||||
},
|
||||
x => Err(ShellError::CantConvert {
|
||||
to_type: "lazy groupby".into(),
|
||||
from_type: x.get_type().to_string(),
|
||||
span: x.span()?,
|
||||
span: x.span(),
|
||||
help: None,
|
||||
}),
|
||||
}
|
||||
|
@ -14,10 +14,7 @@ impl CustomValue for NuWhen {
|
||||
fn clone_value(&self, span: nu_protocol::Span) -> Value {
|
||||
let cloned = self.clone();
|
||||
|
||||
Value::CustomValue {
|
||||
val: Box::new(cloned),
|
||||
span,
|
||||
}
|
||||
Value::custom_value(Box::new(cloned), span)
|
||||
}
|
||||
|
||||
fn value_string(&self) -> String {
|
||||
@ -25,12 +22,12 @@ impl CustomValue for NuWhen {
|
||||
}
|
||||
|
||||
fn to_base_value(&self, span: Span) -> Result<Value, ShellError> {
|
||||
let val = match self {
|
||||
NuWhen::WhenThen(_) => "whenthen".into(),
|
||||
NuWhen::WhenThenThen(_) => "whenthenthen".into(),
|
||||
let val: String = match self {
|
||||
NuWhen::Then(_) => "whenthen".into(),
|
||||
NuWhen::ChainedThen(_) => "whenthenthen".into(),
|
||||
};
|
||||
|
||||
let value = Value::String { val, span };
|
||||
let value = Value::string(val, span);
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
|
@ -2,13 +2,13 @@ mod custom_value;
|
||||
|
||||
use core::fmt;
|
||||
use nu_protocol::{ShellError, Span, Value};
|
||||
use polars::prelude::{col, when, WhenThen, WhenThenThen};
|
||||
use polars::prelude::{col, when, ChainedThen, Then};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum NuWhen {
|
||||
WhenThen(Box<WhenThen>),
|
||||
WhenThenThen(WhenThenThen),
|
||||
Then(Box<Then>),
|
||||
ChainedThen(ChainedThen),
|
||||
}
|
||||
|
||||
// Mocked serialization of the LazyFrame object
|
||||
@ -27,7 +27,7 @@ impl<'de> Deserialize<'de> for NuWhen {
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Ok(NuWhen::WhenThen(Box::new(when(col("a")).then(col("b")))))
|
||||
Ok(NuWhen::Then(Box::new(when(col("a")).then(col("b")))))
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,29 +37,27 @@ impl fmt::Debug for NuWhen {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WhenThen> for NuWhen {
|
||||
fn from(when_then: WhenThen) -> Self {
|
||||
NuWhen::WhenThen(Box::new(when_then))
|
||||
impl From<Then> for NuWhen {
|
||||
fn from(then: Then) -> Self {
|
||||
NuWhen::Then(Box::new(then))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WhenThenThen> for NuWhen {
|
||||
fn from(when_then_then: WhenThenThen) -> Self {
|
||||
NuWhen::WhenThenThen(when_then_then)
|
||||
impl From<ChainedThen> for NuWhen {
|
||||
fn from(chained_when: ChainedThen) -> Self {
|
||||
NuWhen::ChainedThen(chained_when)
|
||||
}
|
||||
}
|
||||
|
||||
impl NuWhen {
|
||||
pub fn into_value(self, span: Span) -> Value {
|
||||
Value::CustomValue {
|
||||
val: Box::new(self),
|
||||
span,
|
||||
}
|
||||
Value::custom_value(Box::new(self), span)
|
||||
}
|
||||
|
||||
pub fn try_from_value(value: Value) -> Result<Self, ShellError> {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::CustomValue { val, span } => match val.as_any().downcast_ref::<Self>() {
|
||||
Value::CustomValue { val, .. } => match val.as_any().downcast_ref::<Self>() {
|
||||
Some(expr) => Ok(expr.clone()),
|
||||
None => Err(ShellError::CantConvert {
|
||||
to_type: "when expression".into(),
|
||||
@ -71,7 +69,7 @@ impl NuWhen {
|
||||
x => Err(ShellError::CantConvert {
|
||||
to_type: "when expression".into(),
|
||||
from_type: x.get_type().to_string(),
|
||||
span: x.span()?,
|
||||
span: x.span(),
|
||||
help: None,
|
||||
}),
|
||||
}
|
||||
|
@ -21,22 +21,25 @@ pub(crate) fn convert_columns(
|
||||
Vec::new(),
|
||||
)
|
||||
})
|
||||
.and_then(|v| v.span())?;
|
||||
.map(|v| v.span())?;
|
||||
|
||||
let res = columns
|
||||
.into_iter()
|
||||
.map(|value| match value {
|
||||
Value::String { val, span } => {
|
||||
col_span = span_join(&[col_span, span]);
|
||||
Ok(Spanned { item: val, span })
|
||||
.map(|value| {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::String { val, .. } => {
|
||||
col_span = span_join(&[col_span, span]);
|
||||
Ok(Spanned { item: val, span })
|
||||
}
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Incorrect column format".into(),
|
||||
"Only string as column name".into(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
}
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Incorrect column format".into(),
|
||||
"Only string as column name".into(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
})
|
||||
.collect::<Result<Vec<Spanned<String>>, _>>()?;
|
||||
|
||||
@ -61,22 +64,25 @@ pub(crate) fn convert_columns_string(
|
||||
Vec::new(),
|
||||
)
|
||||
})
|
||||
.and_then(|v| v.span())?;
|
||||
.map(|v| v.span())?;
|
||||
|
||||
let res = columns
|
||||
.into_iter()
|
||||
.map(|value| match value {
|
||||
Value::String { val, span } => {
|
||||
col_span = span_join(&[col_span, span]);
|
||||
Ok(val)
|
||||
.map(|value| {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::String { val, .. } => {
|
||||
col_span = span_join(&[col_span, span]);
|
||||
Ok(val)
|
||||
}
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Incorrect column format".into(),
|
||||
"Only string as column name".into(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
}
|
||||
_ => Err(ShellError::GenericError(
|
||||
"Incorrect column format".into(),
|
||||
"Only string as column name".into(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
})
|
||||
.collect::<Result<Vec<String>, _>>()?;
|
||||
|
||||
|
@ -5,7 +5,7 @@ edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cmd-extra"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-extra"
|
||||
version = "0.84.0"
|
||||
version = "0.85.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -13,11 +13,11 @@ version = "0.84.0"
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.84.0" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.84.0" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.84.0" }
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.84.0" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.84.0" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.85.0" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.85.0" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.85.0" }
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.85.0" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.85.0" }
|
||||
|
||||
# Potential dependencies for extras
|
||||
Inflector = "0.11"
|
||||
@ -25,10 +25,10 @@ num-traits = "0.2"
|
||||
ahash = "0.8.3"
|
||||
nu-ansi-term = "0.49.0"
|
||||
fancy-regex = "0.11.0"
|
||||
rust-embed = "6.7.0"
|
||||
rust-embed = "8.0.0"
|
||||
serde = "1.0.164"
|
||||
nu-pretty-hex = { version = "0.84.0", path = "../nu-pretty-hex" }
|
||||
nu-json = { version = "0.84.0", path = "../nu-json" }
|
||||
nu-pretty-hex = { version = "0.85.0", path = "../nu-pretty-hex" }
|
||||
nu-json = { version = "0.85.0", path = "../nu-json" }
|
||||
serde_urlencoded = "0.7.1"
|
||||
htmlescape = "0.3.1"
|
||||
|
||||
@ -37,6 +37,6 @@ extra = ["default"]
|
||||
default = []
|
||||
|
||||
[dev-dependencies]
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.84.0" }
|
||||
nu-command = { path = "../nu-command", version = "0.84.0" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.84.0" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.85.0" }
|
||||
nu-command = { path = "../nu-command", version = "0.85.0" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.85.0" }
|
||||
|
@ -15,8 +15,6 @@ mod test_examples {
|
||||
check_example_input_and_output_types_match_command_signature,
|
||||
};
|
||||
|
||||
use crate::MathEuler;
|
||||
use crate::MathPi;
|
||||
use nu_protocol::{
|
||||
engine::{Command, EngineState, StateWorkingSet},
|
||||
Type,
|
||||
@ -64,9 +62,6 @@ mod test_examples {
|
||||
|
||||
working_set.add_decl(Box::new(nu_command::Enumerate));
|
||||
working_set.add_decl(Box::new(nu_cmd_lang::If));
|
||||
// math commands
|
||||
working_set.add_decl(Box::new(MathEuler));
|
||||
working_set.add_decl(Box::new(MathPi));
|
||||
working_set.add_decl(Box::new(nu_command::MathRound));
|
||||
|
||||
// Adding the command that is being tested to the working set
|
||||
|
@ -68,31 +68,30 @@ impl Command for BitsAnd {
|
||||
Example {
|
||||
description: "Apply logical and to a list of numbers",
|
||||
example: "[4 3 2] | bits and 2",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(0), Value::test_int(2), Value::test_int(2)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(0), Value::test_int(2), Value::test_int(2)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn operate(value: Value, target: i64, head: Span) -> Value {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::Int { val, span } => Value::Int {
|
||||
val: val & target,
|
||||
span,
|
||||
},
|
||||
Value::Int { val, .. } => Value::int(val & target, span),
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => value,
|
||||
other => Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
other => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "integer".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: other.expect_span(),
|
||||
}),
|
||||
},
|
||||
src_span: other.span(),
|
||||
},
|
||||
head,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,16 +34,16 @@ impl Command for Bits {
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
Ok(Value::String {
|
||||
val: get_full_help(
|
||||
Ok(Value::string(
|
||||
get_full_help(
|
||||
&Bits.signature(),
|
||||
&Bits.examples(),
|
||||
engine_state,
|
||||
stack,
|
||||
self.is_parser_keyword(),
|
||||
),
|
||||
span: call.head,
|
||||
}
|
||||
call.head,
|
||||
)
|
||||
.into_pipeline_data())
|
||||
}
|
||||
}
|
||||
|
@ -71,58 +71,51 @@ impl Command for BitsInto {
|
||||
Example {
|
||||
description: "convert a binary value into a string, padded to 8 places with 0s",
|
||||
example: "01b | into bits",
|
||||
result: Some(Value::String {
|
||||
val: "00000001".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("00000001",
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "convert an int into a string, padded to 8 places with 0s",
|
||||
example: "1 | into bits",
|
||||
result: Some(Value::String {
|
||||
val: "00000001".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("00000001",
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "convert a filesize value into a string, padded to 8 places with 0s",
|
||||
example: "1b | into bits",
|
||||
result: Some(Value::String {
|
||||
val: "00000001".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("00000001",
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "convert a duration value into a string, padded to 8 places with 0s",
|
||||
example: "1ns | into bits",
|
||||
result: Some(Value::String {
|
||||
val: "00000001".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("00000001",
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "convert a boolean value into a string, padded to 8 places with 0s",
|
||||
example: "true | into bits",
|
||||
result: Some(Value::String {
|
||||
val: "00000001".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("00000001",
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "convert a datetime value into a string, padded to 8 places with 0s",
|
||||
example: "2023-04-17T01:02:03 | into bits",
|
||||
result: Some(Value::String {
|
||||
val: "01001101 01101111 01101110 00100000 01000001 01110000 01110010 00100000 00110001 00110111 00100000 00110000 00110001 00111010 00110000 00110010 00111010 00110000 00110011 00100000 00110010 00110000 00110010 00110011".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("01001101 01101111 01101110 00100000 01000001 01110000 01110010 00100000 00110001 00110111 00100000 00110000 00110001 00111010 00110000 00110010 00111010 00110000 00110011 00100000 00110010 00110000 00110010 00110011",
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "convert a string into a raw binary string, padded with 0s to 8 places",
|
||||
example: "'nushell.sh' | into bits",
|
||||
result: Some(Value::String {
|
||||
val: "01101110 01110101 01110011 01101000 01100101 01101100 01101100 00101110 01110011 01101000".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("01101110 01110101 01110011 01101000 01100101 01101100 01101100 00101110 01110011 01101000",
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -139,22 +132,16 @@ fn into_bits(
|
||||
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
|
||||
|
||||
match input {
|
||||
PipelineData::ExternalStream { stdout: None, .. } => Ok(Value::Binary {
|
||||
val: vec![],
|
||||
span: head,
|
||||
PipelineData::ExternalStream { stdout: None, .. } => {
|
||||
Ok(Value::binary(vec![], head).into_pipeline_data())
|
||||
}
|
||||
.into_pipeline_data()),
|
||||
PipelineData::ExternalStream {
|
||||
stdout: Some(stream),
|
||||
..
|
||||
} => {
|
||||
// TODO: in the future, we may want this to stream out, converting each to bytes
|
||||
let output = stream.into_bytes()?;
|
||||
Ok(Value::Binary {
|
||||
val: output.item,
|
||||
span: head,
|
||||
}
|
||||
.into_pipeline_data())
|
||||
Ok(Value::binary(output.item, head).into_pipeline_data())
|
||||
}
|
||||
_ => {
|
||||
let args = Arguments { cell_paths };
|
||||
@ -170,40 +157,28 @@ fn convert_to_smallest_number_type(num: i64, span: Span) -> Value {
|
||||
for ch in bytes {
|
||||
raw_string.push_str(&format!("{:08b} ", ch));
|
||||
}
|
||||
Value::String {
|
||||
val: raw_string.trim().to_string(),
|
||||
span,
|
||||
}
|
||||
Value::string(raw_string.trim(), span)
|
||||
} else if let Some(v) = num.to_i16() {
|
||||
let bytes = v.to_ne_bytes();
|
||||
let mut raw_string = "".to_string();
|
||||
for ch in bytes {
|
||||
raw_string.push_str(&format!("{:08b} ", ch));
|
||||
}
|
||||
Value::String {
|
||||
val: raw_string.trim().to_string(),
|
||||
span,
|
||||
}
|
||||
Value::string(raw_string.trim(), span)
|
||||
} else if let Some(v) = num.to_i32() {
|
||||
let bytes = v.to_ne_bytes();
|
||||
let mut raw_string = "".to_string();
|
||||
for ch in bytes {
|
||||
raw_string.push_str(&format!("{:08b} ", ch));
|
||||
}
|
||||
Value::String {
|
||||
val: raw_string.trim().to_string(),
|
||||
span,
|
||||
}
|
||||
Value::string(raw_string.trim(), span)
|
||||
} else {
|
||||
let bytes = num.to_ne_bytes();
|
||||
let mut raw_string = "".to_string();
|
||||
for ch in bytes {
|
||||
raw_string.push_str(&format!("{:08b} ", ch));
|
||||
}
|
||||
Value::String {
|
||||
val: raw_string.trim().to_string(),
|
||||
span,
|
||||
}
|
||||
Value::string(raw_string.trim(), span)
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,10 +189,7 @@ pub fn action(input: &Value, _args: &Arguments, span: Span) -> Value {
|
||||
for ch in val {
|
||||
raw_string.push_str(&format!("{:08b} ", ch));
|
||||
}
|
||||
Value::String {
|
||||
val: raw_string.trim().to_string(),
|
||||
span,
|
||||
}
|
||||
Value::string(raw_string.trim(), span)
|
||||
}
|
||||
Value::Int { val, .. } => convert_to_smallest_number_type(*val, span),
|
||||
Value::Filesize { val, .. } => convert_to_smallest_number_type(*val, span),
|
||||
@ -228,10 +200,7 @@ pub fn action(input: &Value, _args: &Arguments, span: Span) -> Value {
|
||||
for ch in raw_bytes {
|
||||
raw_string.push_str(&format!("{:08b} ", ch));
|
||||
}
|
||||
Value::String {
|
||||
val: raw_string.trim().to_string(),
|
||||
span,
|
||||
}
|
||||
Value::string(raw_string.trim(), span)
|
||||
}
|
||||
Value::Bool { val, .. } => {
|
||||
let v = <i64 as From<bool>>::from(*val);
|
||||
@ -244,21 +213,19 @@ pub fn action(input: &Value, _args: &Arguments, span: Span) -> Value {
|
||||
for ch in bytes {
|
||||
raw_string.push_str(&format!("{:08b} ", ch));
|
||||
}
|
||||
Value::String {
|
||||
val: raw_string.trim().to_string(),
|
||||
span,
|
||||
}
|
||||
Value::string(raw_string.trim(), span)
|
||||
}
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => input.clone(),
|
||||
other => Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
other => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "integer, filesize, string, date, duration, binary or bool".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: span,
|
||||
src_span: other.expect_span(),
|
||||
}),
|
||||
},
|
||||
src_span: other.span(),
|
||||
},
|
||||
span,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ enum InputNumType {
|
||||
SignedEight,
|
||||
}
|
||||
|
||||
fn get_number_bytes(number_bytes: &Option<Spanned<String>>) -> NumberBytes {
|
||||
fn get_number_bytes(number_bytes: Option<&Spanned<String>>) -> NumberBytes {
|
||||
match number_bytes.as_ref() {
|
||||
None => NumberBytes::Eight,
|
||||
Some(size) => match size.item.as_str() {
|
||||
|
@ -57,7 +57,7 @@ impl Command for BitsNot {
|
||||
let signed = call.has_flag("signed");
|
||||
let number_bytes: Option<Spanned<String>> =
|
||||
call.get_flag(engine_state, stack, "number-bytes")?;
|
||||
let bytes_len = get_number_bytes(&number_bytes);
|
||||
let bytes_len = get_number_bytes(number_bytes.as_ref());
|
||||
if let NumberBytes::Invalid = bytes_len {
|
||||
if let Some(val) = number_bytes {
|
||||
return Err(ShellError::UnsupportedInput(
|
||||
@ -84,50 +84,51 @@ impl Command for BitsNot {
|
||||
Example {
|
||||
description: "Apply logical negation to a list of numbers",
|
||||
example: "[4 3 2] | bits not",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_int(140737488355323),
|
||||
Value::test_int(140737488355324),
|
||||
Value::test_int(140737488355325),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description:
|
||||
"Apply logical negation to a list of numbers, treat input as 2 bytes number",
|
||||
example: "[4 3 2] | bits not -n '2'",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_int(65531),
|
||||
Value::test_int(65532),
|
||||
Value::test_int(65533),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description:
|
||||
"Apply logical negation to a list of numbers, treat input as signed number",
|
||||
example: "[4 3 2] | bits not -s",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_int(-5),
|
||||
Value::test_int(-4),
|
||||
Value::test_int(-3),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn operate(value: Value, head: Span, signed: bool, number_size: NumberBytes) -> Value {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::Int { val, span } => {
|
||||
Value::Int { val, .. } => {
|
||||
if signed || val < 0 {
|
||||
Value::Int { val: !val, span }
|
||||
Value::int(!val, span)
|
||||
} else {
|
||||
use NumberBytes::*;
|
||||
let out_val = match number_size {
|
||||
@ -149,20 +150,21 @@ fn operate(value: Value, head: Span, signed: bool, number_size: NumberBytes) ->
|
||||
// This case shouldn't happen here, as it's handled before
|
||||
Invalid => 0,
|
||||
};
|
||||
Value::Int { val: out_val, span }
|
||||
Value::int(out_val, span)
|
||||
}
|
||||
}
|
||||
other => match other {
|
||||
// Propagate errors inside the value
|
||||
Value::Error { .. } => other,
|
||||
_ => Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
_ => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "integer".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: other.expect_span(),
|
||||
}),
|
||||
},
|
||||
src_span: other.span(),
|
||||
},
|
||||
head,
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -68,31 +68,30 @@ impl Command for BitsOr {
|
||||
Example {
|
||||
description: "Apply logical or to a list of numbers",
|
||||
example: "[8 3 2] | bits or 2",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::test_int(10), Value::test_int(3), Value::test_int(2)],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_int(10), Value::test_int(3), Value::test_int(2)],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn operate(value: Value, target: i64, head: Span) -> Value {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::Int { val, span } => Value::Int {
|
||||
val: val | target,
|
||||
span,
|
||||
},
|
||||
Value::Int { val, .. } => Value::int(val | target, span),
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => value,
|
||||
other => Value::Error {
|
||||
error: Box::new(ShellError::OnlySupportsThisInputType {
|
||||
other => Value::error(
|
||||
ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "integer".into(),
|
||||
wrong_type: other.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: other.expect_span(),
|
||||
}),
|
||||
},
|
||||
src_span: other.span(),
|
||||
},
|
||||
head,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user