mirror of
https://github.com/nushell/nushell.git
synced 2025-07-01 15:11:52 +02:00
Compare commits
104 Commits
Author | SHA1 | Date | |
---|---|---|---|
33674d3a98 | |||
0167649e6f | |||
cc263ee15d | |||
a4809f2e68 | |||
21770367e2 | |||
6145f734b7 | |||
9d8d305e9d | |||
eb55fd2383 | |||
613d2fb8df | |||
8783742060 | |||
20528e96c7 | |||
3b6c4c1bb5 | |||
cb18dd5200 | |||
ccebdd7a7f | |||
c3efb12733 | |||
d885258dc7 | |||
2da915d0c7 | |||
ae64c58f59 | |||
ff6868b329 | |||
47ef193600 | |||
c2f4969d4f | |||
08c98967e0 | |||
8d091f6f83 | |||
58094987ff | |||
ce26ef97e4 | |||
8f9bd4a299 | |||
45dd7d8770 | |||
0f10d984c3 | |||
2e5d981a09 | |||
c74254c2cb | |||
271fda7c91 | |||
0e5886ace1 | |||
4b89c5f900 | |||
dcab255d59 | |||
fc8512be39 | |||
e10ef4aaae | |||
0b70ca8451 | |||
555d9ee763 | |||
121b801baa | |||
9adcecbbf1 | |||
9f131d998d | |||
cd0a04f02a | |||
aaf5684f9c | |||
2f0cb044a5 | |||
8b55757a0b | |||
84fae6e07e | |||
63e220a763 | |||
a96fc21f88 | |||
1ba5b25b29 | |||
a871f2344a | |||
a217bc0715 | |||
34ab4d8360 | |||
48f1c3a49e | |||
692376e830 | |||
cc99df5ef1 | |||
d255a2a050 | |||
c07835f3ad | |||
78a5067434 | |||
cdeb8de75d | |||
606547ecb4 | |||
3b809b38e8 | |||
7c49a42b68 | |||
87823b0cb5 | |||
ebf845f431 | |||
ce6df93d05 | |||
e7958bebac | |||
233afebdf0 | |||
56069af42d | |||
376d22e331 | |||
7fc8ff60fd | |||
1f4791a191 | |||
2ac7a4d48d | |||
01386f4d58 | |||
1086fbe9b5 | |||
a83bd4ab20 | |||
26caf7e1b2 | |||
dd2a0e35f4 | |||
6a4eabf5c7 | |||
0e2c888f73 | |||
c140da5740 | |||
586c0ea3d8 | |||
d6f4189c7b | |||
7a820b1304 | |||
767201c40d | |||
3c3614a120 | |||
9e24e452a5 | |||
2cffff0c1b | |||
cf2e9cf481 | |||
6b2c7a4c86 | |||
98e199f7b5 | |||
10e463180e | |||
c9d0003818 | |||
e2a21afca8 | |||
2ea209bcc0 | |||
e049ca8ebf | |||
9037a9467b | |||
4c6cf36aa5 | |||
c92211c016 | |||
8bd6b5b913 | |||
b67fe31544 | |||
c8adb06ca7 | |||
9695331eed | |||
d42cfab6ef | |||
2b7c811402 |
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -53,7 +53,7 @@ body:
|
|||||||
| features | clipboard-cli, ctrlc, dataframe, default, rustyline, term, trash, uuid, which, zip |
|
| features | clipboard-cli, ctrlc, dataframe, default, rustyline, term, trash, uuid, which, zip |
|
||||||
| installed_plugins | binaryview, chart bar, chart line, fetch, from bson, from sqlite, inc, match, post, ps, query json, s3, selector, start, sys, textview, to bson, to sqlite, tree, xpath |
|
| installed_plugins | binaryview, chart bar, chart line, fetch, from bson, from sqlite, inc, match, post, ps, query json, s3, selector, start, sys, textview, to bson, to sqlite, tree, xpath |
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: context
|
id: context
|
||||||
attributes:
|
attributes:
|
||||||
|
1
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
1
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@ -1,5 +1,6 @@
|
|||||||
name: Feature Request
|
name: Feature Request
|
||||||
description: "When you want a new feature for something that doesn't already exist"
|
description: "When you want a new feature for something that doesn't already exist"
|
||||||
|
labels: "enhancement"
|
||||||
body:
|
body:
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: problem
|
id: problem
|
||||||
|
21
.github/ISSUE_TEMPLATE/question.yml
vendored
Normal file
21
.github/ISSUE_TEMPLATE/question.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
name: Question
|
||||||
|
description: "When you have a question to ask"
|
||||||
|
labels: "question"
|
||||||
|
body:
|
||||||
|
- type: textarea
|
||||||
|
id: problem
|
||||||
|
attributes:
|
||||||
|
label: Question
|
||||||
|
description: Leave your question here
|
||||||
|
placeholder: |
|
||||||
|
A clear and concise question
|
||||||
|
Example: Is there any equivalent of bash's $CDPATH in Nu?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: context
|
||||||
|
attributes:
|
||||||
|
label: Additional context and details
|
||||||
|
description: Add any other context, screenshots or other media that will help us understand your question here, if needed.
|
||||||
|
validations:
|
||||||
|
required: false
|
48
.github/workflows/ci.yml
vendored
48
.github/workflows/ci.yml
vendored
@ -23,12 +23,13 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Setup Rust toolchain
|
- name: Setup Rust toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||||
with:
|
# makes ci use rust-toolchain.toml
|
||||||
profile: minimal
|
# with:
|
||||||
toolchain: ${{ matrix.rust }}
|
# profile: minimal
|
||||||
override: true
|
# toolchain: ${{ matrix.rust }}
|
||||||
components: rustfmt, clippy
|
# override: true
|
||||||
|
# components: rustfmt, clippy
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@v1
|
- uses: Swatinem/rust-cache@v1
|
||||||
with:
|
with:
|
||||||
@ -74,11 +75,12 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Setup Rust toolchain
|
- name: Setup Rust toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||||
with:
|
# makes ci use rust-toolchain.toml
|
||||||
profile: minimal
|
# with:
|
||||||
toolchain: ${{ matrix.rust }}
|
# profile: minimal
|
||||||
override: true
|
# toolchain: ${{ matrix.rust }}
|
||||||
|
# override: true
|
||||||
|
|
||||||
# Temporarily disabled; the cache was getting huge (2.6GB compressed) on Windows and causing issues.
|
# Temporarily disabled; the cache was getting huge (2.6GB compressed) on Windows and causing issues.
|
||||||
# TODO: investigate why the cache was so big
|
# TODO: investigate why the cache was so big
|
||||||
@ -111,11 +113,12 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Setup Rust toolchain
|
- name: Setup Rust toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||||
with:
|
# makes ci use rust-toolchain.toml
|
||||||
profile: minimal
|
# with:
|
||||||
toolchain: ${{ matrix.rust }}
|
# profile: minimal
|
||||||
override: true
|
# toolchain: ${{ matrix.rust }}
|
||||||
|
# override: true
|
||||||
|
|
||||||
- uses: Swatinem/rust-cache@v1
|
- uses: Swatinem/rust-cache@v1
|
||||||
with:
|
with:
|
||||||
@ -135,7 +138,7 @@ jobs:
|
|||||||
- run: python -m pip install tox
|
- run: python -m pip install tox
|
||||||
|
|
||||||
- name: Install virtualenv
|
- name: Install virtualenv
|
||||||
run: git clone https://github.com/pypa/virtualenv.git
|
run: git clone https://github.com/pypa/virtualenv.git
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Test Nushell in virtualenv
|
- name: Test Nushell in virtualenv
|
||||||
@ -161,11 +164,12 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Setup Rust toolchain
|
- name: Setup Rust toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||||
with:
|
# makes ci use rust-toolchain.toml
|
||||||
profile: minimal
|
# with:
|
||||||
toolchain: ${{ matrix.rust }}
|
# profile: minimal
|
||||||
override: true
|
# toolchain: ${{ matrix.rust }}
|
||||||
|
# override: true
|
||||||
|
|
||||||
- name: Clippy
|
- name: Clippy
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -29,3 +29,9 @@ debian/nu/
|
|||||||
# Coverage tools
|
# Coverage tools
|
||||||
lcov.info
|
lcov.info
|
||||||
tarpaulin-report.html
|
tarpaulin-report.html
|
||||||
|
|
||||||
|
# Visual Studio
|
||||||
|
.vs/*
|
||||||
|
*.rsproj
|
||||||
|
*.rsproj.user
|
||||||
|
*.sln
|
@ -66,3 +66,9 @@ cargo build
|
|||||||
```shell
|
```shell
|
||||||
cargo run --release --features=extra -- --log-level trace
|
cargo run --release --features=extra -- --log-level trace
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- To redirect trace logs to a file, enable the `--log-target file` switch.
|
||||||
|
```shell
|
||||||
|
cargo run --release --features=extra -- --log-level trace --log-target file
|
||||||
|
[($nu.temp-path) nu-($nu.pid).log] | path join | open
|
||||||
|
```
|
||||||
|
336
Cargo.lock
generated
336
Cargo.lock
generated
@ -68,6 +68,15 @@ version = "1.4.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "77e9c9abb82613923ec78d7a461595d52491ba7240f3c64c0bbe0e6d98e0fce0"
|
checksum = "77e9c9abb82613923ec78d7a461595d52491ba7240f3c64c0bbe0e6d98e0fce0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android_system_properties"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d7ed72e1635e121ca3e79420540282af22da58be50de153d36f81ddc6b83aa9e"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ansi-str"
|
name = "ansi-str"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@ -130,9 +139,9 @@ checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrow-format"
|
name = "arrow-format"
|
||||||
version = "0.6.0"
|
version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "216249afef413d7e9e9b4b543e73b3e371ace3a812380af98f1c871521572cdd"
|
checksum = "8df5d25bc6d676271277120c41ef28760fe0a9f070677a58db621c0f983f9c20"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"planus",
|
"planus",
|
||||||
"serde",
|
"serde",
|
||||||
@ -140,16 +149,19 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrow2"
|
name = "arrow2"
|
||||||
version = "0.12.0"
|
version = "0.13.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5feafd6df4e3f577529e6aa2b9b7cdb3c9fe8e8f66ebc8dc29abbe71a7e968f0"
|
checksum = "afc54f0b14083abaf6bc71cf1aeccd7831a24b1e29d07683ba9a4a0f6c5d9326"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
"arrow-format",
|
"arrow-format",
|
||||||
"base64",
|
"base64",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"dyn-clone",
|
||||||
"either",
|
"either",
|
||||||
"fallible-streaming-iterator",
|
"fallible-streaming-iterator",
|
||||||
|
"foreign_vec",
|
||||||
"futures",
|
"futures",
|
||||||
"hash_hasher",
|
"hash_hasher",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
@ -299,6 +311,21 @@ dependencies = [
|
|||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bit-set"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
|
||||||
|
dependencies = [
|
||||||
|
"bit-vec",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bit-vec"
|
||||||
|
version = "0.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit_field"
|
name = "bit_field"
|
||||||
version = "0.10.1"
|
version = "0.10.1"
|
||||||
@ -504,15 +531,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.19"
|
version = "0.4.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
|
checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"iana-time-zone",
|
||||||
|
"js-sys",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
"pure-rust-locales",
|
||||||
"serde",
|
"serde",
|
||||||
"time 0.1.44",
|
"time 0.1.44",
|
||||||
|
"wasm-bindgen",
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -573,7 +603,7 @@ version = "5.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b103d85ca6e209388771bfb7aa6b68a7aeec4afbf6f0a0264bfbf50360e5212e"
|
checksum = "b103d85ca6e209388771bfb7aa6b68a7aeec4afbf6f0a0264bfbf50360e5212e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossterm",
|
"crossterm 0.23.2",
|
||||||
"strum 0.23.0",
|
"strum 0.23.0",
|
||||||
"strum_macros 0.23.1",
|
"strum_macros 0.23.1",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
@ -734,6 +764,22 @@ name = "crossterm"
|
|||||||
version = "0.23.2"
|
version = "0.23.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a2102ea4f781910f8a5b98dd061f4c2023f479ce7bb1236330099ceb5a93cf17"
|
checksum = "a2102ea4f781910f8a5b98dd061f4c2023f479ce7bb1236330099ceb5a93cf17"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"crossterm_winapi",
|
||||||
|
"libc",
|
||||||
|
"mio 0.8.4",
|
||||||
|
"parking_lot",
|
||||||
|
"signal-hook",
|
||||||
|
"signal-hook-mio",
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossterm"
|
||||||
|
version = "0.24.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ab9f7409c70a38a56216480fba371ee460207dd8926ccf5b4160591759559170"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"crossterm_winapi",
|
"crossterm_winapi",
|
||||||
@ -992,6 +1038,12 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541"
|
checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dyn-clone"
|
||||||
|
version = "1.0.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d07a982d1fb29db01e5a59b1918e03da4df7297eaeee7686ac45542fd4e59c8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ego-tree"
|
name = "ego-tree"
|
||||||
version = "0.6.2"
|
version = "0.6.2"
|
||||||
@ -1038,19 +1090,6 @@ dependencies = [
|
|||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "env_logger"
|
|
||||||
version = "0.7.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
|
|
||||||
dependencies = [
|
|
||||||
"atty",
|
|
||||||
"humantime",
|
|
||||||
"log",
|
|
||||||
"regex",
|
|
||||||
"termcolor",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "env_logger"
|
name = "env_logger"
|
||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
@ -1103,6 +1142,16 @@ version = "0.1.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fancy-regex"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0678ab2d46fa5195aaf59ad034c083d351377d4af57f3e073c074d0da3e3c766"
|
||||||
|
dependencies = [
|
||||||
|
"bit-set",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
@ -1175,6 +1224,12 @@ version = "0.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign_vec"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ee1b05cbd864bcaecbd3455d6d967862d446e4ebfc3c2e5e5b9841e53cba6673"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "form_urlencoded"
|
name = "form_urlencoded"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@ -1313,12 +1368,6 @@ version = "0.3.21"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a"
|
checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-timer"
|
|
||||||
version = "3.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-util"
|
name = "futures-util"
|
||||||
version = "0.3.21"
|
version = "0.3.21"
|
||||||
@ -1437,9 +1486,9 @@ checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "git2"
|
name = "git2"
|
||||||
version = "0.14.4"
|
version = "0.15.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d0155506aab710a86160ddb504a480d2964d7ab5b9e62419be69e0032bc5931c"
|
checksum = "2994bee4a3a6a51eb90c218523be382fd7ea09b16380b9312e9dbe955ff7c7d1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"libc",
|
"libc",
|
||||||
@ -1622,15 +1671,6 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "humantime"
|
|
||||||
version = "1.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
|
|
||||||
dependencies = [
|
|
||||||
"quick-error",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "0.14.20"
|
version = "0.14.20"
|
||||||
@ -1670,11 +1710,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iana-time-zone"
|
name = "iana-time-zone"
|
||||||
version = "0.1.37"
|
version = "0.1.44"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "97d0b780e72fefba5e04a8359137b0a5687a44cc893dbda904fcf8a93f2f07e7"
|
checksum = "808cf7d67cf4a22adc5be66e75ebdf769b3f2ea032041437a7061f97a63dad4b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core-foundation",
|
"android_system_properties",
|
||||||
|
"core-foundation-sys",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
@ -1972,9 +2013,9 @@ checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libgit2-sys"
|
name = "libgit2-sys"
|
||||||
version = "0.13.4+1.4.2"
|
version = "0.14.0+1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d0fa6563431ede25f5cc7f6d803c6afbc1c5d3ad3d4925d12c882bf2b526f5d1"
|
checksum = "47a00859c70c8a4f7218e6d1cc32875c4b55f6799445b842b0d8ed5e4c3d959b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
@ -2084,12 +2125,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lscolors"
|
name = "lscolors"
|
||||||
version = "0.10.0"
|
version = "0.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "88e4434edeec6cd16a7e8e13569af4568a66fcd6d79abd8696db22dd95f920e6"
|
checksum = "074bff749d092e2e818fe954952102f88e21f67fc69f4d350621aab15a1810f1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term",
|
"ansi_term",
|
||||||
"crossterm",
|
"crossterm 0.24.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2465,11 +2506,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu"
|
name = "nu"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assert_cmd",
|
"assert_cmd",
|
||||||
"chrono",
|
"chrono",
|
||||||
"crossterm",
|
"crossterm 0.24.0",
|
||||||
"ctrlc",
|
"ctrlc",
|
||||||
"hamcrest2",
|
"hamcrest2",
|
||||||
"is_executable",
|
"is_executable",
|
||||||
@ -2494,13 +2535,14 @@ dependencies = [
|
|||||||
"nu-utils",
|
"nu-utils",
|
||||||
"openssl",
|
"openssl",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"pretty_env_logger",
|
|
||||||
"rayon",
|
"rayon",
|
||||||
"reedline",
|
"reedline",
|
||||||
"rstest",
|
"rstest",
|
||||||
"serial_test",
|
"serial_test",
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
|
"simplelog",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
|
"time 0.3.13",
|
||||||
"winres",
|
"winres",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2516,10 +2558,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-cli"
|
name = "nu-cli"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"crossterm",
|
"crossterm 0.24.0",
|
||||||
|
"fancy-regex",
|
||||||
"fuzzy-matcher",
|
"fuzzy-matcher",
|
||||||
"is_executable",
|
"is_executable",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
@ -2535,15 +2578,15 @@ dependencies = [
|
|||||||
"nu-test-support",
|
"nu-test-support",
|
||||||
"nu-utils",
|
"nu-utils",
|
||||||
"reedline",
|
"reedline",
|
||||||
"regex",
|
|
||||||
"rstest",
|
"rstest",
|
||||||
|
"strip-ansi-escapes",
|
||||||
"sysinfo",
|
"sysinfo",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-color-config"
|
name = "nu-color-config"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
"nu-json",
|
"nu-json",
|
||||||
@ -2554,7 +2597,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-command"
|
name = "nu-command"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"Inflector",
|
"Inflector",
|
||||||
"alphanumeric-sort",
|
"alphanumeric-sort",
|
||||||
@ -2565,7 +2608,7 @@ dependencies = [
|
|||||||
"chrono",
|
"chrono",
|
||||||
"chrono-humanize",
|
"chrono-humanize",
|
||||||
"chrono-tz",
|
"chrono-tz",
|
||||||
"crossterm",
|
"crossterm 0.24.0",
|
||||||
"csv",
|
"csv",
|
||||||
"dialoguer",
|
"dialoguer",
|
||||||
"digest 0.10.3",
|
"digest 0.10.3",
|
||||||
@ -2573,6 +2616,7 @@ dependencies = [
|
|||||||
"dtparse",
|
"dtparse",
|
||||||
"eml-parser",
|
"eml-parser",
|
||||||
"encoding_rs",
|
"encoding_rs",
|
||||||
|
"fancy-regex",
|
||||||
"filesize",
|
"filesize",
|
||||||
"filetime",
|
"filetime",
|
||||||
"fs_extra",
|
"fs_extra",
|
||||||
@ -2604,6 +2648,8 @@ dependencies = [
|
|||||||
"nu-test-support",
|
"nu-test-support",
|
||||||
"nu-utils",
|
"nu-utils",
|
||||||
"num 0.4.0",
|
"num 0.4.0",
|
||||||
|
"num-format",
|
||||||
|
"num-traits",
|
||||||
"pathdiff",
|
"pathdiff",
|
||||||
"polars",
|
"polars",
|
||||||
"powierza-coefficient",
|
"powierza-coefficient",
|
||||||
@ -2613,7 +2659,6 @@ dependencies = [
|
|||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"rayon",
|
"rayon",
|
||||||
"reedline",
|
"reedline",
|
||||||
"regex",
|
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"roxmltree",
|
"roxmltree",
|
||||||
"rstest",
|
"rstest",
|
||||||
@ -2645,7 +2690,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-engine"
|
name = "nu-engine"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"nu-glob",
|
"nu-glob",
|
||||||
@ -2657,7 +2702,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-glob"
|
name = "nu-glob"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"doc-comment",
|
"doc-comment",
|
||||||
"tempdir",
|
"tempdir",
|
||||||
@ -2665,25 +2710,26 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-json"
|
name = "nu-json"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"fancy-regex",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"linked-hash-map",
|
"linked-hash-map",
|
||||||
"nu-path",
|
"nu-path",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"regex",
|
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-parser"
|
name = "nu-parser"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"itertools",
|
"itertools",
|
||||||
"log",
|
"log",
|
||||||
"miette 5.1.1",
|
"miette 5.1.1",
|
||||||
|
"nu-engine",
|
||||||
"nu-path",
|
"nu-path",
|
||||||
"nu-plugin",
|
"nu-plugin",
|
||||||
"nu-protocol",
|
"nu-protocol",
|
||||||
@ -2693,7 +2739,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-path"
|
name = "nu-path"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dirs-next",
|
"dirs-next",
|
||||||
"dunce",
|
"dunce",
|
||||||
@ -2702,7 +2748,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-plugin"
|
name = "nu-plugin"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode",
|
"bincode",
|
||||||
"capnp",
|
"capnp",
|
||||||
@ -2714,7 +2760,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-pretty-hex"
|
name = "nu-pretty-hex"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heapless",
|
"heapless",
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
@ -2723,17 +2769,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-protocol"
|
name = "nu-protocol"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byte-unit",
|
"byte-unit",
|
||||||
"chrono",
|
"chrono",
|
||||||
"chrono-humanize",
|
"chrono-humanize",
|
||||||
|
"fancy-regex",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"miette 5.1.1",
|
"miette 5.1.1",
|
||||||
"nu-json",
|
"nu-json",
|
||||||
|
"nu-path",
|
||||||
"nu-utils",
|
"nu-utils",
|
||||||
"num-format",
|
"num-format",
|
||||||
"regex",
|
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sys-locale",
|
"sys-locale",
|
||||||
@ -2743,7 +2790,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-system"
|
name = "nu-system"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"errno",
|
"errno",
|
||||||
@ -2757,7 +2804,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-table"
|
name = "nu-table"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atty",
|
"atty",
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
@ -2768,7 +2815,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-term-grid"
|
name = "nu-term-grid"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"strip-ansi-escapes",
|
"strip-ansi-escapes",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
@ -2776,22 +2823,27 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-test-support"
|
name = "nu-test-support"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getset",
|
"getset",
|
||||||
"hamcrest2",
|
"hamcrest2",
|
||||||
|
"lazy_static",
|
||||||
"nu-glob",
|
"nu-glob",
|
||||||
"nu-path",
|
"nu-path",
|
||||||
|
"nu-utils",
|
||||||
"num-bigint 0.4.3",
|
"num-bigint 0.4.3",
|
||||||
|
"num-format",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-utils"
|
name = "nu-utils"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossterm_winapi",
|
"crossterm_winapi",
|
||||||
"lscolors",
|
"lscolors",
|
||||||
|
"num-format",
|
||||||
|
"sys-locale",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2806,7 +2858,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu_plugin_example"
|
name = "nu_plugin_example"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nu-plugin",
|
"nu-plugin",
|
||||||
"nu-protocol",
|
"nu-protocol",
|
||||||
@ -2814,7 +2866,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu_plugin_gstat"
|
name = "nu_plugin_gstat"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"git2",
|
"git2",
|
||||||
"nu-engine",
|
"nu-engine",
|
||||||
@ -2824,7 +2876,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu_plugin_inc"
|
name = "nu_plugin_inc"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nu-plugin",
|
"nu-plugin",
|
||||||
"nu-protocol",
|
"nu-protocol",
|
||||||
@ -2833,7 +2885,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu_plugin_query"
|
name = "nu_plugin_query"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gjson",
|
"gjson",
|
||||||
"nu-engine",
|
"nu-engine",
|
||||||
@ -3153,9 +3205,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parquet2"
|
name = "parquet2"
|
||||||
version = "0.13.2"
|
version = "0.14.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "73fd2690ad041f9296876daef1f2706f6347073bdbcc719090887f1691e4a09d"
|
checksum = "33e434af3293ba384075a56d4b400ce659868ca7823142194ef204f01ab35e50"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-stream",
|
"async-stream",
|
||||||
"bitpacking",
|
"bitpacking",
|
||||||
@ -3362,18 +3414,18 @@ checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "planus"
|
name = "planus"
|
||||||
version = "0.2.0"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bffebaf174d6cad46a5f0f1bb1c45c6eb509571688bcb18dfab217f3c9f9b151"
|
checksum = "fc1691dd09e82f428ce8d6310bd6d5da2557c82ff17694d2a32cad7242aea89f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"array-init-cursor",
|
"array-init-cursor",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polars"
|
name = "polars"
|
||||||
version = "0.22.8"
|
version = "0.23.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3d175c67e80ceaef7219258cfc3a8686531d9510875b0cefa25404e5b80a7933"
|
checksum = "a75b1077fda63c0f67acc1cdc8586e7afce419be1e85bf7dfa8935e0e266d6b3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"polars-core",
|
"polars-core",
|
||||||
"polars-io",
|
"polars-io",
|
||||||
@ -3384,9 +3436,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polars-arrow"
|
name = "polars-arrow"
|
||||||
version = "0.22.7"
|
version = "0.23.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f66c7d3da2c10a09131294dbe7802fac792f570be639dc6ebf207bfc3e144287"
|
checksum = "f7b28f858b252436550679609a23be34d62705faf783887f172f845eb58bcb8b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrow2",
|
"arrow2",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
@ -3397,13 +3449,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polars-core"
|
name = "polars-core"
|
||||||
version = "0.22.7"
|
version = "0.23.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f7f15f443a90d5367c4fbbb151e203f03b5b96055c8b928c6bc30655a3644f13"
|
checksum = "eeaec1ca3ac4829ca24b33743adeeb323a43b5a85515bfce20c2c81799c82790"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arrow2",
|
"arrow2",
|
||||||
|
"bitflags",
|
||||||
"chrono",
|
"chrono",
|
||||||
"comfy-table",
|
"comfy-table",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
@ -3418,14 +3471,15 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"smartstring",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polars-io"
|
name = "polars-io"
|
||||||
version = "0.22.7"
|
version = "0.23.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "058d0a847ce5009b974c69ec878ed416e306436f21b626543019f738cee12315"
|
checksum = "51405e46f93e306a3c9280c60ba1101c662e8a6dab33344680d31c3161045f1c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
@ -3451,11 +3505,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polars-lazy"
|
name = "polars-lazy"
|
||||||
version = "0.22.7"
|
version = "0.23.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dad86a4ce7e32540ff12089bce6f77270fd133a5b263328a92be61defdd6b151"
|
checksum = "1340af778bc8124180d8ca1a566f076a5339566a207a42130796048b087fe977"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
|
"bitflags",
|
||||||
"glob",
|
"glob",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"polars-arrow",
|
"polars-arrow",
|
||||||
@ -3470,9 +3525,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polars-ops"
|
name = "polars-ops"
|
||||||
version = "0.22.7"
|
version = "0.23.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "030ecd473be113cd0264f1bc19de39a844fa12fa565db9dc52c859cbc292cf04"
|
checksum = "4a1812e5d5e589d5bd23f8d89dcd8bd4508082c50d055b8ff5fafb6f2a519c9a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"polars-arrow",
|
"polars-arrow",
|
||||||
"polars-core",
|
"polars-core",
|
||||||
@ -3480,9 +3535,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polars-time"
|
name = "polars-time"
|
||||||
version = "0.22.7"
|
version = "0.23.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94047b20d2da3bcc55c421be187a0c6f316cf1eea7fe7ed7347c1160a32d017c"
|
checksum = "fc4ebe97d601a4b443337df71d0b7e673fce953654871c3311850ea394d48297"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"lexical",
|
"lexical",
|
||||||
@ -3494,9 +3549,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polars-utils"
|
name = "polars-utils"
|
||||||
version = "0.22.7"
|
version = "0.23.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fcd3d0238462d5d9f7fbeaaea46e73ed4d58f6fae8b70d53cbe51d7538cc43f5"
|
checksum = "4ea836afadcddee3f1a513dae7624f6d7d0d64abb129063ec7476b8347c8725b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"rayon",
|
"rayon",
|
||||||
@ -3568,16 +3623,6 @@ dependencies = [
|
|||||||
"output_vt100",
|
"output_vt100",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pretty_env_logger"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d"
|
|
||||||
dependencies = [
|
|
||||||
"env_logger 0.7.1",
|
|
||||||
"log",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-error"
|
name = "proc-macro-error"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
@ -3619,9 +3664,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "procfs"
|
name = "procfs"
|
||||||
version = "0.13.2"
|
version = "0.14.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "979e5cb47caafb8e14653bb083358e19917ca8c9c4c2648932eccd935f5c4d80"
|
checksum = "c1391b61957e3b6f25a59ca2e057d22a44415917d87893986f6627fef109d32f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
@ -3632,6 +3677,12 @@ dependencies = [
|
|||||||
"rustix",
|
"rustix",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pure-rust-locales"
|
||||||
|
version = "0.5.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b45c49fc4f91f35bae654f85ebb3a44d60ac64f11b3166ffa609def390c732d8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pwd"
|
name = "pwd"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
@ -3673,7 +3724,7 @@ version = "1.0.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6"
|
checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"env_logger 0.8.4",
|
"env_logger",
|
||||||
"log",
|
"log",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
]
|
]
|
||||||
@ -3872,12 +3923,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reedline"
|
name = "reedline"
|
||||||
version = "0.9.0"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1815a84fe3d1c632106199f4ba844c109d783e16682df293044bb994537671d8"
|
checksum = "d84e8704e9eb141e73ac426c72af95eb195d4c3221a11ea92d5709f4a025adb5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"crossterm",
|
"crossterm 0.24.0",
|
||||||
"fd-lock",
|
"fd-lock",
|
||||||
"gethostname",
|
"gethostname",
|
||||||
"itertools",
|
"itertools",
|
||||||
@ -4004,8 +4055,6 @@ version = "0.15.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e9c9dc66cc29792b663ffb5269be669f1613664e69ad56441fdb895c2347b930"
|
checksum = "e9c9dc66cc29792b663ffb5269be669f1613664e69ad56441fdb895c2347b930"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures",
|
|
||||||
"futures-timer",
|
|
||||||
"rstest_macros",
|
"rstest_macros",
|
||||||
"rustc_version 0.4.0",
|
"rustc_version 0.4.0",
|
||||||
]
|
]
|
||||||
@ -4316,14 +4365,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_yaml"
|
name = "serde_yaml"
|
||||||
version = "0.8.26"
|
version = "0.9.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b"
|
checksum = "79b7c9017c64a49806c6e8df8ef99b92446d09c92457f85f91835b01a8064ae0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
"itoa 1.0.2",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde",
|
"serde",
|
||||||
"yaml-rust",
|
"unsafe-libyaml",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4394,7 +4444,7 @@ checksum = "b2d399ad15b5c90d8e6461da75c751c77501598dd915d81a108401b252aaa99f"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"const_format",
|
"const_format",
|
||||||
"is_debug",
|
"is_debug",
|
||||||
"time 0.3.11",
|
"time 0.3.13",
|
||||||
"tzdb",
|
"tzdb",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4440,6 +4490,17 @@ version = "0.1.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a"
|
checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simplelog"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48dfff04aade74dd495b007c831cd6f4e0cee19c344dd9dc0884c0289b70a786"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"termcolor",
|
||||||
|
"time 0.3.13",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "siphasher"
|
name = "siphasher"
|
||||||
version = "0.3.10"
|
version = "0.3.10"
|
||||||
@ -4461,6 +4522,17 @@ version = "1.9.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
|
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smartstring"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"static_assertions",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smawk"
|
name = "smawk"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@ -4685,9 +4757,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sysinfo"
|
name = "sysinfo"
|
||||||
version = "0.24.7"
|
version = "0.25.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "54cb4ebf3d49308b99e6e9dc95e989e2fdbdc210e4f67c39db0bb89ba927001c"
|
checksum = "1594a36887d0f70096702bffadfb67dfbfe76ad4bf84605e86157dc9fce9961a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"core-foundation-sys",
|
"core-foundation-sys",
|
||||||
@ -4852,15 +4924,22 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.3.11"
|
version = "0.3.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217"
|
checksum = "db76ff9fa4b1458b3c7f077f3ff9887394058460d21e634355b273aaf11eea45"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa 1.0.2",
|
"itoa 1.0.2",
|
||||||
"libc",
|
"libc",
|
||||||
"num_threads",
|
"num_threads",
|
||||||
|
"time-macros",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time-macros"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinyvec"
|
name = "tinyvec"
|
||||||
version = "1.6.0"
|
version = "1.6.0"
|
||||||
@ -5112,6 +5191,12 @@ version = "0.2.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
|
checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unsafe-libyaml"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "931179334a56395bcf64ba5e0ff56781381c1a5832178280c7d7f91d1679aeb0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.2.2"
|
version = "2.2.2"
|
||||||
@ -5549,15 +5634,6 @@ version = "0.13.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "114ba2b24d2167ef6d67d7d04c8cc86522b87f490025f39f0303b7db5bf5e3d8"
|
checksum = "114ba2b24d2167ef6d67d7d04c8cc86522b87f490025f39f0303b7db5bf5e3d8"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "yaml-rust"
|
|
||||||
version = "0.4.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
|
||||||
dependencies = [
|
|
||||||
"linked-hash-map",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zeroize"
|
name = "zeroize"
|
||||||
version = "1.5.7"
|
version = "1.5.7"
|
||||||
|
43
Cargo.toml
43
Cargo.toml
@ -11,7 +11,7 @@ name = "nu"
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://github.com/nushell/nushell"
|
repository = "https://github.com/nushell/nushell"
|
||||||
rust-version = "1.60"
|
rust-version = "1.60"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
@ -33,30 +33,31 @@ members = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = { version = "0.4.19", features = ["serde"] }
|
chrono = { version = "0.4.21", features = ["serde"] }
|
||||||
crossterm = "0.23.0"
|
crossterm = "0.24.0"
|
||||||
ctrlc = "3.2.1"
|
ctrlc = "3.2.1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
miette = "5.1.0"
|
miette = "5.1.0"
|
||||||
nu-ansi-term = "0.46.0"
|
nu-ansi-term = "0.46.0"
|
||||||
nu-cli = { path="./crates/nu-cli", version = "0.66.0" }
|
nu-cli = { path="./crates/nu-cli", version = "0.67.0" }
|
||||||
nu-color-config = { path = "./crates/nu-color-config", version = "0.66.0" }
|
nu-color-config = { path = "./crates/nu-color-config", version = "0.67.0" }
|
||||||
nu-command = { path="./crates/nu-command", version = "0.66.0" }
|
nu-command = { path="./crates/nu-command", version = "0.67.0" }
|
||||||
nu-engine = { path="./crates/nu-engine", version = "0.66.0" }
|
nu-engine = { path="./crates/nu-engine", version = "0.67.0" }
|
||||||
nu-json = { path="./crates/nu-json", version = "0.66.0" }
|
nu-json = { path="./crates/nu-json", version = "0.67.0" }
|
||||||
nu-parser = { path="./crates/nu-parser", version = "0.66.0" }
|
nu-parser = { path="./crates/nu-parser", version = "0.67.0" }
|
||||||
nu-path = { path="./crates/nu-path", version = "0.66.0" }
|
nu-path = { path="./crates/nu-path", version = "0.67.0" }
|
||||||
nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.66.0" }
|
nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.67.0" }
|
||||||
nu-pretty-hex = { path = "./crates/nu-pretty-hex", version = "0.66.0" }
|
nu-pretty-hex = { path = "./crates/nu-pretty-hex", version = "0.67.0" }
|
||||||
nu-protocol = { path = "./crates/nu-protocol", version = "0.66.0" }
|
nu-protocol = { path = "./crates/nu-protocol", version = "0.67.0" }
|
||||||
nu-system = { path = "./crates/nu-system", version = "0.66.0" }
|
nu-system = { path = "./crates/nu-system", version = "0.67.0" }
|
||||||
nu-table = { path = "./crates/nu-table", version = "0.66.0" }
|
nu-table = { path = "./crates/nu-table", version = "0.67.0" }
|
||||||
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.66.0" }
|
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.67.0" }
|
||||||
nu-utils = { path = "./crates/nu-utils", version = "0.66.0" }
|
nu-utils = { path = "./crates/nu-utils", version = "0.67.0" }
|
||||||
reedline = { version = "0.9.0", features = ["bashisms", "sqlite"]}
|
reedline = { version = "0.10.0", features = ["bashisms", "sqlite"]}
|
||||||
pretty_env_logger = "0.4.0"
|
|
||||||
rayon = "1.5.1"
|
rayon = "1.5.1"
|
||||||
is_executable = "1.0.1"
|
is_executable = "1.0.1"
|
||||||
|
simplelog = "0.12.0"
|
||||||
|
time = "0.3.12"
|
||||||
|
|
||||||
[target.'cfg(not(target_os = "windows"))'.dependencies]
|
[target.'cfg(not(target_os = "windows"))'.dependencies]
|
||||||
# Our dependencies don't use OpenSSL on Windows
|
# Our dependencies don't use OpenSSL on Windows
|
||||||
@ -64,13 +65,13 @@ openssl = { version = "0.10.38", features = ["vendored"], optional = true }
|
|||||||
signal-hook = { version = "0.3.14", default-features = false }
|
signal-hook = { version = "0.3.14", default-features = false }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
nu-test-support = { path="./crates/nu-test-support", version = "0.66.0" }
|
nu-test-support = { path="./crates/nu-test-support", version = "0.67.0" }
|
||||||
tempfile = "3.2.0"
|
tempfile = "3.2.0"
|
||||||
assert_cmd = "2.0.2"
|
assert_cmd = "2.0.2"
|
||||||
pretty_assertions = "1.0.0"
|
pretty_assertions = "1.0.0"
|
||||||
serial_test = "0.8.0"
|
serial_test = "0.8.0"
|
||||||
hamcrest2 = "0.3.0"
|
hamcrest2 = "0.3.0"
|
||||||
rstest = "0.15.0"
|
rstest = {version = "0.15.0", default-features = false}
|
||||||
itertools = "0.10.3"
|
itertools = "0.10.3"
|
||||||
|
|
||||||
[target.'cfg(windows)'.build-dependencies]
|
[target.'cfg(windows)'.build-dependencies]
|
||||||
|
@ -10,6 +10,7 @@ NU_PLUGINS=(
|
|||||||
'nu_plugin_gstat'
|
'nu_plugin_gstat'
|
||||||
'nu_plugin_inc'
|
'nu_plugin_inc'
|
||||||
'nu_plugin_query'
|
'nu_plugin_query'
|
||||||
|
'nu_plugin_custom_values'
|
||||||
)
|
)
|
||||||
|
|
||||||
echo "Building nushell"
|
echo "Building nushell"
|
||||||
|
@ -24,9 +24,13 @@ cargo build
|
|||||||
@echo.
|
@echo.
|
||||||
|
|
||||||
@cd ..\..\crates\nu_plugin_query
|
@cd ..\..\crates\nu_plugin_query
|
||||||
|
|
||||||
echo Building nu_plugin_query.exe
|
echo Building nu_plugin_query.exe
|
||||||
cargo build
|
cargo build
|
||||||
@echo.
|
@echo.
|
||||||
|
|
||||||
|
@cd ..\..\crates\nu_plugin_custom_values
|
||||||
|
echo Building nu_plugin_custom_values.exe
|
||||||
|
cargo build
|
||||||
|
@echo.
|
||||||
|
|
||||||
@cd ..\..
|
@cd ..\..
|
@ -11,6 +11,7 @@ let plugins = [
|
|||||||
nu_plugin_gstat,
|
nu_plugin_gstat,
|
||||||
nu_plugin_query,
|
nu_plugin_query,
|
||||||
nu_plugin_example,
|
nu_plugin_example,
|
||||||
|
nu_plugin_custom_values,
|
||||||
]
|
]
|
||||||
|
|
||||||
for plugin in $plugins {
|
for plugin in $plugins {
|
||||||
|
@ -1,36 +1,38 @@
|
|||||||
[package]
|
[package]
|
||||||
authors = ["The Nushell Project Developers"]
|
authors = ["The Nushell Project Developers"]
|
||||||
description = "CLI-related functionality for Nushell"
|
description = "CLI-related functionality for Nushell"
|
||||||
|
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cli"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
name = "nu-cli"
|
name = "nu-cli"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
nu-test-support = { path="../nu-test-support", version = "0.66.0" }
|
nu-test-support = { path="../nu-test-support", version = "0.67.0" }
|
||||||
nu-command = { path = "../nu-command", version = "0.66.0" }
|
nu-command = { path = "../nu-command", version = "0.67.0" }
|
||||||
rstest = "0.15.0"
|
rstest = {version = "0.15.0", default-features = false}
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nu-engine = { path = "../nu-engine", version = "0.66.0" }
|
nu-engine = { path = "../nu-engine", version = "0.67.0" }
|
||||||
nu-path = { path = "../nu-path", version = "0.66.0" }
|
nu-path = { path = "../nu-path", version = "0.67.0" }
|
||||||
nu-parser = { path = "../nu-parser", version = "0.66.0" }
|
nu-parser = { path = "../nu-parser", version = "0.67.0" }
|
||||||
nu-protocol = { path = "../nu-protocol", version = "0.66.0" }
|
nu-protocol = { path = "../nu-protocol", version = "0.67.0" }
|
||||||
nu-utils = { path = "../nu-utils", version = "0.66.0" }
|
nu-utils = { path = "../nu-utils", version = "0.67.0" }
|
||||||
nu-ansi-term = "0.46.0"
|
nu-ansi-term = "0.46.0"
|
||||||
nu-color-config = { path = "../nu-color-config", version = "0.66.0" }
|
nu-color-config = { path = "../nu-color-config", version = "0.67.0" }
|
||||||
reedline = { version = "0.9.0", features = ["bashisms", "sqlite"]}
|
reedline = { version = "0.10.0", features = ["bashisms", "sqlite"]}
|
||||||
crossterm = "0.23.0"
|
|
||||||
miette = { version = "5.1.0", features = ["fancy"] }
|
|
||||||
thiserror = "1.0.31"
|
|
||||||
fuzzy-matcher = "0.3.7"
|
|
||||||
|
|
||||||
chrono = "0.4.19"
|
chrono = "0.4.21"
|
||||||
|
crossterm = "0.24.0"
|
||||||
|
fancy-regex = "0.10.0"
|
||||||
|
fuzzy-matcher = "0.3.7"
|
||||||
is_executable = "1.0.1"
|
is_executable = "1.0.1"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
regex = "1.5.4"
|
miette = { version = "5.1.0", features = ["fancy"] }
|
||||||
sysinfo = "0.24.1"
|
strip-ansi-escapes = "0.1.1"
|
||||||
|
sysinfo = "0.25.2"
|
||||||
|
thiserror = "1.0.31"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
plugin = []
|
plugin = []
|
||||||
|
@ -116,7 +116,8 @@ impl CommandCompletion {
|
|||||||
|
|
||||||
let partial = working_set.get_span_contents(span);
|
let partial = working_set.get_span_contents(span);
|
||||||
let partial = String::from_utf8_lossy(partial).to_string();
|
let partial = String::from_utf8_lossy(partial).to_string();
|
||||||
let results = if find_externals {
|
|
||||||
|
if find_externals {
|
||||||
let results_external = self
|
let results_external = self
|
||||||
.external_command_completion(&partial, match_algorithm)
|
.external_command_completion(&partial, match_algorithm)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -148,9 +149,7 @@ impl CommandCompletion {
|
|||||||
results
|
results
|
||||||
} else {
|
} else {
|
||||||
results
|
results
|
||||||
};
|
}
|
||||||
|
|
||||||
results
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ impl NuCompleter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return vec![];
|
vec![]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use {
|
use {
|
||||||
nu_ansi_term::{ansi::RESET, Style},
|
nu_ansi_term::{ansi::RESET, Style},
|
||||||
reedline::{
|
reedline::{
|
||||||
menu_functions::string_difference, Completer, LineBuffer, Menu, MenuEvent, MenuTextStyle,
|
menu_functions::string_difference, Completer, Editor, Menu, MenuEvent, MenuTextStyle,
|
||||||
Painter, Suggestion,
|
Painter, Suggestion, UndoBehavior,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -459,7 +459,7 @@ impl Menu for DescriptionMenu {
|
|||||||
fn can_partially_complete(
|
fn can_partially_complete(
|
||||||
&mut self,
|
&mut self,
|
||||||
_values_updated: bool,
|
_values_updated: bool,
|
||||||
_line_buffer: &mut LineBuffer,
|
_editor: &mut Editor,
|
||||||
_completer: &mut dyn Completer,
|
_completer: &mut dyn Completer,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
false
|
false
|
||||||
@ -481,19 +481,21 @@ impl Menu for DescriptionMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Updates menu values
|
/// Updates menu values
|
||||||
fn update_values(&mut self, line_buffer: &mut LineBuffer, completer: &mut dyn Completer) {
|
fn update_values(&mut self, editor: &mut Editor, completer: &mut dyn Completer) {
|
||||||
if self.only_buffer_difference {
|
if self.only_buffer_difference {
|
||||||
if let Some(old_string) = &self.input {
|
if let Some(old_string) = &self.input {
|
||||||
let (start, input) = string_difference(line_buffer.get_buffer(), old_string);
|
let (start, input) = string_difference(editor.get_buffer(), old_string);
|
||||||
if !input.is_empty() {
|
if !input.is_empty() {
|
||||||
self.reset_position();
|
self.reset_position();
|
||||||
self.values = completer.complete(input, start);
|
self.values = completer.complete(input, start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let trimmed_buffer = line_buffer.get_buffer().replace('\n', " ");
|
let trimmed_buffer = editor.get_buffer().replace('\n', " ");
|
||||||
self.values =
|
self.values = completer.complete(
|
||||||
completer.complete(trimmed_buffer.as_str(), line_buffer.insertion_point());
|
trimmed_buffer.as_str(),
|
||||||
|
editor.line_buffer().insertion_point(),
|
||||||
|
);
|
||||||
self.reset_position();
|
self.reset_position();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -502,7 +504,7 @@ impl Menu for DescriptionMenu {
|
|||||||
/// collected from the completer
|
/// collected from the completer
|
||||||
fn update_working_details(
|
fn update_working_details(
|
||||||
&mut self,
|
&mut self,
|
||||||
line_buffer: &mut LineBuffer,
|
editor: &mut Editor,
|
||||||
completer: &mut dyn Completer,
|
completer: &mut dyn Completer,
|
||||||
painter: &Painter,
|
painter: &Painter,
|
||||||
) {
|
) {
|
||||||
@ -560,13 +562,13 @@ impl Menu for DescriptionMenu {
|
|||||||
match event {
|
match event {
|
||||||
MenuEvent::Activate(_) => {
|
MenuEvent::Activate(_) => {
|
||||||
self.reset_position();
|
self.reset_position();
|
||||||
self.input = Some(line_buffer.get_buffer().to_string());
|
self.input = Some(editor.get_buffer().to_string());
|
||||||
self.update_values(line_buffer, completer);
|
self.update_values(editor, completer);
|
||||||
}
|
}
|
||||||
MenuEvent::Deactivate => self.active = false,
|
MenuEvent::Deactivate => self.active = false,
|
||||||
MenuEvent::Edit(_) => {
|
MenuEvent::Edit(_) => {
|
||||||
self.reset_position();
|
self.reset_position();
|
||||||
self.update_values(line_buffer, completer);
|
self.update_values(editor, completer);
|
||||||
self.update_examples()
|
self.update_examples()
|
||||||
}
|
}
|
||||||
MenuEvent::NextElement => {
|
MenuEvent::NextElement => {
|
||||||
@ -627,27 +629,28 @@ impl Menu for DescriptionMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The buffer gets replaced in the Span location
|
/// The buffer gets replaced in the Span location
|
||||||
fn replace_in_buffer(&self, line_buffer: &mut LineBuffer) {
|
fn replace_in_buffer(&self, editor: &mut Editor) {
|
||||||
if let Some(Suggestion { value, span, .. }) = self.get_value() {
|
if let Some(Suggestion { value, span, .. }) = self.get_value() {
|
||||||
let start = span.start.min(line_buffer.len());
|
let start = span.start.min(editor.line_buffer().len());
|
||||||
let end = span.end.min(line_buffer.len());
|
let end = span.end.min(editor.line_buffer().len());
|
||||||
|
|
||||||
let string_len = if let Some(example_index) = self.example_index {
|
let replacement = if let Some(example_index) = self.example_index {
|
||||||
let example = self
|
self.examples
|
||||||
.examples
|
|
||||||
.get(example_index)
|
.get(example_index)
|
||||||
.expect("the example index is always checked");
|
.expect("the example index is always checked")
|
||||||
|
|
||||||
line_buffer.replace(start..end, example);
|
|
||||||
example.len()
|
|
||||||
} else {
|
} else {
|
||||||
line_buffer.replace(start..end, &value);
|
&value
|
||||||
value.len()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut offset = line_buffer.insertion_point();
|
editor.edit_buffer(
|
||||||
offset += string_len.saturating_sub(end.saturating_sub(start));
|
|lb| {
|
||||||
line_buffer.set_insertion_point(offset);
|
lb.replace_range(start..end, replacement);
|
||||||
|
let mut offset = lb.insertion_point();
|
||||||
|
offset += lb.len().saturating_sub(end.saturating_sub(start));
|
||||||
|
lb.set_insertion_point(offset);
|
||||||
|
},
|
||||||
|
UndoBehavior::CreateUndoPoint,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -814,7 +814,6 @@ fn event_from_record(
|
|||||||
) -> Result<ReedlineEvent, ShellError> {
|
) -> Result<ReedlineEvent, ShellError> {
|
||||||
let event = match name {
|
let event = match name {
|
||||||
"none" => ReedlineEvent::None,
|
"none" => ReedlineEvent::None,
|
||||||
"actionhandler" => ReedlineEvent::ActionHandler,
|
|
||||||
"clearscreen" => ReedlineEvent::ClearScreen,
|
"clearscreen" => ReedlineEvent::ClearScreen,
|
||||||
"clearscrollback" => ReedlineEvent::ClearScrollback,
|
"clearscrollback" => ReedlineEvent::ClearScrollback,
|
||||||
"historyhintcomplete" => ReedlineEvent::HistoryHintComplete,
|
"historyhintcomplete" => ReedlineEvent::HistoryHintComplete,
|
||||||
|
@ -5,6 +5,7 @@ use crate::{
|
|||||||
util::{eval_source, get_guaranteed_cwd, report_error, report_error_new},
|
util::{eval_source, get_guaranteed_cwd, report_error, report_error_new},
|
||||||
NuHighlighter, NuValidator, NushellPrompt,
|
NuHighlighter, NuValidator, NushellPrompt,
|
||||||
};
|
};
|
||||||
|
use fancy_regex::Regex;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use log::{info, trace, warn};
|
use log::{info, trace, warn};
|
||||||
use miette::{IntoDiagnostic, Result};
|
use miette::{IntoDiagnostic, Result};
|
||||||
@ -14,12 +15,13 @@ use nu_parser::{lex, parse};
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::PathMember,
|
ast::PathMember,
|
||||||
engine::{EngineState, Stack, StateWorkingSet},
|
engine::{EngineState, Stack, StateWorkingSet},
|
||||||
BlockId, HistoryFileFormat, PipelineData, PositionalArg, ShellError, Span, Type, Value, VarId,
|
format_duration, BlockId, HistoryFileFormat, PipelineData, PositionalArg, ShellError, Span,
|
||||||
|
Type, Value, VarId,
|
||||||
};
|
};
|
||||||
use reedline::{DefaultHinter, Emacs, SqliteBackedHistory, Vi};
|
use reedline::{DefaultHinter, Emacs, SqliteBackedHistory, Vi};
|
||||||
use regex::Regex;
|
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::{sync::atomic::Ordering, time::Instant};
|
use std::{sync::atomic::Ordering, time::Instant};
|
||||||
|
use strip_ansi_escapes::strip;
|
||||||
use sysinfo::SystemExt;
|
use sysinfo::SystemExt;
|
||||||
|
|
||||||
// According to Daniel Imms @Tyriar, we need to do these this way:
|
// According to Daniel Imms @Tyriar, we need to do these this way:
|
||||||
@ -119,6 +121,25 @@ pub fn evaluate_repl(
|
|||||||
|
|
||||||
let sys = sysinfo::System::new();
|
let sys = sysinfo::System::new();
|
||||||
|
|
||||||
|
let show_banner = config.show_banner;
|
||||||
|
let use_ansi = config.use_ansi_coloring;
|
||||||
|
if show_banner {
|
||||||
|
let banner = get_banner(engine_state, stack);
|
||||||
|
if use_ansi {
|
||||||
|
println!("{}", banner);
|
||||||
|
} else {
|
||||||
|
let stripped_string = {
|
||||||
|
if let Ok(bytes) = strip(&banner) {
|
||||||
|
String::from_utf8_lossy(&bytes).to_string()
|
||||||
|
} else {
|
||||||
|
banner
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("{}", stripped_string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if is_perf_true {
|
if is_perf_true {
|
||||||
info!(
|
info!(
|
||||||
@ -312,24 +333,7 @@ pub fn evaluate_repl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if shell_integration {
|
if shell_integration {
|
||||||
run_ansi_sequence(RESET_APPLICATION_MODE)?;
|
|
||||||
run_ansi_sequence(PRE_EXECUTE_MARKER)?;
|
run_ansi_sequence(PRE_EXECUTE_MARKER)?;
|
||||||
// if let Some(cwd) = stack.get_env_var(engine_state, "PWD") {
|
|
||||||
// let path = cwd.as_string()?;
|
|
||||||
// // Try to abbreviate string for windows title
|
|
||||||
// let maybe_abbrev_path = if let Some(p) = nu_path::home_dir() {
|
|
||||||
// path.replace(&p.as_path().display().to_string(), "~")
|
|
||||||
// } else {
|
|
||||||
// path
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // Set window title too
|
|
||||||
// // https://tldp.org/HOWTO/Xterm-Title-3.html
|
|
||||||
// // ESC]0;stringBEL -- Set icon name and window title to string
|
|
||||||
// // ESC]1;stringBEL -- Set icon name to string
|
|
||||||
// // ESC]2;stringBEL -- Set window title to string
|
|
||||||
// run_ansi_sequence(&format!("\x1b]2;{}\x07", maybe_abbrev_path))?;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
@ -391,9 +395,23 @@ pub fn evaluate_repl(
|
|||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let last_shell = stack.get_env_var(engine_state, "NUSHELL_LAST_SHELL");
|
||||||
|
let last_shell = if let Some(v) = last_shell {
|
||||||
|
v.as_integer().unwrap_or_default() as usize
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
shells[current_shell] = Value::String { val: path, span };
|
shells[current_shell] = Value::String { val: path, span };
|
||||||
|
|
||||||
stack.add_env_var("NUSHELL_SHELLS".into(), Value::List { vals: shells, span });
|
stack.add_env_var("NUSHELL_SHELLS".into(), Value::List { vals: shells, span });
|
||||||
|
stack.add_env_var(
|
||||||
|
"NUSHELL_LAST_SHELL".into(),
|
||||||
|
Value::Int {
|
||||||
|
val: last_shell as i64,
|
||||||
|
span,
|
||||||
|
},
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
trace!("eval source: {}", s);
|
trace!("eval source: {}", s);
|
||||||
|
|
||||||
@ -445,6 +463,7 @@ pub fn evaluate_repl(
|
|||||||
// ESC]2;stringBEL -- Set window title to string
|
// ESC]2;stringBEL -- Set window title to string
|
||||||
run_ansi_sequence(&format!("\x1b]2;{}\x07", maybe_abbrev_path))?;
|
run_ansi_sequence(&format!("\x1b]2;{}\x07", maybe_abbrev_path))?;
|
||||||
}
|
}
|
||||||
|
run_ansi_sequence(RESET_APPLICATION_MODE)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Signal::CtrlC) => {
|
Ok(Signal::CtrlC) => {
|
||||||
@ -476,6 +495,115 @@ pub fn evaluate_repl(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_banner(engine_state: &mut EngineState, stack: &mut Stack) -> String {
|
||||||
|
let age = match eval_string_with_input(
|
||||||
|
engine_state,
|
||||||
|
stack,
|
||||||
|
None,
|
||||||
|
"(date now) - ('05/10/2019' | into datetime)",
|
||||||
|
) {
|
||||||
|
Ok(Value::Duration { val, .. }) => format_duration(val),
|
||||||
|
_ => "".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let banner = format!(
|
||||||
|
r#"{} __ ,
|
||||||
|
{} .--()°'.' {}Welcome to {}Nushell{},
|
||||||
|
{}'|, . ,' {}based on the {}nu{} language,
|
||||||
|
{} !_-(_\ {}where all data is structured!
|
||||||
|
|
||||||
|
Please join our {}Discord{} community at {}https://discord.gg/NtAbbGn{}
|
||||||
|
Our {}GitHub{} repository is at {}https://github.com/nushell/nushell{}
|
||||||
|
Our {}Documentation{} is located at {}http://nushell.sh{}
|
||||||
|
{}Tweet{} us at {}@nu_shell{}
|
||||||
|
|
||||||
|
{}Nushell{} has been around for:
|
||||||
|
{}
|
||||||
|
|
||||||
|
{}You can disable this banner using the {}config nu{}{} command
|
||||||
|
to modify the config.nu file and setting show_banner to false.
|
||||||
|
|
||||||
|
let-env config {{
|
||||||
|
show_banner: false
|
||||||
|
...
|
||||||
|
}}{}
|
||||||
|
"#,
|
||||||
|
"\x1b[32m", //start line 1 green
|
||||||
|
"\x1b[32m", //start line 2
|
||||||
|
"\x1b[0m", //before welcome
|
||||||
|
"\x1b[32m", //before nushell
|
||||||
|
"\x1b[0m", //after nushell
|
||||||
|
"\x1b[32m", //start line 3
|
||||||
|
"\x1b[0m", //before based
|
||||||
|
"\x1b[32m", //before nu
|
||||||
|
"\x1b[0m", //after nu
|
||||||
|
"\x1b[32m", //start line 4
|
||||||
|
"\x1b[0m", //before where
|
||||||
|
"\x1b[35m", //before Discord purple
|
||||||
|
"\x1b[0m", //after Discord
|
||||||
|
"\x1b[35m", //before Discord URL
|
||||||
|
"\x1b[0m", //after Discord URL
|
||||||
|
"\x1b[1;32m", //before GitHub green_bold
|
||||||
|
"\x1b[0m", //after GitHub
|
||||||
|
"\x1b[1;32m", //before GitHub URL
|
||||||
|
"\x1b[0m", //after GitHub URL
|
||||||
|
"\x1b[32m", //before Documentation
|
||||||
|
"\x1b[0m", //after Documentation
|
||||||
|
"\x1b[32m", //before Documentation URL
|
||||||
|
"\x1b[0m", //after Documentation URL
|
||||||
|
"\x1b[36m", //before Tweet blue
|
||||||
|
"\x1b[0m", //after Tweet
|
||||||
|
"\x1b[1;36m", //before @nu_shell cyan_bold
|
||||||
|
"\x1b[0m", //after @nu_shell
|
||||||
|
"\x1b[32m", //before Nushell
|
||||||
|
"\x1b[0m", //after Nushell
|
||||||
|
age,
|
||||||
|
"\x1b[2;37m", //before banner disable dim white
|
||||||
|
"\x1b[2;36m", //before config nu dim cyan
|
||||||
|
"\x1b[0m", //after config nu
|
||||||
|
"\x1b[2;37m", //after config nu dim white
|
||||||
|
"\x1b[0m", //after banner disable
|
||||||
|
);
|
||||||
|
|
||||||
|
banner
|
||||||
|
}
|
||||||
|
|
||||||
|
// Taken from Nana's simple_eval
|
||||||
|
/// Evaluate a block of Nu code, optionally with input.
|
||||||
|
/// For example, source="$in * 2" will multiply the value in input by 2.
|
||||||
|
pub fn eval_string_with_input(
|
||||||
|
engine_state: &mut EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
input: Option<Value>,
|
||||||
|
source: &str,
|
||||||
|
) -> Result<Value, ShellError> {
|
||||||
|
let (block, delta) = {
|
||||||
|
let mut working_set = StateWorkingSet::new(engine_state);
|
||||||
|
let (output, _) = parse(&mut working_set, None, source.as_bytes(), false, &[]);
|
||||||
|
|
||||||
|
(output, working_set.render())
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(err) = engine_state.merge_delta(delta) {
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
let input_as_pipeline_data = match input {
|
||||||
|
Some(input) => PipelineData::Value(input, None),
|
||||||
|
None => PipelineData::new(Span::test_data()),
|
||||||
|
};
|
||||||
|
|
||||||
|
eval_block(
|
||||||
|
engine_state,
|
||||||
|
stack,
|
||||||
|
&block,
|
||||||
|
input_as_pipeline_data,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.map(|x| x.into_value(Span::test_data()))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_command_finished_marker(stack: &Stack, engine_state: &EngineState) -> String {
|
pub fn get_command_finished_marker(stack: &Stack, engine_state: &EngineState) -> String {
|
||||||
let exit_code = stack
|
let exit_code = stack
|
||||||
.get_env_var(engine_state, "LAST_EXIT_CODE")
|
.get_env_var(engine_state, "LAST_EXIT_CODE")
|
||||||
@ -658,9 +786,6 @@ pub fn eval_hook(
|
|||||||
for var_id in var_ids.iter() {
|
for var_id in var_ids.iter() {
|
||||||
stack.vars.remove(var_id);
|
stack.vars.remove(var_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
let cwd = get_guaranteed_cwd(engine_state, stack);
|
|
||||||
engine_state.merge_env(stack, cwd)?;
|
|
||||||
}
|
}
|
||||||
Value::Block {
|
Value::Block {
|
||||||
val: block_id,
|
val: block_id,
|
||||||
@ -668,8 +793,6 @@ pub fn eval_hook(
|
|||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
run_hook_block(engine_state, stack, block_id, arguments, block_span)?;
|
run_hook_block(engine_state, stack, block_id, arguments, block_span)?;
|
||||||
let cwd = get_guaranteed_cwd(engine_state, stack);
|
|
||||||
engine_state.merge_env(stack, cwd)?;
|
|
||||||
}
|
}
|
||||||
other => {
|
other => {
|
||||||
return Err(ShellError::UnsupportedConfigValue(
|
return Err(ShellError::UnsupportedConfigValue(
|
||||||
@ -697,6 +820,9 @@ pub fn eval_hook(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let cwd = get_guaranteed_cwd(engine_state, stack);
|
||||||
|
engine_state.merge_env(stack, cwd)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -789,7 +915,7 @@ lazy_static! {
|
|||||||
fn looks_like_path(orig: &str) -> bool {
|
fn looks_like_path(orig: &str) -> bool {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
{
|
{
|
||||||
if DRIVE_PATH_REGEX.is_match(orig) {
|
if DRIVE_PATH_REGEX.is_match(orig).unwrap_or(false) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
[package]
|
[package]
|
||||||
authors = ["The Nushell Project Developers"]
|
authors = ["The Nushell Project Developers"]
|
||||||
description = "Color configuration code used by Nushell"
|
description = "Color configuration code used by Nushell"
|
||||||
|
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-color-config"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
name = "nu-color-config"
|
name = "nu-color-config"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nu-protocol = { path = "../nu-protocol", version = "0.66.0" }
|
nu-protocol = { path = "../nu-protocol", version = "0.67.0" }
|
||||||
nu-ansi-term = "0.46.0"
|
nu-ansi-term = "0.46.0"
|
||||||
nu-json = { path = "../nu-json", version = "0.66.0" }
|
nu-json = { path = "../nu-json", version = "0.67.0" }
|
||||||
nu-table = { path = "../nu-table", version = "0.66.0" }
|
nu-table = { path = "../nu-table", version = "0.67.0" }
|
||||||
serde = { version="1.0.123", features=["derive"] }
|
serde = { version="1.0.123", features=["derive"] }
|
||||||
|
@ -11,12 +11,12 @@ pub struct NuStyle {
|
|||||||
pub fn parse_nustyle(nu_style: NuStyle) -> Style {
|
pub fn parse_nustyle(nu_style: NuStyle) -> Style {
|
||||||
// get the nu_ansi_term::Color foreground color
|
// get the nu_ansi_term::Color foreground color
|
||||||
let fg_color = match nu_style.fg {
|
let fg_color = match nu_style.fg {
|
||||||
Some(fg) => color_from_hex(&fg).expect("error with foreground color"),
|
Some(fg) => color_from_hex(&fg).unwrap_or_default(),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
// get the nu_ansi_term::Color background color
|
// get the nu_ansi_term::Color background color
|
||||||
let bg_color = match nu_style.bg {
|
let bg_color = match nu_style.bg {
|
||||||
Some(bg) => color_from_hex(&bg).expect("error with background color"),
|
Some(bg) => color_from_hex(&bg).unwrap_or_default(),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
// get the attributes
|
// get the attributes
|
||||||
|
@ -1,29 +1,31 @@
|
|||||||
[package]
|
[package]
|
||||||
authors = ["The Nushell Project Developers"]
|
authors = ["The Nushell Project Developers"]
|
||||||
description = "Nushell's built-in commands"
|
description = "Nushell's built-in commands"
|
||||||
|
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-command"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
name = "nu-command"
|
name = "nu-command"
|
||||||
version = "0.66.0"
|
version = "0.67.0"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nu-color-config = { path = "../nu-color-config", version = "0.66.0" }
|
nu-color-config = { path = "../nu-color-config", version = "0.67.0" }
|
||||||
nu-engine = { path = "../nu-engine", version = "0.66.0" }
|
nu-engine = { path = "../nu-engine", version = "0.67.0" }
|
||||||
nu-glob = { path = "../nu-glob", version = "0.66.0" }
|
nu-glob = { path = "../nu-glob", version = "0.67.0" }
|
||||||
nu-json = { path = "../nu-json", version = "0.66.0" }
|
nu-json = { path = "../nu-json", version = "0.67.0" }
|
||||||
nu-parser = { path = "../nu-parser", version = "0.66.0" }
|
nu-parser = { path = "../nu-parser", version = "0.67.0" }
|
||||||
nu-path = { path = "../nu-path", version = "0.66.0" }
|
nu-path = { path = "../nu-path", version = "0.67.0" }
|
||||||
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.66.0" }
|
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.67.0" }
|
||||||
nu-protocol = { path = "../nu-protocol", version = "0.66.0" }
|
nu-protocol = { path = "../nu-protocol", version = "0.67.0" }
|
||||||
nu-system = { path = "../nu-system", version = "0.66.0" }
|
nu-system = { path = "../nu-system", version = "0.67.0" }
|
||||||
nu-table = { path = "../nu-table", version = "0.66.0" }
|
nu-table = { path = "../nu-table", version = "0.67.0" }
|
||||||
nu-term-grid = { path = "../nu-term-grid", version = "0.66.0" }
|
nu-term-grid = { path = "../nu-term-grid", version = "0.67.0" }
|
||||||
nu-test-support = { path = "../nu-test-support", version = "0.66.0" }
|
nu-test-support = { path = "../nu-test-support", version = "0.67.0" }
|
||||||
nu-utils = { path = "../nu-utils", version = "0.66.0" }
|
nu-utils = { path = "../nu-utils", version = "0.67.0" }
|
||||||
nu-ansi-term = "0.46.0"
|
nu-ansi-term = "0.46.0"
|
||||||
|
num-format = { version = "0.4.0" }
|
||||||
|
|
||||||
# Potential dependencies for extras
|
# Potential dependencies for extras
|
||||||
alphanumeric-sort = "1.4.4"
|
alphanumeric-sort = "1.4.4"
|
||||||
@ -31,16 +33,17 @@ base64 = "0.13.0"
|
|||||||
byteorder = "1.4.3"
|
byteorder = "1.4.3"
|
||||||
bytesize = "1.1.0"
|
bytesize = "1.1.0"
|
||||||
calamine = "0.18.0"
|
calamine = "0.18.0"
|
||||||
chrono = { version = "0.4.19", features = ["serde"] }
|
chrono = { version = "0.4.21", features = ["serde", "unstable-locales"] }
|
||||||
chrono-humanize = "0.2.1"
|
chrono-humanize = "0.2.1"
|
||||||
chrono-tz = "0.6.1"
|
chrono-tz = "0.6.3"
|
||||||
crossterm = "0.23.0"
|
crossterm = "0.24.0"
|
||||||
csv = "1.1.6"
|
csv = "1.1.6"
|
||||||
dialoguer = "0.9.0"
|
dialoguer = "0.9.0"
|
||||||
digest = "0.10.0"
|
digest = "0.10.0"
|
||||||
dtparse = "1.2.0"
|
dtparse = "1.2.0"
|
||||||
eml-parser = "0.1.0"
|
eml-parser = "0.1.0"
|
||||||
encoding_rs = "0.8.30"
|
encoding_rs = "0.8.30"
|
||||||
|
fancy-regex = "0.10.0"
|
||||||
filesize = "0.2.0"
|
filesize = "0.2.0"
|
||||||
filetime = "0.2.15"
|
filetime = "0.2.15"
|
||||||
fs_extra = "1.2.0"
|
fs_extra = "1.2.0"
|
||||||
@ -52,30 +55,30 @@ is-root = "0.1.2"
|
|||||||
itertools = "0.10.0"
|
itertools = "0.10.0"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
lscolors = { version = "0.10.0", features = ["crossterm"]}
|
lscolors = { version = "0.12.0", features = ["crossterm"]}
|
||||||
md5 = { package = "md-5", version = "0.10.0" }
|
md5 = { package = "md-5", version = "0.10.0" }
|
||||||
meval = "0.2.0"
|
meval = "0.2.0"
|
||||||
mime = "0.3.16"
|
mime = "0.3.16"
|
||||||
notify = "4.0.17"
|
notify = "4.0.17"
|
||||||
num = { version = "0.4.0", optional = true }
|
num = { version = "0.4.0", optional = true }
|
||||||
|
num-traits = "0.2.14"
|
||||||
pathdiff = "0.2.1"
|
pathdiff = "0.2.1"
|
||||||
powierza-coefficient = "1.0.1"
|
powierza-coefficient = "1.0.1"
|
||||||
quick-xml = "0.23.0"
|
quick-xml = "0.23.0"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
rayon = "1.5.1"
|
rayon = "1.5.1"
|
||||||
regex = "1.5.4"
|
|
||||||
reqwest = {version = "0.11", features = ["blocking", "json"] }
|
reqwest = {version = "0.11", features = ["blocking", "json"] }
|
||||||
roxmltree = "0.14.0"
|
roxmltree = "0.14.0"
|
||||||
rust-embed = "6.3.0"
|
rust-embed = "6.3.0"
|
||||||
serde = { version="1.0.123", features=["derive"] }
|
serde = { version="1.0.123", features=["derive"] }
|
||||||
serde_ini = "0.2.0"
|
serde_ini = "0.2.0"
|
||||||
serde_urlencoded = "0.7.0"
|
serde_urlencoded = "0.7.0"
|
||||||
serde_yaml = "0.8.16"
|
serde_yaml = "0.9.4"
|
||||||
sha2 = "0.10.0"
|
sha2 = "0.10.0"
|
||||||
# Disable default features b/c the default features build Git (very slow to compile)
|
# Disable default features b/c the default features build Git (very slow to compile)
|
||||||
shadow-rs = { version = "0.16.1", default-features = false }
|
shadow-rs = { version = "0.16.1", default-features = false }
|
||||||
strip-ansi-escapes = "0.1.1"
|
strip-ansi-escapes = "0.1.1"
|
||||||
sysinfo = "0.24.6"
|
sysinfo = "0.25.2"
|
||||||
terminal_size = "0.2.1"
|
terminal_size = "0.2.1"
|
||||||
thiserror = "1.0.31"
|
thiserror = "1.0.31"
|
||||||
titlecase = "2.0.0"
|
titlecase = "2.0.0"
|
||||||
@ -84,7 +87,7 @@ unicode-segmentation = "1.8.0"
|
|||||||
url = "2.2.1"
|
url = "2.2.1"
|
||||||
uuid = { version = "1.1.2", features = ["v4"] }
|
uuid = { version = "1.1.2", features = ["v4"] }
|
||||||
which = { version = "4.2.2", optional = true }
|
which = { version = "4.2.2", optional = true }
|
||||||
reedline = { version = "0.9.0", features = ["bashisms", "sqlite"]}
|
reedline = { version = "0.10.0", features = ["bashisms", "sqlite"]}
|
||||||
wax = { version = "0.5.0", features = ["diagnostics"] }
|
wax = { version = "0.5.0", features = ["diagnostics"] }
|
||||||
rusqlite = { version = "0.28.0", features = ["bundled"], optional = true }
|
rusqlite = { version = "0.28.0", features = ["bundled"], optional = true }
|
||||||
sqlparser = { version = "0.16.0", features = ["serde"], optional = true }
|
sqlparser = { version = "0.16.0", features = ["serde"], optional = true }
|
||||||
@ -98,15 +101,33 @@ version = "2.1.3"
|
|||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
[dependencies.polars]
|
[dependencies.polars]
|
||||||
version = "0.22.8"
|
version = "0.23.2"
|
||||||
# path = "../../../../polars/polars"
|
|
||||||
optional = true
|
optional = true
|
||||||
features = [
|
features = [
|
||||||
"default", "to_dummies", "parquet", "json", "serde", "serde-lazy",
|
"arg_where",
|
||||||
"object", "checked_arithmetic", "strings", "cum_agg", "is_in",
|
"checked_arithmetic",
|
||||||
"rolling_window", "strings", "rows", "random",
|
"concat_str",
|
||||||
"dtype-datetime", "dtype-struct", "lazy", "cross_join",
|
"cross_join",
|
||||||
"dynamic_groupby", "dtype-categorical", "concat_str"
|
"csv-file",
|
||||||
|
"cum_agg",
|
||||||
|
"default",
|
||||||
|
"dtype-datetime",
|
||||||
|
"dtype-struct",
|
||||||
|
"dtype-categorical",
|
||||||
|
"dynamic_groupby",
|
||||||
|
"is_in",
|
||||||
|
"json",
|
||||||
|
"lazy",
|
||||||
|
"object",
|
||||||
|
"parquet",
|
||||||
|
"random",
|
||||||
|
"rolling_window",
|
||||||
|
"rows",
|
||||||
|
"serde",
|
||||||
|
"serde-lazy",
|
||||||
|
"strings",
|
||||||
|
"strings",
|
||||||
|
"to_dummies",
|
||||||
]
|
]
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies.windows]
|
[target.'cfg(windows)'.dependencies.windows]
|
||||||
@ -133,4 +154,4 @@ hamcrest2 = "0.3.0"
|
|||||||
dirs-next = "2.0.0"
|
dirs-next = "2.0.0"
|
||||||
quickcheck = "1.0.3"
|
quickcheck = "1.0.3"
|
||||||
quickcheck_macros = "1.0.0"
|
quickcheck_macros = "1.0.0"
|
||||||
rstest = "0.15.0"
|
rstest = {version = "0.15.0", default-features = false}
|
||||||
|
@ -3,16 +3,18 @@ use std::process::Command;
|
|||||||
fn main() -> shadow_rs::SdResult<()> {
|
fn main() -> shadow_rs::SdResult<()> {
|
||||||
// Look up the current Git commit ourselves instead of relying on shadow_rs,
|
// Look up the current Git commit ourselves instead of relying on shadow_rs,
|
||||||
// because shadow_rs does it in a really slow-to-compile way (it builds libgit2)
|
// because shadow_rs does it in a really slow-to-compile way (it builds libgit2)
|
||||||
let hash = get_git_hash().expect("failed to get latest git commit hash");
|
let hash = get_git_hash().unwrap_or_default();
|
||||||
println!("cargo:rustc-env=NU_COMMIT_HASH={}", hash);
|
println!("cargo:rustc-env=NU_COMMIT_HASH={}", hash);
|
||||||
|
|
||||||
shadow_rs::new()
|
shadow_rs::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_git_hash() -> Result<String, std::io::Error> {
|
fn get_git_hash() -> Option<String> {
|
||||||
let out = Command::new("git").args(["rev-parse", "HEAD"]).output()?;
|
Command::new("git")
|
||||||
Ok(String::from_utf8(out.stdout)
|
.args(["rev-parse", "HEAD"])
|
||||||
.expect("could not convert stdout to string")
|
.output()
|
||||||
.trim()
|
.ok()
|
||||||
.to_string())
|
.filter(|output| output.status.success())
|
||||||
|
.and_then(|output| String::from_utf8(output.stdout).ok())
|
||||||
|
.map(|hash| hash.trim().to_string())
|
||||||
}
|
}
|
||||||
|
100
crates/nu-command/src/bits/and.rs
Normal file
100
crates/nu-command/src/bits/and.rs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::{
|
||||||
|
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SubCommand;
|
||||||
|
|
||||||
|
impl Command for SubCommand {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"bits and"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("bits and")
|
||||||
|
.required(
|
||||||
|
"target",
|
||||||
|
SyntaxShape::Int,
|
||||||
|
"target integer to perform bit and",
|
||||||
|
)
|
||||||
|
.category(Category::Bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Performs bitwise and for integers"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["logic and"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
let head = call.head;
|
||||||
|
let target: i64 = call.req(engine_state, stack, 0)?;
|
||||||
|
|
||||||
|
input.map(
|
||||||
|
move |value| operate(value, target, head),
|
||||||
|
engine_state.ctrlc.clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![
|
||||||
|
Example {
|
||||||
|
description: "Apply bits and to two numbers",
|
||||||
|
example: "2 | bits and 2",
|
||||||
|
result: Some(Value::Int {
|
||||||
|
val: 2,
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
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(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn operate(value: Value, target: i64, head: Span) -> Value {
|
||||||
|
match value {
|
||||||
|
Value::Int { val, span } => Value::Int {
|
||||||
|
val: val & target,
|
||||||
|
span,
|
||||||
|
},
|
||||||
|
other => Value::Error {
|
||||||
|
error: ShellError::UnsupportedInput(
|
||||||
|
format!(
|
||||||
|
"Only integer values are supported, input type: {:?}",
|
||||||
|
other.get_type()
|
||||||
|
),
|
||||||
|
other.span().unwrap_or(head),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
use crate::test_examples;
|
||||||
|
|
||||||
|
test_examples(SubCommand {})
|
||||||
|
}
|
||||||
|
}
|
49
crates/nu-command/src/bits/bits_.rs
Normal file
49
crates/nu-command/src/bits/bits_.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
use nu_engine::get_full_help;
|
||||||
|
use nu_protocol::{
|
||||||
|
ast::Call,
|
||||||
|
engine::{Command, EngineState, Stack},
|
||||||
|
Category, IntoPipelineData, PipelineData, Signature, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Bits;
|
||||||
|
|
||||||
|
impl Command for Bits {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"bits"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("bits").category(Category::Bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Various commands for working with bits"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
_input: PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
Ok(Value::String {
|
||||||
|
val: get_full_help(&Bits.signature(), &Bits.examples(), engine_state, stack),
|
||||||
|
span: call.head,
|
||||||
|
}
|
||||||
|
.into_pipeline_data())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::Bits;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
use crate::test_examples;
|
||||||
|
|
||||||
|
test_examples(Bits {})
|
||||||
|
}
|
||||||
|
}
|
99
crates/nu-command/src/bits/mod.rs
Normal file
99
crates/nu-command/src/bits/mod.rs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
mod and;
|
||||||
|
mod bits_;
|
||||||
|
mod not;
|
||||||
|
mod or;
|
||||||
|
mod rotate_left;
|
||||||
|
mod rotate_right;
|
||||||
|
mod shift_left;
|
||||||
|
mod shift_right;
|
||||||
|
mod xor;
|
||||||
|
|
||||||
|
use nu_protocol::Spanned;
|
||||||
|
|
||||||
|
pub use and::SubCommand as BitsAnd;
|
||||||
|
pub use bits_::Bits;
|
||||||
|
pub use not::SubCommand as BitsNot;
|
||||||
|
pub use or::SubCommand as BitsOr;
|
||||||
|
pub use rotate_left::SubCommand as BitsRotateLeft;
|
||||||
|
pub use rotate_right::SubCommand as BitsRotateRight;
|
||||||
|
pub use shift_left::SubCommand as BitsShiftLeft;
|
||||||
|
pub use shift_right::SubCommand as BitsShiftRight;
|
||||||
|
pub use xor::SubCommand as BitsXor;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum NumberBytes {
|
||||||
|
One,
|
||||||
|
Two,
|
||||||
|
Four,
|
||||||
|
Eight,
|
||||||
|
Auto,
|
||||||
|
Invalid,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum InputNumType {
|
||||||
|
One,
|
||||||
|
Two,
|
||||||
|
Four,
|
||||||
|
Eight,
|
||||||
|
SignedOne,
|
||||||
|
SignedTwo,
|
||||||
|
SignedFour,
|
||||||
|
SignedEight,
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
||||||
|
"1" => NumberBytes::One,
|
||||||
|
"2" => NumberBytes::Two,
|
||||||
|
"4" => NumberBytes::Four,
|
||||||
|
"8" => NumberBytes::Eight,
|
||||||
|
"auto" => NumberBytes::Auto,
|
||||||
|
_ => NumberBytes::Invalid,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_input_num_type(val: i64, signed: bool, number_size: NumberBytes) -> InputNumType {
|
||||||
|
if signed || val < 0 {
|
||||||
|
match number_size {
|
||||||
|
NumberBytes::One => InputNumType::SignedOne,
|
||||||
|
NumberBytes::Two => InputNumType::SignedTwo,
|
||||||
|
NumberBytes::Four => InputNumType::SignedFour,
|
||||||
|
NumberBytes::Eight => InputNumType::SignedEight,
|
||||||
|
NumberBytes::Auto => {
|
||||||
|
if val <= 0x7F && val >= -(2i64.pow(7)) {
|
||||||
|
InputNumType::SignedOne
|
||||||
|
} else if val <= 0x7FFF && val >= -(2i64.pow(15)) {
|
||||||
|
InputNumType::SignedTwo
|
||||||
|
} else if val <= 0x7FFFFFFF && val >= -(2i64.pow(31)) {
|
||||||
|
InputNumType::SignedFour
|
||||||
|
} else {
|
||||||
|
InputNumType::SignedEight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NumberBytes::Invalid => InputNumType::SignedFour,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match number_size {
|
||||||
|
NumberBytes::One => InputNumType::One,
|
||||||
|
NumberBytes::Two => InputNumType::Two,
|
||||||
|
NumberBytes::Four => InputNumType::Four,
|
||||||
|
NumberBytes::Eight => InputNumType::Eight,
|
||||||
|
NumberBytes::Auto => {
|
||||||
|
if val <= 0xFF {
|
||||||
|
InputNumType::One
|
||||||
|
} else if val <= 0xFFFF {
|
||||||
|
InputNumType::Two
|
||||||
|
} else if val <= 0xFFFFFFFF {
|
||||||
|
InputNumType::Four
|
||||||
|
} else {
|
||||||
|
InputNumType::Eight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NumberBytes::Invalid => InputNumType::Four,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
163
crates/nu-command/src/bits/not.rs
Normal file
163
crates/nu-command/src/bits/not.rs
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
use super::{get_number_bytes, NumberBytes};
|
||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::{
|
||||||
|
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SubCommand;
|
||||||
|
|
||||||
|
impl Command for SubCommand {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"bits not"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("bits not")
|
||||||
|
.switch(
|
||||||
|
"signed",
|
||||||
|
"always treat input number as a signed number",
|
||||||
|
Some('s'),
|
||||||
|
)
|
||||||
|
.named(
|
||||||
|
"number-bytes",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"the size of unsigned number in bytes, it can be 1, 2, 4, 8, auto",
|
||||||
|
Some('n'),
|
||||||
|
)
|
||||||
|
.category(Category::Bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Performs logical negation on each bit"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["negation"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
let head = call.head;
|
||||||
|
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);
|
||||||
|
if let NumberBytes::Invalid = bytes_len {
|
||||||
|
if let Some(val) = number_bytes {
|
||||||
|
return Err(ShellError::UnsupportedInput(
|
||||||
|
"Only 1, 2, 4, 8, or 'auto' bytes are supported as word sizes".to_string(),
|
||||||
|
val.span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input.map(
|
||||||
|
move |value| operate(value, head, signed, bytes_len),
|
||||||
|
engine_state.ctrlc.clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![
|
||||||
|
Example {
|
||||||
|
description: "Apply logical negation to a list of numbers",
|
||||||
|
example: "[4 3 2] | bits not",
|
||||||
|
result: Some(Value::List {
|
||||||
|
vals: vec![
|
||||||
|
Value::test_int(140737488355323),
|
||||||
|
Value::test_int(140737488355324),
|
||||||
|
Value::test_int(140737488355325),
|
||||||
|
],
|
||||||
|
span: 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![
|
||||||
|
Value::test_int(65531),
|
||||||
|
Value::test_int(65532),
|
||||||
|
Value::test_int(65533),
|
||||||
|
],
|
||||||
|
span: 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![
|
||||||
|
Value::test_int(-5),
|
||||||
|
Value::test_int(-4),
|
||||||
|
Value::test_int(-3),
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn operate(value: Value, head: Span, signed: bool, number_size: NumberBytes) -> Value {
|
||||||
|
match value {
|
||||||
|
Value::Int { val, span } => {
|
||||||
|
if signed || val < 0 {
|
||||||
|
Value::Int { val: !val, span }
|
||||||
|
} else {
|
||||||
|
use NumberBytes::*;
|
||||||
|
let out_val = match number_size {
|
||||||
|
One => !val & 0x00_00_00_00_00_FF,
|
||||||
|
Two => !val & 0x00_00_00_00_FF_FF,
|
||||||
|
Four => !val & 0x00_00_FF_FF_FF_FF,
|
||||||
|
Eight => !val & 0x7F_FF_FF_FF_FF_FF,
|
||||||
|
Auto => {
|
||||||
|
if val <= 0xFF {
|
||||||
|
!val & 0x00_00_00_00_00_FF
|
||||||
|
} else if val <= 0xFF_FF {
|
||||||
|
!val & 0x00_00_00_00_FF_FF
|
||||||
|
} else if val <= 0xFF_FF_FF_FF {
|
||||||
|
!val & 0x00_00_FF_FF_FF_FF
|
||||||
|
} else {
|
||||||
|
!val & 0x7F_FF_FF_FF_FF_FF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// This case shouldn't happen here, as it's handled before
|
||||||
|
Invalid => 0,
|
||||||
|
};
|
||||||
|
Value::Int { val: out_val, span }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other => Value::Error {
|
||||||
|
error: ShellError::UnsupportedInput(
|
||||||
|
format!(
|
||||||
|
"Only numerical values are supported, input type: {:?}",
|
||||||
|
other.get_type()
|
||||||
|
),
|
||||||
|
other.span().unwrap_or(head),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
use crate::test_examples;
|
||||||
|
|
||||||
|
test_examples(SubCommand {})
|
||||||
|
}
|
||||||
|
}
|
100
crates/nu-command/src/bits/or.rs
Normal file
100
crates/nu-command/src/bits/or.rs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::{
|
||||||
|
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SubCommand;
|
||||||
|
|
||||||
|
impl Command for SubCommand {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"bits or"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("bits or")
|
||||||
|
.required(
|
||||||
|
"target",
|
||||||
|
SyntaxShape::Int,
|
||||||
|
"target integer to perform bit or",
|
||||||
|
)
|
||||||
|
.category(Category::Bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Performs bitwise or for integers"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["logic or"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
let head = call.head;
|
||||||
|
let target: i64 = call.req(engine_state, stack, 0)?;
|
||||||
|
|
||||||
|
input.map(
|
||||||
|
move |value| operate(value, target, head),
|
||||||
|
engine_state.ctrlc.clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![
|
||||||
|
Example {
|
||||||
|
description: "Apply bits or to two numbers",
|
||||||
|
example: "2 | bits or 6",
|
||||||
|
result: Some(Value::Int {
|
||||||
|
val: 6,
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
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(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn operate(value: Value, target: i64, head: Span) -> Value {
|
||||||
|
match value {
|
||||||
|
Value::Int { val, span } => Value::Int {
|
||||||
|
val: val | target,
|
||||||
|
span,
|
||||||
|
},
|
||||||
|
other => Value::Error {
|
||||||
|
error: ShellError::UnsupportedInput(
|
||||||
|
format!(
|
||||||
|
"Only integer values are supported, input type: {:?}",
|
||||||
|
other.get_type()
|
||||||
|
),
|
||||||
|
other.span().unwrap_or(head),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
use crate::test_examples;
|
||||||
|
|
||||||
|
test_examples(SubCommand {})
|
||||||
|
}
|
||||||
|
}
|
156
crates/nu-command/src/bits/rotate_left.rs
Normal file
156
crates/nu-command/src/bits/rotate_left.rs
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
use super::{get_input_num_type, get_number_bytes, InputNumType, NumberBytes};
|
||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::{
|
||||||
|
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value,
|
||||||
|
};
|
||||||
|
use num_traits::int::PrimInt;
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SubCommand;
|
||||||
|
|
||||||
|
impl Command for SubCommand {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"bits rol"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("bits rol")
|
||||||
|
.required("bits", SyntaxShape::Int, "number of bits to rotate left")
|
||||||
|
.switch(
|
||||||
|
"signed",
|
||||||
|
"always treat input number as a signed number",
|
||||||
|
Some('s'),
|
||||||
|
)
|
||||||
|
.named(
|
||||||
|
"number-bytes",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"the word size in number of bytes, it can be 1, 2, 4, 8, auto, default value `8`",
|
||||||
|
Some('n'),
|
||||||
|
)
|
||||||
|
.category(Category::Bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Bitwise rotate left for integers"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["rotate left"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
let head = call.head;
|
||||||
|
let bits: usize = call.req(engine_state, stack, 0)?;
|
||||||
|
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);
|
||||||
|
if let NumberBytes::Invalid = bytes_len {
|
||||||
|
if let Some(val) = number_bytes {
|
||||||
|
return Err(ShellError::UnsupportedInput(
|
||||||
|
"Only 1, 2, 4, 8, or 'auto' bytes are supported as word sizes".to_string(),
|
||||||
|
val.span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input.map(
|
||||||
|
move |value| operate(value, bits, head, signed, bytes_len),
|
||||||
|
engine_state.ctrlc.clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![
|
||||||
|
Example {
|
||||||
|
description: "Rotate left a number with 2 bits",
|
||||||
|
example: "17 | bits rol 2",
|
||||||
|
result: Some(Value::Int {
|
||||||
|
val: 68,
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Rotate left a list of numbers with 2 bits",
|
||||||
|
example: "[5 3 2] | bits rol 2",
|
||||||
|
result: Some(Value::List {
|
||||||
|
vals: vec![Value::test_int(20), Value::test_int(12), Value::test_int(8)],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_rotate_left<T: Display + PrimInt>(val: T, bits: u32, span: Span) -> Value
|
||||||
|
where
|
||||||
|
i64: std::convert::TryFrom<T>,
|
||||||
|
{
|
||||||
|
let rotate_result = i64::try_from(val.rotate_left(bits));
|
||||||
|
match rotate_result {
|
||||||
|
Ok(val) => Value::Int { val, span },
|
||||||
|
Err(_) => Value::Error {
|
||||||
|
error: ShellError::GenericError(
|
||||||
|
"Rotate left result beyond the range of 64 bit signed number".to_string(),
|
||||||
|
format!(
|
||||||
|
"{} of the specified number of bytes rotate left {} bits exceed limit",
|
||||||
|
val, bits
|
||||||
|
),
|
||||||
|
Some(span),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: NumberBytes) -> Value {
|
||||||
|
match value {
|
||||||
|
Value::Int { val, span } => {
|
||||||
|
use InputNumType::*;
|
||||||
|
// let bits = (((bits % 64) + 64) % 64) as u32;
|
||||||
|
let bits = bits as u32;
|
||||||
|
let input_type = get_input_num_type(val, signed, number_size);
|
||||||
|
match input_type {
|
||||||
|
One => get_rotate_left(val as u8, bits, span),
|
||||||
|
Two => get_rotate_left(val as u16, bits, span),
|
||||||
|
Four => get_rotate_left(val as u32, bits, span),
|
||||||
|
Eight => get_rotate_left(val as u64, bits, span),
|
||||||
|
SignedOne => get_rotate_left(val as i8, bits, span),
|
||||||
|
SignedTwo => get_rotate_left(val as i16, bits, span),
|
||||||
|
SignedFour => get_rotate_left(val as i32, bits, span),
|
||||||
|
SignedEight => get_rotate_left(val as i64, bits, span),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other => Value::Error {
|
||||||
|
error: ShellError::UnsupportedInput(
|
||||||
|
format!(
|
||||||
|
"Only integer values are supported, input type: {:?}",
|
||||||
|
other.get_type()
|
||||||
|
),
|
||||||
|
other.span().unwrap_or(head),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
use crate::test_examples;
|
||||||
|
|
||||||
|
test_examples(SubCommand {})
|
||||||
|
}
|
||||||
|
}
|
160
crates/nu-command/src/bits/rotate_right.rs
Normal file
160
crates/nu-command/src/bits/rotate_right.rs
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
use super::{get_input_num_type, get_number_bytes, InputNumType, NumberBytes};
|
||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::{
|
||||||
|
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value,
|
||||||
|
};
|
||||||
|
use num_traits::int::PrimInt;
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SubCommand;
|
||||||
|
|
||||||
|
impl Command for SubCommand {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"bits ror"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("bits ror")
|
||||||
|
.required("bits", SyntaxShape::Int, "number of bits to rotate right")
|
||||||
|
.switch(
|
||||||
|
"signed",
|
||||||
|
"always treat input number as a signed number",
|
||||||
|
Some('s'),
|
||||||
|
)
|
||||||
|
.named(
|
||||||
|
"number-bytes",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"the word size in number of bytes, it can be 1, 2, 4, 8, auto, default value `8`",
|
||||||
|
Some('n'),
|
||||||
|
)
|
||||||
|
.category(Category::Bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Bitwise rotate right for integers"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["rotate right"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
let head = call.head;
|
||||||
|
let bits: usize = call.req(engine_state, stack, 0)?;
|
||||||
|
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);
|
||||||
|
if let NumberBytes::Invalid = bytes_len {
|
||||||
|
if let Some(val) = number_bytes {
|
||||||
|
return Err(ShellError::UnsupportedInput(
|
||||||
|
"Only 1, 2, 4, 8, or 'auto' bytes are supported as word sizes".to_string(),
|
||||||
|
val.span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input.map(
|
||||||
|
move |value| operate(value, bits, head, signed, bytes_len),
|
||||||
|
engine_state.ctrlc.clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![
|
||||||
|
Example {
|
||||||
|
description: "Rotate right a number with 60 bits",
|
||||||
|
example: "17 | bits ror 60",
|
||||||
|
result: Some(Value::Int {
|
||||||
|
val: 272,
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Rotate right a list of numbers of one byte",
|
||||||
|
example: "[15 33 92] | bits ror 2 -n 1",
|
||||||
|
result: Some(Value::List {
|
||||||
|
vals: vec![
|
||||||
|
Value::test_int(195),
|
||||||
|
Value::test_int(72),
|
||||||
|
Value::test_int(23),
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_rotate_right<T: Display + PrimInt>(val: T, bits: u32, span: Span) -> Value
|
||||||
|
where
|
||||||
|
i64: std::convert::TryFrom<T>,
|
||||||
|
{
|
||||||
|
let rotate_result = i64::try_from(val.rotate_right(bits));
|
||||||
|
match rotate_result {
|
||||||
|
Ok(val) => Value::Int { val, span },
|
||||||
|
Err(_) => Value::Error {
|
||||||
|
error: ShellError::GenericError(
|
||||||
|
"Rotate right result beyond the range of 64 bit signed number".to_string(),
|
||||||
|
format!(
|
||||||
|
"{} of the specified number of bytes rotate right {} bits exceed limit",
|
||||||
|
val, bits
|
||||||
|
),
|
||||||
|
Some(span),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: NumberBytes) -> Value {
|
||||||
|
match value {
|
||||||
|
Value::Int { val, span } => {
|
||||||
|
use InputNumType::*;
|
||||||
|
// let bits = (((bits % 64) + 64) % 64) as u32;
|
||||||
|
let bits = bits as u32;
|
||||||
|
let input_type = get_input_num_type(val, signed, number_size);
|
||||||
|
match input_type {
|
||||||
|
One => get_rotate_right(val as u8, bits, span),
|
||||||
|
Two => get_rotate_right(val as u16, bits, span),
|
||||||
|
Four => get_rotate_right(val as u32, bits, span),
|
||||||
|
Eight => get_rotate_right(val as u64, bits, span),
|
||||||
|
SignedOne => get_rotate_right(val as i8, bits, span),
|
||||||
|
SignedTwo => get_rotate_right(val as i16, bits, span),
|
||||||
|
SignedFour => get_rotate_right(val as i32, bits, span),
|
||||||
|
SignedEight => get_rotate_right(val as i64, bits, span),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other => Value::Error {
|
||||||
|
error: ShellError::UnsupportedInput(
|
||||||
|
format!(
|
||||||
|
"Only integer values are supported, input type: {:?}",
|
||||||
|
other.get_type()
|
||||||
|
),
|
||||||
|
other.span().unwrap_or(head),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
use crate::test_examples;
|
||||||
|
|
||||||
|
test_examples(SubCommand {})
|
||||||
|
}
|
||||||
|
}
|
188
crates/nu-command/src/bits/shift_left.rs
Normal file
188
crates/nu-command/src/bits/shift_left.rs
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
use super::{get_input_num_type, get_number_bytes, InputNumType, NumberBytes};
|
||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::{
|
||||||
|
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value,
|
||||||
|
};
|
||||||
|
use num_traits::CheckedShl;
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SubCommand;
|
||||||
|
|
||||||
|
impl Command for SubCommand {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"bits shl"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("bits shl")
|
||||||
|
.required("bits", SyntaxShape::Int, "number of bits to shift left")
|
||||||
|
.switch(
|
||||||
|
"signed",
|
||||||
|
"always treat input number as a signed number",
|
||||||
|
Some('s'),
|
||||||
|
)
|
||||||
|
.named(
|
||||||
|
"number-bytes",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"the word size in number of bytes, it can be 1, 2, 4, 8, auto, default value `8`",
|
||||||
|
Some('n'),
|
||||||
|
)
|
||||||
|
.category(Category::Bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Bitwise shift left for integers"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["shift left"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
let head = call.head;
|
||||||
|
let bits: usize = call.req(engine_state, stack, 0)?;
|
||||||
|
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);
|
||||||
|
if let NumberBytes::Invalid = bytes_len {
|
||||||
|
if let Some(val) = number_bytes {
|
||||||
|
return Err(ShellError::UnsupportedInput(
|
||||||
|
"Only 1, 2, 4, 8, or 'auto' bytes are supported as word sizes".to_string(),
|
||||||
|
val.span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input.map(
|
||||||
|
move |value| operate(value, bits, head, signed, bytes_len),
|
||||||
|
engine_state.ctrlc.clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![
|
||||||
|
Example {
|
||||||
|
description: "Shift left a number by 7 bits",
|
||||||
|
example: "2 | bits shl 7",
|
||||||
|
result: Some(Value::Int {
|
||||||
|
val: 256,
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Shift left a number with 1 byte by 7 bits",
|
||||||
|
example: "2 | bits shl 7 -n 1",
|
||||||
|
result: Some(Value::Int {
|
||||||
|
val: 0,
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Shift left a signed number by 1 bit",
|
||||||
|
example: "0x7F | bits shl 1 -s",
|
||||||
|
result: Some(Value::Int {
|
||||||
|
val: 254,
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Shift left a list of numbers",
|
||||||
|
example: "[5 3 2] | bits shl 2",
|
||||||
|
result: Some(Value::List {
|
||||||
|
vals: vec![Value::test_int(20), Value::test_int(12), Value::test_int(8)],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_shift_left<T: CheckedShl + Display + Copy>(val: T, bits: u32, span: Span) -> Value
|
||||||
|
where
|
||||||
|
i64: std::convert::TryFrom<T>,
|
||||||
|
{
|
||||||
|
match val.checked_shl(bits) {
|
||||||
|
Some(val) => {
|
||||||
|
let shift_result = i64::try_from(val);
|
||||||
|
match shift_result {
|
||||||
|
Ok(val) => Value::Int { val, span },
|
||||||
|
Err(_) => Value::Error {
|
||||||
|
error: ShellError::GenericError(
|
||||||
|
"Shift left result beyond the range of 64 bit signed number".to_string(),
|
||||||
|
format!(
|
||||||
|
"{} of the specified number of bytes shift left {} bits exceed limit",
|
||||||
|
val, bits
|
||||||
|
),
|
||||||
|
Some(span),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => Value::Error {
|
||||||
|
error: ShellError::GenericError(
|
||||||
|
"Shift left failed".to_string(),
|
||||||
|
format!(
|
||||||
|
"{} shift left {} bits failed, you may shift too many bits",
|
||||||
|
val, bits
|
||||||
|
),
|
||||||
|
Some(span),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: NumberBytes) -> Value {
|
||||||
|
match value {
|
||||||
|
Value::Int { val, span } => {
|
||||||
|
use InputNumType::*;
|
||||||
|
// let bits = (((bits % 64) + 64) % 64) as u32;
|
||||||
|
let bits = bits as u32;
|
||||||
|
let input_type = get_input_num_type(val, signed, number_size);
|
||||||
|
match input_type {
|
||||||
|
One => get_shift_left(val as u8, bits, span),
|
||||||
|
Two => get_shift_left(val as u16, bits, span),
|
||||||
|
Four => get_shift_left(val as u32, bits, span),
|
||||||
|
Eight => get_shift_left(val as u64, bits, span),
|
||||||
|
SignedOne => get_shift_left(val as i8, bits, span),
|
||||||
|
SignedTwo => get_shift_left(val as i16, bits, span),
|
||||||
|
SignedFour => get_shift_left(val as i32, bits, span),
|
||||||
|
SignedEight => get_shift_left(val as i64, bits, span),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other => Value::Error {
|
||||||
|
error: ShellError::UnsupportedInput(
|
||||||
|
format!(
|
||||||
|
"Only integer values are supported, input type: {:?}",
|
||||||
|
other.get_type()
|
||||||
|
),
|
||||||
|
other.span().unwrap_or(head),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
use crate::test_examples;
|
||||||
|
|
||||||
|
test_examples(SubCommand {})
|
||||||
|
}
|
||||||
|
}
|
172
crates/nu-command/src/bits/shift_right.rs
Normal file
172
crates/nu-command/src/bits/shift_right.rs
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
use super::{get_input_num_type, get_number_bytes, InputNumType, NumberBytes};
|
||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::{
|
||||||
|
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value,
|
||||||
|
};
|
||||||
|
use num_traits::CheckedShr;
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SubCommand;
|
||||||
|
|
||||||
|
impl Command for SubCommand {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"bits shr"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("bits shr")
|
||||||
|
.required("bits", SyntaxShape::Int, "number of bits to shift right")
|
||||||
|
.switch(
|
||||||
|
"signed",
|
||||||
|
"always treat input number as a signed number",
|
||||||
|
Some('s'),
|
||||||
|
)
|
||||||
|
.named(
|
||||||
|
"number-bytes",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"the word size in number of bytes, it can be 1, 2, 4, 8, auto, default value `8`",
|
||||||
|
Some('n'),
|
||||||
|
)
|
||||||
|
.category(Category::Bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Bitwise shift right for integers"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["shift right"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
let head = call.head;
|
||||||
|
let bits: usize = call.req(engine_state, stack, 0)?;
|
||||||
|
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);
|
||||||
|
if let NumberBytes::Invalid = bytes_len {
|
||||||
|
if let Some(val) = number_bytes {
|
||||||
|
return Err(ShellError::UnsupportedInput(
|
||||||
|
"Only 1, 2, 4, 8, or 'auto' bytes are supported as word sizes".to_string(),
|
||||||
|
val.span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input.map(
|
||||||
|
move |value| operate(value, bits, head, signed, bytes_len),
|
||||||
|
engine_state.ctrlc.clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![
|
||||||
|
Example {
|
||||||
|
description: "Shift right a number with 2 bits",
|
||||||
|
example: "8 | bits shr 2",
|
||||||
|
result: Some(Value::Int {
|
||||||
|
val: 2,
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Shift right a list of numbers",
|
||||||
|
example: "[15 35 2] | bits shr 2",
|
||||||
|
result: Some(Value::List {
|
||||||
|
vals: vec![Value::test_int(3), Value::test_int(8), Value::test_int(0)],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_shift_right<T: CheckedShr + Display + Copy>(val: T, bits: u32, span: Span) -> Value
|
||||||
|
where
|
||||||
|
i64: std::convert::TryFrom<T>,
|
||||||
|
{
|
||||||
|
match val.checked_shr(bits) {
|
||||||
|
Some(val) => {
|
||||||
|
let shift_result = i64::try_from(val);
|
||||||
|
match shift_result {
|
||||||
|
Ok(val) => Value::Int { val, span },
|
||||||
|
Err(_) => Value::Error {
|
||||||
|
error: ShellError::GenericError(
|
||||||
|
"Shift right result beyond the range of 64 bit signed number".to_string(),
|
||||||
|
format!(
|
||||||
|
"{} of the specified number of bytes shift right {} bits exceed limit",
|
||||||
|
val, bits
|
||||||
|
),
|
||||||
|
Some(span),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => Value::Error {
|
||||||
|
error: ShellError::GenericError(
|
||||||
|
"Shift right failed".to_string(),
|
||||||
|
format!(
|
||||||
|
"{} shift right {} bits failed, you may shift too many bits",
|
||||||
|
val, bits
|
||||||
|
),
|
||||||
|
Some(span),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn operate(value: Value, bits: usize, head: Span, signed: bool, number_size: NumberBytes) -> Value {
|
||||||
|
match value {
|
||||||
|
Value::Int { val, span } => {
|
||||||
|
use InputNumType::*;
|
||||||
|
// let bits = (((bits % 64) + 64) % 64) as u32;
|
||||||
|
let bits = bits as u32;
|
||||||
|
let input_type = get_input_num_type(val, signed, number_size);
|
||||||
|
match input_type {
|
||||||
|
One => get_shift_right(val as u8, bits, span),
|
||||||
|
Two => get_shift_right(val as u16, bits, span),
|
||||||
|
Four => get_shift_right(val as u32, bits, span),
|
||||||
|
Eight => get_shift_right(val as u64, bits, span),
|
||||||
|
SignedOne => get_shift_right(val as i8, bits, span),
|
||||||
|
SignedTwo => get_shift_right(val as i16, bits, span),
|
||||||
|
SignedFour => get_shift_right(val as i32, bits, span),
|
||||||
|
SignedEight => get_shift_right(val as i64, bits, span),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other => Value::Error {
|
||||||
|
error: ShellError::UnsupportedInput(
|
||||||
|
format!(
|
||||||
|
"Only integer values are supported, input type: {:?}",
|
||||||
|
other.get_type()
|
||||||
|
),
|
||||||
|
other.span().unwrap_or(head),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
use crate::test_examples;
|
||||||
|
|
||||||
|
test_examples(SubCommand {})
|
||||||
|
}
|
||||||
|
}
|
100
crates/nu-command/src/bits/xor.rs
Normal file
100
crates/nu-command/src/bits/xor.rs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::{
|
||||||
|
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SubCommand;
|
||||||
|
|
||||||
|
impl Command for SubCommand {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"bits xor"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("bits xor")
|
||||||
|
.required(
|
||||||
|
"target",
|
||||||
|
SyntaxShape::Int,
|
||||||
|
"target integer to perform bit xor",
|
||||||
|
)
|
||||||
|
.category(Category::Bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Performs bitwise xor for integers"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["logic xor"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
let head = call.head;
|
||||||
|
let target: i64 = call.req(engine_state, stack, 0)?;
|
||||||
|
|
||||||
|
input.map(
|
||||||
|
move |value| operate(value, target, head),
|
||||||
|
engine_state.ctrlc.clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![
|
||||||
|
Example {
|
||||||
|
description: "Apply bits xor to two numbers",
|
||||||
|
example: "2 | bits xor 2",
|
||||||
|
result: Some(Value::Int {
|
||||||
|
val: 0,
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Apply logical xor to a list of numbers",
|
||||||
|
example: "[8 3 2] | bits xor 2",
|
||||||
|
result: Some(Value::List {
|
||||||
|
vals: vec![Value::test_int(10), Value::test_int(1), Value::test_int(0)],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn operate(value: Value, target: i64, head: Span) -> Value {
|
||||||
|
match value {
|
||||||
|
Value::Int { val, span } => Value::Int {
|
||||||
|
val: val ^ target,
|
||||||
|
span,
|
||||||
|
},
|
||||||
|
other => Value::Error {
|
||||||
|
error: ShellError::UnsupportedInput(
|
||||||
|
format!(
|
||||||
|
"Only integer values are supported, input type: {:?}",
|
||||||
|
other.get_type()
|
||||||
|
),
|
||||||
|
other.span().unwrap_or(head),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
use crate::test_examples;
|
||||||
|
|
||||||
|
test_examples(SubCommand {})
|
||||||
|
}
|
||||||
|
}
|
@ -47,7 +47,7 @@ impl Command for BytesAdd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
"add specified bytes to the input"
|
"Add specified bytes to the input"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
@ -41,7 +41,7 @@ impl Command for BytesRemove {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
"remove bytes"
|
"Remove bytes"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
@ -311,7 +311,7 @@ fn action(
|
|||||||
Some(dt) => match DateTime::parse_from_str(val, &dt.0) {
|
Some(dt) => match DateTime::parse_from_str(val, &dt.0) {
|
||||||
Ok(d) => Value::Date { val: d, span: head },
|
Ok(d) => Value::Date { val: d, span: head },
|
||||||
Err(reason) => {
|
Err(reason) => {
|
||||||
return Value::Error {
|
Value::Error {
|
||||||
error: ShellError::CantConvert(
|
error: ShellError::CantConvert(
|
||||||
format!("could not parse as datetime using format '{}'", dt.0),
|
format!("could not parse as datetime using format '{}'", dt.0),
|
||||||
reason.to_string(),
|
reason.to_string(),
|
||||||
|
@ -42,7 +42,7 @@ impl Command for SubCommand {
|
|||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "Convert string to integer in table",
|
description: "Convert string to decimal in table",
|
||||||
example: "[[num]; ['5.01']] | into decimal num",
|
example: "[[num]; ['5.01']] | into decimal num",
|
||||||
result: Some(Value::List {
|
result: Some(Value::List {
|
||||||
vals: vec![Value::Record {
|
vals: vec![Value::Record {
|
||||||
@ -54,15 +54,20 @@ impl Command for SubCommand {
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Convert string to integer",
|
description: "Convert string to decimal",
|
||||||
example: "'1.345' | into decimal",
|
example: "'1.345' | into decimal",
|
||||||
result: Some(Value::test_float(1.345)),
|
result: Some(Value::test_float(1.345)),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Convert decimal to integer",
|
description: "Convert decimal to decimal",
|
||||||
example: "'-5.9' | into decimal",
|
example: "'-5.9' | into decimal",
|
||||||
result: Some(Value::test_float(-5.9)),
|
result: Some(Value::test_float(-5.9)),
|
||||||
},
|
},
|
||||||
|
Example {
|
||||||
|
description: "Convert boolean to decimal",
|
||||||
|
example: "true | into decimal",
|
||||||
|
result: Some(Value::test_float(1.0)),
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,6 +123,13 @@ fn action(input: &Value, head: Span) -> Value {
|
|||||||
val: *v as f64,
|
val: *v as f64,
|
||||||
span: *span,
|
span: *span,
|
||||||
},
|
},
|
||||||
|
Value::Bool { val: b, span } => Value::Float {
|
||||||
|
val: match b {
|
||||||
|
true => 1.0,
|
||||||
|
false => 0.0,
|
||||||
|
},
|
||||||
|
span: *span,
|
||||||
|
},
|
||||||
other => {
|
other => {
|
||||||
let span = other.span();
|
let span = other.span();
|
||||||
match span {
|
match span {
|
||||||
|
@ -5,8 +5,8 @@ use nu_protocol::{
|
|||||||
into_code, Category, Config, Example, IntoPipelineData, PipelineData, ShellError, Signature,
|
into_code, Category, Config, Example, IntoPipelineData, PipelineData, ShellError, Signature,
|
||||||
Span, SyntaxShape, Value,
|
Span, SyntaxShape, Value,
|
||||||
};
|
};
|
||||||
|
use nu_utils::get_system_locale;
|
||||||
// TODO num_format::SystemLocale once platform-specific dependencies are stable (see Cargo.toml)
|
use num_format::ToFormattedString;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
@ -216,21 +216,8 @@ pub fn action(
|
|||||||
) -> Value {
|
) -> Value {
|
||||||
match input {
|
match input {
|
||||||
Value::Int { val, .. } => {
|
Value::Int { val, .. } => {
|
||||||
let res = if group_digits {
|
let decimal_value = digits.unwrap_or(0) as usize;
|
||||||
format_int(*val) // int.to_formatted_string(*locale)
|
let res = format_int(*val, group_digits, decimal_value);
|
||||||
} else if let Some(dig) = digits {
|
|
||||||
let mut val_with_trailing_zeroes = val.to_string();
|
|
||||||
if dig != 0 {
|
|
||||||
val_with_trailing_zeroes.push('.');
|
|
||||||
}
|
|
||||||
for _ in 0..dig {
|
|
||||||
val_with_trailing_zeroes.push('0');
|
|
||||||
}
|
|
||||||
val_with_trailing_zeroes
|
|
||||||
} else {
|
|
||||||
val.to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
Value::String { val: res, span }
|
Value::String { val: res, span }
|
||||||
}
|
}
|
||||||
Value::Float { val, .. } => {
|
Value::Float { val, .. } => {
|
||||||
@ -305,21 +292,29 @@ pub fn action(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn format_int(int: i64) -> String {
|
|
||||||
int.to_string()
|
|
||||||
|
|
||||||
// TODO once platform-specific dependencies are stable (see Cargo.toml)
|
fn format_int(int: i64, group_digits: bool, decimals: usize) -> String {
|
||||||
// #[cfg(windows)]
|
let locale = get_system_locale();
|
||||||
// {
|
|
||||||
// int.to_formatted_string(&Locale::en)
|
let str = if group_digits {
|
||||||
// }
|
int.to_formatted_string(&locale)
|
||||||
// #[cfg(not(windows))]
|
} else {
|
||||||
// {
|
int.to_string()
|
||||||
// match SystemLocale::default() {
|
};
|
||||||
// Ok(locale) => int.to_formatted_string(&locale),
|
|
||||||
// Err(_) => int.to_formatted_string(&Locale::en),
|
if decimals > 0 {
|
||||||
// }
|
let decimal_point = locale.decimal();
|
||||||
// }
|
|
||||||
|
format!(
|
||||||
|
"{}{decimal_point}{dummy:0<decimals$}",
|
||||||
|
str,
|
||||||
|
decimal_point = decimal_point,
|
||||||
|
dummy = "",
|
||||||
|
decimals = decimals
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
str
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -18,7 +18,7 @@ impl Command for ExportCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
"Export custom commands or environment variables from a module."
|
"Export definitions or environment variables from a module."
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
|
56
crates/nu-command/src/core_commands/export_use.rs
Normal file
56
crates/nu-command/src/core_commands/export_use.rs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::{Category, Example, PipelineData, Signature, Span, SyntaxShape, Value};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ExportUse;
|
||||||
|
|
||||||
|
impl Command for ExportUse {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"export use"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Use definitions from a module and export them from this module"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
|
Signature::build("export use")
|
||||||
|
.required("pattern", SyntaxShape::ImportPattern, "import pattern")
|
||||||
|
.category(Category::Core)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extra_usage(&self) -> &str {
|
||||||
|
r#"This command is a parser keyword. For details, check:
|
||||||
|
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_parser_keyword(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
_engine_state: &EngineState,
|
||||||
|
_stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
_input: PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
Ok(PipelineData::new(call.head))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
description: "Re-export a command from another module",
|
||||||
|
example: r#"module spam { export def foo [] { "foo" } }
|
||||||
|
module eggs { export use spam foo }
|
||||||
|
use eggs foo
|
||||||
|
foo
|
||||||
|
"#,
|
||||||
|
result: Some(Value::String {
|
||||||
|
val: "foo".to_string(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
use fancy_regex::Regex;
|
||||||
use nu_ansi_term::{
|
use nu_ansi_term::{
|
||||||
Color::{Default, Red, White},
|
Color::{Default, Red, White},
|
||||||
Style,
|
Style,
|
||||||
@ -11,7 +12,6 @@ use nu_protocol::{
|
|||||||
ShellError, Signature, Span, Spanned, SyntaxShape, Value,
|
ShellError, Signature, Span, Spanned, SyntaxShape, Value,
|
||||||
};
|
};
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Help;
|
pub struct Help;
|
||||||
|
|
||||||
@ -142,7 +142,7 @@ fn help(
|
|||||||
|
|
||||||
cols.push("is_custom".into());
|
cols.push("is_custom".into());
|
||||||
vals.push(Value::Bool {
|
vals.push(Value::Bool {
|
||||||
val: decl.get_block_id().is_some(),
|
val: decl.is_custom_command(),
|
||||||
span: head,
|
span: head,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -243,7 +243,7 @@ fn help(
|
|||||||
|
|
||||||
cols.push("is_custom".into());
|
cols.push("is_custom".into());
|
||||||
vals.push(Value::Bool {
|
vals.push(Value::Bool {
|
||||||
val: decl.get_block_id().is_some(),
|
val: decl.is_custom_command(),
|
||||||
span: head,
|
span: head,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -350,7 +350,7 @@ pub fn highlight_search_string(
|
|||||||
string_style: &Style,
|
string_style: &Style,
|
||||||
) -> Result<String, ShellError> {
|
) -> Result<String, ShellError> {
|
||||||
let regex_string = format!("(?i){}", needle);
|
let regex_string = format!("(?i){}", needle);
|
||||||
let regex = match regex::Regex::new(®ex_string) {
|
let regex = match Regex::new(®ex_string) {
|
||||||
Ok(regex) => regex,
|
Ok(regex) => regex,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
return Err(ShellError::GenericError(
|
return Err(ShellError::GenericError(
|
||||||
@ -367,21 +367,34 @@ pub fn highlight_search_string(
|
|||||||
let mut highlighted = String::new();
|
let mut highlighted = String::new();
|
||||||
|
|
||||||
for cap in regex.captures_iter(haystack) {
|
for cap in regex.captures_iter(haystack) {
|
||||||
let start = match cap.get(0) {
|
match cap {
|
||||||
Some(cap) => cap.start(),
|
Ok(capture) => {
|
||||||
None => 0,
|
let start = match capture.get(0) {
|
||||||
};
|
Some(acap) => acap.start(),
|
||||||
let end = match cap.get(0) {
|
None => 0,
|
||||||
Some(cap) => cap.end(),
|
};
|
||||||
None => 0,
|
let end = match capture.get(0) {
|
||||||
};
|
Some(acap) => acap.end(),
|
||||||
highlighted.push_str(
|
None => 0,
|
||||||
&string_style
|
};
|
||||||
.paint(&haystack[last_match_end..start])
|
highlighted.push_str(
|
||||||
.to_string(),
|
&string_style
|
||||||
);
|
.paint(&haystack[last_match_end..start])
|
||||||
highlighted.push_str(&style.paint(&haystack[start..end]).to_string());
|
.to_string(),
|
||||||
last_match_end = end;
|
);
|
||||||
|
highlighted.push_str(&style.paint(&haystack[start..end]).to_string());
|
||||||
|
last_match_end = end;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(ShellError::GenericError(
|
||||||
|
"Error with regular expression capture".into(),
|
||||||
|
e.to_string(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
highlighted.push_str(&string_style.paint(&haystack[last_match_end..]).to_string());
|
highlighted.push_str(&string_style.paint(&haystack[last_match_end..]).to_string());
|
||||||
|
@ -19,11 +19,11 @@ impl Command for Hide {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
"Hide symbols in the current scope"
|
"Hide definitions in the current scope"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"Symbols are hidden by priority: First aliases, then custom commands, then environment variables.
|
r#"Definitions are hidden by priority: First aliases, then custom commands.
|
||||||
|
|
||||||
This command is a parser keyword. For details, check:
|
This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
||||||
|
75
crates/nu-command/src/core_commands/hide_env.rs
Normal file
75
crates/nu-command/src/core_commands/hide_env.rs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::{
|
||||||
|
did_you_mean, Category, Example, PipelineData, ShellError, Signature, Span, Spanned,
|
||||||
|
SyntaxShape, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct HideEnv;
|
||||||
|
|
||||||
|
impl Command for HideEnv {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"hide-env"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
|
Signature::build("hide-env")
|
||||||
|
.rest(
|
||||||
|
"name",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"environment variable names to hide",
|
||||||
|
)
|
||||||
|
.switch(
|
||||||
|
"ignore-errors",
|
||||||
|
"do not throw an error if an environment variable was not found",
|
||||||
|
Some('i'),
|
||||||
|
)
|
||||||
|
.category(Category::Core)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Hide environment variables in the current scope"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
_input: PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
let env_var_names: Vec<Spanned<String>> = call.rest(engine_state, stack, 0)?;
|
||||||
|
let ignore_errors = call.has_flag("ignore-errors");
|
||||||
|
|
||||||
|
for name in env_var_names {
|
||||||
|
if stack.remove_env_var(engine_state, &name.item).is_none() && !ignore_errors {
|
||||||
|
let all_names: Vec<String> = stack
|
||||||
|
.get_env_var_names(engine_state)
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
if let Some(closest_match) = did_you_mean(&all_names, &name.item) {
|
||||||
|
return Err(ShellError::DidYouMeanCustom(
|
||||||
|
format!("Environment variable '{}' not found", name.item),
|
||||||
|
closest_match,
|
||||||
|
name.span,
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::EnvVarNotFoundAtRuntime(name.item, name.span));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(PipelineData::new(call.head))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
description: "Hide an environment variable",
|
||||||
|
example: r#"let-env HZ_ENV_ABC = 1; hide-env HZ_ENV_ABC; 'HZ_ENV_ABC' in (env).name"#,
|
||||||
|
result: Some(Value::boolean(false, Span::test_data())),
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,10 @@ impl Command for Ignore {
|
|||||||
Signature::build("ignore").category(Category::Core)
|
Signature::build("ignore").category(Category::Core)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["silent", "quiet", "out-null"]
|
||||||
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
_engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
|
@ -12,10 +12,12 @@ mod export_def;
|
|||||||
mod export_def_env;
|
mod export_def_env;
|
||||||
mod export_env;
|
mod export_env;
|
||||||
mod export_extern;
|
mod export_extern;
|
||||||
|
mod export_use;
|
||||||
mod extern_;
|
mod extern_;
|
||||||
mod for_;
|
mod for_;
|
||||||
pub mod help;
|
pub mod help;
|
||||||
mod hide;
|
mod hide;
|
||||||
|
mod hide_env;
|
||||||
mod if_;
|
mod if_;
|
||||||
mod ignore;
|
mod ignore;
|
||||||
mod let_;
|
mod let_;
|
||||||
@ -40,10 +42,12 @@ pub use export_def::ExportDef;
|
|||||||
pub use export_def_env::ExportDefEnv;
|
pub use export_def_env::ExportDefEnv;
|
||||||
pub use export_env::ExportEnv;
|
pub use export_env::ExportEnv;
|
||||||
pub use export_extern::ExportExtern;
|
pub use export_extern::ExportExtern;
|
||||||
|
pub use export_use::ExportUse;
|
||||||
pub use extern_::Extern;
|
pub use extern_::Extern;
|
||||||
pub use for_::For;
|
pub use for_::For;
|
||||||
pub use help::Help;
|
pub use help::Help;
|
||||||
pub use hide::Hide;
|
pub use hide::Hide;
|
||||||
|
pub use hide_env::HideEnv;
|
||||||
pub use if_::If;
|
pub use if_::If;
|
||||||
pub use ignore::Ignore;
|
pub use ignore::Ignore;
|
||||||
pub use let_::Let;
|
pub use let_::Let;
|
||||||
|
@ -24,12 +24,16 @@ impl Command for OverlayAdd {
|
|||||||
SyntaxShape::String,
|
SyntaxShape::String,
|
||||||
"Module name to create overlay for",
|
"Module name to create overlay for",
|
||||||
)
|
)
|
||||||
// TODO:
|
.optional(
|
||||||
// .switch(
|
"as",
|
||||||
// "prefix",
|
SyntaxShape::Keyword(b"as".to_vec(), Box::new(SyntaxShape::String)),
|
||||||
// "Prepend module name to the imported symbols",
|
"as keyword followed by a new name",
|
||||||
// Some('p'),
|
)
|
||||||
// )
|
.switch(
|
||||||
|
"prefix",
|
||||||
|
"Prepend module name to the imported commands and aliases",
|
||||||
|
Some('p'),
|
||||||
|
)
|
||||||
.category(Category::Core)
|
.category(Category::Core)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,67 +55,86 @@ impl Command for OverlayAdd {
|
|||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let name_arg: Spanned<String> = call.req(engine_state, stack, 0)?;
|
let name_arg: Spanned<String> = call.req(engine_state, stack, 0)?;
|
||||||
|
|
||||||
let maybe_overlay_name = if engine_state
|
let (overlay_name, overlay_name_span) = if let Some(kw_expression) = call.positional_nth(1)
|
||||||
|
{
|
||||||
|
// If renamed via the 'as' keyword, use the new name as the overlay name
|
||||||
|
if let Some(new_name_expression) = kw_expression.as_keyword() {
|
||||||
|
if let Some(new_name) = new_name_expression.as_string() {
|
||||||
|
(new_name, new_name_expression.span)
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::NushellFailedSpanned(
|
||||||
|
"Wrong keyword type".to_string(),
|
||||||
|
"keyword argument not a string".to_string(),
|
||||||
|
new_name_expression.span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::NushellFailedSpanned(
|
||||||
|
"Wrong keyword type".to_string(),
|
||||||
|
"keyword argument not a keyword".to_string(),
|
||||||
|
kw_expression.span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else if engine_state
|
||||||
.find_overlay(name_arg.item.as_bytes())
|
.find_overlay(name_arg.item.as_bytes())
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
Some(name_arg.item.clone())
|
(name_arg.item, name_arg.span)
|
||||||
} else if let Some(os_str) = Path::new(&name_arg.item).file_stem() {
|
} else if let Some(os_str) = Path::new(&name_arg.item).file_stem() {
|
||||||
os_str.to_str().map(|name| name.to_string())
|
if let Some(name) = os_str.to_str() {
|
||||||
} else {
|
(name.to_string(), name_arg.span)
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(overlay_name) = maybe_overlay_name {
|
|
||||||
if let Some(overlay_id) = engine_state.find_overlay(overlay_name.as_bytes()) {
|
|
||||||
let old_module_id = engine_state.get_overlay(overlay_id).origin;
|
|
||||||
|
|
||||||
stack.add_overlay(overlay_name.clone());
|
|
||||||
|
|
||||||
if let Some(new_module_id) = engine_state.find_module(overlay_name.as_bytes(), &[])
|
|
||||||
{
|
|
||||||
if !stack.has_env_overlay(&overlay_name, engine_state)
|
|
||||||
|| (old_module_id != new_module_id)
|
|
||||||
{
|
|
||||||
// Add environment variables only if:
|
|
||||||
// a) adding a new overlay
|
|
||||||
// b) refreshing an active overlay (the origin module changed)
|
|
||||||
let module = engine_state.get_module(new_module_id);
|
|
||||||
|
|
||||||
for (name, block_id) in module.env_vars() {
|
|
||||||
let name = if let Ok(s) = String::from_utf8(name.clone()) {
|
|
||||||
s
|
|
||||||
} else {
|
|
||||||
return Err(ShellError::NonUtf8(call.head));
|
|
||||||
};
|
|
||||||
|
|
||||||
let block = engine_state.get_block(block_id);
|
|
||||||
|
|
||||||
let val = eval_block(
|
|
||||||
engine_state,
|
|
||||||
stack,
|
|
||||||
block,
|
|
||||||
PipelineData::new(call.head),
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
)?
|
|
||||||
.into_value(call.head);
|
|
||||||
|
|
||||||
stack.add_env_var(name, val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return Err(ShellError::OverlayNotFoundAtRuntime(
|
return Err(ShellError::NonUtf8(name_arg.span));
|
||||||
name_arg.item,
|
|
||||||
name_arg.span,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(ShellError::OverlayNotFoundAtRuntime(
|
return Err(ShellError::OverlayNotFoundAtRuntime(
|
||||||
name_arg.item,
|
name_arg.item,
|
||||||
name_arg.span,
|
name_arg.span,
|
||||||
));
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(overlay_id) = engine_state.find_overlay(overlay_name.as_bytes()) {
|
||||||
|
let old_module_id = engine_state.get_overlay(overlay_id).origin;
|
||||||
|
|
||||||
|
stack.add_overlay(overlay_name.clone());
|
||||||
|
|
||||||
|
if let Some(new_module_id) = engine_state.find_module(overlay_name.as_bytes(), &[]) {
|
||||||
|
if !stack.has_env_overlay(&overlay_name, engine_state)
|
||||||
|
|| (old_module_id != new_module_id)
|
||||||
|
{
|
||||||
|
// Add environment variables only if:
|
||||||
|
// a) adding a new overlay
|
||||||
|
// b) refreshing an active overlay (the origin module changed)
|
||||||
|
let module = engine_state.get_module(new_module_id);
|
||||||
|
|
||||||
|
for (name, block_id) in module.env_vars() {
|
||||||
|
let name = if let Ok(s) = String::from_utf8(name.clone()) {
|
||||||
|
s
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::NonUtf8(call.head));
|
||||||
|
};
|
||||||
|
|
||||||
|
let block = engine_state.get_block(block_id);
|
||||||
|
|
||||||
|
let val = eval_block(
|
||||||
|
engine_state,
|
||||||
|
stack,
|
||||||
|
block,
|
||||||
|
PipelineData::new(call.head),
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
)?
|
||||||
|
.into_value(call.head);
|
||||||
|
|
||||||
|
stack.add_env_var(name, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::OverlayNotFoundAtRuntime(
|
||||||
|
overlay_name,
|
||||||
|
overlay_name_span,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(PipelineData::new(call.head))
|
Ok(PipelineData::new(call.head))
|
||||||
@ -122,13 +145,22 @@ impl Command for OverlayAdd {
|
|||||||
Example {
|
Example {
|
||||||
description: "Create an overlay from a module",
|
description: "Create an overlay from a module",
|
||||||
example: r#"module spam { export def foo [] { "foo" } }
|
example: r#"module spam { export def foo [] { "foo" } }
|
||||||
overlay add spam"#,
|
overlay add spam
|
||||||
|
foo"#,
|
||||||
|
result: None,
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Create an overlay with a prefix",
|
||||||
|
example: r#"echo 'export def foo { "foo" }'
|
||||||
|
overlay add --prefix spam
|
||||||
|
spam foo"#,
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Create an overlay from a file",
|
description: "Create an overlay from a file",
|
||||||
example: r#"echo 'export env FOO { "foo" }' | save spam.nu
|
example: r#"echo 'export env FOO { "foo" }' | save spam.nu
|
||||||
overlay add spam.nu"#,
|
overlay add spam.nu
|
||||||
|
$env.FOO"#,
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
@ -32,17 +32,16 @@ impl Command for AliasDb {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "Creates an alias for a selected table",
|
description: "Creates an alias for a selected table",
|
||||||
example: r#"open db.mysql
|
example: r#"open db.sqlite
|
||||||
| into db
|
| from table table_1
|
||||||
| select a
|
| select a
|
||||||
| from table_1
|
|
||||||
| as t1
|
| as t1
|
||||||
| describe"#,
|
| describe"#,
|
||||||
result: Some(Value::Record {
|
result: Some(Value::Record {
|
||||||
cols: vec!["connection".into(), "query".into()],
|
cols: vec!["connection".into(), "query".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
Value::String {
|
Value::String {
|
||||||
val: "db.mysql".into(),
|
val: "db.sqlite".into(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
},
|
},
|
||||||
Value::String {
|
Value::String {
|
||||||
@ -55,22 +54,20 @@ impl Command for AliasDb {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Creates an alias for a derived table",
|
description: "Creates an alias for a derived table",
|
||||||
example: r#"open db.mysql
|
example: r#"open db.sqlite
|
||||||
| into db
|
| from table (
|
||||||
| select a
|
open db.sqlite
|
||||||
| from (
|
| from table table_a
|
||||||
open db.mysql
|
|
||||||
| into db
|
|
||||||
| select a b
|
| select a b
|
||||||
| from table_a
|
|
||||||
)
|
)
|
||||||
|
| select a
|
||||||
| as t1
|
| as t1
|
||||||
| describe"#,
|
| describe"#,
|
||||||
result: Some(Value::Record {
|
result: Some(Value::Record {
|
||||||
cols: vec!["connection".into(), "query".into()],
|
cols: vec!["connection".into(), "query".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
Value::String {
|
Value::String {
|
||||||
val: "db.mysql".into(),
|
val: "db.sqlite".into(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
},
|
},
|
||||||
Value::String {
|
Value::String {
|
||||||
@ -148,15 +145,13 @@ fn alias_db(
|
|||||||
Vec::new(),
|
Vec::new(),
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
s => {
|
s => Err(ShellError::GenericError(
|
||||||
return Err(ShellError::GenericError(
|
"Connection doesn't define a query".into(),
|
||||||
"Connection doesn't define a query".into(),
|
format!("Expected a connection with query. Got {}", s),
|
||||||
format!("Expected a connection with query. Got {}", s),
|
Some(call.head),
|
||||||
Some(call.head),
|
None,
|
||||||
None,
|
Vec::new(),
|
||||||
Vec::new(),
|
)),
|
||||||
))
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,10 +38,9 @@ impl Command for AndDb {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "Selects a column from a database with an AND clause",
|
description: "Selects a column from a database with an AND clause",
|
||||||
example: r#"open db.mysql
|
example: r#"open db.sqlite
|
||||||
| into db
|
| from table table_1
|
||||||
| select a
|
| select a
|
||||||
| from table_1
|
|
||||||
| where ((field a) > 1)
|
| where ((field a) > 1)
|
||||||
| and ((field b) == 1)
|
| and ((field b) == 1)
|
||||||
| describe"#,
|
| describe"#,
|
||||||
@ -49,7 +48,7 @@ impl Command for AndDb {
|
|||||||
cols: vec!["connection".into(), "query".into()],
|
cols: vec!["connection".into(), "query".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
Value::String {
|
Value::String {
|
||||||
val: "db.mysql".into(),
|
val: "db.sqlite".into(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
},
|
},
|
||||||
Value::String {
|
Value::String {
|
||||||
@ -62,10 +61,9 @@ impl Command for AndDb {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Creates a AND clause combined with an expression AND",
|
description: "Creates a AND clause combined with an expression AND",
|
||||||
example: r#"open db.mysql
|
example: r#"open db.sqlite
|
||||||
| into db
|
| from table table_1
|
||||||
| select a
|
| select a
|
||||||
| from table_1
|
|
||||||
| where ((field a) > 1 | and ((field a) < 10))
|
| where ((field a) > 1 | and ((field a) < 10))
|
||||||
| and ((field b) == 1)
|
| and ((field b) == 1)
|
||||||
| describe"#,
|
| describe"#,
|
||||||
@ -73,7 +71,7 @@ impl Command for AndDb {
|
|||||||
cols: vec!["connection".into(), "query".into()],
|
cols: vec!["connection".into(), "query".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
Value::String {
|
Value::String {
|
||||||
val: "db.mysql".into(),
|
val: "db.sqlite".into(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
},
|
},
|
||||||
Value::String {
|
Value::String {
|
||||||
|
@ -28,7 +28,7 @@ impl Command for CollectDb {
|
|||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Collect from a select query",
|
description: "Collect from a select query",
|
||||||
example: "open foo.db | into db | select a | from table_1 | collect",
|
example: "open foo.db | from table table_1 db | select a | collect",
|
||||||
result: None,
|
result: None,
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ impl Command for DescribeDb {
|
|||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Describe SQLite database constructed query",
|
description: "Describe SQLite database constructed query",
|
||||||
example: "open foo.db | into db | select col_1 | from table_1 | describe",
|
example: "open foo.db | from table table_1 | select col_1 | describe",
|
||||||
result: Some(Value::Record {
|
result: Some(Value::Record {
|
||||||
cols: vec!["connection".into(), "query".into()],
|
cols: vec!["connection".into(), "query".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
|
@ -15,7 +15,7 @@ pub struct FromDb;
|
|||||||
|
|
||||||
impl Command for FromDb {
|
impl Command for FromDb {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"from"
|
"from table"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
@ -35,7 +35,7 @@ impl Command for FromDb {
|
|||||||
"Alias for the selected table",
|
"Alias for the selected table",
|
||||||
Some('a'),
|
Some('a'),
|
||||||
)
|
)
|
||||||
.input_type(Type::Custom("database".into()))
|
.input_type(Type::Any)
|
||||||
.output_type(Type::Custom("database".into()))
|
.output_type(Type::Custom("database".into()))
|
||||||
.category(Category::Custom("database".into()))
|
.category(Category::Custom("database".into()))
|
||||||
}
|
}
|
||||||
@ -47,12 +47,12 @@ impl Command for FromDb {
|
|||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Selects a table from database",
|
description: "Selects a table from database",
|
||||||
example: "open db.mysql | into db | from table_a | describe",
|
example: "open db.sqlite | from table table_a | describe",
|
||||||
result: Some(Value::Record {
|
result: Some(Value::Record {
|
||||||
cols: vec!["connection".into(), "query".into()],
|
cols: vec!["connection".into(), "query".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
Value::String {
|
Value::String {
|
||||||
val: "db.mysql".into(),
|
val: "db.sqlite".into(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
},
|
},
|
||||||
Value::String {
|
Value::String {
|
||||||
|
@ -42,9 +42,8 @@ impl Command for GroupByDb {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "groups by column a and calculates the max",
|
description: "groups by column a and calculates the max",
|
||||||
example: r#"open db.mysql
|
example: r#"open db.sqlite
|
||||||
| into db
|
| from table table_a
|
||||||
| from table_a
|
|
||||||
| select (fn max a)
|
| select (fn max a)
|
||||||
| group-by a
|
| group-by a
|
||||||
| describe"#,
|
| describe"#,
|
||||||
@ -52,7 +51,7 @@ impl Command for GroupByDb {
|
|||||||
cols: vec!["connection".into(), "query".into()],
|
cols: vec!["connection".into(), "query".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
Value::String {
|
Value::String {
|
||||||
val: "db.mysql".into(),
|
val: "db.sqlite".into(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
},
|
},
|
||||||
Value::String {
|
Value::String {
|
||||||
@ -65,9 +64,8 @@ impl Command for GroupByDb {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "groups by column column a and counts records",
|
description: "groups by column column a and counts records",
|
||||||
example: r#"open db.mysql
|
example: r#"open db.sqlite
|
||||||
| into db
|
| from table table_a
|
||||||
| from table_a
|
|
||||||
| select (fn count *)
|
| select (fn count *)
|
||||||
| group-by a
|
| group-by a
|
||||||
| describe"#,
|
| describe"#,
|
||||||
@ -75,7 +73,7 @@ impl Command for GroupByDb {
|
|||||||
cols: vec!["connection".into(), "query".into()],
|
cols: vec!["connection".into(), "query".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
Value::String {
|
Value::String {
|
||||||
val: "db.mysql".into(),
|
val: "db.sqlite".into(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
},
|
},
|
||||||
Value::String {
|
Value::String {
|
||||||
|
344
crates/nu-command/src/database/commands/into_sqlite.rs
Normal file
344
crates/nu-command/src/database/commands/into_sqlite.rs
Normal file
@ -0,0 +1,344 @@
|
|||||||
|
use crate::database::values::sqlite::open_sqlite_db;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::{
|
||||||
|
Category, Config, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span,
|
||||||
|
Spanned, SyntaxShape, Type, Value,
|
||||||
|
};
|
||||||
|
use std::iter;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct IntoSqliteDb;
|
||||||
|
|
||||||
|
impl Command for IntoSqliteDb {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"into sqlite"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("into sqlite")
|
||||||
|
.required(
|
||||||
|
"file_name",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"Specify the filename to save the database to",
|
||||||
|
)
|
||||||
|
.named(
|
||||||
|
"table_name",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"Specify table name to store the data in",
|
||||||
|
Some('t'),
|
||||||
|
)
|
||||||
|
.category(Category::Conversions)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
operate(engine_state, stack, call, input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Convert table into a sqlite database"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["convert", "sqlite", "database"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
description: "Convert ls entries into a sqlite database with 'main' as the table name",
|
||||||
|
example: "ls | into sqlite my_ls.db",
|
||||||
|
result: None,
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Convert ls entries into a sqlite database with 'my_table' as the table name",
|
||||||
|
example: "ls | into sqlite my_ls.db -t my_table",
|
||||||
|
result: None,
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Convert table literal into a sqlite database with 'main' as the table name",
|
||||||
|
example: "[[name]; [-----] [someone] [=====] [somename] ['(((((']] | into sqlite filename.db",
|
||||||
|
result: None,
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Convert a variety of values in table literal form into a sqlite database",
|
||||||
|
example: "[one 2 5.2 six true 100mib 25sec] | into sqlite variety.db",
|
||||||
|
result: None,
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn operate(
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let span = call.head;
|
||||||
|
let config = engine_state.get_config();
|
||||||
|
let file_name: Spanned<String> = call.req(engine_state, stack, 0)?;
|
||||||
|
let table_name: Option<Spanned<String>> = call.get_flag(engine_state, stack, "table_name")?;
|
||||||
|
|
||||||
|
// collect the input into a value
|
||||||
|
let table_entries = input.into_value(span);
|
||||||
|
|
||||||
|
match action(&table_entries, table_name, file_name, config, span) {
|
||||||
|
Ok(val) => Ok(val.into_pipeline_data()),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn action(
|
||||||
|
input: &Value,
|
||||||
|
table: Option<Spanned<String>>,
|
||||||
|
file: Spanned<String>,
|
||||||
|
config: &Config,
|
||||||
|
span: Span,
|
||||||
|
) -> Result<Value, ShellError> {
|
||||||
|
let table_name = if let Some(table_name) = table {
|
||||||
|
table_name.item
|
||||||
|
} else {
|
||||||
|
"main".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
match input {
|
||||||
|
Value::List { vals, span } => {
|
||||||
|
// find the column names, and sqlite data types
|
||||||
|
let columns = get_columns_with_sqlite_types(vals);
|
||||||
|
|
||||||
|
let table_columns_creation = columns
|
||||||
|
.iter()
|
||||||
|
.map(|(name, sql_type)| format!("{} {}", name, sql_type))
|
||||||
|
.join(",");
|
||||||
|
|
||||||
|
// get the values
|
||||||
|
let table_values = vals
|
||||||
|
.iter()
|
||||||
|
.map(|list_value| {
|
||||||
|
format!(
|
||||||
|
"({})",
|
||||||
|
match list_value {
|
||||||
|
Value::Record {
|
||||||
|
cols: _,
|
||||||
|
vals,
|
||||||
|
span: _,
|
||||||
|
} => {
|
||||||
|
vals.iter()
|
||||||
|
.map(|rec_val| {
|
||||||
|
format!(
|
||||||
|
"'{}'",
|
||||||
|
nu_value_to_string(rec_val.clone(), "", config)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.join(",")
|
||||||
|
}
|
||||||
|
// Number formats so keep them without quotes
|
||||||
|
Value::Int { val: _, span: _ }
|
||||||
|
| Value::Float { val: _, span: _ }
|
||||||
|
| Value::Filesize { val: _, span: _ }
|
||||||
|
| Value::Duration { val: _, span: _ } =>
|
||||||
|
nu_value_to_string(list_value.clone(), "", config),
|
||||||
|
_ =>
|
||||||
|
// String formats so add quotes around them
|
||||||
|
format!("'{}'", nu_value_to_string(list_value.clone(), "", config)),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.join(",");
|
||||||
|
|
||||||
|
// create the sqlite database table
|
||||||
|
let conn = open_sqlite_db(Path::new(&file.item), file.span)?;
|
||||||
|
|
||||||
|
// create a string for sql table creation
|
||||||
|
let create_statement = format!(
|
||||||
|
"CREATE TABLE IF NOT EXISTS {} ({})",
|
||||||
|
table_name, table_columns_creation
|
||||||
|
);
|
||||||
|
|
||||||
|
// prepare the string as a sqlite statement
|
||||||
|
let mut stmt = conn.prepare(&create_statement).map_err(|e| {
|
||||||
|
ShellError::GenericError(
|
||||||
|
"Failed to prepare SQLite statement".into(),
|
||||||
|
e.to_string(),
|
||||||
|
Some(file.span),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// execute the statement
|
||||||
|
stmt.execute([]).map_err(|e| {
|
||||||
|
ShellError::GenericError(
|
||||||
|
"Failed to execute SQLite statement".into(),
|
||||||
|
e.to_string(),
|
||||||
|
Some(file.span),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// use normal sql to create the table
|
||||||
|
// insert into table_name
|
||||||
|
// values
|
||||||
|
// ('xx', 'yy', 'zz'),
|
||||||
|
// ('aa', 'bb', 'cc'),
|
||||||
|
// ('dd', 'ee', 'ff')
|
||||||
|
|
||||||
|
// create the string for inserting data into the table
|
||||||
|
let insert_statement = format!("INSERT INTO {} VALUES {}", table_name, table_values);
|
||||||
|
|
||||||
|
// prepare the string as a sqlite statement
|
||||||
|
let mut stmt = conn.prepare(&insert_statement).map_err(|e| {
|
||||||
|
ShellError::GenericError(
|
||||||
|
"Failed to prepare SQLite statement".into(),
|
||||||
|
e.to_string(),
|
||||||
|
Some(file.span),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// execute the statement
|
||||||
|
stmt.execute([]).map_err(|e| {
|
||||||
|
ShellError::GenericError(
|
||||||
|
"Failed to execute SQLite statement".into(),
|
||||||
|
e.to_string(),
|
||||||
|
Some(file.span),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// and we're done
|
||||||
|
Ok(Value::Nothing { span: *span })
|
||||||
|
}
|
||||||
|
_ => Err(ShellError::UnsupportedInput(
|
||||||
|
format!(
|
||||||
|
"Expected a list but instead received a {}",
|
||||||
|
input.get_type()
|
||||||
|
),
|
||||||
|
span,
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is taken from to text local_into_string but tweaks it a bit so that certain formatting does not happen
|
||||||
|
fn nu_value_to_string(value: Value, separator: &str, config: &Config) -> String {
|
||||||
|
match value {
|
||||||
|
Value::Bool { val, .. } => val.to_string(),
|
||||||
|
Value::Int { val, .. } => val.to_string(),
|
||||||
|
Value::Float { val, .. } => val.to_string(),
|
||||||
|
Value::Filesize { val, .. } => val.to_string(),
|
||||||
|
Value::Duration { val, .. } => val.to_string(),
|
||||||
|
Value::Date { val, .. } => val.to_string(),
|
||||||
|
Value::Range { val, .. } => {
|
||||||
|
format!(
|
||||||
|
"{}..{}",
|
||||||
|
nu_value_to_string(val.from, ", ", config),
|
||||||
|
nu_value_to_string(val.to, ", ", config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Value::String { val, .. } => {
|
||||||
|
// don't store ansi escape sequences in the database
|
||||||
|
let stripped = {
|
||||||
|
match strip_ansi_escapes::strip(&val) {
|
||||||
|
Ok(item) => String::from_utf8(item).unwrap_or(val),
|
||||||
|
Err(_) => val,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// escape single quotes
|
||||||
|
stripped.replace('\'', "''")
|
||||||
|
}
|
||||||
|
Value::List { vals: val, .. } => val
|
||||||
|
.iter()
|
||||||
|
.map(|x| nu_value_to_string(x.clone(), ", ", config))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(separator),
|
||||||
|
Value::Record { cols, vals, .. } => cols
|
||||||
|
.iter()
|
||||||
|
.zip(vals.iter())
|
||||||
|
.map(|(x, y)| format!("{}: {}", x, nu_value_to_string(y.clone(), ", ", config)))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(separator),
|
||||||
|
Value::Block { val, .. } => format!("<Block {}>", val),
|
||||||
|
Value::Nothing { .. } => String::new(),
|
||||||
|
Value::Error { error } => format!("{:?}", error),
|
||||||
|
Value::Binary { val, .. } => format!("{:?}", val),
|
||||||
|
Value::CellPath { val, .. } => val.into_string(),
|
||||||
|
Value::CustomValue { val, .. } => val.value_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each value stored in an SQLite database (or manipulated by the database engine) has one of the following storage classes:
|
||||||
|
// NULL. The value is a NULL value.
|
||||||
|
// INTEGER. The value is a signed integer, stored in 0, 1, 2, 3, 4, 6, or 8 bytes depending on the magnitude of the value.
|
||||||
|
// REAL. The value is a floating point value, stored as an 8-byte IEEE floating point number.
|
||||||
|
// TEXT. The value is a text string, stored using the database encoding (UTF-8, UTF-16BE or UTF-16LE).
|
||||||
|
// BLOB. The value is a blob of data, stored exactly as it was input.
|
||||||
|
fn nu_type_to_sqlite_type(nu_type: Type) -> &'static str {
|
||||||
|
match nu_type {
|
||||||
|
Type::Int => "INTEGER",
|
||||||
|
Type::Float => "REAL",
|
||||||
|
Type::String => "TEXT",
|
||||||
|
Type::Bool => "TEXT",
|
||||||
|
Type::Nothing => "NULL",
|
||||||
|
Type::Filesize => "INTEGER",
|
||||||
|
Type::Date => "TEXT",
|
||||||
|
_ => "TEXT",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_columns_with_sqlite_types(input: &[Value]) -> Vec<(String, String)> {
|
||||||
|
let mut columns: Vec<(String, String)> = vec![];
|
||||||
|
let mut added = false;
|
||||||
|
|
||||||
|
for item in input {
|
||||||
|
// let sqlite_type = nu_type_to_sqlite_type(item.get_type());
|
||||||
|
// eprintln!(
|
||||||
|
// "item_type: {:?}, sqlite_type: {:?}",
|
||||||
|
// item.get_type(),
|
||||||
|
// sqlite_type
|
||||||
|
// );
|
||||||
|
|
||||||
|
if let Value::Record { cols, vals, .. } = item {
|
||||||
|
for (c, v) in iter::zip(cols, vals) {
|
||||||
|
if !columns.iter().any(|(name, _)| name == c) {
|
||||||
|
columns.push((
|
||||||
|
c.to_string(),
|
||||||
|
nu_type_to_sqlite_type(v.get_type()).to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// force every other type to a string
|
||||||
|
if !added {
|
||||||
|
columns.push(("value".to_string(), "TEXT".to_string()));
|
||||||
|
added = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
columns
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
// use super::{action, IntoSqliteDb};
|
||||||
|
// use nu_protocol::Type::Error;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
use crate::test_examples;
|
||||||
|
|
||||||
|
test_examples(IntoSqliteDb {})
|
||||||
|
}
|
||||||
|
}
|
@ -54,17 +54,16 @@ impl Command for JoinDb {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "joins two tables on col_b",
|
description: "joins two tables on col_b",
|
||||||
example: r#"open db.mysql
|
example: r#"open db.sqlite
|
||||||
| into db
|
| from table table_1 --as t1
|
||||||
| select col_a
|
|
||||||
| from table_1 --as t1
|
|
||||||
| join table_2 col_b --as t2
|
| join table_2 col_b --as t2
|
||||||
|
| select col_a
|
||||||
| describe"#,
|
| describe"#,
|
||||||
result: Some(Value::Record {
|
result: Some(Value::Record {
|
||||||
cols: vec!["connection".into(), "query".into()],
|
cols: vec!["connection".into(), "query".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
Value::String {
|
Value::String {
|
||||||
val: "db.mysql".into(),
|
val: "db.sqlite".into(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
},
|
},
|
||||||
Value::String {
|
Value::String {
|
||||||
@ -78,22 +77,20 @@ impl Command for JoinDb {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "joins a table with a derived table using aliases",
|
description: "joins a table with a derived table using aliases",
|
||||||
example: r#"open db.mysql
|
example: r#"open db.sqlite
|
||||||
| into db
|
| from table table_1 --as t1
|
||||||
| select col_a
|
|
||||||
| from table_1 --as t1
|
|
||||||
| join (
|
| join (
|
||||||
open db.mysql
|
open db.sqlite
|
||||||
| into db
|
| from table table_2
|
||||||
| select col_c
|
| select col_c
|
||||||
| from table_2
|
|
||||||
) ((field t1.col_a) == (field t2.col_c)) --as t2 --right
|
) ((field t1.col_a) == (field t2.col_c)) --as t2 --right
|
||||||
|
| select col_a
|
||||||
| describe"#,
|
| describe"#,
|
||||||
result: Some(Value::Record {
|
result: Some(Value::Record {
|
||||||
cols: vec!["connection".into(), "query".into()],
|
cols: vec!["connection".into(), "query".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
Value::String {
|
Value::String {
|
||||||
val: "db.mysql".into(),
|
val: "db.sqlite".into(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
},
|
},
|
||||||
Value::String {
|
Value::String {
|
||||||
|
@ -40,9 +40,8 @@ impl Command for LimitDb {
|
|||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Limits selection from table",
|
description: "Limits selection from table",
|
||||||
example: r#"open db.mysql
|
example: r#"open db.sqlite
|
||||||
| into db
|
| from table table_a
|
||||||
| from table_a
|
|
||||||
| select a
|
| select a
|
||||||
| limit 10
|
| limit 10
|
||||||
| describe"#,
|
| describe"#,
|
||||||
@ -50,7 +49,7 @@ impl Command for LimitDb {
|
|||||||
cols: vec!["connection".into(), "query".into()],
|
cols: vec!["connection".into(), "query".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
Value::String {
|
Value::String {
|
||||||
val: "db.mysql".into(),
|
val: "db.sqlite".into(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
},
|
},
|
||||||
Value::String {
|
Value::String {
|
||||||
|
@ -7,6 +7,7 @@ mod collect;
|
|||||||
mod describe;
|
mod describe;
|
||||||
mod from;
|
mod from;
|
||||||
mod group_by;
|
mod group_by;
|
||||||
|
mod into_sqlite;
|
||||||
mod join;
|
mod join;
|
||||||
mod limit;
|
mod limit;
|
||||||
mod open;
|
mod open;
|
||||||
@ -22,16 +23,16 @@ mod where_;
|
|||||||
mod testing;
|
mod testing;
|
||||||
use testing::TestingDb;
|
use testing::TestingDb;
|
||||||
|
|
||||||
use nu_protocol::engine::StateWorkingSet;
|
|
||||||
|
|
||||||
use alias::AliasDb;
|
use alias::AliasDb;
|
||||||
use and::AndDb;
|
use and::AndDb;
|
||||||
use collect::CollectDb;
|
use collect::CollectDb;
|
||||||
pub(crate) use describe::DescribeDb;
|
pub(crate) use describe::DescribeDb;
|
||||||
pub(crate) use from::FromDb;
|
pub(crate) use from::FromDb;
|
||||||
use group_by::GroupByDb;
|
use group_by::GroupByDb;
|
||||||
|
use into_sqlite::IntoSqliteDb;
|
||||||
use join::JoinDb;
|
use join::JoinDb;
|
||||||
use limit::LimitDb;
|
use limit::LimitDb;
|
||||||
|
use nu_protocol::engine::StateWorkingSet;
|
||||||
use open::OpenDb;
|
use open::OpenDb;
|
||||||
use or::OrDb;
|
use or::OrDb;
|
||||||
use order_by::OrderByDb;
|
use order_by::OrderByDb;
|
||||||
@ -60,6 +61,7 @@ pub fn add_commands_decls(working_set: &mut StateWorkingSet) {
|
|||||||
DescribeDb,
|
DescribeDb,
|
||||||
FromDb,
|
FromDb,
|
||||||
GroupByDb,
|
GroupByDb,
|
||||||
|
IntoSqliteDb,
|
||||||
JoinDb,
|
JoinDb,
|
||||||
LimitDb,
|
LimitDb,
|
||||||
OpenDb,
|
OpenDb,
|
||||||
|
@ -38,10 +38,9 @@ impl Command for OrDb {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "selects a column from a database with an OR clause",
|
description: "selects a column from a database with an OR clause",
|
||||||
example: r#"open db.mysql
|
example: r#"open db.sqlite
|
||||||
| into db
|
| from table table_1
|
||||||
| select a
|
| select a
|
||||||
| from table_1
|
|
||||||
| where ((field a) > 1)
|
| where ((field a) > 1)
|
||||||
| or ((field b) == 1)
|
| or ((field b) == 1)
|
||||||
| describe"#,
|
| describe"#,
|
||||||
@ -49,7 +48,7 @@ impl Command for OrDb {
|
|||||||
cols: vec!["connection".into(), "query".into()],
|
cols: vec!["connection".into(), "query".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
Value::String {
|
Value::String {
|
||||||
val: "db.mysql".into(),
|
val: "db.sqlite".into(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
},
|
},
|
||||||
Value::String {
|
Value::String {
|
||||||
@ -62,10 +61,9 @@ impl Command for OrDb {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Creates an OR clause in the column names and a column",
|
description: "Creates an OR clause in the column names and a column",
|
||||||
example: r#"open db.mysql
|
example: r#"open db.sqlite
|
||||||
| into db
|
| from table table_1
|
||||||
| select a
|
| select a
|
||||||
| from table_1
|
|
||||||
| where ((field a) > 1 | or ((field a) < 10))
|
| where ((field a) > 1 | or ((field a) < 10))
|
||||||
| or ((field b) == 1)
|
| or ((field b) == 1)
|
||||||
| describe"#,
|
| describe"#,
|
||||||
@ -73,7 +71,7 @@ impl Command for OrDb {
|
|||||||
cols: vec!["connection".into(), "query".into()],
|
cols: vec!["connection".into(), "query".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
Value::String {
|
Value::String {
|
||||||
val: "db.mysql".into(),
|
val: "db.sqlite".into(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
},
|
},
|
||||||
Value::String {
|
Value::String {
|
||||||
|
@ -44,9 +44,8 @@ impl Command for OrderByDb {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "orders query by a column",
|
description: "orders query by a column",
|
||||||
example: r#"open db.mysql
|
example: r#"open db.sqlite
|
||||||
| into db
|
| from table table_a
|
||||||
| from table_a
|
|
||||||
| select a
|
| select a
|
||||||
| order-by a
|
| order-by a
|
||||||
| describe"#,
|
| describe"#,
|
||||||
@ -54,7 +53,7 @@ impl Command for OrderByDb {
|
|||||||
cols: vec!["connection".into(), "query".into()],
|
cols: vec!["connection".into(), "query".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
Value::String {
|
Value::String {
|
||||||
val: "db.mysql".into(),
|
val: "db.sqlite".into(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
},
|
},
|
||||||
Value::String {
|
Value::String {
|
||||||
@ -67,9 +66,8 @@ impl Command for OrderByDb {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "orders query by column a ascending and by column b",
|
description: "orders query by column a ascending and by column b",
|
||||||
example: r#"open db.mysql
|
example: r#"open db.sqlite
|
||||||
| into db
|
| from table table_a
|
||||||
| from table_a
|
|
||||||
| select a
|
| select a
|
||||||
| order-by a --ascending
|
| order-by a --ascending
|
||||||
| order-by b
|
| order-by b
|
||||||
@ -78,7 +76,7 @@ impl Command for OrderByDb {
|
|||||||
cols: vec!["connection".into(), "query".into()],
|
cols: vec!["connection".into(), "query".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
Value::String {
|
Value::String {
|
||||||
val: "db.mysql".into(),
|
val: "db.sqlite".into(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
},
|
},
|
||||||
Value::String {
|
Value::String {
|
||||||
|
@ -13,17 +13,17 @@ pub struct QueryDb;
|
|||||||
|
|
||||||
impl Command for QueryDb {
|
impl Command for QueryDb {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"query"
|
"query db"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name())
|
Signature::build(self.name())
|
||||||
.required(
|
.required(
|
||||||
"query",
|
"SQL",
|
||||||
SyntaxShape::String,
|
SyntaxShape::String,
|
||||||
"SQL to execute against the database",
|
"SQL to execute against the database",
|
||||||
)
|
)
|
||||||
.input_type(Type::Custom("database".into()))
|
.input_type(Type::Any)
|
||||||
.output_type(Type::Any)
|
.output_type(Type::Any)
|
||||||
.category(Category::Custom("database".into()))
|
.category(Category::Custom("database".into()))
|
||||||
}
|
}
|
||||||
@ -34,8 +34,8 @@ impl Command for QueryDb {
|
|||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Execute a query statement using the database connection",
|
description: "Execute SQL against a SQLite database",
|
||||||
example: r#"open foo.db | into db | query "SELECT * FROM Bar""#,
|
example: r#"open foo.db | query db "SELECT * FROM Bar""#,
|
||||||
result: None,
|
result: None,
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ impl Command for SchemaDb {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name())
|
Signature::build(self.name())
|
||||||
.input_type(Type::Custom("database".into()))
|
.input_type(Type::Any)
|
||||||
.output_type(Type::Any)
|
.output_type(Type::Any)
|
||||||
.category(Category::Custom("database".into()))
|
.category(Category::Custom("database".into()))
|
||||||
}
|
}
|
||||||
@ -28,7 +28,7 @@ impl Command for SchemaDb {
|
|||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Show the schema of a SQLite database",
|
description: "Show the schema of a SQLite database",
|
||||||
example: r#"open foo.db | into db | schema"#,
|
example: r#"open foo.db | schema"#,
|
||||||
result: None,
|
result: None,
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
@ -40,12 +40,12 @@ impl Command for ProjectionDb {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "selects a column from a database",
|
description: "selects a column from a database",
|
||||||
example: "open db.mysql | into db | select a | describe",
|
example: "open db.sqlite | into db | select a | describe",
|
||||||
result: Some(Value::Record {
|
result: Some(Value::Record {
|
||||||
cols: vec!["connection".into(), "query".into()],
|
cols: vec!["connection".into(), "query".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
Value::String {
|
Value::String {
|
||||||
val: "db.mysql".into(),
|
val: "db.sqlite".into(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
},
|
},
|
||||||
Value::String {
|
Value::String {
|
||||||
@ -58,16 +58,16 @@ impl Command for ProjectionDb {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "selects columns from a database using alias",
|
description: "selects columns from a database using alias",
|
||||||
example: r#"open db.mysql
|
example: r#"open db.sqlite
|
||||||
| into db
|
| into db
|
||||||
| select (field a | as new_a) b c
|
| select (field a | as new_a) b c
|
||||||
| from table_1
|
| from table table_1
|
||||||
| describe"#,
|
| describe"#,
|
||||||
result: Some(Value::Record {
|
result: Some(Value::Record {
|
||||||
cols: vec!["connection".into(), "query".into()],
|
cols: vec!["connection".into(), "query".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
Value::String {
|
Value::String {
|
||||||
val: "db.mysql".into(),
|
val: "db.sqlite".into(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
},
|
},
|
||||||
Value::String {
|
Value::String {
|
||||||
|
@ -18,6 +18,10 @@ impl Command for ToDataBase {
|
|||||||
"Converts into an open db connection"
|
"Converts into an open db connection"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn extra_usage(&self) -> &str {
|
||||||
|
"This function is used as type hint for parser, specially if the query is not started with 'from table'"
|
||||||
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name())
|
Signature::build(self.name())
|
||||||
.input_type(Type::Any)
|
.input_type(Type::Any)
|
||||||
@ -32,7 +36,7 @@ impl Command for ToDataBase {
|
|||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Converts an open file into a db object",
|
description: "Converts an open file into a db object",
|
||||||
example: "open db.mysql | into db",
|
example: "open db.sqlite | into db",
|
||||||
result: None,
|
result: None,
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
@ -37,17 +37,16 @@ impl Command for WhereDb {
|
|||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![Example {
|
||||||
description: "selects a column from a database with a where clause",
|
description: "selects a column from a database with a where clause",
|
||||||
example: r#"open db.mysql
|
example: r#"open db.sqlite
|
||||||
| into db
|
| from table table_1
|
||||||
| select a
|
| select a
|
||||||
| from table_1
|
|
||||||
| where ((field a) > 1)
|
| where ((field a) > 1)
|
||||||
| describe"#,
|
| describe"#,
|
||||||
result: Some(Value::Record {
|
result: Some(Value::Record {
|
||||||
cols: vec!["connection".into(), "query".into()],
|
cols: vec!["connection".into(), "query".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
Value::String {
|
Value::String {
|
||||||
val: "db.mysql".into(),
|
val: "db.sqlite".into(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
},
|
},
|
||||||
Value::String {
|
Value::String {
|
||||||
|
@ -68,16 +68,15 @@ impl Command for FunctionExpr {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "orders query by a column",
|
description: "orders query by a column",
|
||||||
example: r#"open db.mysql
|
example: r#"open db.sqlite
|
||||||
| into db
|
| from table table_a
|
||||||
| select (fn lead col_a)
|
| select (fn lead col_a)
|
||||||
| from table_a
|
|
||||||
| describe"#,
|
| describe"#,
|
||||||
result: Some(Value::Record {
|
result: Some(Value::Record {
|
||||||
cols: vec!["connection".into(), "query".into()],
|
cols: vec!["connection".into(), "query".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
Value::String {
|
Value::String {
|
||||||
val: "db.mysql".into(),
|
val: "db.sqlite".into(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
},
|
},
|
||||||
Value::String {
|
Value::String {
|
||||||
|
@ -69,16 +69,15 @@ impl Command for OverExpr {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "orders query by a column",
|
description: "orders query by a column",
|
||||||
example: r#"open db.mysql
|
example: r#"open db.sqlite
|
||||||
| into db
|
| from table table_a
|
||||||
| select (fn lead col_a | over col_b)
|
| select (fn lead col_a | over col_b)
|
||||||
| from table_a
|
|
||||||
| describe"#,
|
| describe"#,
|
||||||
result: Some(Value::Record {
|
result: Some(Value::Record {
|
||||||
cols: vec!["connection".into(), "query".into()],
|
cols: vec!["connection".into(), "query".into()],
|
||||||
vals: vec![
|
vals: vec![
|
||||||
Value::String {
|
Value::String {
|
||||||
val: "db.mysql".into(),
|
val: "db.sqlite".into(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
},
|
},
|
||||||
Value::String {
|
Value::String {
|
||||||
|
@ -3,7 +3,7 @@ use super::db_table::DbTable;
|
|||||||
// Thank you gobang
|
// Thank you gobang
|
||||||
// https://github.com/TaKO8Ki/gobang/blob/main/database-tree/src/lib.rs
|
// https://github.com/TaKO8Ki/gobang/blob/main/database-tree/src/lib.rs
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub struct Db {
|
pub struct Db {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub tables: Vec<DbTable>,
|
pub tables: Vec<DbTable>,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use super::db_table::DbTable;
|
use super::db_table::DbTable;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub struct DbSchema {
|
pub struct DbSchema {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub tables: Vec<DbTable>,
|
pub tables: Vec<DbTable>,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub struct DbTable {
|
pub struct DbTable {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub create_time: Option<chrono::DateTime<chrono::Utc>>,
|
pub create_time: Option<chrono::DateTime<chrono::Utc>>,
|
||||||
|
@ -11,7 +11,7 @@ pub mod db_row;
|
|||||||
pub mod db_schema;
|
pub mod db_schema;
|
||||||
pub mod db_table;
|
pub mod db_table;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
pub enum ConnectionDb {
|
pub enum ConnectionDb {
|
||||||
Path(PathBuf),
|
Path(PathBuf),
|
||||||
}
|
}
|
||||||
|
@ -366,16 +366,21 @@ impl CustomValue for SQLiteDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn to_base_value(&self, span: Span) -> Result<Value, ShellError> {
|
fn to_base_value(&self, span: Span) -> Result<Value, ShellError> {
|
||||||
let db = open_sqlite_db(self.connection.as_path(span)?, span)?;
|
match self.statement {
|
||||||
read_entire_sqlite_db(db, span).map_err(|e| {
|
None => {
|
||||||
ShellError::GenericError(
|
let db = open_sqlite_db(self.connection.as_path(span)?, span)?;
|
||||||
"Failed to read from SQLite database".into(),
|
read_entire_sqlite_db(db, span).map_err(|e| {
|
||||||
e.to_string(),
|
ShellError::GenericError(
|
||||||
Some(span),
|
"Failed to read from SQLite database".into(),
|
||||||
None,
|
e.to_string(),
|
||||||
Vec::new(),
|
Some(span),
|
||||||
)
|
None,
|
||||||
})
|
Vec::new(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Some(_) => self.collect(span),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
@ -410,7 +415,7 @@ impl CustomValue for SQLiteDatabase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_sqlite_db(path: &Path, call_span: Span) -> Result<Connection, nu_protocol::ShellError> {
|
pub fn open_sqlite_db(path: &Path, call_span: Span) -> Result<Connection, nu_protocol::ShellError> {
|
||||||
let path = path.to_string_lossy().to_string();
|
let path = path.to_string_lossy().to_string();
|
||||||
|
|
||||||
Connection::open(path).map_err(|e| {
|
Connection::open(path).map_err(|e| {
|
||||||
@ -425,18 +430,8 @@ fn open_sqlite_db(path: &Path, call_span: Span) -> Result<Connection, nu_protoco
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run_sql_query(conn: Connection, sql: &Spanned<String>) -> Result<Value, rusqlite::Error> {
|
fn run_sql_query(conn: Connection, sql: &Spanned<String>) -> Result<Value, rusqlite::Error> {
|
||||||
let mut stmt = conn.prepare(&sql.item)?;
|
let stmt = conn.prepare(&sql.item)?;
|
||||||
let results = stmt.query([])?;
|
prepared_statement_to_nu_list(stmt, sql.span)
|
||||||
|
|
||||||
let nu_records = results
|
|
||||||
.mapped(|row| Result::Ok(convert_sqlite_row_to_nu_value(row, sql.span)))
|
|
||||||
.into_iter()
|
|
||||||
.collect::<Result<Vec<Value>, rusqlite::Error>>()?;
|
|
||||||
|
|
||||||
Ok(Value::List {
|
|
||||||
vals: nu_records,
|
|
||||||
span: sql.span,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_single_table(
|
fn read_single_table(
|
||||||
@ -444,14 +439,30 @@ fn read_single_table(
|
|||||||
table_name: String,
|
table_name: String,
|
||||||
call_span: Span,
|
call_span: Span,
|
||||||
) -> Result<Value, rusqlite::Error> {
|
) -> Result<Value, rusqlite::Error> {
|
||||||
let mut stmt = conn.prepare(&format!("SELECT * FROM {}", table_name))?;
|
let stmt = conn.prepare(&format!("SELECT * FROM {}", table_name))?;
|
||||||
let results = stmt.query([])?;
|
prepared_statement_to_nu_list(stmt, call_span)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prepared_statement_to_nu_list(
|
||||||
|
mut stmt: rusqlite::Statement,
|
||||||
|
call_span: Span,
|
||||||
|
) -> Result<Value, rusqlite::Error> {
|
||||||
|
let column_names = stmt
|
||||||
|
.column_names()
|
||||||
|
.iter()
|
||||||
|
.map(|c| c.to_string())
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
let results = stmt.query([])?;
|
||||||
let nu_records = results
|
let nu_records = results
|
||||||
.mapped(|row| Result::Ok(convert_sqlite_row_to_nu_value(row, call_span)))
|
.mapped(|row| {
|
||||||
|
Result::Ok(convert_sqlite_row_to_nu_value(
|
||||||
|
row,
|
||||||
|
call_span,
|
||||||
|
column_names.clone(),
|
||||||
|
))
|
||||||
|
})
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect::<Result<Vec<Value>, rusqlite::Error>>()?;
|
.collect::<Result<Vec<Value>, rusqlite::Error>>()?;
|
||||||
|
|
||||||
Ok(Value::List {
|
Ok(Value::List {
|
||||||
vals: nu_records,
|
vals: nu_records,
|
||||||
span: call_span,
|
span: call_span,
|
||||||
@ -470,19 +481,9 @@ fn read_entire_sqlite_db(conn: Connection, call_span: Span) -> Result<Value, rus
|
|||||||
let table_name: String = row?;
|
let table_name: String = row?;
|
||||||
table_names.push(table_name.clone());
|
table_names.push(table_name.clone());
|
||||||
|
|
||||||
let mut rows = Vec::new();
|
let table_stmt = conn.prepare(&format!("select * from [{}]", table_name))?;
|
||||||
let mut table_stmt = conn.prepare(&format!("select * from [{}]", table_name))?;
|
let rows = prepared_statement_to_nu_list(table_stmt, call_span)?;
|
||||||
let mut table_rows = table_stmt.query([])?;
|
tables.push(rows);
|
||||||
while let Some(table_row) = table_rows.next()? {
|
|
||||||
rows.push(convert_sqlite_row_to_nu_value(table_row, call_span))
|
|
||||||
}
|
|
||||||
|
|
||||||
let table_record = Value::List {
|
|
||||||
vals: rows,
|
|
||||||
span: call_span,
|
|
||||||
};
|
|
||||||
|
|
||||||
tables.push(table_record);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Record {
|
Ok(Value::Record {
|
||||||
@ -492,19 +493,16 @@ fn read_entire_sqlite_db(conn: Connection, call_span: Span) -> Result<Value, rus
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn convert_sqlite_row_to_nu_value(row: &Row, span: Span) -> Value {
|
pub fn convert_sqlite_row_to_nu_value(row: &Row, span: Span, column_names: Vec<String>) -> Value {
|
||||||
let mut vals = Vec::new();
|
let mut vals = Vec::with_capacity(column_names.len());
|
||||||
let colnamestr = row.as_ref().column_names().to_vec();
|
|
||||||
let colnames = colnamestr.iter().map(|s| s.to_string()).collect();
|
|
||||||
|
|
||||||
for (i, c) in row.as_ref().column_names().iter().enumerate() {
|
for i in 0..column_names.len() {
|
||||||
let _column = c.to_string();
|
|
||||||
let val = convert_sqlite_value_to_nu_value(row.get_ref_unwrap(i), span);
|
let val = convert_sqlite_value_to_nu_value(row.get_ref_unwrap(i), span);
|
||||||
vals.push(val);
|
vals.push(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Record {
|
Value::Record {
|
||||||
cols: colnames,
|
cols: column_names,
|
||||||
vals,
|
vals,
|
||||||
span,
|
span,
|
||||||
}
|
}
|
||||||
|
94
crates/nu-command/src/dataframe/eager/columns.rs
Normal file
94
crates/nu-command/src/dataframe/eager/columns.rs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
use super::super::values::NuDataFrame;
|
||||||
|
use nu_protocol::{
|
||||||
|
ast::Call,
|
||||||
|
engine::{Command, EngineState, Stack},
|
||||||
|
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ColumnsDF;
|
||||||
|
|
||||||
|
impl Command for ColumnsDF {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"columns"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Show dataframe columns"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Any)
|
||||||
|
.category(Category::Custom("dataframe".into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
description: "Dataframe columns",
|
||||||
|
example: "[[a b]; [1 2] [3 4]] | into df | columns",
|
||||||
|
result: Some(Value::List {
|
||||||
|
vals: vec![
|
||||||
|
Value::String {
|
||||||
|
val: "a".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::String {
|
||||||
|
val: "b".into(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
command(engine_state, stack, call, input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::needless_collect)]
|
||||||
|
fn command(
|
||||||
|
_engine_state: &EngineState,
|
||||||
|
_stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||||
|
|
||||||
|
let names: Vec<Value> = df
|
||||||
|
.as_ref()
|
||||||
|
.get_column_names()
|
||||||
|
.iter()
|
||||||
|
.map(|v| Value::String {
|
||||||
|
val: v.to_string(),
|
||||||
|
span: call.head,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let names = Value::List {
|
||||||
|
vals: names,
|
||||||
|
span: call.head,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(PipelineData::Value(names, None))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::super::super::test_dataframe::test_dataframe;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_dataframe(vec![Box::new(ColumnsDF {})])
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
use super::super::values::{utils::DEFAULT_ROWS, Column, NuDataFrame};
|
use super::super::values::{Column, NuDataFrame};
|
||||||
use nu_engine::CallExt;
|
use nu_engine::CallExt;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::Call,
|
ast::Call,
|
||||||
@ -15,30 +15,54 @@ impl Command for FirstDF {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
"Creates new dataframe with first rows"
|
"Show only the first number of rows."
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build(self.name())
|
Signature::build(self.name())
|
||||||
.optional("rows", SyntaxShape::Int, "Number of rows for head")
|
.optional(
|
||||||
|
"rows",
|
||||||
|
SyntaxShape::Int,
|
||||||
|
"starting from the front, the number of rows to return",
|
||||||
|
)
|
||||||
.input_type(Type::Custom("dataframe".into()))
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
.output_type(Type::Custom("dataframe".into()))
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
.category(Category::Custom("dataframe".into()))
|
.category(Category::Custom("dataframe".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![
|
||||||
description: "Create new dataframe with head rows",
|
Example {
|
||||||
example: "[[a b]; [1 2] [3 4]] | into df | first 1",
|
description: "Return the first row of a dataframe",
|
||||||
result: Some(
|
example: "[[a b]; [1 2] [3 4]] | into df | first",
|
||||||
NuDataFrame::try_from_columns(vec![
|
result: Some(
|
||||||
Column::new("a".to_string(), vec![Value::test_int(1)]),
|
NuDataFrame::try_from_columns(vec![
|
||||||
Column::new("b".to_string(), vec![Value::test_int(2)]),
|
Column::new("a".to_string(), vec![Value::test_int(1)]),
|
||||||
])
|
Column::new("b".to_string(), vec![Value::test_int(2)]),
|
||||||
.expect("simple df for test should not fail")
|
])
|
||||||
.into_value(Span::test_data()),
|
.expect("should not fail")
|
||||||
),
|
.into_value(Span::test_data()),
|
||||||
}]
|
),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Return the first two rows of a dataframe",
|
||||||
|
example: "[[a b]; [1 2] [3 4]] | into df | first 2",
|
||||||
|
result: Some(
|
||||||
|
NuDataFrame::try_from_columns(vec![
|
||||||
|
Column::new(
|
||||||
|
"a".to_string(),
|
||||||
|
vec![Value::test_int(1), Value::test_int(3)],
|
||||||
|
),
|
||||||
|
Column::new(
|
||||||
|
"b".to_string(),
|
||||||
|
vec![Value::test_int(2), Value::test_int(4)],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.expect("should not fail")
|
||||||
|
.into_value(Span::test_data()),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
@ -60,7 +84,7 @@ fn command(
|
|||||||
df: NuDataFrame,
|
df: NuDataFrame,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let rows: Option<usize> = call.opt(engine_state, stack, 0)?;
|
let rows: Option<usize> = call.opt(engine_state, stack, 0)?;
|
||||||
let rows = rows.unwrap_or(DEFAULT_ROWS);
|
let rows = rows.unwrap_or(1);
|
||||||
|
|
||||||
let res = df.as_ref().head(Some(rows));
|
let res = df.as_ref().head(Some(rows));
|
||||||
Ok(PipelineData::Value(
|
Ok(PipelineData::Value(
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
mod append;
|
mod append;
|
||||||
|
mod columns;
|
||||||
mod describe;
|
mod describe;
|
||||||
mod drop;
|
mod drop;
|
||||||
mod drop_duplicates;
|
mod drop_duplicates;
|
||||||
@ -26,6 +27,7 @@ mod with_column;
|
|||||||
use nu_protocol::engine::StateWorkingSet;
|
use nu_protocol::engine::StateWorkingSet;
|
||||||
|
|
||||||
pub use append::AppendDF;
|
pub use append::AppendDF;
|
||||||
|
pub use columns::ColumnsDF;
|
||||||
pub use describe::DescribeDF;
|
pub use describe::DescribeDF;
|
||||||
pub use drop::DropDF;
|
pub use drop::DropDF;
|
||||||
pub use drop_duplicates::DropDuplicates;
|
pub use drop_duplicates::DropDuplicates;
|
||||||
@ -63,6 +65,7 @@ pub fn add_eager_decls(working_set: &mut StateWorkingSet) {
|
|||||||
// Dataframe commands
|
// Dataframe commands
|
||||||
bind_command!(
|
bind_command!(
|
||||||
AppendDF,
|
AppendDF,
|
||||||
|
ColumnsDF,
|
||||||
DataTypes,
|
DataTypes,
|
||||||
DescribeDF,
|
DescribeDF,
|
||||||
DropDF,
|
DropDF,
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
use super::super::values::NuDataFrame;
|
use super::super::values::{NuDataFrame, NuLazyFrame};
|
||||||
use nu_engine::CallExt;
|
use nu_engine::CallExt;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::Call,
|
ast::Call,
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Type,
|
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{fs::File, io::BufReader, path::PathBuf};
|
use std::{fs::File, io::BufReader, path::PathBuf};
|
||||||
|
|
||||||
use polars::prelude::{CsvEncoding, CsvReader, JsonReader, ParquetReader, SerReader};
|
use polars::prelude::{
|
||||||
|
CsvEncoding, CsvReader, JsonReader, LazyCsvReader, LazyFrame, ParallelStrategy, ParquetReader,
|
||||||
|
ScanArgsParquet, SerReader,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct OpenDataFrame;
|
pub struct OpenDataFrame;
|
||||||
@ -29,6 +32,7 @@ impl Command for OpenDataFrame {
|
|||||||
SyntaxShape::Filepath,
|
SyntaxShape::Filepath,
|
||||||
"file path to load values from",
|
"file path to load values from",
|
||||||
)
|
)
|
||||||
|
.switch("lazy", "creates a lazy dataframe", Some('l'))
|
||||||
.named(
|
.named(
|
||||||
"delimiter",
|
"delimiter",
|
||||||
SyntaxShape::String,
|
SyntaxShape::String,
|
||||||
@ -87,7 +91,6 @@ fn command(
|
|||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let span = call.head;
|
|
||||||
let file: Spanned<PathBuf> = call.req(engine_state, stack, 0)?;
|
let file: Spanned<PathBuf> = call.req(engine_state, stack, 0)?;
|
||||||
|
|
||||||
match file.item.extension() {
|
match file.item.extension() {
|
||||||
@ -105,49 +108,80 @@ fn command(
|
|||||||
file.span,
|
file.span,
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
.map(|df| PipelineData::Value(NuDataFrame::dataframe_into_value(df, span), None))
|
.map(|value| PipelineData::Value(value, None))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_parquet(
|
fn from_parquet(
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
) -> Result<polars::prelude::DataFrame, ShellError> {
|
) -> Result<Value, ShellError> {
|
||||||
let file: Spanned<PathBuf> = call.req(engine_state, stack, 0)?;
|
if call.has_flag("lazy") {
|
||||||
let columns: Option<Vec<String>> = call.get_flag(engine_state, stack, "columns")?;
|
let file: String = call.req(engine_state, stack, 0)?;
|
||||||
|
let args = ScanArgsParquet {
|
||||||
|
n_rows: None,
|
||||||
|
cache: true,
|
||||||
|
parallel: ParallelStrategy::Auto,
|
||||||
|
rechunk: false,
|
||||||
|
row_count: None,
|
||||||
|
low_memory: false,
|
||||||
|
};
|
||||||
|
|
||||||
let r = File::open(&file.item).map_err(|e| {
|
let df: NuLazyFrame = LazyFrame::scan_parquet(file, args)
|
||||||
ShellError::GenericError(
|
.map_err(|e| {
|
||||||
"Error opening file".into(),
|
ShellError::GenericError(
|
||||||
e.to_string(),
|
"Parquet reader error".into(),
|
||||||
Some(file.span),
|
format!("{:?}", e),
|
||||||
None,
|
Some(call.head),
|
||||||
Vec::new(),
|
None,
|
||||||
)
|
Vec::new(),
|
||||||
})?;
|
)
|
||||||
let reader = ParquetReader::new(r);
|
})?
|
||||||
|
.into();
|
||||||
|
|
||||||
let reader = match columns {
|
df.into_value(call.head)
|
||||||
None => reader,
|
} else {
|
||||||
Some(columns) => reader.with_columns(Some(columns)),
|
let file: Spanned<PathBuf> = call.req(engine_state, stack, 0)?;
|
||||||
};
|
let columns: Option<Vec<String>> = call.get_flag(engine_state, stack, "columns")?;
|
||||||
|
|
||||||
reader.finish().map_err(|e| {
|
let r = File::open(&file.item).map_err(|e| {
|
||||||
ShellError::GenericError(
|
ShellError::GenericError(
|
||||||
"Parquet reader error".into(),
|
"Error opening file".into(),
|
||||||
format!("{:?}", e),
|
e.to_string(),
|
||||||
Some(call.head),
|
Some(file.span),
|
||||||
None,
|
None,
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
)
|
)
|
||||||
})
|
})?;
|
||||||
|
let reader = ParquetReader::new(r);
|
||||||
|
|
||||||
|
let reader = match columns {
|
||||||
|
None => reader,
|
||||||
|
Some(columns) => reader.with_columns(Some(columns)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let df: NuDataFrame = reader
|
||||||
|
.finish()
|
||||||
|
.map_err(|e| {
|
||||||
|
ShellError::GenericError(
|
||||||
|
"Parquet reader error".into(),
|
||||||
|
format!("{:?}", e),
|
||||||
|
Some(call.head),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
.into();
|
||||||
|
|
||||||
|
Ok(df.into_value(call.head))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_json(
|
fn from_json(
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
) -> Result<polars::prelude::DataFrame, ShellError> {
|
) -> Result<Value, ShellError> {
|
||||||
let file: Spanned<PathBuf> = call.req(engine_state, stack, 0)?;
|
let file: Spanned<PathBuf> = call.req(engine_state, stack, 0)?;
|
||||||
let file = File::open(&file.item).map_err(|e| {
|
let file = File::open(&file.item).map_err(|e| {
|
||||||
ShellError::GenericError(
|
ShellError::GenericError(
|
||||||
@ -162,86 +196,149 @@ fn from_json(
|
|||||||
let buf_reader = BufReader::new(file);
|
let buf_reader = BufReader::new(file);
|
||||||
let reader = JsonReader::new(buf_reader);
|
let reader = JsonReader::new(buf_reader);
|
||||||
|
|
||||||
reader.finish().map_err(|e| {
|
let df: NuDataFrame = reader
|
||||||
ShellError::GenericError(
|
.finish()
|
||||||
"Json reader error".into(),
|
.map_err(|e| {
|
||||||
format!("{:?}", e),
|
ShellError::GenericError(
|
||||||
Some(call.head),
|
"Json reader error".into(),
|
||||||
None,
|
format!("{:?}", e),
|
||||||
Vec::new(),
|
Some(call.head),
|
||||||
)
|
None,
|
||||||
})
|
Vec::new(),
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
.into();
|
||||||
|
|
||||||
|
Ok(df.into_value(call.head))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_csv(
|
fn from_csv(
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
) -> Result<polars::prelude::DataFrame, ShellError> {
|
) -> Result<Value, ShellError> {
|
||||||
let file: Spanned<PathBuf> = call.req(engine_state, stack, 0)?;
|
|
||||||
let delimiter: Option<Spanned<String>> = call.get_flag(engine_state, stack, "delimiter")?;
|
let delimiter: Option<Spanned<String>> = call.get_flag(engine_state, stack, "delimiter")?;
|
||||||
let no_header: bool = call.has_flag("no-header");
|
let no_header: bool = call.has_flag("no-header");
|
||||||
let infer_schema: Option<usize> = call.get_flag(engine_state, stack, "infer-schema")?;
|
let infer_schema: Option<usize> = call.get_flag(engine_state, stack, "infer-schema")?;
|
||||||
let skip_rows: Option<usize> = call.get_flag(engine_state, stack, "skip-rows")?;
|
let skip_rows: Option<usize> = call.get_flag(engine_state, stack, "skip-rows")?;
|
||||||
let columns: Option<Vec<String>> = call.get_flag(engine_state, stack, "columns")?;
|
let columns: Option<Vec<String>> = call.get_flag(engine_state, stack, "columns")?;
|
||||||
|
|
||||||
let csv_reader = CsvReader::from_path(&file.item)
|
if call.has_flag("lazy") {
|
||||||
.map_err(|e| {
|
let file: String = call.req(engine_state, stack, 0)?;
|
||||||
ShellError::GenericError(
|
let csv_reader = LazyCsvReader::new(file);
|
||||||
"Error creating CSV reader".into(),
|
|
||||||
e.to_string(),
|
|
||||||
Some(file.span),
|
|
||||||
None,
|
|
||||||
Vec::new(),
|
|
||||||
)
|
|
||||||
})?
|
|
||||||
.with_encoding(CsvEncoding::LossyUtf8);
|
|
||||||
|
|
||||||
let csv_reader = match delimiter {
|
let csv_reader = match delimiter {
|
||||||
None => csv_reader,
|
None => csv_reader,
|
||||||
Some(d) => {
|
Some(d) => {
|
||||||
if d.item.len() != 1 {
|
if d.item.len() != 1 {
|
||||||
return Err(ShellError::GenericError(
|
return Err(ShellError::GenericError(
|
||||||
"Incorrect delimiter".into(),
|
"Incorrect delimiter".into(),
|
||||||
"Delimiter has to be one character".into(),
|
"Delimiter has to be one character".into(),
|
||||||
Some(d.span),
|
Some(d.span),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
let delimiter = match d.item.chars().next() {
|
||||||
|
Some(d) => d as u8,
|
||||||
|
None => unreachable!(),
|
||||||
|
};
|
||||||
|
csv_reader.with_delimiter(delimiter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let csv_reader = csv_reader.has_header(!no_header);
|
||||||
|
|
||||||
|
let csv_reader = match infer_schema {
|
||||||
|
None => csv_reader,
|
||||||
|
Some(r) => csv_reader.with_infer_schema_length(Some(r)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let csv_reader = match skip_rows {
|
||||||
|
None => csv_reader,
|
||||||
|
Some(r) => csv_reader.with_skip_rows(r),
|
||||||
|
};
|
||||||
|
|
||||||
|
let df: NuLazyFrame = csv_reader
|
||||||
|
.finish()
|
||||||
|
.map_err(|e| {
|
||||||
|
ShellError::GenericError(
|
||||||
|
"Parquet reader error".into(),
|
||||||
|
format!("{:?}", e),
|
||||||
|
Some(call.head),
|
||||||
None,
|
None,
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
));
|
)
|
||||||
} else {
|
})?
|
||||||
let delimiter = match d.item.chars().next() {
|
.into();
|
||||||
Some(d) => d as u8,
|
|
||||||
None => unreachable!(),
|
df.into_value(call.head)
|
||||||
};
|
} else {
|
||||||
csv_reader.with_delimiter(delimiter)
|
let file: Spanned<PathBuf> = call.req(engine_state, stack, 0)?;
|
||||||
|
let csv_reader = CsvReader::from_path(&file.item)
|
||||||
|
.map_err(|e| {
|
||||||
|
ShellError::GenericError(
|
||||||
|
"Error creating CSV reader".into(),
|
||||||
|
e.to_string(),
|
||||||
|
Some(file.span),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
.with_encoding(CsvEncoding::LossyUtf8);
|
||||||
|
|
||||||
|
let csv_reader = match delimiter {
|
||||||
|
None => csv_reader,
|
||||||
|
Some(d) => {
|
||||||
|
if d.item.len() != 1 {
|
||||||
|
return Err(ShellError::GenericError(
|
||||||
|
"Incorrect delimiter".into(),
|
||||||
|
"Delimiter has to be one character".into(),
|
||||||
|
Some(d.span),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
let delimiter = match d.item.chars().next() {
|
||||||
|
Some(d) => d as u8,
|
||||||
|
None => unreachable!(),
|
||||||
|
};
|
||||||
|
csv_reader.with_delimiter(delimiter)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
let csv_reader = csv_reader.has_header(!no_header);
|
let csv_reader = csv_reader.has_header(!no_header);
|
||||||
|
|
||||||
let csv_reader = match infer_schema {
|
let csv_reader = match infer_schema {
|
||||||
None => csv_reader,
|
None => csv_reader,
|
||||||
Some(r) => csv_reader.infer_schema(Some(r)),
|
Some(r) => csv_reader.infer_schema(Some(r)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let csv_reader = match skip_rows {
|
let csv_reader = match skip_rows {
|
||||||
None => csv_reader,
|
None => csv_reader,
|
||||||
Some(r) => csv_reader.with_skip_rows(r),
|
Some(r) => csv_reader.with_skip_rows(r),
|
||||||
};
|
};
|
||||||
|
|
||||||
let csv_reader = match columns {
|
let csv_reader = match columns {
|
||||||
None => csv_reader,
|
None => csv_reader,
|
||||||
Some(columns) => csv_reader.with_columns(Some(columns)),
|
Some(columns) => csv_reader.with_columns(Some(columns)),
|
||||||
};
|
};
|
||||||
|
|
||||||
csv_reader.finish().map_err(|e| {
|
let df: NuDataFrame = csv_reader
|
||||||
ShellError::GenericError(
|
.finish()
|
||||||
"Parquet reader error".into(),
|
.map_err(|e| {
|
||||||
format!("{:?}", e),
|
ShellError::GenericError(
|
||||||
Some(call.head),
|
"Parquet reader error".into(),
|
||||||
None,
|
format!("{:?}", e),
|
||||||
Vec::new(),
|
Some(call.head),
|
||||||
)
|
None,
|
||||||
})
|
Vec::new(),
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
.into();
|
||||||
|
|
||||||
|
Ok(df.into_value(call.head))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
76
crates/nu-command/src/dataframe/expressions/arg_where.rs
Normal file
76
crates/nu-command/src/dataframe/expressions/arg_where.rs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
use crate::dataframe::values::{Column, NuDataFrame, NuExpression};
|
||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::{
|
||||||
|
ast::Call,
|
||||||
|
engine::{Command, EngineState, Stack},
|
||||||
|
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
|
||||||
|
};
|
||||||
|
use polars::prelude::arg_where;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ExprArgWhere;
|
||||||
|
|
||||||
|
impl Command for ExprArgWhere {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"arg-where"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Creates an expression that returns the arguments where expression is true"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
|
.required("column name", SyntaxShape::Any, "Expression to evaluate")
|
||||||
|
.input_type(Type::Any)
|
||||||
|
.output_type(Type::Custom("expression".into()))
|
||||||
|
.category(Category::Custom("expression".into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
description: "Return a dataframe where the value match the expression",
|
||||||
|
example: "let df = ([[a b]; [one 1] [two 2] [three 3]] | into df);
|
||||||
|
$df | select (arg-where ((col b) >= 2) | as b_arg)",
|
||||||
|
result: Some(
|
||||||
|
NuDataFrame::try_from_columns(vec![Column::new(
|
||||||
|
"b_arg".to_string(),
|
||||||
|
vec![Value::test_int(1), Value::test_int(2)],
|
||||||
|
)])
|
||||||
|
.expect("simple df for test should not fail")
|
||||||
|
.into_value(Span::test_data()),
|
||||||
|
),
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
_input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let value: Value = call.req(engine_state, stack, 0)?;
|
||||||
|
let expr = NuExpression::try_from_value(value)?;
|
||||||
|
let expr: NuExpression = arg_where(expr.into_polars()).into();
|
||||||
|
|
||||||
|
Ok(PipelineData::Value(expr.into_value(call.head), None))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::super::super::test_dataframe::test_dataframe;
|
||||||
|
use super::*;
|
||||||
|
use crate::dataframe::expressions::ExprAlias;
|
||||||
|
use crate::dataframe::lazy::LazySelect;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_dataframe(vec![
|
||||||
|
Box::new(ExprArgWhere {}),
|
||||||
|
Box::new(ExprAlias {}),
|
||||||
|
Box::new(LazySelect {}),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
110
crates/nu-command/src/dataframe/expressions/is_in.rs
Normal file
110
crates/nu-command/src/dataframe/expressions/is_in.rs
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
use crate::dataframe::values::{Column, NuDataFrame, NuExpression};
|
||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::{
|
||||||
|
ast::Call,
|
||||||
|
engine::{Command, EngineState, Stack},
|
||||||
|
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
|
||||||
|
};
|
||||||
|
use polars::prelude::{lit, DataType};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ExprIsIn;
|
||||||
|
|
||||||
|
impl Command for ExprIsIn {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"is-in"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Creates an is-in expression"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
|
.required(
|
||||||
|
"list",
|
||||||
|
SyntaxShape::List(Box::new(SyntaxShape::Any)),
|
||||||
|
"List to check if values are in",
|
||||||
|
)
|
||||||
|
.input_type(Type::Custom("expression".into()))
|
||||||
|
.output_type(Type::Custom("expression".into()))
|
||||||
|
.category(Category::Custom("expression".into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
description: "Creates a is-in expression",
|
||||||
|
example: r#"let df = ([[a b]; [one 1] [two 2] [three 3]] | into df);
|
||||||
|
$df | with-column (col a | is-in [one two] | as a_in)"#,
|
||||||
|
result: Some(
|
||||||
|
NuDataFrame::try_from_columns(vec![
|
||||||
|
Column::new(
|
||||||
|
"a".to_string(),
|
||||||
|
vec![
|
||||||
|
Value::test_string("one"),
|
||||||
|
Value::test_string("two"),
|
||||||
|
Value::test_string("three"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Column::new(
|
||||||
|
"b".to_string(),
|
||||||
|
vec![Value::test_int(1), Value::test_int(2), Value::test_int(3)],
|
||||||
|
),
|
||||||
|
Column::new(
|
||||||
|
"a_in".to_string(),
|
||||||
|
vec![
|
||||||
|
Value::test_bool(true),
|
||||||
|
Value::test_bool(true),
|
||||||
|
Value::test_bool(false),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.expect("simple df for test should not fail")
|
||||||
|
.into_value(Span::test_data()),
|
||||||
|
),
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let list: Vec<Value> = call.req(engine_state, stack, 0)?;
|
||||||
|
let expr = NuExpression::try_from_pipeline(input, call.head)?;
|
||||||
|
|
||||||
|
let values = NuDataFrame::try_from_columns(vec![Column::new("list".to_string(), list)])?;
|
||||||
|
let list = values.as_series(call.head)?;
|
||||||
|
|
||||||
|
if matches!(list.dtype(), DataType::Object(..)) {
|
||||||
|
return Err(ShellError::IncompatibleParametersSingle(
|
||||||
|
"Cannot use a mixed list as argument".into(),
|
||||||
|
call.head,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let expr: NuExpression = expr.into_polars().is_in(lit(list)).into();
|
||||||
|
Ok(PipelineData::Value(expr.into_value(call.head), None))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::super::super::test_dataframe::test_dataframe;
|
||||||
|
use super::*;
|
||||||
|
use crate::dataframe::eager::WithColumn;
|
||||||
|
use crate::dataframe::expressions::alias::ExprAlias;
|
||||||
|
use crate::dataframe::expressions::col::ExprCol;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_dataframe(vec![
|
||||||
|
Box::new(ExprIsIn {}),
|
||||||
|
Box::new(ExprAlias {}),
|
||||||
|
Box::new(ExprCol {}),
|
||||||
|
Box::new(WithColumn {}),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,10 @@
|
|||||||
mod alias;
|
mod alias;
|
||||||
|
mod arg_where;
|
||||||
mod as_nu;
|
mod as_nu;
|
||||||
mod col;
|
mod col;
|
||||||
mod concat_str;
|
mod concat_str;
|
||||||
mod expressions_macro;
|
mod expressions_macro;
|
||||||
|
mod is_in;
|
||||||
mod lit;
|
mod lit;
|
||||||
mod otherwise;
|
mod otherwise;
|
||||||
mod quantile;
|
mod quantile;
|
||||||
@ -11,10 +13,12 @@ mod when;
|
|||||||
use nu_protocol::engine::StateWorkingSet;
|
use nu_protocol::engine::StateWorkingSet;
|
||||||
|
|
||||||
pub(crate) use crate::dataframe::expressions::alias::ExprAlias;
|
pub(crate) use crate::dataframe::expressions::alias::ExprAlias;
|
||||||
|
use crate::dataframe::expressions::arg_where::ExprArgWhere;
|
||||||
use crate::dataframe::expressions::as_nu::ExprAsNu;
|
use crate::dataframe::expressions::as_nu::ExprAsNu;
|
||||||
pub(super) use crate::dataframe::expressions::col::ExprCol;
|
pub(super) use crate::dataframe::expressions::col::ExprCol;
|
||||||
pub(super) use crate::dataframe::expressions::concat_str::ExprConcatStr;
|
pub(super) use crate::dataframe::expressions::concat_str::ExprConcatStr;
|
||||||
pub(crate) use crate::dataframe::expressions::expressions_macro::*;
|
pub(crate) use crate::dataframe::expressions::expressions_macro::*;
|
||||||
|
pub(super) use crate::dataframe::expressions::is_in::ExprIsIn;
|
||||||
pub(super) use crate::dataframe::expressions::lit::ExprLit;
|
pub(super) use crate::dataframe::expressions::lit::ExprLit;
|
||||||
pub(super) use crate::dataframe::expressions::otherwise::ExprOtherwise;
|
pub(super) use crate::dataframe::expressions::otherwise::ExprOtherwise;
|
||||||
pub(super) use crate::dataframe::expressions::quantile::ExprQuantile;
|
pub(super) use crate::dataframe::expressions::quantile::ExprQuantile;
|
||||||
@ -33,6 +37,7 @@ pub fn add_expressions(working_set: &mut StateWorkingSet) {
|
|||||||
// Dataframe commands
|
// Dataframe commands
|
||||||
bind_command!(
|
bind_command!(
|
||||||
ExprAlias,
|
ExprAlias,
|
||||||
|
ExprArgWhere,
|
||||||
ExprCol,
|
ExprCol,
|
||||||
ExprConcatStr,
|
ExprConcatStr,
|
||||||
ExprCount,
|
ExprCount,
|
||||||
@ -49,6 +54,7 @@ pub fn add_expressions(working_set: &mut StateWorkingSet) {
|
|||||||
ExprFirst,
|
ExprFirst,
|
||||||
ExprLast,
|
ExprLast,
|
||||||
ExprNUnique,
|
ExprNUnique,
|
||||||
|
ExprIsIn,
|
||||||
ExprIsNotNull,
|
ExprIsNotNull,
|
||||||
ExprIsNull,
|
ExprIsNull,
|
||||||
ExprNot,
|
ExprNot,
|
||||||
|
84
crates/nu-command/src/dataframe/lazy/filter.rs
Normal file
84
crates/nu-command/src/dataframe/lazy/filter.rs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
use crate::dataframe::values::{Column, NuDataFrame, NuExpression, NuLazyFrame};
|
||||||
|
|
||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::{
|
||||||
|
ast::Call,
|
||||||
|
engine::{Command, EngineState, Stack},
|
||||||
|
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct LazyFilter;
|
||||||
|
|
||||||
|
impl Command for LazyFilter {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"filter"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Filter dataframe based in expression"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
|
.required(
|
||||||
|
"filter expression",
|
||||||
|
SyntaxShape::Any,
|
||||||
|
"Expression that define the column selection",
|
||||||
|
)
|
||||||
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
|
.category(Category::Custom("lazyframe".into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
description: "Filter dataframe using an expression",
|
||||||
|
example: "[[a b]; [6 2] [4 2] [2 2]] | into df | filter ((col a) >= 4)",
|
||||||
|
result: Some(
|
||||||
|
NuDataFrame::try_from_columns(vec![
|
||||||
|
Column::new(
|
||||||
|
"a".to_string(),
|
||||||
|
vec![Value::test_int(6), Value::test_int(4)],
|
||||||
|
),
|
||||||
|
Column::new(
|
||||||
|
"b".to_string(),
|
||||||
|
vec![Value::test_int(2), Value::test_int(2)],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.expect("simple df for test should not fail")
|
||||||
|
.into_value(Span::test_data()),
|
||||||
|
),
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let value: Value = call.req(engine_state, stack, 0)?;
|
||||||
|
let expression = NuExpression::try_from_value(value)?;
|
||||||
|
|
||||||
|
let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?;
|
||||||
|
let lazy = NuLazyFrame::new(
|
||||||
|
lazy.from_eager,
|
||||||
|
lazy.into_polars().filter(expression.into_polars()),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(PipelineData::Value(lazy.into_value(call.head)?, None))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::super::super::test_dataframe::test_dataframe;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
test_dataframe(vec![Box::new(LazyFilter {})])
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ mod collect;
|
|||||||
mod fetch;
|
mod fetch;
|
||||||
mod fill_na;
|
mod fill_na;
|
||||||
mod fill_null;
|
mod fill_null;
|
||||||
|
mod filter;
|
||||||
pub mod groupby;
|
pub mod groupby;
|
||||||
mod join;
|
mod join;
|
||||||
mod macro_commands;
|
mod macro_commands;
|
||||||
@ -13,17 +14,17 @@ mod to_lazy;
|
|||||||
|
|
||||||
use nu_protocol::engine::StateWorkingSet;
|
use nu_protocol::engine::StateWorkingSet;
|
||||||
|
|
||||||
pub(crate) use crate::dataframe::lazy::macro_commands::*;
|
|
||||||
|
|
||||||
use crate::dataframe::lazy::aggregate::LazyAggregate;
|
use crate::dataframe::lazy::aggregate::LazyAggregate;
|
||||||
pub use crate::dataframe::lazy::collect::LazyCollect;
|
pub use crate::dataframe::lazy::collect::LazyCollect;
|
||||||
use crate::dataframe::lazy::fetch::LazyFetch;
|
use crate::dataframe::lazy::fetch::LazyFetch;
|
||||||
use crate::dataframe::lazy::fill_na::LazyFillNA;
|
use crate::dataframe::lazy::fill_na::LazyFillNA;
|
||||||
use crate::dataframe::lazy::fill_null::LazyFillNull;
|
use crate::dataframe::lazy::fill_null::LazyFillNull;
|
||||||
|
use crate::dataframe::lazy::filter::LazyFilter;
|
||||||
use crate::dataframe::lazy::groupby::ToLazyGroupBy;
|
use crate::dataframe::lazy::groupby::ToLazyGroupBy;
|
||||||
use crate::dataframe::lazy::join::LazyJoin;
|
use crate::dataframe::lazy::join::LazyJoin;
|
||||||
|
pub(crate) use crate::dataframe::lazy::macro_commands::*;
|
||||||
use crate::dataframe::lazy::quantile::LazyQuantile;
|
use crate::dataframe::lazy::quantile::LazyQuantile;
|
||||||
use crate::dataframe::lazy::select::LazySelect;
|
pub(crate) use crate::dataframe::lazy::select::LazySelect;
|
||||||
use crate::dataframe::lazy::sort_by_expr::LazySortBy;
|
use crate::dataframe::lazy::sort_by_expr::LazySortBy;
|
||||||
pub use crate::dataframe::lazy::to_lazy::ToLazyFrame;
|
pub use crate::dataframe::lazy::to_lazy::ToLazyFrame;
|
||||||
|
|
||||||
@ -45,6 +46,7 @@ pub fn add_lazy_decls(working_set: &mut StateWorkingSet) {
|
|||||||
LazyFetch,
|
LazyFetch,
|
||||||
LazyFillNA,
|
LazyFillNA,
|
||||||
LazyFillNull,
|
LazyFillNull,
|
||||||
|
LazyFilter,
|
||||||
LazyJoin,
|
LazyJoin,
|
||||||
LazyQuantile,
|
LazyQuantile,
|
||||||
LazyMax,
|
LazyMax,
|
||||||
|
@ -6,8 +6,6 @@ use nu_protocol::{
|
|||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
|
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
|
||||||
};
|
};
|
||||||
use polars::prelude::Expr;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct LazySelect;
|
pub struct LazySelect;
|
||||||
|
|
||||||
@ -61,17 +59,6 @@ impl Command for LazySelect {
|
|||||||
};
|
};
|
||||||
let expressions = NuExpression::extract_exprs(value)?;
|
let expressions = NuExpression::extract_exprs(value)?;
|
||||||
|
|
||||||
if expressions
|
|
||||||
.iter()
|
|
||||||
.any(|expr| !matches!(expr, Expr::Column(..)))
|
|
||||||
{
|
|
||||||
let value: Value = call.req(engine_state, stack, 0)?;
|
|
||||||
return Err(ShellError::IncompatibleParametersSingle(
|
|
||||||
"Expected only Col expressions".into(),
|
|
||||||
value.span()?,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?;
|
let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?;
|
||||||
let lazy = NuLazyFrame::new(lazy.from_eager, lazy.into_polars().select(&expressions));
|
let lazy = NuLazyFrame::new(lazy.from_eager, lazy.into_polars().select(&expressions));
|
||||||
|
|
||||||
|
@ -32,6 +32,11 @@ impl Command for LazySortBy {
|
|||||||
"Reverse sorting. Default is false",
|
"Reverse sorting. Default is false",
|
||||||
Some('r'),
|
Some('r'),
|
||||||
)
|
)
|
||||||
|
.switch(
|
||||||
|
"nulls-last",
|
||||||
|
"nulls are shown last in the dataframe",
|
||||||
|
Some('n'),
|
||||||
|
)
|
||||||
.input_type(Type::Custom("dataframe".into()))
|
.input_type(Type::Custom("dataframe".into()))
|
||||||
.output_type(Type::Custom("dataframe".into()))
|
.output_type(Type::Custom("dataframe".into()))
|
||||||
.category(Category::Custom("lazyframe".into()))
|
.category(Category::Custom("lazyframe".into()))
|
||||||
@ -102,6 +107,7 @@ impl Command for LazySortBy {
|
|||||||
span: call.head,
|
span: call.head,
|
||||||
};
|
};
|
||||||
let expressions = NuExpression::extract_exprs(value)?;
|
let expressions = NuExpression::extract_exprs(value)?;
|
||||||
|
let nulls_last = call.has_flag("nulls-last");
|
||||||
|
|
||||||
let reverse: Option<Vec<bool>> = call.get_flag(engine_state, stack, "reverse")?;
|
let reverse: Option<Vec<bool>> = call.get_flag(engine_state, stack, "reverse")?;
|
||||||
let reverse = match reverse {
|
let reverse = match reverse {
|
||||||
@ -128,7 +134,8 @@ impl Command for LazySortBy {
|
|||||||
let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?;
|
let lazy = NuLazyFrame::try_from_pipeline(input, call.head)?;
|
||||||
let lazy = NuLazyFrame::new(
|
let lazy = NuLazyFrame::new(
|
||||||
lazy.from_eager,
|
lazy.from_eager,
|
||||||
lazy.into_polars().sort_by_exprs(&expressions, reverse),
|
lazy.into_polars()
|
||||||
|
.sort_by_exprs(&expressions, reverse, nulls_last),
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(PipelineData::Value(
|
Ok(PipelineData::Value(
|
||||||
|
@ -35,7 +35,7 @@ impl Command for GetWeekDay {
|
|||||||
result: Some(
|
result: Some(
|
||||||
NuDataFrame::try_from_columns(vec![Column::new(
|
NuDataFrame::try_from_columns(vec![Column::new(
|
||||||
"0".to_string(),
|
"0".to_string(),
|
||||||
vec![Value::test_int(2), Value::test_int(2)],
|
vec![Value::test_int(1), Value::test_int(1)],
|
||||||
)])
|
)])
|
||||||
.expect("simple df for test should not fail")
|
.expect("simple df for test should not fail")
|
||||||
.into_value(Span::test_data()),
|
.into_value(Span::test_data()),
|
||||||
|
@ -5,7 +5,7 @@ use nu_protocol::{
|
|||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
|
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
|
||||||
};
|
};
|
||||||
use polars::prelude::IntoSeries;
|
use polars::prelude::{arg_where, col, IntoLazy};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ArgTrue;
|
pub struct ArgTrue;
|
||||||
@ -59,23 +59,41 @@ fn command(
|
|||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||||
|
let columns = df.as_ref().get_column_names();
|
||||||
let series = df.as_series(call.head)?;
|
if columns.len() > 1 {
|
||||||
let bool = series.bool().map_err(|_| {
|
return Err(ShellError::GenericError(
|
||||||
ShellError::GenericError(
|
"Error using as series".into(),
|
||||||
"Error converting to bool".into(),
|
"dataframe has more than one column".into(),
|
||||||
"all-false only works with series of type bool".into(),
|
|
||||||
Some(call.head),
|
Some(call.head),
|
||||||
None,
|
None,
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
)
|
));
|
||||||
})?;
|
}
|
||||||
|
|
||||||
let mut res = bool.arg_true().into_series();
|
match columns.first() {
|
||||||
res.rename("arg_true");
|
Some(column) => {
|
||||||
|
let expression = arg_where(col(column).eq(true)).alias("arg_true");
|
||||||
|
let res = df
|
||||||
|
.as_ref()
|
||||||
|
.clone()
|
||||||
|
.lazy()
|
||||||
|
.select(&[expression])
|
||||||
|
.collect()
|
||||||
|
.map_err(|err| {
|
||||||
|
ShellError::GenericError(
|
||||||
|
"Error creating index column".into(),
|
||||||
|
err.to_string(),
|
||||||
|
Some(call.head),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
NuDataFrame::try_from_series(vec![res], call.head)
|
let value = NuDataFrame::dataframe_into_value(res, call.head);
|
||||||
.map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None))
|
Ok(PipelineData::Value(value, None))
|
||||||
|
}
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -146,7 +146,7 @@ fn command(
|
|||||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||||
}
|
}
|
||||||
Value::Float { val, span } => {
|
Value::Float { val, span } => {
|
||||||
let chunked = series.as_ref().f64().map_err(|e| {
|
let chunked = series.f64().map_err(|e| {
|
||||||
ShellError::GenericError(
|
ShellError::GenericError(
|
||||||
"Error casting to f64".into(),
|
"Error casting to f64".into(),
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
@ -169,7 +169,7 @@ fn command(
|
|||||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||||
}
|
}
|
||||||
Value::String { val, span } => {
|
Value::String { val, span } => {
|
||||||
let chunked = series.as_ref().utf8().map_err(|e| {
|
let chunked = series.utf8().map_err(|e| {
|
||||||
ShellError::GenericError(
|
ShellError::GenericError(
|
||||||
"Error casting to string".into(),
|
"Error casting to string".into(),
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
|
@ -27,26 +27,46 @@ impl Command for IsDuplicated {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![
|
||||||
description: "Create mask indicating duplicated values",
|
Example {
|
||||||
example: "[5 6 6 6 8 8 8] | into df | is-duplicated",
|
description: "Create mask indicating duplicated values",
|
||||||
result: Some(
|
example: "[5 6 6 6 8 8 8] | into df | is-duplicated",
|
||||||
NuDataFrame::try_from_columns(vec![Column::new(
|
result: Some(
|
||||||
"is_duplicated".to_string(),
|
NuDataFrame::try_from_columns(vec![Column::new(
|
||||||
vec![
|
"is_duplicated".to_string(),
|
||||||
Value::test_bool(false),
|
vec![
|
||||||
Value::test_bool(true),
|
Value::test_bool(false),
|
||||||
Value::test_bool(true),
|
Value::test_bool(true),
|
||||||
Value::test_bool(true),
|
Value::test_bool(true),
|
||||||
Value::test_bool(true),
|
Value::test_bool(true),
|
||||||
Value::test_bool(true),
|
Value::test_bool(true),
|
||||||
Value::test_bool(true),
|
Value::test_bool(true),
|
||||||
],
|
Value::test_bool(true),
|
||||||
)])
|
],
|
||||||
.expect("simple df for test should not fail")
|
)])
|
||||||
.into_value(Span::test_data()),
|
.expect("simple df for test should not fail")
|
||||||
),
|
.into_value(Span::test_data()),
|
||||||
}]
|
),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Create mask indicating duplicated rows in a dataframe",
|
||||||
|
example: "[[a, b]; [1 2] [1 2] [3 3] [3 3] [1 1]] | into df | is-duplicated",
|
||||||
|
result: Some(
|
||||||
|
NuDataFrame::try_from_columns(vec![Column::new(
|
||||||
|
"is_duplicated".to_string(),
|
||||||
|
vec![
|
||||||
|
Value::test_bool(true),
|
||||||
|
Value::test_bool(true),
|
||||||
|
Value::test_bool(true),
|
||||||
|
Value::test_bool(true),
|
||||||
|
Value::test_bool(false),
|
||||||
|
],
|
||||||
|
)])
|
||||||
|
.expect("simple df for test should not fail")
|
||||||
|
.into_value(Span::test_data()),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
@ -69,7 +89,7 @@ fn command(
|
|||||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||||
|
|
||||||
let mut res = df
|
let mut res = df
|
||||||
.as_series(call.head)?
|
.as_ref()
|
||||||
.is_duplicated()
|
.is_duplicated()
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
ShellError::GenericError(
|
ShellError::GenericError(
|
||||||
@ -84,7 +104,7 @@ fn command(
|
|||||||
|
|
||||||
res.rename("is_duplicated");
|
res.rename("is_duplicated");
|
||||||
|
|
||||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
NuDataFrame::try_from_series(vec![res], call.head)
|
||||||
.map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None))
|
.map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,26 +27,46 @@ impl Command for IsUnique {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![Example {
|
vec![
|
||||||
description: "Create mask indicating unique values",
|
Example {
|
||||||
example: "[5 6 6 6 8 8 8] | into df | is-unique",
|
description: "Create mask indicating unique values",
|
||||||
result: Some(
|
example: "[5 6 6 6 8 8 8] | into df | is-unique",
|
||||||
NuDataFrame::try_from_columns(vec![Column::new(
|
result: Some(
|
||||||
"is_unique".to_string(),
|
NuDataFrame::try_from_columns(vec![Column::new(
|
||||||
vec![
|
"is_unique".to_string(),
|
||||||
Value::test_bool(true),
|
vec![
|
||||||
Value::test_bool(false),
|
Value::test_bool(true),
|
||||||
Value::test_bool(false),
|
Value::test_bool(false),
|
||||||
Value::test_bool(false),
|
Value::test_bool(false),
|
||||||
Value::test_bool(false),
|
Value::test_bool(false),
|
||||||
Value::test_bool(false),
|
Value::test_bool(false),
|
||||||
Value::test_bool(false),
|
Value::test_bool(false),
|
||||||
],
|
Value::test_bool(false),
|
||||||
)])
|
],
|
||||||
.expect("simple df for test should not fail")
|
)])
|
||||||
.into_value(Span::test_data()),
|
.expect("simple df for test should not fail")
|
||||||
),
|
.into_value(Span::test_data()),
|
||||||
}]
|
),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Create mask indicating duplicated rows in a dataframe",
|
||||||
|
example: "[[a, b]; [1 2] [1 2] [3 3] [3 3] [1 1]] | into df | is-unique",
|
||||||
|
result: Some(
|
||||||
|
NuDataFrame::try_from_columns(vec![Column::new(
|
||||||
|
"is_unique".to_string(),
|
||||||
|
vec![
|
||||||
|
Value::test_bool(false),
|
||||||
|
Value::test_bool(false),
|
||||||
|
Value::test_bool(false),
|
||||||
|
Value::test_bool(false),
|
||||||
|
Value::test_bool(true),
|
||||||
|
],
|
||||||
|
)])
|
||||||
|
.expect("simple df for test should not fail")
|
||||||
|
.into_value(Span::test_data()),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
@ -68,18 +88,23 @@ fn command(
|
|||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||||
|
|
||||||
let mut res = df.as_series(call.head)?.is_unique().map_err(|e| {
|
let mut res = df
|
||||||
ShellError::GenericError(
|
.as_ref()
|
||||||
"Error finding unique values".into(),
|
.is_unique()
|
||||||
e.to_string(),
|
.map_err(|e| {
|
||||||
Some(call.head),
|
ShellError::GenericError(
|
||||||
None,
|
"Error finding unique values".into(),
|
||||||
Vec::new(),
|
e.to_string(),
|
||||||
)
|
Some(call.head),
|
||||||
})?;
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
.into_series();
|
||||||
|
|
||||||
res.rename("is_unique");
|
res.rename("is_unique");
|
||||||
|
|
||||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
NuDataFrame::try_from_series(vec![res], call.head)
|
||||||
.map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None))
|
.map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ fn command(
|
|||||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||||
}
|
}
|
||||||
Value::Float { val, span } => {
|
Value::Float { val, span } => {
|
||||||
let chunked = series.as_ref().f64().map_err(|e| {
|
let chunked = series.f64().map_err(|e| {
|
||||||
ShellError::GenericError(
|
ShellError::GenericError(
|
||||||
"Error casting to f64".into(),
|
"Error casting to f64".into(),
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
@ -152,7 +152,7 @@ fn command(
|
|||||||
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
NuDataFrame::try_from_series(vec![res.into_series()], call.head)
|
||||||
}
|
}
|
||||||
Value::String { val, span } => {
|
Value::String { val, span } => {
|
||||||
let chunked = series.as_ref().utf8().map_err(|e| {
|
let chunked = series.utf8().map_err(|e| {
|
||||||
ShellError::GenericError(
|
ShellError::GenericError(
|
||||||
"Error casting to string".into(),
|
"Error casting to string".into(),
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
|
@ -6,6 +6,8 @@ use nu_protocol::{
|
|||||||
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
|
Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use polars::prelude::SeriesMethods;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ValueCount;
|
pub struct ValueCount;
|
||||||
|
|
||||||
@ -66,7 +68,7 @@ fn command(
|
|||||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||||
let series = df.as_series(call.head)?;
|
let series = df.as_series(call.head)?;
|
||||||
|
|
||||||
let res = series.value_counts(false).map_err(|e| {
|
let res = series.value_counts(false, false).map_err(|e| {
|
||||||
ShellError::GenericError(
|
ShellError::GenericError(
|
||||||
"Error calculating value counts values".into(),
|
"Error calculating value counts values".into(),
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use super::{operations::Axis, NuDataFrame};
|
use super::{operations::Axis, NuDataFrame};
|
||||||
|
|
||||||
use nu_protocol::{ast::Operator, span, ShellError, Span, Spanned, Value};
|
use nu_protocol::{ast::Operator, span, ShellError, Span, Spanned, Value};
|
||||||
use num::Zero;
|
use num::Zero;
|
||||||
use polars::prelude::{
|
use polars::prelude::{
|
||||||
@ -294,7 +293,7 @@ pub(super) fn compute_series_single_value(
|
|||||||
compare_series_decimal(&lhs, *val, ChunkedArray::equal, lhs_span)
|
compare_series_decimal(&lhs, *val, ChunkedArray::equal, lhs_span)
|
||||||
}
|
}
|
||||||
Value::String { val, .. } => {
|
Value::String { val, .. } => {
|
||||||
let equal_pattern = format!("^{}$", regex::escape(val));
|
let equal_pattern = format!("^{}$", fancy_regex::escape(val));
|
||||||
contains_series_pat(&lhs, &equal_pattern, lhs_span)
|
contains_series_pat(&lhs, &equal_pattern, lhs_span)
|
||||||
}
|
}
|
||||||
Value::Date { val, .. } => {
|
Value::Date { val, .. } => {
|
||||||
@ -406,7 +405,7 @@ pub(super) fn compute_series_single_value(
|
|||||||
},
|
},
|
||||||
Operator::StartsWith => match &right {
|
Operator::StartsWith => match &right {
|
||||||
Value::String { val, .. } => {
|
Value::String { val, .. } => {
|
||||||
let starts_with_pattern = format!("^{}", regex::escape(val));
|
let starts_with_pattern = format!("^{}", fancy_regex::escape(val));
|
||||||
contains_series_pat(&lhs, &starts_with_pattern, lhs_span)
|
contains_series_pat(&lhs, &starts_with_pattern, lhs_span)
|
||||||
}
|
}
|
||||||
_ => Err(ShellError::OperatorMismatch {
|
_ => Err(ShellError::OperatorMismatch {
|
||||||
@ -419,7 +418,7 @@ pub(super) fn compute_series_single_value(
|
|||||||
},
|
},
|
||||||
Operator::EndsWith => match &right {
|
Operator::EndsWith => match &right {
|
||||||
Value::String { val, .. } => {
|
Value::String { val, .. } => {
|
||||||
let ends_with_pattern = format!("{}$", regex::escape(val));
|
let ends_with_pattern = format!("{}$", fancy_regex::escape(val));
|
||||||
contains_series_pat(&lhs, &ends_with_pattern, lhs_span)
|
contains_series_pat(&lhs, &ends_with_pattern, lhs_span)
|
||||||
}
|
}
|
||||||
_ => Err(ShellError::OperatorMismatch {
|
_ => Err(ShellError::OperatorMismatch {
|
||||||
|
@ -446,7 +446,7 @@ impl NuDataFrame {
|
|||||||
// sorting dataframe by the first column
|
// sorting dataframe by the first column
|
||||||
let column_names = self.as_ref().get_column_names();
|
let column_names = self.as_ref().get_column_names();
|
||||||
let first_col = column_names
|
let first_col = column_names
|
||||||
.get(0)
|
.first()
|
||||||
.expect("already checked that dataframe is different than 0");
|
.expect("already checked that dataframe is different than 0");
|
||||||
|
|
||||||
// if unable to sort, then unable to compare
|
// if unable to sort, then unable to compare
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use chrono::Local;
|
use chrono::{DateTime, Local, Locale, TimeZone};
|
||||||
use chrono::{DateTime, TimeZone};
|
|
||||||
|
|
||||||
use nu_engine::CallExt;
|
use nu_engine::CallExt;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
@ -7,6 +6,7 @@ use nu_protocol::{
|
|||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value,
|
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value,
|
||||||
};
|
};
|
||||||
|
use nu_utils::locale::get_system_locale_string;
|
||||||
use std::fmt::{Display, Write};
|
use std::fmt::{Display, Write};
|
||||||
|
|
||||||
use super::utils::parse_date_from_string;
|
use super::utils::parse_date_from_string;
|
||||||
@ -98,7 +98,13 @@ where
|
|||||||
Tz::Offset: Display,
|
Tz::Offset: Display,
|
||||||
{
|
{
|
||||||
let mut formatter_buf = String::new();
|
let mut formatter_buf = String::new();
|
||||||
let format = date_time.format(formatter);
|
let locale: Locale = get_system_locale_string()
|
||||||
|
.map(|l| l.replace('-', "_")) // `chrono::Locale` needs something like `xx_xx`, rather than `xx-xx`
|
||||||
|
.unwrap_or_else(|| String::from("en_US"))
|
||||||
|
.as_str()
|
||||||
|
.try_into()
|
||||||
|
.unwrap_or(Locale::en_US);
|
||||||
|
let format = date_time.format_localized(formatter, locale);
|
||||||
|
|
||||||
match formatter_buf.write_fmt(format_args!("{}", format)) {
|
match formatter_buf.write_fmt(format_args!("{}", format)) {
|
||||||
Ok(_) => Value::String {
|
Ok(_) => Value::String {
|
||||||
|
@ -42,10 +42,12 @@ pub fn create_default_context() -> EngineState {
|
|||||||
ExportDefEnv,
|
ExportDefEnv,
|
||||||
ExportEnv,
|
ExportEnv,
|
||||||
ExportExtern,
|
ExportExtern,
|
||||||
|
ExportUse,
|
||||||
Extern,
|
Extern,
|
||||||
For,
|
For,
|
||||||
Help,
|
Help,
|
||||||
Hide,
|
Hide,
|
||||||
|
HideEnv,
|
||||||
If,
|
If,
|
||||||
Ignore,
|
Ignore,
|
||||||
Overlay,
|
Overlay,
|
||||||
@ -206,6 +208,19 @@ pub fn create_default_context() -> EngineState {
|
|||||||
StrUpcase
|
StrUpcase
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Bits
|
||||||
|
bind_command! {
|
||||||
|
Bits,
|
||||||
|
BitsAnd,
|
||||||
|
BitsNot,
|
||||||
|
BitsOr,
|
||||||
|
BitsXor,
|
||||||
|
BitsRotateLeft,
|
||||||
|
BitsRotateRight,
|
||||||
|
BitsShiftLeft,
|
||||||
|
BitsShiftRight,
|
||||||
|
}
|
||||||
|
|
||||||
// Bytes
|
// Bytes
|
||||||
bind_command! {
|
bind_command! {
|
||||||
Bytes,
|
Bytes,
|
||||||
@ -342,8 +357,8 @@ pub fn create_default_context() -> EngineState {
|
|||||||
WithEnv,
|
WithEnv,
|
||||||
ConfigNu,
|
ConfigNu,
|
||||||
ConfigEnv,
|
ConfigEnv,
|
||||||
ConfigReset,
|
|
||||||
ConfigMeta,
|
ConfigMeta,
|
||||||
|
ConfigReset,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Math
|
// Math
|
||||||
@ -402,7 +417,6 @@ pub fn create_default_context() -> EngineState {
|
|||||||
Hash,
|
Hash,
|
||||||
HashMd5::default(),
|
HashMd5::default(),
|
||||||
HashSha256::default(),
|
HashSha256::default(),
|
||||||
HashBase64,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Experimental
|
// Experimental
|
||||||
@ -413,17 +427,11 @@ pub fn create_default_context() -> EngineState {
|
|||||||
|
|
||||||
// Deprecated
|
// Deprecated
|
||||||
bind_command! {
|
bind_command! {
|
||||||
PivotDeprecated,
|
HashBase64,
|
||||||
StrDatetimeDeprecated,
|
StrDatetimeDeprecated,
|
||||||
StrDecimalDeprecated,
|
StrDecimalDeprecated,
|
||||||
StrIntDeprecated,
|
StrIntDeprecated,
|
||||||
MatchDeprecated,
|
|
||||||
NthDeprecated,
|
|
||||||
UnaliasDeprecated,
|
|
||||||
StrFindReplaceDeprecated,
|
StrFindReplaceDeprecated,
|
||||||
KeepDeprecated,
|
|
||||||
KeepUntilDeprecated,
|
|
||||||
KeepWhileDeprecated,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "plugin")]
|
#[cfg(feature = "plugin")]
|
||||||
|
15
crates/nu-command/src/deprecated/deprecated_commands.rs
Normal file
15
crates/nu-command/src/deprecated/deprecated_commands.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
/// Return map of <deprecated_command_name, new_command_name>
|
||||||
|
/// This covers simple deprecated commands nicely, but it's not great for deprecating
|
||||||
|
/// subcommands like `foo bar` where `foo` is still a valid command.
|
||||||
|
/// For those, it's currently easiest to have a "stub" command that just returns an error.
|
||||||
|
pub fn deprecated_commands() -> HashMap<String, String> {
|
||||||
|
let mut commands = HashMap::new();
|
||||||
|
commands.insert("keep".to_string(), "take".to_string());
|
||||||
|
commands.insert("match".to_string(), "find".to_string());
|
||||||
|
commands.insert("nth".to_string(), "select".to_string());
|
||||||
|
commands.insert("pivot".to_string(), "transpose".to_string());
|
||||||
|
commands.insert("unalias".to_string(), "hide".to_string());
|
||||||
|
commands
|
||||||
|
}
|
@ -1,36 +0,0 @@
|
|||||||
use nu_protocol::{
|
|
||||||
ast::Call,
|
|
||||||
engine::{Command, EngineState, Stack},
|
|
||||||
Category, PipelineData, Signature,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct KeepDeprecated;
|
|
||||||
|
|
||||||
impl Command for KeepDeprecated {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"keep"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build(self.name()).category(Category::Deprecated)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Deprecated command"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
_engine_state: &EngineState,
|
|
||||||
_stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
_input: PipelineData,
|
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
|
||||||
Err(nu_protocol::ShellError::DeprecatedCommand(
|
|
||||||
self.name().to_string(),
|
|
||||||
"take".to_string(),
|
|
||||||
call.head,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
use nu_protocol::{
|
|
||||||
ast::Call,
|
|
||||||
engine::{Command, EngineState, Stack},
|
|
||||||
Category, PipelineData, Signature,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct KeepUntilDeprecated;
|
|
||||||
|
|
||||||
impl Command for KeepUntilDeprecated {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"keep until"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build(self.name()).category(Category::Deprecated)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Deprecated command"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
_engine_state: &EngineState,
|
|
||||||
_stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
_input: PipelineData,
|
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
|
||||||
Err(nu_protocol::ShellError::DeprecatedCommand(
|
|
||||||
self.name().to_string(),
|
|
||||||
"take until".to_string(),
|
|
||||||
call.head,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
use nu_protocol::{
|
|
||||||
ast::Call,
|
|
||||||
engine::{Command, EngineState, Stack},
|
|
||||||
Category, PipelineData, Signature,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct KeepWhileDeprecated;
|
|
||||||
|
|
||||||
impl Command for KeepWhileDeprecated {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"keep while"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build(self.name()).category(Category::Deprecated)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Deprecated command"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
_engine_state: &EngineState,
|
|
||||||
_stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
_input: PipelineData,
|
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
|
||||||
Err(nu_protocol::ShellError::DeprecatedCommand(
|
|
||||||
self.name().to_string(),
|
|
||||||
"take while".to_string(),
|
|
||||||
call.head,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
use nu_protocol::{
|
|
||||||
ast::Call,
|
|
||||||
engine::{Command, EngineState, Stack},
|
|
||||||
Category, PipelineData, Signature,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct MatchDeprecated;
|
|
||||||
|
|
||||||
impl Command for MatchDeprecated {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"match"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build(self.name()).category(Category::Deprecated)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Deprecated command"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
_engine_state: &EngineState,
|
|
||||||
_stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
_input: PipelineData,
|
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
|
||||||
Err(nu_protocol::ShellError::DeprecatedCommand(
|
|
||||||
self.name().to_string(),
|
|
||||||
"find".to_string(),
|
|
||||||
call.head,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +1,13 @@
|
|||||||
|
mod deprecated_commands;
|
||||||
mod hash_base64;
|
mod hash_base64;
|
||||||
mod keep_;
|
|
||||||
mod keep_until;
|
|
||||||
mod keep_while;
|
|
||||||
mod match_;
|
|
||||||
mod nth;
|
|
||||||
mod pivot;
|
|
||||||
mod str_datetime;
|
mod str_datetime;
|
||||||
mod str_decimal;
|
mod str_decimal;
|
||||||
mod str_find_replace;
|
mod str_find_replace;
|
||||||
mod str_int;
|
mod str_int;
|
||||||
mod unalias;
|
|
||||||
|
|
||||||
|
pub use deprecated_commands::*;
|
||||||
pub use hash_base64::HashBase64;
|
pub use hash_base64::HashBase64;
|
||||||
pub use keep_::KeepDeprecated;
|
|
||||||
pub use keep_until::KeepUntilDeprecated;
|
|
||||||
pub use keep_while::KeepWhileDeprecated;
|
|
||||||
pub use match_::MatchDeprecated;
|
|
||||||
pub use nth::NthDeprecated;
|
|
||||||
pub use pivot::PivotDeprecated;
|
|
||||||
pub use str_datetime::StrDatetimeDeprecated;
|
pub use str_datetime::StrDatetimeDeprecated;
|
||||||
pub use str_decimal::StrDecimalDeprecated;
|
pub use str_decimal::StrDecimalDeprecated;
|
||||||
pub use str_find_replace::StrFindReplaceDeprecated;
|
pub use str_find_replace::StrFindReplaceDeprecated;
|
||||||
pub use str_int::StrIntDeprecated;
|
pub use str_int::StrIntDeprecated;
|
||||||
pub use unalias::UnaliasDeprecated;
|
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
use nu_protocol::{
|
|
||||||
ast::Call,
|
|
||||||
engine::{Command, EngineState, Stack},
|
|
||||||
Category, PipelineData, Signature,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct NthDeprecated;
|
|
||||||
|
|
||||||
impl Command for NthDeprecated {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"nth"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build(self.name()).category(Category::Deprecated)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Deprecated command"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
_engine_state: &EngineState,
|
|
||||||
_stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
_input: PipelineData,
|
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
|
||||||
Err(nu_protocol::ShellError::DeprecatedCommand(
|
|
||||||
self.name().to_string(),
|
|
||||||
"select".to_string(),
|
|
||||||
call.head,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
use nu_protocol::{
|
|
||||||
ast::Call,
|
|
||||||
engine::{Command, EngineState, Stack},
|
|
||||||
Category, PipelineData, Signature,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct PivotDeprecated;
|
|
||||||
|
|
||||||
impl Command for PivotDeprecated {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"pivot"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build(self.name()).category(Category::Deprecated)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Deprecated command"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
_engine_state: &EngineState,
|
|
||||||
_stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
_input: PipelineData,
|
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
|
||||||
Err(nu_protocol::ShellError::DeprecatedCommand(
|
|
||||||
self.name().to_string(),
|
|
||||||
"transpose".to_string(),
|
|
||||||
call.head,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
use nu_protocol::{
|
|
||||||
ast::Call,
|
|
||||||
engine::{Command, EngineState, Stack},
|
|
||||||
Category, PipelineData, Signature,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct UnaliasDeprecated;
|
|
||||||
|
|
||||||
impl Command for UnaliasDeprecated {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"unalias"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build(self.name()).category(Category::Deprecated)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Deprecated command"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
_engine_state: &EngineState,
|
|
||||||
_stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
_input: PipelineData,
|
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
|
||||||
Err(nu_protocol::ShellError::DeprecatedCommand(
|
|
||||||
self.name().to_string(),
|
|
||||||
"hide".to_string(),
|
|
||||||
call.head,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,6 +4,7 @@ use nu_protocol::{
|
|||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, PipelineData, ShellError, Signature,
|
Category, Example, PipelineData, ShellError, Signature,
|
||||||
};
|
};
|
||||||
|
use nu_utils::{get_default_config, get_default_env};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -61,7 +62,7 @@ impl Command for ConfigReset {
|
|||||||
if !only_env {
|
if !only_env {
|
||||||
let mut nu_config = config_path.clone();
|
let mut nu_config = config_path.clone();
|
||||||
nu_config.push("config.nu");
|
nu_config.push("config.nu");
|
||||||
let config_file = include_str!("../../../../../docs/sample_config/default_config.nu");
|
let config_file = get_default_config();
|
||||||
if !no_backup {
|
if !no_backup {
|
||||||
let mut backup_path = config_path.clone();
|
let mut backup_path = config_path.clone();
|
||||||
backup_path.push(format!(
|
backup_path.push(format!(
|
||||||
@ -87,7 +88,7 @@ impl Command for ConfigReset {
|
|||||||
if !only_nu {
|
if !only_nu {
|
||||||
let mut env_config = config_path.clone();
|
let mut env_config = config_path.clone();
|
||||||
env_config.push("env.nu");
|
env_config.push("env.nu");
|
||||||
let config_file = include_str!("../../../../../docs/sample_config/default_env.nu");
|
let config_file = get_default_env();
|
||||||
if !no_backup {
|
if !no_backup {
|
||||||
let mut backup_path = config_path.clone();
|
let mut backup_path = config_path.clone();
|
||||||
backup_path.push(format!("oldenv-{}.nu", Local::now().format("%F-%H-%M-%S"),));
|
backup_path.push(format!("oldenv-{}.nu", Local::now().format("%F-%H-%M-%S"),));
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user