Compare commits

...

55 Commits

Author SHA1 Message Date
2df8775b48 Include chart binaries. (#2667) 2020-10-13 17:04:27 -05:00
e02b4f1443 Update wix plugin check with base test. (#2666) 2020-10-13 16:22:49 -05:00
194782215f Update main.wxs
Rename the plugins to be the production names
2020-10-14 09:01:13 +13:00
df17d28c0f Create README.build.txt 2020-10-14 07:14:47 +13:00
5f43c8f024 Update lib.rs 2020-10-14 06:45:04 +13:00
1a18734f9a Update Cargo.toml 2020-10-14 06:44:06 +13:00
4a70c1ff4f Update Cargo.toml
Get around the mutual dependency?
2020-10-14 06:42:24 +13:00
770e5d89f2 Bump to 0.21 (#2663) 2020-10-14 06:19:09 +13:00
cfac8e84dd Disable rustyline bracketed paste mode by default (#2659)
Multiline pastes wait for the user to hit enter before running,
because they enter a special paste mode in rustyline called
'bracketed paste' by default. This commit disables that mode
by default for nushell, causing multiline pastes to be executed
immediately, treating each new line as a separate command.
2020-10-13 19:33:36 +13:00
43d90c1745 Root level cleanup (#2654)
* Remove unused files from rootdir

* Remove unused build deps
2020-10-12 22:47:46 -05:00
38bdb053d2 Add tests for get_data_by_key (#2658)
* Add test for get_data_by_key

* Apply same order for ValuExt impl

* Nothing helper for tests

* Use get_data_by_key from ValueExt
2020-10-12 22:46:58 -05:00
95e61773a5 Restore bigint/bigdecimal serialization. (#2662) 2020-10-12 21:44:28 -05:00
4e931fa73f Extract out xpath to a plugin. (#2661) 2020-10-12 18:18:39 -05:00
2573441e28 xpath command for nushell (#2656)
* xpath prototype

* new xpath engine is finally working

* nearly there

* closer

* working with list, started to add test, code cleanup

* broken again

* working again - time for some cleanup

* cleaned up code, added error handling and test

* update example, fix clippy

* removed commented char
2020-10-12 08:03:00 -05:00
5770b15270 Use iterator chain instead of string concat. (#2655)
* Use iterator chain instead of string concat

* Add regression test for multi-value lines
2020-10-10 18:30:48 +13:00
6817b472d0 Handle inf/nan in delimited data (#2652) 2020-10-09 19:27:01 +13:00
2b076369e0 handle duration overflow error (#2616)
* handle duration overflow error

* handle checked_add_signed result
2020-10-09 14:51:47 +13:00
973a8ee8f3 Allow config to work with column paths. (#2653)
Nu has many commands that allow the nuño to customize behavior such
as UI and behavior. Today, coloring can be customized, the line editor,
and other things. The more options there are, the higher the complexity
in managing them.

To mitigate this Nu can store configuration options as nested properties.

But to add and edit them can be taxing. With column path support we can
work with them easier.
2020-10-08 20:04:19 -05:00
1159d3365a Fix clippy lints (#2651) 2020-10-09 10:47:51 +13:00
152ba32eb7 Debugging tips for contributors (#2647) 2020-10-08 15:14:59 +13:00
153320ef33 Added -1 back when determining term_width (#2646)
* Added -1 back

* retrigger checks

* removed the max

* fixed a mistake
2020-10-07 12:45:57 -05:00
ff236da72c [wasi] Update time & instant crates (#2645)
* [wasi] Update time & instant crates

In https://github.com/nushell/nushell/pull/2643 instant was updated by adding it as a hard dependency in Cargo.toml, but it's better to avoid it and only update in Cargo.lock via `cargo update -p ...`.

Additionally, updated `time` crate so that now some basic commands like `ls` work too, although formatting is pretty bad.

* Update default terminal width to 80

If termsize can't return anything, use 80 chars (e.g. on WASI).
2020-10-07 15:26:16 +13:00
54326869e4 Parse decimals as BigDecimal (#2644)
Use implicit serde from BigDecimal crate
2020-10-07 14:01:40 +13:00
f14f4e39c5 Begin adding wasi support (#2643)
* Begin adding wasi support

* Now it builds and runs but needs more help
2020-10-07 11:21:24 +13:00
a18b2702ca Parse integers as BigInt (#2642)
* Parse integer shape as BigInt

* Use implicit serde from BigInt crate
2020-10-07 06:30:18 +13:00
93410c470e Bump dtparse to fix panic (#2632) 2020-10-07 06:27:06 +13:00
5d945ef869 empty? rewrite. (#2641) 2020-10-06 05:21:20 -05:00
df07be6a42 Fix to_md function name (#2636)
* Fix to_md function name

* rustfmt
2020-10-05 18:13:27 -05:00
3c32d4947c added blink and underline options to coloring (#2638) 2020-10-05 18:12:56 -05:00
2ea5235aea Ensure Wix lists Nu plugin binaries. (#2637) 2020-10-05 14:29:04 -05:00
c096f031ce update wix to include _core_ and _extra_ plugins + s3, chart, line (#2634) 2020-10-04 05:56:33 +13:00
ae1d4bdb4c Nushell internal commands. Anchor locations tracker surveying. (#2635) 2020-10-03 09:06:02 -05:00
0adf2accdd Fix defaulting alias var values (#2631) 2020-10-03 09:18:23 +13:00
4201f48be5 Left Pad and Right Pad String (#2630)
* WIP

* left and right pad strings

* fixed some tests
2020-10-02 14:45:59 -05:00
b076e375ca Fix broken removal of sockets (#2629)
* make sort-by fail gracefully if mismatched types are compared

* Added a test to check if sorted-by with invalid types exists gracefully

* Linter changes

* removed redundant pattern matching

* Changed the error message

* Added a comma after every argument

* Changed the test to accomodate the new err messages

* Err message for sort-by invalid types now shows the mismatched types

* Lints problems

* Changed unwrap to expect

* Added the -f flag to rm command

Now when you a use rm -f there will be no error message, even if the
file doesnt actually exist

* Lint problems

* Fixed the wrong line

* Removed println

* Spelling mistake

* Fix problems when you mv a file into itself

* Lint mistakes

* Remove unecessary filtering in most cases

* Allow the removal of sockets

* Conditional compilations to systems without socket
2020-10-02 17:50:55 +13:00
2f1016d44f Add examples to update cmd (#2628) 2020-10-01 20:13:42 -05:00
ddf9d61346 Line charts. Chart plugin sub command extraction. (#2627) 2020-10-01 19:23:10 -05:00
f0b7ab5ecc chart tweaks for windows (#2626) 2020-10-01 14:48:57 -05:00
e4c6336bd4 Convert to string before clip (#2624) 2020-10-01 18:22:19 +13:00
66061192f8 Fix "mv allows moving a directory into itself" (#2619)
* make sort-by fail gracefully if mismatched types are compared

* Added a test to check if sorted-by with invalid types exists gracefully

* Linter changes

* removed redundant pattern matching

* Changed the error message

* Added a comma after every argument

* Changed the test to accomodate the new err messages

* Err message for sort-by invalid types now shows the mismatched types

* Lints problems

* Changed unwrap to expect

* Added the -f flag to rm command

Now when you a use rm -f there will be no error message, even if the
file doesnt actually exist

* Lint problems

* Fixed the wrong line

* Removed println

* Spelling mistake

* Fix problems when you mv a file into itself

* Lint mistakes

* Remove unecessary filtering in most cases
2020-10-01 14:01:05 +13:00
b7bc4c1f80 Exit bar visualization if any key is pressed other than left and right arrow keys. (#2623) 2020-09-30 14:34:29 -05:00
a56abb6502 Bar Chart baseline. (#2621)
Bar Chart ready.
2020-09-30 13:27:52 -05:00
892a416211 Move BTreeMap to IndexMap to preserve order (#2617) 2020-09-30 19:49:40 +13:00
f45adecd01 fix select for column names with spaces (#2613) 2020-09-30 10:00:07 +13:00
bd015e82dc Tidy up crates in nu-protocol (#2611)
* Remove unneeded crates from nu-protocol

* Simplify join, use std fn
2020-09-29 16:33:43 +13:00
cf43b74f26 did_you_mean without dependency (#2610) 2020-09-29 16:32:29 +13:00
18909ec14a Describe object now matches cmd name (#2603) 2020-09-27 14:54:47 +13:00
ed243c88d2 Move non-essential deps into specific crates (#2601) 2020-09-26 18:32:52 +12:00
cb7723f423 Refactor scope (#2602)
* Refactor scope to have parents

* Refactor scope to have parents

* Refactor scope to have parents

* Clippy

Co-authored-by: Jonathan Turner <jonathan@pop-os.localdomain>
2020-09-26 11:40:02 +12:00
9dc88f8a95 Add env var during benchmark to randomize stack (#2600) 2020-09-26 10:57:48 +12:00
0a439fe52f Removed unused files in nu-data (#2598) 2020-09-25 15:44:59 +12:00
a8b65e35ec Consolidate suggestions code (#2597) 2020-09-25 15:44:24 +12:00
bd9e598bf0 did_you_mean returns just the word matches (#2595) 2020-09-24 15:56:19 +12:00
75f8247af1 added .cargo/config.toml to build with bigger stack on windows (#2594)
* added .cargo/config.toml to build with bigger stack on windows

* updated comments
2020-09-24 15:55:33 +12:00
e8ec5027ff remove without check path exist, rm -f (#2590) 2020-09-22 17:11:31 -04:00
295 changed files with 5229 additions and 2047 deletions

6
.cargo/config.toml Normal file
View File

@ -0,0 +1,6 @@
# use LLD as linker on Windows because it could be faster
# for full and incremental builds compared to default
[target.x86_64-pc-windows-msvc]
#linker = "lld-link.exe"
rustflags = ["-C", "link-args=-stack:10000000"]

View File

@ -31,6 +31,11 @@ cargo build
cargo build --release && cargo run --release cargo build --release && cargo run --release
``` ```
- Build and run with extra features:
```shell
cargo build --release --features=extra && cargo run --release --features=extra
```
- Run Clippy on Nushell: - Run Clippy on Nushell:
```shell ```shell
@ -60,3 +65,11 @@ cargo build
```shell ```shell
cargo fmt --all cargo fmt --all
``` ```
### Debugging Tips
- To view verbose logs when developing, enable the `trace` log level.
```shell
cargo build --release --features=extra && cargo run --release --features=extra -- --loglevel trace
```

209
Cargo.lock generated
View File

@ -607,6 +607,12 @@ dependencies = [
"zip", "zip",
] ]
[[package]]
name = "cassowary"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.59" version = "1.0.59"
@ -940,6 +946,22 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "crossterm"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2fcdc3c9cf8ee446222e8ee8691a6d21b563b8fe1a64b1873080db7b5b23cf0"
dependencies = [
"bitflags",
"crossterm_winapi",
"lazy_static 1.4.0",
"libc",
"mio 0.7.0",
"parking_lot 0.11.0",
"signal-hook",
"winapi 0.3.9",
]
[[package]] [[package]]
name = "crossterm_winapi" name = "crossterm_winapi"
version = "0.6.1" version = "0.6.1"
@ -1185,9 +1207,9 @@ checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b"
[[package]] [[package]]
name = "dtparse" name = "dtparse"
version = "1.1.0" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9713da7ca51bcd8ecbaedbd6309110eb1ca930d2109ef595a125f84fa1bc608b" checksum = "13276c5dbd7f365e00efe6631242772fe6615e1899df84d1f6ce3ae7b48209f6"
dependencies = [ dependencies = [
"chrono", "chrono",
"chrono-tz", "chrono-tz",
@ -1725,7 +1747,7 @@ checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"wasi", "wasi 0.9.0+wasi-snapshot-preview1",
] ]
[[package]] [[package]]
@ -2206,9 +2228,12 @@ dependencies = [
[[package]] [[package]]
name = "instant" name = "instant"
version = "0.1.6" version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b141fdc7836c525d4d594027d318c84161ca17aaf8113ab1f81ab93ae897485" checksum = "63312a18f7ea8760cdd0a7c5aac1a619752a246b833545e3e36d1f81f7cd9e66"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "iovec" name = "iovec"
@ -2749,15 +2774,6 @@ dependencies = [
"tempfile", "tempfile",
] ]
[[package]]
name = "natural"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65e6b44f8ddc659cde3555e0140d3441ad26cb03a1410774af1f9a19097c1867"
dependencies = [
"rust-stemmers",
]
[[package]] [[package]]
name = "neso" name = "neso"
version = "0.5.0" version = "0.5.0"
@ -2842,10 +2858,9 @@ dependencies = [
[[package]] [[package]]
name = "nu" name = "nu"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"clap", "clap",
"crossterm",
"ctrlc", "ctrlc",
"dunce", "dunce",
"futures 0.3.5", "futures 0.3.5",
@ -2860,6 +2875,7 @@ dependencies = [
"nu-test-support", "nu-test-support",
"nu-value-ext", "nu-value-ext",
"nu_plugin_binaryview", "nu_plugin_binaryview",
"nu_plugin_chart",
"nu_plugin_fetch", "nu_plugin_fetch",
"nu_plugin_from_bson", "nu_plugin_from_bson",
"nu_plugin_from_sqlite", "nu_plugin_from_sqlite",
@ -2874,17 +2890,13 @@ dependencies = [
"nu_plugin_to_bson", "nu_plugin_to_bson",
"nu_plugin_to_sqlite", "nu_plugin_to_sqlite",
"nu_plugin_tree", "nu_plugin_tree",
"nu_plugin_xpath",
"pretty_env_logger", "pretty_env_logger",
"quick-xml 0.18.1",
"semver 0.10.0",
"serde 1.0.115",
"toml",
"url 2.1.1",
] ]
[[package]] [[package]]
name = "nu-cli" name = "nu-cli"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"Inflector", "Inflector",
"ansi_term 0.12.1", "ansi_term 0.12.1",
@ -2924,7 +2936,6 @@ dependencies = [
"itertools", "itertools",
"log 0.4.11", "log 0.4.11",
"meval", "meval",
"natural",
"nu-data", "nu-data",
"nu-errors", "nu-errors",
"nu-parser", "nu-parser",
@ -2962,6 +2973,8 @@ dependencies = [
"sha2 0.9.1", "sha2 0.9.1",
"shellexpand", "shellexpand",
"strip-ansi-escapes", "strip-ansi-escapes",
"sxd-document",
"sxd-xpath",
"tempfile", "tempfile",
"term", "term",
"term_size", "term_size",
@ -2980,7 +2993,7 @@ dependencies = [
[[package]] [[package]]
name = "nu-data" name = "nu-data"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"ansi_term 0.12.1", "ansi_term 0.12.1",
"bigdecimal", "bigdecimal",
@ -2996,6 +3009,7 @@ dependencies = [
"nu-protocol", "nu-protocol",
"nu-source", "nu-source",
"nu-table", "nu-table",
"nu-test-support",
"nu-value-ext", "nu-value-ext",
"num-bigint 0.3.0", "num-bigint 0.3.0",
"num-traits 0.2.12", "num-traits 0.2.12",
@ -3008,7 +3022,7 @@ dependencies = [
[[package]] [[package]]
name = "nu-errors" name = "nu-errors"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"ansi_term 0.12.1", "ansi_term 0.12.1",
"bigdecimal", "bigdecimal",
@ -3027,7 +3041,7 @@ dependencies = [
[[package]] [[package]]
name = "nu-parser" name = "nu-parser"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"bigdecimal", "bigdecimal",
"codespan-reporting", "codespan-reporting",
@ -3045,7 +3059,7 @@ dependencies = [
[[package]] [[package]]
name = "nu-plugin" name = "nu-plugin"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"bigdecimal", "bigdecimal",
"indexmap", "indexmap",
@ -3060,19 +3074,15 @@ dependencies = [
[[package]] [[package]]
name = "nu-protocol" name = "nu-protocol"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"ansi_term 0.12.1",
"bigdecimal", "bigdecimal",
"byte-unit", "byte-unit",
"chrono", "chrono",
"codespan-reporting",
"derive-new", "derive-new",
"getset", "getset",
"indexmap", "indexmap",
"itertools",
"log 0.4.11", "log 0.4.11",
"natural",
"nu-errors", "nu-errors",
"nu-source", "nu-source",
"num-bigint 0.3.0", "num-bigint 0.3.0",
@ -3087,7 +3097,7 @@ dependencies = [
[[package]] [[package]]
name = "nu-source" name = "nu-source"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"derive-new", "derive-new",
"getset", "getset",
@ -3098,7 +3108,7 @@ dependencies = [
[[package]] [[package]]
name = "nu-table" name = "nu-table"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"ansi_term 0.12.1", "ansi_term 0.12.1",
"unicode-width", "unicode-width",
@ -3106,20 +3116,24 @@ dependencies = [
[[package]] [[package]]
name = "nu-test-support" name = "nu-test-support"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"chrono",
"dunce", "dunce",
"getset", "getset",
"glob", "glob",
"indexmap", "indexmap",
"nu-errors",
"nu-protocol", "nu-protocol",
"nu-source", "nu-source",
"nu-value-ext",
"num-bigint 0.3.0",
"tempfile", "tempfile",
] ]
[[package]] [[package]]
name = "nu-value-ext" name = "nu-value-ext"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"itertools", "itertools",
@ -3131,10 +3145,10 @@ dependencies = [
[[package]] [[package]]
name = "nu_plugin_binaryview" name = "nu_plugin_binaryview"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"ansi_term 0.12.1", "ansi_term 0.12.1",
"crossterm", "crossterm 0.18.0",
"image", "image",
"neso", "neso",
"nu-errors", "nu-errors",
@ -3145,9 +3159,24 @@ dependencies = [
"rawkey", "rawkey",
] ]
[[package]]
name = "nu_plugin_chart"
version = "0.21.0"
dependencies = [
"crossterm 0.18.0",
"nu-cli",
"nu-data",
"nu-errors",
"nu-plugin",
"nu-protocol",
"nu-source",
"nu-value-ext",
"tui",
]
[[package]] [[package]]
name = "nu_plugin_fetch" name = "nu_plugin_fetch"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"base64 0.12.3", "base64 0.12.3",
"futures 0.3.5", "futures 0.3.5",
@ -3161,7 +3190,7 @@ dependencies = [
[[package]] [[package]]
name = "nu_plugin_from_bson" name = "nu_plugin_from_bson"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"bigdecimal", "bigdecimal",
"bson", "bson",
@ -3175,7 +3204,7 @@ dependencies = [
[[package]] [[package]]
name = "nu_plugin_from_sqlite" name = "nu_plugin_from_sqlite"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"bigdecimal", "bigdecimal",
"nu-errors", "nu-errors",
@ -3190,7 +3219,7 @@ dependencies = [
[[package]] [[package]]
name = "nu_plugin_inc" name = "nu_plugin_inc"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"nu-errors", "nu-errors",
"nu-plugin", "nu-plugin",
@ -3202,7 +3231,7 @@ dependencies = [
[[package]] [[package]]
name = "nu_plugin_match" name = "nu_plugin_match"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"nu-errors", "nu-errors",
"nu-plugin", "nu-plugin",
@ -3213,7 +3242,7 @@ dependencies = [
[[package]] [[package]]
name = "nu_plugin_post" name = "nu_plugin_post"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"base64 0.12.3", "base64 0.12.3",
"futures 0.3.5", "futures 0.3.5",
@ -3229,7 +3258,7 @@ dependencies = [
[[package]] [[package]]
name = "nu_plugin_ps" name = "nu_plugin_ps"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"futures 0.3.5", "futures 0.3.5",
"futures-timer", "futures-timer",
@ -3243,7 +3272,7 @@ dependencies = [
[[package]] [[package]]
name = "nu_plugin_s3" name = "nu_plugin_s3"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"futures 0.3.5", "futures 0.3.5",
"nu-errors", "nu-errors",
@ -3255,7 +3284,7 @@ dependencies = [
[[package]] [[package]]
name = "nu_plugin_start" name = "nu_plugin_start"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"glob", "glob",
"nu-errors", "nu-errors",
@ -3268,7 +3297,7 @@ dependencies = [
[[package]] [[package]]
name = "nu_plugin_sys" name = "nu_plugin_sys"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"battery", "battery",
"futures 0.3.5", "futures 0.3.5",
@ -3283,7 +3312,7 @@ dependencies = [
[[package]] [[package]]
name = "nu_plugin_textview" name = "nu_plugin_textview"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"ansi_term 0.12.1", "ansi_term 0.12.1",
"bat", "bat",
@ -3298,7 +3327,7 @@ dependencies = [
[[package]] [[package]]
name = "nu_plugin_to_bson" name = "nu_plugin_to_bson"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"bson", "bson",
"nu-errors", "nu-errors",
@ -3311,7 +3340,7 @@ dependencies = [
[[package]] [[package]]
name = "nu_plugin_to_sqlite" name = "nu_plugin_to_sqlite"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"hex 0.4.2", "hex 0.4.2",
"nu-errors", "nu-errors",
@ -3326,7 +3355,7 @@ dependencies = [
[[package]] [[package]]
name = "nu_plugin_tree" name = "nu_plugin_tree"
version = "0.20.0" version = "0.21.0"
dependencies = [ dependencies = [
"derive-new", "derive-new",
"nu-errors", "nu-errors",
@ -3336,6 +3365,21 @@ dependencies = [
"ptree", "ptree",
] ]
[[package]]
name = "nu_plugin_xpath"
version = "0.21.0"
dependencies = [
"bigdecimal",
"indexmap",
"nu-errors",
"nu-plugin",
"nu-protocol",
"nu-source",
"nu-test-support",
"sxd-document",
"sxd-xpath",
]
[[package]] [[package]]
name = "num" name = "num"
version = "0.2.1" version = "0.2.1"
@ -3699,6 +3743,12 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "peresil"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f658886ed52e196e850cfbbfddab9eaa7f6d90dd0929e264c31e5cec07e09e57"
[[package]] [[package]]
name = "pest" name = "pest"
version = "2.1.3" version = "2.1.3"
@ -4482,16 +4532,6 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2"
[[package]]
name = "rust-stemmers"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e46a2036019fdb888131db7a4c847a1063a7493f971ed94ea82c67eada63ca54"
dependencies = [
"serde 1.0.115",
"serde_derive",
]
[[package]] [[package]]
name = "rust_decimal" name = "rust_decimal"
version = "0.10.2" version = "0.10.2"
@ -5034,6 +5074,27 @@ dependencies = [
"web-sys", "web-sys",
] ]
[[package]]
name = "sxd-document"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94d82f37be9faf1b10a82c4bd492b74f698e40082f0f40de38ab275f31d42078"
dependencies = [
"peresil",
"typed-arena",
]
[[package]]
name = "sxd-xpath"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36e39da5d30887b5690e29de4c5ebb8ddff64ebd9933f98a01daaa4fd11b36ea"
dependencies = [
"peresil",
"quick-error",
"sxd-document",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.39" version = "1.0.39"
@ -5198,11 +5259,12 @@ dependencies = [
[[package]] [[package]]
name = "time" name = "time"
version = "0.1.43" 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 = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [ dependencies = [
"libc", "libc",
"wasi 0.10.0+wasi-snapshot-preview1",
"winapi 0.3.9", "winapi 0.3.9",
] ]
@ -5499,6 +5561,19 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "tui"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2eaeee894a1e9b90f80aa466fe59154fdb471980b5e104d8836fcea309ae17e"
dependencies = [
"bitflags",
"cassowary",
"crossterm 0.17.8",
"unicode-segmentation",
"unicode-width",
]
[[package]] [[package]]
name = "typed-arena" name = "typed-arena"
version = "1.7.0" version = "1.7.0"
@ -5778,6 +5853,12 @@ version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.67" version = "0.2.67"

View File

@ -10,7 +10,7 @@ license = "MIT"
name = "nu" name = "nu"
readme = "README.md" readme = "README.md"
repository = "https://github.com/nushell/nushell" repository = "https://github.com/nushell/nushell"
version = "0.20.0" version = "0.21.0"
[workspace] [workspace]
members = ["crates/*/"] members = ["crates/*/"]
@ -18,51 +18,57 @@ members = ["crates/*/"]
# 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-cli = {version = "0.20.0", path = "./crates/nu-cli"} nu-cli = {version = "0.21.0", path = "./crates/nu-cli"}
nu-data = {version = "0.20.0", path = "./crates/nu-data"} nu-data = {version = "0.21.0", path = "./crates/nu-data"}
nu-errors = {version = "0.20.0", path = "./crates/nu-errors"} nu-errors = {version = "0.21.0", path = "./crates/nu-errors"}
nu-parser = {version = "0.20.0", path = "./crates/nu-parser"} nu-parser = {version = "0.21.0", path = "./crates/nu-parser"}
nu-plugin = {version = "0.20.0", path = "./crates/nu-plugin"} nu-plugin = {version = "0.21.0", path = "./crates/nu-plugin"}
nu-protocol = {version = "0.20.0", path = "./crates/nu-protocol"} nu-protocol = {version = "0.21.0", path = "./crates/nu-protocol"}
nu-source = {version = "0.20.0", path = "./crates/nu-source"} nu-source = {version = "0.21.0", path = "./crates/nu-source"}
nu-value-ext = {version = "0.20.0", path = "./crates/nu-value-ext"} nu-value-ext = {version = "0.21.0", path = "./crates/nu-value-ext"}
nu_plugin_binaryview = {version = "0.20.0", path = "./crates/nu_plugin_binaryview", optional = true} nu_plugin_binaryview = {version = "0.21.0", path = "./crates/nu_plugin_binaryview", optional = true}
nu_plugin_fetch = {version = "0.20.0", path = "./crates/nu_plugin_fetch", optional = true} nu_plugin_chart = {version = "0.21.0", path = "./crates/nu_plugin_chart", optional = true}
nu_plugin_from_bson = {version = "0.20.0", path = "./crates/nu_plugin_from_bson", optional = true} nu_plugin_fetch = {version = "0.21.0", path = "./crates/nu_plugin_fetch", optional = true}
nu_plugin_from_sqlite = {version = "0.20.0", path = "./crates/nu_plugin_from_sqlite", optional = true} nu_plugin_from_bson = {version = "0.21.0", path = "./crates/nu_plugin_from_bson", optional = true}
nu_plugin_inc = {version = "0.20.0", path = "./crates/nu_plugin_inc", optional = true} nu_plugin_from_sqlite = {version = "0.21.0", path = "./crates/nu_plugin_from_sqlite", optional = true}
nu_plugin_match = {version = "0.20.0", path = "./crates/nu_plugin_match", optional = true} nu_plugin_inc = {version = "0.21.0", path = "./crates/nu_plugin_inc", optional = true}
nu_plugin_post = {version = "0.20.0", path = "./crates/nu_plugin_post", optional = true} nu_plugin_match = {version = "0.21.0", path = "./crates/nu_plugin_match", optional = true}
nu_plugin_ps = {version = "0.20.0", path = "./crates/nu_plugin_ps", optional = true} nu_plugin_post = {version = "0.21.0", path = "./crates/nu_plugin_post", optional = true}
nu_plugin_s3 = {version = "0.20.0", path = "./crates/nu_plugin_s3", optional = true} nu_plugin_ps = {version = "0.21.0", path = "./crates/nu_plugin_ps", optional = true}
nu_plugin_start = {version = "0.20.0", path = "./crates/nu_plugin_start", optional = true} nu_plugin_s3 = {version = "0.21.0", path = "./crates/nu_plugin_s3", optional = true}
nu_plugin_sys = {version = "0.20.0", path = "./crates/nu_plugin_sys", optional = true} nu_plugin_start = {version = "0.21.0", path = "./crates/nu_plugin_start", optional = true}
nu_plugin_textview = {version = "0.20.0", path = "./crates/nu_plugin_textview", optional = true} nu_plugin_sys = {version = "0.21.0", path = "./crates/nu_plugin_sys", optional = true}
nu_plugin_to_bson = {version = "0.20.0", path = "./crates/nu_plugin_to_bson", optional = true} nu_plugin_textview = {version = "0.21.0", path = "./crates/nu_plugin_textview", optional = true}
nu_plugin_to_sqlite = {version = "0.20.0", path = "./crates/nu_plugin_to_sqlite", optional = true} nu_plugin_to_bson = {version = "0.21.0", path = "./crates/nu_plugin_to_bson", optional = true}
nu_plugin_tree = {version = "0.20.0", path = "./crates/nu_plugin_tree", optional = true} nu_plugin_to_sqlite = {version = "0.21.0", path = "./crates/nu_plugin_to_sqlite", optional = true}
nu_plugin_tree = {version = "0.21.0", path = "./crates/nu_plugin_tree", optional = true}
crossterm = {version = "0.17", optional = true} nu_plugin_xpath = {version = "0.21.0", path = "./crates/nu_plugin_xpath", optional = true}
semver = {version = "0.10.0", optional = true}
url = {version = "2.1.1", optional = true}
# Required to bootstrap the main binary
clap = "2.33.3" clap = "2.33.3"
ctrlc = "3.1.6" ctrlc = {version = "3.1.6", optional = true}
dunce = "1.0.1"
futures = {version = "0.3.5", features = ["compat", "io-compat"]} futures = {version = "0.3.5", features = ["compat", "io-compat"]}
log = "0.4.11" log = "0.4.11"
pretty_env_logger = "0.4.0" pretty_env_logger = "0.4.0"
quick-xml = "0.18.1"
[dev-dependencies] [dev-dependencies]
nu-test-support = {version = "0.20.0", path = "./crates/nu-test-support"} dunce = "1.0.1"
nu-test-support = {version = "0.21.0", path = "./crates/nu-test-support"}
[build-dependencies] [build-dependencies]
serde = {version = "1.0.115", features = ["derive"]}
toml = "0.5.6"
[features] [features]
ctrlc-support = ["nu-cli/ctrlc"]
directories-support = ["nu-cli/directories", "nu-cli/dirs", "nu-data/directories", "nu-data/dirs"]
git-support = ["nu-cli/git2"]
ptree-support = ["nu-cli/ptree"]
rich-benchmark = ["nu-cli/rich-benchmark"]
rustyline-support = ["nu-cli/rustyline-support"]
term-support = ["nu-cli/term"]
uuid-support = ["nu-cli/uuid_crate"]
which-support = ["nu-cli/ichwh", "nu-cli/which"]
default = [ default = [
"sys", "sys",
"ps", "ps",
@ -81,38 +87,33 @@ default = [
"fetch", "fetch",
"rich-benchmark", "rich-benchmark",
] ]
extra = ["default", "binaryview", "tree", "clipboard-cli", "trash-support", "start", "bson", "sqlite", "s3"] extra = ["default", "binaryview", "tree", "clipboard-cli", "trash-support", "start", "bson", "sqlite", "s3", "chart", "xpath"]
stable = ["default"] stable = ["default"]
# Default wasi = ["inc", "match", "directories-support", "ptree-support", "match", "tree", "rustyline-support"]
inc = ["semver", "nu_plugin_inc"]
ps = ["nu_plugin_ps"]
sys = ["nu_plugin_sys"]
textview = ["crossterm", "url", "nu_plugin_textview"]
# Stable trace = ["nu-parser/trace"]
binaryview = ["nu_plugin_binaryview"]
bson = ["nu_plugin_from_bson", "nu_plugin_to_bson"] # Stable (Default)
fetch = ["nu_plugin_fetch"] fetch = ["nu_plugin_fetch"]
inc = ["nu_plugin_inc"]
match = ["nu_plugin_match"] match = ["nu_plugin_match"]
post = ["nu_plugin_post"] post = ["nu_plugin_post"]
ps = ["nu_plugin_ps"]
sys = ["nu_plugin_sys"]
textview = ["nu_plugin_textview"]
# Extra
binaryview = ["nu_plugin_binaryview"]
bson = ["nu_plugin_from_bson", "nu_plugin_to_bson"]
chart = ["nu_plugin_chart"]
clipboard-cli = ["nu-cli/clipboard-cli"]
s3 = ["nu_plugin_s3"] s3 = ["nu_plugin_s3"]
sqlite = ["nu_plugin_from_sqlite", "nu_plugin_to_sqlite"] sqlite = ["nu_plugin_from_sqlite", "nu_plugin_to_sqlite"]
start = ["nu_plugin_start"] start = ["nu_plugin_start"]
trace = ["nu-parser/trace"]
tree = ["nu_plugin_tree"]
clipboard-cli = ["nu-cli/clipboard-cli"]
ctrlc-support = ["nu-cli/ctrlc"]
directories-support = ["nu-cli/directories", "nu-cli/dirs", "nu-data/directories", "nu-data/dirs"]
git-support = ["nu-cli/git2"]
ptree-support = ["nu-cli/ptree"]
rich-benchmark = ["nu-cli/rich-benchmark"]
rustyline-support = ["nu-cli/rustyline-support"]
term-support = ["nu-cli/term"]
trash-support = ["nu-cli/trash-support"] trash-support = ["nu-cli/trash-support"]
uuid-support = ["nu-cli/uuid_crate"] tree = ["nu_plugin_tree"]
which-support = ["nu-cli/ichwh", "nu-cli/which"] xpath = ["nu_plugin_xpath"]
# Core plugins that ship with `cargo install nu` by default # Core plugins that ship with `cargo install nu` by default
# Currently, Cargo limits us to installing only one binary # Currently, Cargo limits us to installing only one binary
@ -174,6 +175,21 @@ name = "nu_plugin_extra_s3"
path = "src/plugins/nu_plugin_extra_s3.rs" path = "src/plugins/nu_plugin_extra_s3.rs"
required-features = ["s3"] required-features = ["s3"]
[[bin]]
name = "nu_plugin_extra_chart_bar"
path = "src/plugins/nu_plugin_extra_chart_bar.rs"
required-features = ["chart"]
[[bin]]
name = "nu_plugin_extra_chart_line"
path = "src/plugins/nu_plugin_extra_chart_line.rs"
required-features = ["chart"]
[[bin]]
name = "nu_plugin_extra_xpath"
path = "src/plugins/nu_plugin_extra_xpath.rs"
required-features = ["xpath"]
# Main nu binary # Main nu binary
[[bin]] [[bin]]
name = "nu" name = "nu"

View File

View File

@ -4,21 +4,21 @@ description = "CLI for nushell"
edition = "2018" edition = "2018"
license = "MIT" license = "MIT"
name = "nu-cli" name = "nu-cli"
version = "0.20.0" version = "0.21.0"
[lib] [lib]
doctest = false doctest = false
[dependencies] [dependencies]
nu-data = {version = "0.20.0", path = "../nu-data"} nu-data = {version = "0.21.0", path = "../nu-data"}
nu-errors = {version = "0.20.0", path = "../nu-errors"} nu-errors = {version = "0.21.0", path = "../nu-errors"}
nu-parser = {version = "0.20.0", path = "../nu-parser"} nu-parser = {version = "0.21.0", path = "../nu-parser"}
nu-plugin = {version = "0.20.0", path = "../nu-plugin"} nu-plugin = {version = "0.21.0", path = "../nu-plugin"}
nu-protocol = {version = "0.20.0", path = "../nu-protocol"} nu-protocol = {version = "0.21.0", path = "../nu-protocol"}
nu-source = {version = "0.20.0", path = "../nu-source"} nu-source = {version = "0.21.0", path = "../nu-source"}
nu-table = {version = "0.20.0", path = "../nu-table"} nu-table = {version = "0.21.0", path = "../nu-table"}
nu-test-support = {version = "0.20.0", path = "../nu-test-support"} nu-test-support = {version = "0.21.0", path = "../nu-test-support"}
nu-value-ext = {version = "0.20.0", path = "../nu-value-ext"} nu-value-ext = {version = "0.21.0", path = "../nu-value-ext"}
ansi_term = "0.12.1" ansi_term = "0.12.1"
async-recursion = "0.3.1" async-recursion = "0.3.1"
@ -36,7 +36,7 @@ ctrlc = {version = "3.1.6", optional = true}
derive-new = "0.5.8" derive-new = "0.5.8"
directories = {version = "3.0.1", optional = true} directories = {version = "3.0.1", optional = true}
dirs = {version = "3.0.1", optional = true} dirs = {version = "3.0.1", optional = true}
dtparse = "1.1.0" dtparse = "1.2.0"
dunce = "1.0.1" dunce = "1.0.1"
eml-parser = "0.1.0" eml-parser = "0.1.0"
filesize = "0.2.0" filesize = "0.2.0"
@ -55,7 +55,6 @@ indexmap = {version = "1.6.0", features = ["serde-1"]}
itertools = "0.9.0" itertools = "0.9.0"
log = "0.4.11" log = "0.4.11"
meval = "0.2.0" meval = "0.2.0"
natural = "0.5.0"
num-bigint = {version = "0.3.0", features = ["serde"]} num-bigint = {version = "0.3.0", features = ["serde"]}
num-format = {version = "0.4.0", features = ["with-num-bigint"]} num-format = {version = "0.4.0", features = ["with-num-bigint"]}
num-traits = "0.2.12" num-traits = "0.2.12"
@ -64,6 +63,7 @@ pin-utils = "0.1.0"
pretty-hex = "0.2.0" pretty-hex = "0.2.0"
ptree = {version = "0.3.0", optional = true} ptree = {version = "0.3.0", optional = true}
query_interface = "0.3.5" query_interface = "0.3.5"
quick-xml = "0.18.1"
rand = "0.7.3" rand = "0.7.3"
regex = "1.3.9" regex = "1.3.9"
roxmltree = "0.13.0" roxmltree = "0.13.0"
@ -79,6 +79,8 @@ serde_yaml = "0.8.13"
sha2 = "0.9.1" sha2 = "0.9.1"
shellexpand = "2.0.0" shellexpand = "2.0.0"
strip-ansi-escapes = "0.1.0" strip-ansi-escapes = "0.1.0"
sxd-document = "0.3.2"
sxd-xpath = "0.4.2"
tempfile = "3.1.0" tempfile = "3.1.0"
term = {version = "0.6.1", optional = true} term = {version = "0.6.1", optional = true}
term_size = "0.3.2" term_size = "0.3.2"
@ -93,7 +95,6 @@ zip = {version = "0.5.7", optional = true}
Inflector = "0.11" Inflector = "0.11"
clipboard = {version = "0.5.0", optional = true} clipboard = {version = "0.5.0", optional = true}
encoding_rs = "0.8.24" encoding_rs = "0.8.24"
quick-xml = "0.18.1"
rayon = "1.4.0" rayon = "1.4.0"
trash = {version = "1.1.1", optional = true} trash = {version = "1.1.1", optional = true}
url = "2.1.1" url = "2.1.1"

View File

@ -9,7 +9,7 @@ use crate::EnvironmentSyncer;
use futures_codec::FramedRead; use futures_codec::FramedRead;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::hir::{ClassifiedCommand, Expression, InternalCommand, Literal, NamedArguments}; use nu_protocol::hir::{ClassifiedCommand, Expression, InternalCommand, Literal, NamedArguments};
use nu_protocol::{Primitive, ReturnSuccess, UntaggedValue, Value}; use nu_protocol::{Primitive, ReturnSuccess, Scope, UntaggedValue, Value};
use log::{debug, trace}; use log::{debug, trace};
#[cfg(feature = "rustyline-support")] #[cfg(feature = "rustyline-support")]
@ -95,7 +95,7 @@ pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Bo
whole_stream_command(Kill), whole_stream_command(Kill),
whole_stream_command(Version), whole_stream_command(Version),
whole_stream_command(Clear), whole_stream_command(Clear),
whole_stream_command(What), whole_stream_command(Describe),
whole_stream_command(Which), whole_stream_command(Which),
whole_stream_command(Debug), whole_stream_command(Debug),
whole_stream_command(Alias), whole_stream_command(Alias),
@ -114,6 +114,8 @@ pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Bo
whole_stream_command(Shells), whole_stream_command(Shells),
whole_stream_command(Enter), whole_stream_command(Enter),
whole_stream_command(Exit), whole_stream_command(Exit),
// Viz
whole_stream_command(Chart),
// Viewers // Viewers
whole_stream_command(Autoview), whole_stream_command(Autoview),
whole_stream_command(Table), whole_stream_command(Table),
@ -145,7 +147,9 @@ pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Bo
whole_stream_command(StrEndsWith), whole_stream_command(StrEndsWith),
whole_stream_command(StrCollect), whole_stream_command(StrCollect),
whole_stream_command(StrLength), whole_stream_command(StrLength),
whole_stream_command(StrLPad),
whole_stream_command(StrReverse), whole_stream_command(StrReverse),
whole_stream_command(StrRPad),
whole_stream_command(StrCamelCase), whole_stream_command(StrCamelCase),
whole_stream_command(StrPascalCase), whole_stream_command(StrPascalCase),
whole_stream_command(StrKebabCase), whole_stream_command(StrKebabCase),
@ -192,7 +196,7 @@ pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Bo
whole_stream_command(Each), whole_stream_command(Each),
whole_stream_command(EachGroup), whole_stream_command(EachGroup),
whole_stream_command(EachWindow), whole_stream_command(EachWindow),
whole_stream_command(IsEmpty), whole_stream_command(Empty),
// Table manipulation // Table manipulation
whole_stream_command(Move), whole_stream_command(Move),
whole_stream_command(Merge), whole_stream_command(Merge),
@ -395,9 +399,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
&prompt_block.block, &prompt_block.block,
&mut context, &mut context,
InputStream::empty(), InputStream::empty(),
&Value::nothing(), Scope::from_env(env),
&IndexMap::new(),
&env,
) )
.await .await
{ {
@ -667,6 +669,9 @@ fn default_rustyline_editor_configuration() -> Editor<Helper> {
Cmd::Move(Movement::ForwardWord(1, At::AfterEnd, Word::Vi)), Cmd::Move(Movement::ForwardWord(1, At::AfterEnd, Word::Vi)),
); );
// workaround for multiline-paste hang in rustyline (see https://github.com/kkawakam/rustyline/issues/202)
rl.bind_sequence(KeyPress::BracketedPasteStart, rustyline::Cmd::Noop);
// Let's set the defaults up front and then override them later if the user indicates // Let's set the defaults up front and then override them later if the user indicates
// defaults taken from here https://github.com/kkawakam/rustyline/blob/2fe886c9576c1ea13ca0e5808053ad491a6fe049/src/config.rs#L150-L167 // defaults taken from here https://github.com/kkawakam/rustyline/blob/2fe886c9576c1ea13ca0e5808053ad491a6fe049/src/config.rs#L150-L167
rl.set_max_history_size(100); rl.set_max_history_size(100);
@ -862,9 +867,7 @@ pub async fn parse_and_eval(line: &str, ctx: &mut EvaluationContext) -> Result<S
&classified_block.block, &classified_block.block,
ctx, ctx,
input_stream, input_stream,
&Value::nothing(), Scope::from_env(env),
&IndexMap::new(),
&env,
) )
.await? .await?
.collect_string(Tag::unknown()) .collect_string(Tag::unknown())
@ -1021,9 +1024,7 @@ pub async fn process_line(
&classified_block.block, &classified_block.block,
ctx, ctx,
input_stream, input_stream,
&Value::nothing(), Scope::from_env(env),
&IndexMap::new(),
&env,
) )
.await .await
{ {

View File

@ -17,6 +17,7 @@ pub(crate) mod build_string;
pub(crate) mod cal; pub(crate) mod cal;
pub(crate) mod cd; pub(crate) mod cd;
pub(crate) mod char_; pub(crate) mod char_;
pub(crate) mod chart;
pub(crate) mod classified; pub(crate) mod classified;
#[cfg(feature = "clipboard-cli")] #[cfg(feature = "clipboard-cli")]
pub(crate) mod clip; pub(crate) mod clip;
@ -29,11 +30,13 @@ pub(crate) mod cp;
pub(crate) mod date; pub(crate) mod date;
pub(crate) mod debug; pub(crate) mod debug;
pub(crate) mod default; pub(crate) mod default;
pub(crate) mod describe;
pub(crate) mod do_; pub(crate) mod do_;
pub(crate) mod drop; pub(crate) mod drop;
pub(crate) mod du; pub(crate) mod du;
pub(crate) mod each; pub(crate) mod each;
pub(crate) mod echo; pub(crate) mod echo;
pub(crate) mod empty;
pub(crate) mod enter; pub(crate) mod enter;
pub(crate) mod every; pub(crate) mod every;
pub(crate) mod exec; pub(crate) mod exec;
@ -65,7 +68,6 @@ pub(crate) mod history;
pub(crate) mod if_; pub(crate) mod if_;
pub(crate) mod insert; pub(crate) mod insert;
pub(crate) mod into_int; pub(crate) mod into_int;
pub(crate) mod is_empty;
pub(crate) mod keep; pub(crate) mod keep;
pub(crate) mod last; pub(crate) mod last;
pub(crate) mod lines; pub(crate) mod lines;
@ -120,7 +122,6 @@ pub(crate) mod uniq;
pub(crate) mod update; pub(crate) mod update;
pub(crate) mod url_; pub(crate) mod url_;
pub(crate) mod version; pub(crate) mod version;
pub(crate) mod what;
pub(crate) mod where_; pub(crate) mod where_;
pub(crate) mod which_; pub(crate) mod which_;
pub(crate) mod with_env; pub(crate) mod with_env;
@ -134,7 +135,7 @@ pub(crate) use command::{
pub(crate) use alias::Alias; pub(crate) use alias::Alias;
pub(crate) use ansi::Ansi; pub(crate) use ansi::Ansi;
pub(crate) use append::Append; pub(crate) use append::Command as Append;
pub(crate) use autoenv::Autoenv; pub(crate) use autoenv::Autoenv;
pub(crate) use autoenv_trust::AutoenvTrust; pub(crate) use autoenv_trust::AutoenvTrust;
pub(crate) use autoenv_untrust::AutoenvUnTrust; pub(crate) use autoenv_untrust::AutoenvUnTrust;
@ -142,6 +143,7 @@ pub(crate) use benchmark::Benchmark;
pub(crate) use build_string::BuildString; pub(crate) use build_string::BuildString;
pub(crate) use cal::Cal; pub(crate) use cal::Cal;
pub(crate) use char_::Char; pub(crate) use char_::Char;
pub(crate) use chart::Chart;
pub(crate) use compact::Compact; pub(crate) use compact::Compact;
pub(crate) use config::{ pub(crate) use config::{
Config, ConfigClear, ConfigGet, ConfigLoad, ConfigPath, ConfigRemove, ConfigSet, ConfigSetInto, Config, ConfigClear, ConfigGet, ConfigLoad, ConfigPath, ConfigRemove, ConfigSet, ConfigSetInto,
@ -151,6 +153,7 @@ pub(crate) use cp::Cpy;
pub(crate) use date::{Date, DateFormat, DateNow, DateUTC}; pub(crate) use date::{Date, DateFormat, DateNow, DateUTC};
pub(crate) use debug::Debug; pub(crate) use debug::Debug;
pub(crate) use default::Default; pub(crate) use default::Default;
pub(crate) use describe::Describe;
pub(crate) use do_::Do; pub(crate) use do_::Do;
pub(crate) use drop::Drop; pub(crate) use drop::Drop;
pub(crate) use du::Du; pub(crate) use du::Du;
@ -158,10 +161,10 @@ pub(crate) use each::Each;
pub(crate) use each::EachGroup; pub(crate) use each::EachGroup;
pub(crate) use each::EachWindow; pub(crate) use each::EachWindow;
pub(crate) use echo::Echo; pub(crate) use echo::Echo;
pub(crate) use empty::Command as Empty;
pub(crate) use if_::If; pub(crate) use if_::If;
pub(crate) use is_empty::IsEmpty;
pub(crate) use nu::NuPlugin; pub(crate) use nu::NuPlugin;
pub(crate) use update::Update; pub(crate) use update::Command as Update;
pub(crate) mod kill; pub(crate) mod kill;
pub(crate) use kill::Kill; pub(crate) use kill::Kill;
pub(crate) mod clear; pub(crate) mod clear;
@ -190,13 +193,13 @@ pub(crate) use from_xml::FromXML;
pub(crate) use from_yaml::FromYAML; pub(crate) use from_yaml::FromYAML;
pub(crate) use from_yaml::FromYML; pub(crate) use from_yaml::FromYML;
pub(crate) use get::Get; pub(crate) use get::Get;
pub(crate) use group_by::GroupBy; pub(crate) use group_by::Command as GroupBy;
pub(crate) use group_by_date::GroupByDate; pub(crate) use group_by_date::GroupByDate;
pub(crate) use headers::Headers; pub(crate) use headers::Headers;
pub(crate) use help::Help; pub(crate) use help::Help;
pub(crate) use histogram::Histogram; pub(crate) use histogram::Histogram;
pub(crate) use history::History; pub(crate) use history::History;
pub(crate) use insert::Insert; pub(crate) use insert::Command as Insert;
pub(crate) use into_int::IntoInt; pub(crate) use into_int::IntoInt;
pub(crate) use keep::{Keep, KeepUntil, KeepWhile}; pub(crate) use keep::{Keep, KeepUntil, KeepWhile};
pub(crate) use last::Last; pub(crate) use last::Last;
@ -243,9 +246,9 @@ pub(crate) use split::{Split, SplitChars, SplitColumn, SplitRow};
pub(crate) use split_by::SplitBy; pub(crate) use split_by::SplitBy;
pub(crate) use str_::{ pub(crate) use str_::{
Str, StrCamelCase, StrCapitalize, StrCollect, StrContains, StrDowncase, StrEndsWith, Str, StrCamelCase, StrCapitalize, StrCollect, StrContains, StrDowncase, StrEndsWith,
StrFindReplace, StrFrom, StrIndexOf, StrKebabCase, StrLength, StrPascalCase, StrReverse, StrFindReplace, StrFrom, StrIndexOf, StrKebabCase, StrLPad, StrLength, StrPascalCase, StrRPad,
StrScreamingSnakeCase, StrSet, StrSnakeCase, StrStartsWith, StrSubstring, StrToDatetime, StrReverse, StrScreamingSnakeCase, StrSet, StrSnakeCase, StrStartsWith, StrSubstring,
StrToDecimal, StrToInteger, StrTrim, StrTrimLeft, StrTrimRight, StrUpcase, StrToDatetime, StrToDecimal, StrToInteger, StrTrim, StrTrimLeft, StrTrimRight, StrUpcase,
}; };
pub(crate) use table::Table; pub(crate) use table::Table;
pub(crate) use tags::Tags; pub(crate) use tags::Tags;
@ -263,8 +266,43 @@ pub(crate) use touch::Touch;
pub(crate) use uniq::Uniq; pub(crate) use uniq::Uniq;
pub(crate) use url_::{UrlCommand, UrlHost, UrlPath, UrlQuery, UrlScheme}; pub(crate) use url_::{UrlCommand, UrlHost, UrlPath, UrlQuery, UrlScheme};
pub(crate) use version::Version; pub(crate) use version::Version;
pub(crate) use what::What;
pub(crate) use where_::Where; pub(crate) use where_::Where;
pub(crate) use which_::Which; pub(crate) use which_::Which;
pub(crate) use with_env::WithEnv; pub(crate) use with_env::WithEnv;
pub(crate) use wrap::Wrap; pub(crate) use wrap::Wrap;
#[cfg(test)]
mod tests {
use super::*;
use crate::commands::whole_stream_command;
use crate::examples::{test_anchors, test_examples};
use nu_errors::ShellError;
fn commands() -> Vec<Command> {
vec![
whole_stream_command(Append),
whole_stream_command(GroupBy),
whole_stream_command(Insert),
whole_stream_command(Update),
whole_stream_command(Empty),
]
}
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
for cmd in commands() {
test_examples(cmd)?;
}
Ok(())
}
#[test]
fn tracks_metadata() -> Result<(), ShellError> {
for cmd in commands() {
test_anchors(cmd)?;
}
Ok(())
}
}

View File

@ -340,11 +340,12 @@ fn find_block_shapes(block: &Block, registry: &CommandRegistry) -> Result<ShapeM
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Alias; use super::Alias;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Alias {}) Ok(test_examples(Alias {})?)
} }
} }

View File

@ -135,11 +135,12 @@ pub fn str_to_ansi_color(s: String) -> Option<String> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Ansi; use super::Ansi;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Ansi {}) Ok(test_examples(Ansi {})?)
} }
} }

View File

@ -2,17 +2,17 @@ use crate::command_registry::CommandRegistry;
use crate::commands::WholeStreamCommand; use crate::commands::WholeStreamCommand;
use crate::prelude::*; use crate::prelude::*;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{Signature, SyntaxShape, UntaggedValue, Value}; use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
#[derive(Deserialize)] #[derive(Deserialize)]
struct AppendArgs { struct Arguments {
row: Value, row: Value,
} }
pub struct Append; pub struct Command;
#[async_trait] #[async_trait]
impl WholeStreamCommand for Append { impl WholeStreamCommand for Command {
fn name(&self) -> &str { fn name(&self) -> &str {
"append" "append"
} }
@ -34,11 +34,18 @@ impl WholeStreamCommand for Append {
args: CommandArgs, args: CommandArgs,
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let (AppendArgs { row }, input) = args.process(registry).await?; let (Arguments { mut row }, input) = args.process(registry).await?;
let eos = futures::stream::iter(vec![row]); let input: Vec<Value> = input.collect().await;
Ok(input.chain(eos).to_output_stream()) if let Some(first) = input.get(0) {
row.tag = first.tag();
}
Ok(
futures::stream::iter(input.into_iter().chain(vec![row]).map(ReturnSuccess::value))
.to_output_stream(),
)
} }
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
@ -54,15 +61,3 @@ impl WholeStreamCommand for Append {
}] }]
} }
} }
#[cfg(test)]
mod tests {
use super::Append;
#[test]
fn examples_work_as_expected() {
use crate::examples::test as test_examples;
test_examples(Append {})
}
}

View File

@ -318,7 +318,7 @@ fn create_default_command_args(context: &RunnableContextWithoutInput) -> RawComm
external_redirection: ExternalRedirection::Stdout, external_redirection: ExternalRedirection::Stdout,
}, },
name_tag: context.name.clone(), name_tag: context.name.clone(),
scope: Scope::new(), scope: Scope::create(),
}, },
} }
} }
@ -326,11 +326,12 @@ fn create_default_command_args(context: &RunnableContextWithoutInput) -> RawComm
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Command; use super::Command;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Command {}) Ok(test_examples(Command {})?)
} }
} }

View File

@ -10,25 +10,16 @@ pub enum AutoPivotMode {
impl AutoPivotMode { impl AutoPivotMode {
pub fn is_auto(&self) -> bool { pub fn is_auto(&self) -> bool {
match &self { matches!(self, AutoPivotMode::Auto)
AutoPivotMode::Auto => true,
_ => false,
}
} }
pub fn is_always(&self) -> bool { pub fn is_always(&self) -> bool {
match &self { matches!(self, AutoPivotMode::Always)
AutoPivotMode::Always => true,
_ => false,
}
} }
#[allow(unused)] #[allow(unused)]
pub fn is_never(&self) -> bool { pub fn is_never(&self) -> bool {
match &self { matches!(self, AutoPivotMode::Never)
AutoPivotMode::Never => true,
_ => false,
}
} }
} }

View File

@ -8,6 +8,10 @@ use nu_protocol::{
hir::{Block, ClassifiedCommand, Commands, InternalCommand}, hir::{Block, ClassifiedCommand, Commands, InternalCommand},
Dictionary, Scope, Signature, SyntaxShape, UntaggedValue, Value, Dictionary, Scope, Signature, SyntaxShape, UntaggedValue, Value,
}; };
use rand::{
distributions::Alphanumeric,
prelude::{thread_rng, Rng},
};
use std::convert::TryInto; use std::convert::TryInto;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
@ -79,20 +83,18 @@ async fn benchmark(
let scope = raw_args.call_info.scope.clone(); let scope = raw_args.call_info.scope.clone();
let (BenchmarkArgs { block, passthrough }, input) = raw_args.process(&registry).await?; let (BenchmarkArgs { block, passthrough }, input) = raw_args.process(&registry).await?;
let env = scope.env();
let name = generate_free_name(&env);
let mut env = IndexMap::new();
env.insert(name, generate_random_env_value());
let scope = Scope::append_env(scope, env);
let start_time = Instant::now(); let start_time = Instant::now();
#[cfg(feature = "rich-benchmark")] #[cfg(feature = "rich-benchmark")]
let start = time().await; let start = time().await;
let result = run_block( let result = run_block(&block, &mut context, input, scope.clone()).await;
&block,
&mut context,
input,
&scope.it,
&scope.vars,
&scope.env,
)
.await;
let output = result?.into_vec().await; let output = result?.into_vec().await;
#[cfg(feature = "rich-benchmark")] #[cfg(feature = "rich-benchmark")]
@ -108,7 +110,7 @@ async fn benchmark(
let real_time = into_big_int(end_time - start_time); let real_time = into_big_int(end_time - start_time);
indexmap.insert("real time".to_string(), real_time); indexmap.insert("real time".to_string(), real_time);
benchmark_output(indexmap, output, passthrough, &tag, &mut context, &scope).await benchmark_output(indexmap, output, passthrough, &tag, &mut context, scope).await
} }
// return advanced stats // return advanced stats
#[cfg(feature = "rich-benchmark")] #[cfg(feature = "rich-benchmark")]
@ -127,7 +129,7 @@ async fn benchmark(
let idle_time = into_big_int(end.idle() - start.idle()); let idle_time = into_big_int(end.idle() - start.idle());
indexmap.insert("idle time".to_string(), idle_time); indexmap.insert("idle time".to_string(), idle_time);
benchmark_output(indexmap, output, passthrough, &tag, &mut context, &scope).await benchmark_output(indexmap, output, passthrough, &tag, &mut context, scope).await
} else { } else {
Err(ShellError::untagged_runtime_error( Err(ShellError::untagged_runtime_error(
"Could not retreive CPU time", "Could not retreive CPU time",
@ -141,7 +143,7 @@ async fn benchmark_output<T, Output>(
passthrough: Option<Block>, passthrough: Option<Block>,
tag: T, tag: T,
context: &mut EvaluationContext, context: &mut EvaluationContext,
scope: &Scope, scope: Arc<Scope>,
) -> Result<OutputStream, ShellError> ) -> Result<OutputStream, ShellError>
where where
T: Into<Tag> + Copy, T: Into<Tag> + Copy,
@ -161,15 +163,7 @@ where
// add autoview for an empty block // add autoview for an empty block
let time_block = add_implicit_autoview(time_block); let time_block = add_implicit_autoview(time_block);
let _ = run_block( let _ = run_block(&time_block, context, benchmark_output, scope).await?;
&time_block,
context,
benchmark_output,
&scope.it,
&scope.vars,
&scope.env,
)
.await?;
context.clear_errors(); context.clear_errors();
Ok(block_output.into()) Ok(block_output.into())
@ -200,3 +194,19 @@ fn into_big_int<T: TryInto<Duration>>(time: T) -> BigInt {
.as_nanos() .as_nanos()
.into() .into()
} }
fn generate_random_env_value() -> String {
let mut thread_rng = thread_rng();
let len = thread_rng.gen_range(1, 16 * 1024);
thread_rng.sample_iter(&Alphanumeric).take(len).collect()
}
fn generate_free_name(env: &indexmap::IndexMap<String, String>) -> String {
let mut thread_rng = thread_rng();
loop {
let candidate_name = format!("NU_RANDOM_VALUE_{}", thread_rng.gen::<usize>());
if !env.contains_key(&candidate_name) {
return candidate_name;
}
}
}

View File

@ -339,11 +339,12 @@ fn add_month_to_table(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Cal; use super::Cal;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Cal {}) Ok(test_examples(Cal {})?)
} }
} }

View File

@ -72,11 +72,12 @@ impl WholeStreamCommand for Cd {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Cd; use super::Cd;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Cd {}) Ok(test_examples(Cd {})?)
} }
} }

View File

@ -130,11 +130,12 @@ fn str_to_character(s: &str) -> Option<String> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Char; use super::Char;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Char {}) Ok(test_examples(Char {})?)
} }
} }

View File

@ -0,0 +1,53 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
#[derive(Clone)]
pub struct Chart;
#[async_trait]
impl WholeStreamCommand for Chart {
fn name(&self) -> &str {
"chart"
}
fn signature(&self) -> Signature {
Signature::build("chart")
}
fn usage(&self) -> &str {
"Displays charts."
}
async fn run(
&self,
_args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
if registry.get_command("chart bar").is_none() {
return Err(ShellError::untagged_runtime_error(
"nu_plugin_chart not installed.",
));
}
let registry = registry.clone();
Ok(OutputStream::one(Ok(ReturnSuccess::Value(
UntaggedValue::string(crate::commands::help::get_help(&Chart, &registry))
.into_value(Tag::unknown()),
))))
}
}
#[cfg(test)]
mod tests {
use super::Chart;
use super::ShellError;
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples;
Ok(test_examples(Chart {})?)
}
}

View File

@ -6,16 +6,14 @@ use crate::stream::InputStream;
use futures::stream::TryStreamExt; use futures::stream::TryStreamExt;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::hir::{Block, ClassifiedCommand, Commands}; use nu_protocol::hir::{Block, ClassifiedCommand, Commands};
use nu_protocol::{ReturnSuccess, UntaggedValue, Value}; use nu_protocol::{ReturnSuccess, Scope, UntaggedValue, Value};
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
pub(crate) async fn run_block( pub(crate) async fn run_block(
block: &Block, block: &Block,
ctx: &mut EvaluationContext, ctx: &mut EvaluationContext,
mut input: InputStream, mut input: InputStream,
it: &Value, scope: Arc<Scope>,
vars: &IndexMap<String, Value>,
env: &IndexMap<String, String>,
) -> Result<InputStream, ShellError> { ) -> Result<InputStream, ShellError> {
let mut output: Result<InputStream, ShellError> = Ok(InputStream::empty()); let mut output: Result<InputStream, ShellError> = Ok(InputStream::empty());
for pipeline in &block.block { for pipeline in &block.block {
@ -54,7 +52,7 @@ pub(crate) async fn run_block(
return Err(e); return Err(e);
} }
} }
output = run_pipeline(pipeline, ctx, input, it, vars, env).await; output = run_pipeline(pipeline, ctx, input, scope.clone()).await;
input = InputStream::empty(); input = InputStream::empty();
} }
@ -66,9 +64,7 @@ async fn run_pipeline(
commands: &Commands, commands: &Commands,
ctx: &mut EvaluationContext, ctx: &mut EvaluationContext,
mut input: InputStream, mut input: InputStream,
it: &Value, scope: Arc<Scope>,
vars: &IndexMap<String, Value>,
env: &IndexMap<String, String>,
) -> Result<InputStream, ShellError> { ) -> Result<InputStream, ShellError> {
for item in commands.list.clone() { for item in commands.list.clone() {
input = match item { input = match item {
@ -77,13 +73,13 @@ async fn run_pipeline(
} }
ClassifiedCommand::Expr(expr) => { ClassifiedCommand::Expr(expr) => {
run_expression_block(*expr, ctx, it, vars, env).await? run_expression_block(*expr, ctx, scope.clone()).await?
} }
ClassifiedCommand::Error(err) => return Err(err.into()), ClassifiedCommand::Error(err) => return Err(err.into()),
ClassifiedCommand::Internal(left) => { ClassifiedCommand::Internal(left) => {
run_internal_command(left, ctx, input, it, vars, env).await? run_internal_command(left, ctx, input, scope.clone()).await?
} }
}; };
} }

View File

@ -6,14 +6,12 @@ use log::{log_enabled, trace};
use futures::stream::once; use futures::stream::once;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::hir::SpannedExpression; use nu_protocol::hir::SpannedExpression;
use nu_protocol::Value; use nu_protocol::Scope;
pub(crate) async fn run_expression_block( pub(crate) async fn run_expression_block(
expr: SpannedExpression, expr: SpannedExpression,
context: &mut EvaluationContext, context: &mut EvaluationContext,
it: &Value, scope: Arc<Scope>,
vars: &IndexMap<String, Value>,
env: &IndexMap<String, String>,
) -> Result<InputStream, ShellError> { ) -> Result<InputStream, ShellError> {
if log_enabled!(log::Level::Trace) { if log_enabled!(log::Level::Trace) {
trace!(target: "nu::run::expr", "->"); trace!(target: "nu::run::expr", "->");
@ -21,7 +19,7 @@ pub(crate) async fn run_expression_block(
} }
let registry = context.registry().clone(); let registry = context.registry().clone();
let output = evaluate_baseline_expr(&expr, &registry, it, vars, env).await?; let output = evaluate_baseline_expr(&expr, &registry, scope).await?;
Ok(once(async { Ok(output) }).to_input_stream()) Ok(once(async { Ok(output) }).to_input_stream())
} }

View File

@ -21,7 +21,7 @@ pub(crate) async fn run_external_command(
command: ExternalCommand, command: ExternalCommand,
context: &mut EvaluationContext, context: &mut EvaluationContext,
input: InputStream, input: InputStream,
scope: &Scope, scope: Arc<Scope>,
external_redirection: ExternalRedirection, external_redirection: ExternalRedirection,
) -> Result<InputStream, ShellError> { ) -> Result<InputStream, ShellError> {
trace!(target: "nu::run::external", "-> {}", command.name); trace!(target: "nu::run::external", "-> {}", command.name);
@ -41,7 +41,7 @@ async fn run_with_stdin(
command: ExternalCommand, command: ExternalCommand,
context: &mut EvaluationContext, context: &mut EvaluationContext,
input: InputStream, input: InputStream,
scope: &Scope, scope: Arc<Scope>,
external_redirection: ExternalRedirection, external_redirection: ExternalRedirection,
) -> Result<InputStream, ShellError> { ) -> Result<InputStream, ShellError> {
let path = context.shell_manager.path(); let path = context.shell_manager.path();
@ -50,9 +50,7 @@ async fn run_with_stdin(
let mut command_args = vec![]; let mut command_args = vec![];
for arg in command.args.iter() { for arg in command.args.iter() {
let value = let value = evaluate_baseline_expr(arg, &context.registry, scope.clone()).await?;
evaluate_baseline_expr(arg, &context.registry, &scope.it, &scope.vars, &scope.env)
.await?;
// Skip any arguments that don't really exist, treating them as optional // Skip any arguments that don't really exist, treating them as optional
// FIXME: we may want to preserve the gap in the future, though it's hard to say // FIXME: we may want to preserve the gap in the future, though it's hard to say
@ -138,7 +136,7 @@ fn spawn(
args: &[String], args: &[String],
input: InputStream, input: InputStream,
external_redirection: ExternalRedirection, external_redirection: ExternalRedirection,
scope: &Scope, scope: Arc<Scope>,
) -> Result<InputStream, ShellError> { ) -> Result<InputStream, ShellError> {
let command = command.clone(); let command = command.clone();
@ -169,7 +167,7 @@ fn spawn(
trace!(target: "nu::run::external", "cwd = {:?}", &path); trace!(target: "nu::run::external", "cwd = {:?}", &path);
process.env_clear(); process.env_clear();
process.envs(scope.env.iter()); process.envs(scope.env());
// We want stdout regardless of what // We want stdout regardless of what
// we are doing ($it case or pipe stdin) // we are doing ($it case or pipe stdin)
@ -580,7 +578,7 @@ mod tests {
cmd, cmd,
&mut ctx, &mut ctx,
input, input,
&Scope::new(), Scope::create(),
ExternalRedirection::Stdout ExternalRedirection::Stdout
) )
.await .await

View File

@ -11,20 +11,13 @@ pub(crate) async fn run_internal_command(
command: InternalCommand, command: InternalCommand,
context: &mut EvaluationContext, context: &mut EvaluationContext,
input: InputStream, input: InputStream,
it: &Value, scope: Arc<Scope>,
vars: &IndexMap<String, Value>,
env: &IndexMap<String, String>,
) -> Result<InputStream, ShellError> { ) -> Result<InputStream, ShellError> {
if log_enabled!(log::Level::Trace) { if log_enabled!(log::Level::Trace) {
trace!(target: "nu::run::internal", "->"); trace!(target: "nu::run::internal", "->");
trace!(target: "nu::run::internal", "{}", command.name); trace!(target: "nu::run::internal", "{}", command.name);
} }
let scope = Scope {
it: it.clone(),
vars: vars.clone(),
env: env.clone(),
};
let objects: InputStream = trace_stream!(target: "nu::trace_stream::internal", "input" = input); let objects: InputStream = trace_stream!(target: "nu::trace_stream::internal", "input" = input);
let internal_command = context.expect_command(&command.name); let internal_command = context.expect_command(&command.name);
@ -38,7 +31,7 @@ pub(crate) async fn run_internal_command(
internal_command?, internal_command?,
Tag::unknown_anchor(command.name_span), Tag::unknown_anchor(command.name_span),
command.args.clone(), command.args.clone(),
&scope, scope.clone(),
objects, objects,
) )
.await? .await?
@ -48,8 +41,6 @@ pub(crate) async fn run_internal_command(
//let context = Arc::new(context.clone()); //let context = Arc::new(context.clone());
let context = context.clone(); let context = context.clone();
let command = Arc::new(command); let command = Arc::new(command);
let scope = Arc::new(scope);
// let scope = scope.clone();
Ok(InputStream::from_stream( Ok(InputStream::from_stream(
result result
@ -90,7 +81,7 @@ pub(crate) async fn run_internal_command(
external_redirection: ExternalRedirection::Stdout, external_redirection: ExternalRedirection::Stdout,
}, },
name_tag: Tag::unknown_anchor(command.name_span), name_tag: Tag::unknown_anchor(command.name_span),
scope: (&*scope).clone(), scope,
}, },
}; };
let result = converter let result = converter

View File

@ -130,7 +130,7 @@ async fn run_filter(
UntaggedValue::Primitive(Primitive::EndOfStream).into_untagged_value() UntaggedValue::Primitive(Primitive::EndOfStream).into_untagged_value()
]); ]);
let args = args.evaluate_once_with_scope(&registry, &scope).await?; let args = args.evaluate_once_with_scope(&registry, scope).await?;
let real_path = Path::new(&path); let real_path = Path::new(&path);
let ext = real_path.extension(); let ext = real_path.extension();

View File

@ -43,15 +43,3 @@ impl WholeStreamCommand for Clear {
}] }]
} }
} }
#[cfg(test)]
mod tests {
use super::Clear;
#[test]
fn examples_work_as_expected() {
use crate::examples::test as test_examples;
test_examples(Clear {})
}
}

View File

@ -32,11 +32,18 @@ impl WholeStreamCommand for Clip {
} }
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
vec![Example { vec![
description: "Save text to the clipboard", Example {
example: "echo 'secret value' | clip", description: "Save text to the clipboard",
result: None, example: "echo 'secret value' | clip",
}] result: None,
},
Example {
description: "Save numbers to the clipboard",
example: "random integer 10000000..99999999 | clip",
result: None,
},
]
} }
} }
@ -61,16 +68,14 @@ pub async fn clip(
first = false; first = false;
} }
let string: String = match i.as_string() { let string: String = i.convert_to_string();
Ok(string) => string.to_string(), if string.is_empty() {
Err(_) => { return Err(ShellError::labeled_error(
return Err(ShellError::labeled_error( "Unable to convert to string",
"Given non-string data", "Unable to convert to string",
"expected strings from pipeline", name,
name, ));
)) }
}
};
new_copy_data.push_str(&string); new_copy_data.push_str(&string);
} }
@ -99,11 +104,12 @@ pub async fn clip(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Clip; use super::Clip;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Clip {}) Ok(test_examples(Clip {})?)
} }
} }

View File

@ -17,27 +17,12 @@ use std::sync::atomic::AtomicBool;
pub struct UnevaluatedCallInfo { pub struct UnevaluatedCallInfo {
pub args: hir::Call, pub args: hir::Call,
pub name_tag: Tag, pub name_tag: Tag,
pub scope: Scope, pub scope: Arc<Scope>,
} }
impl UnevaluatedCallInfo { impl UnevaluatedCallInfo {
pub async fn evaluate(self, registry: &CommandRegistry) -> Result<CallInfo, ShellError> { pub async fn evaluate(self, registry: &CommandRegistry) -> Result<CallInfo, ShellError> {
let args = evaluate_args(&self.args, registry, &self.scope).await?; let args = evaluate_args(&self.args, registry, self.scope.clone()).await?;
Ok(CallInfo {
args,
name_tag: self.name_tag,
})
}
pub async fn evaluate_with_new_it(
self,
registry: &CommandRegistry,
it: &Value,
) -> Result<CallInfo, ShellError> {
let mut scope = self.scope.clone();
scope.it = it.clone();
let args = evaluate_args(&self.args, registry, &scope).await?;
Ok(CallInfo { Ok(CallInfo {
args, args,
@ -115,7 +100,7 @@ impl CommandArgs {
pub async fn evaluate_once_with_scope( pub async fn evaluate_once_with_scope(
self, self,
registry: &CommandRegistry, registry: &CommandRegistry,
scope: &Scope, scope: Arc<Scope>,
) -> Result<EvaluatedWholeStreamCommandArgs, ShellError> { ) -> Result<EvaluatedWholeStreamCommandArgs, ShellError> {
let host = self.host.clone(); let host = self.host.clone();
let ctrl_c = self.ctrl_c.clone(); let ctrl_c = self.ctrl_c.clone();
@ -215,37 +200,6 @@ impl EvaluatedWholeStreamCommandArgs {
} }
} }
#[derive(Getters)]
#[get = "pub"]
pub struct EvaluatedFilterCommandArgs {
args: EvaluatedCommandArgs,
}
impl Deref for EvaluatedFilterCommandArgs {
type Target = EvaluatedCommandArgs;
fn deref(&self) -> &Self::Target {
&self.args
}
}
impl EvaluatedFilterCommandArgs {
pub fn new(
host: Arc<parking_lot::Mutex<dyn Host>>,
ctrl_c: Arc<AtomicBool>,
shell_manager: ShellManager,
call_info: CallInfo,
) -> EvaluatedFilterCommandArgs {
EvaluatedFilterCommandArgs {
args: EvaluatedCommandArgs {
host,
ctrl_c,
shell_manager,
call_info,
},
}
}
}
#[derive(Getters, new)] #[derive(Getters, new)]
#[get = "pub(crate)"] #[get = "pub(crate)"]
pub struct EvaluatedCommandArgs { pub struct EvaluatedCommandArgs {
@ -381,69 +335,6 @@ impl Command {
} }
} }
pub struct FnFilterCommand {
name: String,
func: fn(EvaluatedFilterCommandArgs) -> Result<OutputStream, ShellError>,
}
#[async_trait]
impl WholeStreamCommand for FnFilterCommand {
fn name(&self) -> &str {
&self.name
}
fn usage(&self) -> &str {
"usage"
}
async fn run(
&self,
CommandArgs {
host,
ctrl_c,
shell_manager,
call_info,
input,
..
}: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = Arc::new(registry.clone());
let func = self.func;
Ok(input
.then(move |it| {
let host = host.clone();
let registry = registry.clone();
let ctrl_c = ctrl_c.clone();
let shell_manager = shell_manager.clone();
let call_info = call_info.clone();
async move {
let call_info = match call_info.evaluate_with_new_it(&*registry, &it).await {
Err(err) => {
return OutputStream::one(Err(err));
}
Ok(args) => args,
};
let args = EvaluatedFilterCommandArgs::new(
host.clone(),
ctrl_c.clone(),
shell_manager.clone(),
call_info,
);
match func(args) {
Err(err) => return OutputStream::one(Err(err)),
Ok(stream) => stream,
}
}
})
.flatten()
.to_output_stream())
}
}
pub fn whole_stream_command(command: impl WholeStreamCommand + 'static) -> Command { pub fn whole_stream_command(command: impl WholeStreamCommand + 'static) -> Command {
Command(Arc::new(command)) Command(Arc::new(command))
} }

View File

@ -37,22 +37,11 @@ impl WholeStreamCommand for Compact {
} }
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
vec![ vec![Example {
Example { description: "Filter out all directory entries having no 'target'",
description: "Filter out all null entries in a list", example: "ls -la | compact target",
example: "echo [1 2 $null 3 $null $null] | compact", result: None,
result: Some(vec![ }]
UntaggedValue::int(1).into(),
UntaggedValue::int(2).into(),
UntaggedValue::int(3).into(),
]),
},
Example {
description: "Filter out all directory entries having no 'target'",
example: "ls -la | compact target",
result: None,
},
]
} }
} }
@ -95,11 +84,12 @@ pub async fn compact(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Compact; use super::Compact;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Compact {}) Ok(test_examples(Compact {})?)
} }
} }

View File

@ -2,14 +2,13 @@ use crate::command_registry::CommandRegistry;
use crate::commands::WholeStreamCommand; use crate::commands::WholeStreamCommand;
use crate::prelude::*; use crate::prelude::*;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;
pub struct SubCommand; pub struct SubCommand;
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct GetArgs { pub struct GetArgs {
get: Tagged<String>, path: ColumnPath,
} }
#[async_trait] #[async_trait]
@ -21,7 +20,7 @@ impl WholeStreamCommand for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("config get").required( Signature::build("config get").required(
"get", "get",
SyntaxShape::Any, SyntaxShape::ColumnPath,
"value to get from the config", "value to get from the config",
) )
} }
@ -51,17 +50,14 @@ pub async fn get(
args: CommandArgs, args: CommandArgs,
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let name_span = args.call_info.name_tag.clone(); let name_tag = args.call_info.name_tag.clone();
let (GetArgs { get }, _) = args.process(&registry).await?; let (GetArgs { path }, _) = args.process(&registry).await?;
// NOTE: None because we are not loading a new config file, we just want to read from the // NOTE: None because we are not loading a new config file, we just want to read from the
// existing config // existing config
let result = nu_data::config::read(name_span, &None)?; let result = UntaggedValue::row(nu_data::config::read(&name_tag, &None)?).into_value(&name_tag);
let key = get.to_string(); let value = crate::commands::get::get_column_path(&path, &result)?;
let value = result
.get(&key)
.ok_or_else(|| ShellError::labeled_error("Missing key in config", "key", get.tag()))?;
Ok(match value { Ok(match value {
Value { Value {
@ -75,9 +71,6 @@ pub async fn get(
futures::stream::iter(list).to_output_stream() futures::stream::iter(list).to_output_stream()
} }
x => { x => OutputStream::one(ReturnSuccess::value(x)),
let x = x.clone();
OutputStream::one(ReturnSuccess::value(x))
}
}) })
} }

View File

@ -2,14 +2,13 @@ use crate::command_registry::CommandRegistry;
use crate::commands::WholeStreamCommand; use crate::commands::WholeStreamCommand;
use crate::prelude::*; use crate::prelude::*;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;
pub struct SubCommand; pub struct SubCommand;
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct SetArgs { pub struct SetArgs {
key: Tagged<String>, path: ColumnPath,
value: Value, value: Value,
} }
@ -21,7 +20,7 @@ impl WholeStreamCommand for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("config set") Signature::build("config set")
.required("key", SyntaxShape::String, "variable name to set") .required("key", SyntaxShape::ColumnPath, "variable name to set")
.required("value", SyntaxShape::Any, "value to use") .required("value", SyntaxShape::Any, "value to use")
} }
@ -38,11 +37,28 @@ impl WholeStreamCommand for SubCommand {
} }
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
vec![Example { vec![
description: "Set nonzero_exit_errors to true", Example {
example: "config set nonzero_exit_errors $true", description: "Set auto pivoting",
result: None, example: "config set pivot_mode always",
}] result: None,
},
Example {
description: "Set line editor options",
example: "config set line_editor [[edit_mode, completion_type]; [emacs circular]]",
result: None,
},
Example {
description: "Set coloring options",
example: "config set color_config [[header_align header_bold]; [left $true]]",
result: None,
},
Example {
description: "Set nested options",
example: "config set color_config.header_color white",
result: None,
},
]
} }
} }
@ -50,18 +66,32 @@ pub async fn set(
args: CommandArgs, args: CommandArgs,
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let name_span = args.call_info.name_tag.clone(); let name_tag = args.call_info.name_tag.clone();
let (SetArgs { key, value }, _) = args.process(&registry).await?; let (SetArgs { path, mut value }, _) = args.process(&registry).await?;
// NOTE: None because we are not loading a new config file, we just want to read from the // NOTE: None because we are not loading a new config file, we just want to read from the
// existing config // existing config
let mut result = nu_data::config::read(name_span, &None)?; let raw_entries = nu_data::config::read(&name_tag, &None)?;
let configuration = UntaggedValue::row(raw_entries).into_value(&name_tag);
result.insert(key.to_string(), value.clone()); if let UntaggedValue::Table(rows) = &value.value {
if rows.len() == 1 && rows[0].is_row() {
value = rows[0].clone();
}
}
config::write(&result, &None)?; match configuration.forgiving_insert_data_at_column_path(&path, value) {
Ok(Value {
value: UntaggedValue::Row(changes),
..
}) => {
config::write(&changes.entries, &None)?;
Ok(OutputStream::one(ReturnSuccess::value( Ok(OutputStream::one(ReturnSuccess::value(
UntaggedValue::Row(result.into()).into_value(&value.tag), UntaggedValue::Row(changes).into_value(name_tag),
))) )))
}
Ok(_) => Ok(OutputStream::empty()),
Err(reason) => Err(reason),
}
} }

View File

@ -80,11 +80,12 @@ impl WholeStreamCommand for Count {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Count; use super::Count;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Count {}) Ok(test_examples(Count {})?)
} }
} }

View File

@ -66,11 +66,12 @@ impl WholeStreamCommand for Cpy {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Cpy; use super::Cpy;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Cpy {}) Ok(test_examples(Cpy {})?)
} }
} }

View File

@ -36,11 +36,12 @@ impl WholeStreamCommand for Command {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Command; use super::Command;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Command {}) Ok(test_examples(Command {})?)
} }
} }

View File

@ -61,3 +61,16 @@ pub async fn format(
Ok(OutputStream::one(value)) Ok(OutputStream::one(value))
} }
#[cfg(test)]
mod tests {
use super::Date;
use super::ShellError;
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples;
Ok(test_examples(Date {})?)
}
}

View File

@ -48,3 +48,16 @@ pub async fn now(
Ok(OutputStream::one(value)) Ok(OutputStream::one(value))
} }
#[cfg(test)]
mod tests {
use super::Date;
use super::ShellError;
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples;
Ok(test_examples(Date {})?)
}
}

View File

@ -48,3 +48,16 @@ pub async fn utc(
Ok(OutputStream::one(value)) Ok(OutputStream::one(value))
} }
#[cfg(test)]
mod tests {
use super::Date;
use super::ShellError;
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples;
Ok(test_examples(Date {})?)
}
}

View File

@ -55,11 +55,12 @@ async fn debug_value(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Debug; use super::Debug;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Debug {}) Ok(test_examples(Debug {})?)
} }
} }

View File

@ -83,11 +83,12 @@ async fn default(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Default; use super::Default;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Default {}) Ok(test_examples(Default {})?)
} }
} }

View File

@ -4,13 +4,13 @@ use crate::prelude::*;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue}; use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
pub struct What; pub struct Describe;
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct WhatArgs {} pub struct DescribeArgs {}
#[async_trait] #[async_trait]
impl WholeStreamCommand for What { impl WholeStreamCommand for Describe {
fn name(&self) -> &str { fn name(&self) -> &str {
"describe" "describe"
} }
@ -28,11 +28,11 @@ impl WholeStreamCommand for What {
args: CommandArgs, args: CommandArgs,
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
what(args, registry).await describe(args, registry).await
} }
} }
pub async fn what( pub async fn describe(
args: CommandArgs, args: CommandArgs,
_registry: &CommandRegistry, _registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
@ -49,12 +49,13 @@ pub async fn what(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::What; use super::Describe;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(What {}) Ok(test_examples(Describe {})?)
} }
} }

View File

@ -95,15 +95,7 @@ async fn do_(
block.set_redirect(block_redirection); block.set_redirect(block_redirection);
let result = run_block( let result = run_block(&block, &mut context, input, scope).await;
&block,
&mut context,
input,
&scope.it,
&scope.vars,
&scope.env,
)
.await;
if ignore_errors { if ignore_errors {
// To properly ignore errors we need to redirect stderr, consume it, and remove // To properly ignore errors we need to redirect stderr, consume it, and remove
@ -125,11 +117,12 @@ async fn do_(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Do; use super::Do;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Do {}) Ok(test_examples(Do {})?)
} }
} }

View File

@ -85,11 +85,12 @@ async fn drop(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStr
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Drop; use super::Drop;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Drop {}) Ok(test_examples(Drop {})?)
} }
} }

View File

@ -427,11 +427,12 @@ impl From<FileInfo> for Value {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Du; use super::Du;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Du {}) Ok(test_examples(Du {})?)
} }
} }

View File

@ -97,9 +97,7 @@ pub async fn process_row(
&block, &block,
Arc::make_mut(&mut context), Arc::make_mut(&mut context),
input_stream, input_stream,
&input, Scope::append_it(scope, input),
&scope.vars,
&scope.env,
) )
.await? .await?
.to_output_stream()) .to_output_stream())
@ -119,7 +117,7 @@ async fn each(
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = registry.clone(); let registry = registry.clone();
let head = Arc::new(raw_args.call_info.args.head.clone()); let head = Arc::new(raw_args.call_info.args.head.clone());
let scope = Arc::new(raw_args.call_info.scope.clone()); let scope = raw_args.call_info.scope.clone();
let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry)); let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry));
let (each_args, input): (EachArgs, _) = raw_args.process(&registry).await?; let (each_args, input): (EachArgs, _) = raw_args.process(&registry).await?;
let block = Arc::new(each_args.block); let block = Arc::new(each_args.block);
@ -166,11 +164,12 @@ async fn each(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Each; use super::Each;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Each {}) Ok(test_examples(Each {})?)
} }
} }

View File

@ -53,7 +53,7 @@ impl WholeStreamCommand for EachGroup {
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = registry.clone(); let registry = registry.clone();
let head = Arc::new(raw_args.call_info.args.head.clone()); let head = Arc::new(raw_args.call_info.args.head.clone());
let scope = Arc::new(raw_args.call_info.scope.clone()); let scope = raw_args.call_info.scope.clone();
let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry)); let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry));
let (each_args, input): (EachGroupArgs, _) = raw_args.process(&registry).await?; let (each_args, input): (EachGroupArgs, _) = raw_args.process(&registry).await?;
let block = Arc::new(each_args.block); let block = Arc::new(each_args.block);
@ -123,11 +123,12 @@ pub(crate) fn run_block_on_vec(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::EachGroup; use super::EachGroup;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(EachGroup {}) Ok(test_examples(EachGroup {})?)
} }
} }

View File

@ -57,7 +57,7 @@ impl WholeStreamCommand for EachWindow {
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = registry.clone(); let registry = registry.clone();
let head = Arc::new(raw_args.call_info.args.head.clone()); let head = Arc::new(raw_args.call_info.args.head.clone());
let scope = Arc::new(raw_args.call_info.scope.clone()); let scope = raw_args.call_info.scope.clone();
let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry)); let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry));
let (each_args, mut input): (EachWindowArgs, _) = raw_args.process(&registry).await?; let (each_args, mut input): (EachWindowArgs, _) = raw_args.process(&registry).await?;
let block = Arc::new(each_args.block); let block = Arc::new(each_args.block);
@ -103,11 +103,12 @@ impl WholeStreamCommand for EachWindow {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::EachWindow; use super::EachWindow;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(EachWindow {}) Ok(test_examples(EachWindow {})?)
} }
} }

View File

@ -162,11 +162,12 @@ impl Iterator for RangeIterator {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Echo; use super::Echo;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Echo {}) Ok(test_examples(Echo {})?)
} }
} }

View File

@ -0,0 +1,288 @@
use crate::command_registry::CommandRegistry;
use crate::commands::classified::block::run_block;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_errors::ShellError;
use nu_protocol::{
hir::Block, ColumnPath, Primitive, ReturnSuccess, Scope, Signature, SyntaxShape, UntaggedValue,
Value,
};
use nu_source::Tagged;
use nu_value_ext::{as_string, ValueExt};
use futures::stream::once;
use indexmap::indexmap;
#[derive(Deserialize)]
pub struct Arguments {
rest: Vec<Value>,
}
pub struct Command;
#[async_trait]
impl WholeStreamCommand for Command {
fn name(&self) -> &str {
"empty?"
}
fn signature(&self) -> Signature {
Signature::build("empty?").rest(
SyntaxShape::Any,
"the names of the columns to check emptiness. Pass an optional block to replace if empty",
)
}
fn usage(&self) -> &str {
"Check for empty values"
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
is_empty(args, registry).await
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "Check if a value is empty",
example: "echo '' | empty?",
result: Some(vec![UntaggedValue::boolean(true).into()]),
},
Example {
description: "more than one column",
example: "echo [[meal size]; [arepa small] [taco '']] | empty? meal size",
result: Some(
vec![
UntaggedValue::row(indexmap! {
"meal".to_string() => Value::from(false),
"size".to_string() => Value::from(false),
})
.into(),
UntaggedValue::row(indexmap! {
"meal".to_string() => Value::from(false),
"size".to_string() => Value::from(true),
})
.into(),
],
),
},Example {
description: "use a block if setting the empty cell contents is wanted",
example: "echo [[2020/04/16 2020/07/10 2020/11/16]; ['' [27] [37]]] | empty? 2020/04/16 { = [33 37] }",
result: Some(
vec![
UntaggedValue::row(indexmap! {
"2020/04/16".to_string() => UntaggedValue::table(&[UntaggedValue::int(33).into(), UntaggedValue::int(37).into()]).into(),
"2020/07/10".to_string() => UntaggedValue::table(&[UntaggedValue::int(27).into()]).into(),
"2020/11/16".to_string() => UntaggedValue::table(&[UntaggedValue::int(37).into()]).into(),
})
.into(),
],
),
},
]
}
}
async fn is_empty(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let tag = args.call_info.name_tag.clone();
let name_tag = Arc::new(args.call_info.name_tag.clone());
let context = Arc::new(EvaluationContext::from_raw(&args, &registry));
let scope = args.call_info.scope.clone();
let (Arguments { rest }, input) = args.process(&registry).await?;
let (columns, default_block): (Vec<ColumnPath>, Option<Block>) = arguments(rest)?;
let default_block = Arc::new(default_block);
if input.is_empty() {
let stream = futures::stream::iter(vec![
UntaggedValue::Primitive(Primitive::Nothing).into_value(tag)
]);
return Ok(InputStream::from_stream(stream)
.then(move |input| {
let tag = name_tag.clone();
let scope = scope.clone();
let context = context.clone();
let block = default_block.clone();
let columns = vec![];
async {
match process_row(scope, context, input, block, columns, tag).await {
Ok(s) => s,
Err(e) => OutputStream::one(Err(e)),
}
}
})
.flatten()
.to_output_stream());
}
Ok(input
.then(move |input| {
let tag = name_tag.clone();
let scope = scope.clone();
let context = context.clone();
let block = default_block.clone();
let columns = columns.clone();
async {
match process_row(scope, context, input, block, columns, tag).await {
Ok(s) => s,
Err(e) => OutputStream::one(Err(e)),
}
}
})
.flatten()
.to_output_stream())
}
fn arguments(rest: Vec<Value>) -> Result<(Vec<ColumnPath>, Option<Block>), ShellError> {
let mut rest = rest;
let mut columns = vec![];
let mut default = None;
let last_argument = rest.pop();
match last_argument {
Some(Value {
value: UntaggedValue::Block(call),
..
}) => default = Some(call),
Some(other) => {
let Tagged { item: path, .. } = other.as_column_path()?;
columns = vec![path];
}
None => {}
};
for argument in rest {
let Tagged { item: path, .. } = argument.as_column_path()?;
columns.push(path);
}
Ok((columns, default))
}
async fn process_row(
scope: Arc<Scope>,
mut context: Arc<EvaluationContext>,
input: Value,
default_block: Arc<Option<Block>>,
column_paths: Vec<ColumnPath>,
tag: Arc<Tag>,
) -> Result<OutputStream, ShellError> {
let _tag = &*tag;
let mut out = Arc::new(None);
let results = Arc::make_mut(&mut out);
if let Some(default_block) = &*default_block {
let for_block = input.clone();
let input_stream = once(async { Ok(for_block) }).to_input_stream();
let scope = Scope::append_it(scope, input.clone());
let mut stream = run_block(
&default_block,
Arc::make_mut(&mut context),
input_stream,
scope,
)
.await?;
*results = Some({
let values = stream.drain_vec().await;
let errors = context.get_errors();
if let Some(error) = errors.first() {
return Err(error.clone());
}
if values.len() == 1 {
let value = values
.get(0)
.ok_or_else(|| ShellError::unexpected("No value."))?;
Value {
value: value.value.clone(),
tag: input.tag.clone(),
}
} else if values.is_empty() {
UntaggedValue::nothing().into_value(&input.tag)
} else {
UntaggedValue::table(&values).into_value(&input.tag)
}
});
}
match input {
Value {
value: UntaggedValue::Row(ref r),
ref tag,
} => {
if column_paths.is_empty() {
Ok(OutputStream::one(ReturnSuccess::value({
let is_empty = input.is_empty();
if default_block.is_some() {
if is_empty {
results
.clone()
.unwrap_or_else(|| UntaggedValue::boolean(true).into_value(tag))
} else {
input.clone()
}
} else {
UntaggedValue::boolean(is_empty).into_value(tag)
}
})))
} else {
let mut obj = input.clone();
for column in column_paths.clone() {
let path = UntaggedValue::Primitive(Primitive::ColumnPath(column.clone()))
.into_value(tag);
let data = r.get_data(&as_string(&path)?).borrow().clone();
let is_empty = data.is_empty();
let default = if default_block.is_some() {
if is_empty {
results
.clone()
.unwrap_or_else(|| UntaggedValue::boolean(true).into_value(tag))
} else {
data.clone()
}
} else {
UntaggedValue::boolean(is_empty).into_value(tag)
};
if let Ok(value) =
obj.swap_data_by_column_path(&column, Box::new(move |_| Ok(default)))
{
obj = value;
}
}
Ok(OutputStream::one(ReturnSuccess::value(obj)))
}
}
other => Ok(OutputStream::one(ReturnSuccess::value({
if other.is_empty() {
results
.clone()
.unwrap_or_else(|| UntaggedValue::boolean(true).into_value(other.tag))
} else {
UntaggedValue::boolean(false).into_value(other.tag)
}
}))),
}
}

View File

@ -191,11 +191,12 @@ async fn enter(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Enter; use super::Enter;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Enter {}) Ok(test_examples(Enter {})?)
} }
} }

View File

@ -93,11 +93,12 @@ async fn every(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputSt
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Every; use super::Every;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Every {}) Ok(test_examples(Every {})?)
} }
} }

View File

@ -63,11 +63,12 @@ pub async fn exit(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Exit; use super::Exit;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Exit {}) Ok(test_examples(Exit {})?)
} }
} }

View File

@ -72,11 +72,12 @@ async fn first(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputSt
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::First; use super::First;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(First {}) Ok(test_examples(First {})?)
} }
} }

View File

@ -3,7 +3,7 @@ use crate::commands::WholeStreamCommand;
use crate::evaluate::evaluate_baseline_expr; use crate::evaluate::evaluate_baseline_expr;
use crate::prelude::*; use crate::prelude::*;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue}; use nu_protocol::{ReturnSuccess, Scope, Signature, SyntaxShape, UntaggedValue};
use nu_source::Tagged; use nu_source::Tagged;
use std::borrow::Borrow; use std::borrow::Borrow;
@ -54,7 +54,7 @@ async fn format_command(
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = Arc::new(registry.clone()); let registry = Arc::new(registry.clone());
let scope = Arc::new(args.call_info.scope.clone()); let scope = args.call_info.scope.clone();
let (FormatArgs { pattern }, input) = args.process(&registry).await?; let (FormatArgs { pattern }, input) = args.process(&registry).await?;
let format_pattern = format(&pattern); let format_pattern = format(&pattern);
@ -83,9 +83,7 @@ async fn format_command(
let result = evaluate_baseline_expr( let result = evaluate_baseline_expr(
&full_column_path.0, &full_column_path.0,
&registry, &registry,
&value, Scope::append_it(scope.clone(), value.clone()),
&scope.vars,
&scope.env,
) )
.await; .await;
@ -153,11 +151,12 @@ fn format(input: &str) -> Vec<FormatCommand> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Format; use super::Format;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Format {}) Ok(test_examples(Format {})?)
} }
} }

View File

@ -35,11 +35,12 @@ impl WholeStreamCommand for From {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::From; use super::From;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(From {}) Ok(test_examples(From {})?)
} }
} }

View File

@ -109,11 +109,12 @@ async fn from_csv(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::FromCSV; use super::FromCSV;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(FromCSV {}) Ok(test_examples(FromCSV {})?)
} }
} }

View File

@ -130,11 +130,12 @@ async fn from_eml(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::FromEML; use super::FromEML;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(FromEML {}) Ok(test_examples(FromEML {})?)
} }
} }

View File

@ -249,11 +249,12 @@ fn params_to_value(params: Vec<(String, Vec<String>)>, tag: Tag) -> Value {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::FromIcs; use super::FromIcs;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(FromIcs {}) Ok(test_examples(FromIcs {})?)
} }
} }

View File

@ -95,11 +95,12 @@ async fn from_ini(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::FromINI; use super::FromINI;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(FromINI {}) Ok(test_examples(FromINI {})?)
} }
} }

View File

@ -144,11 +144,12 @@ async fn from_json(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::FromJSON; use super::FromJSON;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(FromJSON {}) Ok(test_examples(FromJSON {})?)
} }
} }

View File

@ -102,11 +102,12 @@ async fn from_ods(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::FromODS; use super::FromODS;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(FromODS {}) Ok(test_examples(FromODS {})?)
} }
} }

View File

@ -135,7 +135,7 @@ fn parse_aligned_columns<'a>(
.flat_map(|s| find_indices(*s)) .flat_map(|s| find_indices(*s))
.collect::<Vec<usize>>(); .collect::<Vec<usize>>();
indices.sort(); indices.sort_unstable();
indices.dedup(); indices.dedup();
let headers: Vec<(String, usize)> = indices let headers: Vec<(String, usize)> = indices
@ -302,7 +302,9 @@ async fn from_ssv(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::ShellError;
use super::*; use super::*;
fn owned(x: &str, y: &str) -> (String, String) { fn owned(x: &str, y: &str) -> (String, String) {
(String::from(x), String::from(y)) (String::from(x), String::from(y))
} }
@ -504,10 +506,10 @@ mod tests {
} }
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use super::FromSSV; use super::FromSSV;
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(FromSSV {}) Ok(test_examples(FromSSV {})?)
} }
} }

View File

@ -101,11 +101,12 @@ pub async fn from_toml(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::FromTOML; use super::FromTOML;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(FromTOML {}) Ok(test_examples(FromTOML {})?)
} }
} }

View File

@ -52,11 +52,12 @@ async fn from_tsv(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::FromTSV; use super::FromTSV;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(FromTSV {}) Ok(test_examples(FromTSV {})?)
} }
} }

View File

@ -64,11 +64,12 @@ async fn from_url(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::FromURL; use super::FromURL;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(FromURL {}) Ok(test_examples(FromURL {})?)
} }
} }

View File

@ -104,11 +104,12 @@ fn params_to_value(params: Vec<(String, Vec<String>)>, tag: Tag) -> Value {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::FromVcf; use super::FromVcf;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(FromVcf {}) Ok(test_examples(FromVcf {})?)
} }
} }

View File

@ -102,11 +102,12 @@ async fn from_xlsx(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::FromXLSX; use super::FromXLSX;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(FromXLSX {}) Ok(test_examples(FromXLSX {})?)
} }
} }

View File

@ -135,6 +135,7 @@ async fn from_xml(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::ShellError;
use crate::commands::from_xml; use crate::commands::from_xml;
use indexmap::IndexMap; use indexmap::IndexMap;
use nu_protocol::{UntaggedValue, Value}; use nu_protocol::{UntaggedValue, Value};
@ -304,10 +305,10 @@ mod tests {
} }
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use super::FromXML; use super::FromXML;
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(FromXML {}) Ok(test_examples(FromXML {})?)
} }
} }

View File

@ -173,15 +173,16 @@ async fn from_yaml(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::ShellError;
use super::*; use super::*;
use nu_plugin::row; use nu_plugin::row;
use nu_plugin::test_helpers::value::string; use nu_plugin::test_helpers::value::string;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(FromYAML {}) Ok(test_examples(FromYAML {})?)
} }
#[test] #[test]

View File

@ -129,10 +129,10 @@ pub fn get_column_path(path: &ColumnPath, obj: &Value) -> Result<Value, ShellErr
_ => {} _ => {}
} }
if let Some(suggestions) = did_you_mean(&obj_source, column_path_tried) { if let Some(suggestions) = did_you_mean(&obj_source, column_path_tried.as_string()) {
ShellError::labeled_error( ShellError::labeled_error(
"Unknown column", "Unknown column",
format!("did you mean '{}'?", suggestions[0].1), format!("did you mean '{}'?", suggestions[0]),
column_path_tried.span.since(path_members_span), column_path_tried.span.since(path_members_span),
) )
} else { } else {
@ -155,8 +155,8 @@ pub fn get_column_path_from_table_error(
let suggestions: IndexSet<_> = rows let suggestions: IndexSet<_> = rows
.iter() .iter()
.filter_map(|r| did_you_mean(&r, &column_path_tried)) .filter_map(|r| did_you_mean(&r, column_path_tried.as_string()))
.map(|s| s[0].1.to_owned()) .map(|s| s[0].to_owned())
.collect(); .collect();
let mut existing_columns: IndexSet<_> = IndexSet::default(); let mut existing_columns: IndexSet<_> = IndexSet::default();
let mut names: Vec<String> = vec![]; let mut names: Vec<String> = vec![];
@ -232,14 +232,14 @@ pub fn get_column_from_row_error(
} => { } => {
let primary_label = format!("There isn't a column named '{}'", &column); let primary_label = format!("There isn't a column named '{}'", &column);
if let Some(suggestions) = did_you_mean(&obj_source, column_path_tried) { if let Some(suggestions) = did_you_mean(&obj_source, column_path_tried.as_string()) {
Some(ShellError::labeled_error_with_secondary( Some(ShellError::labeled_error_with_secondary(
"Unknown column", "Unknown column",
primary_label, primary_label,
column_path_tried.span, column_path_tried.span,
format!( format!(
"Perhaps you meant '{}'? Columns available: {}", "Perhaps you meant '{}'? Columns available: {}",
suggestions[0].1, suggestions[0],
&obj_source.data_descriptors().join(", ") &obj_source.data_descriptors().join(", ")
), ),
column_path_tried.span.since(path_members_span), column_path_tried.span.since(path_members_span),
@ -267,11 +267,12 @@ pub fn get_column_from_row_error(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Get; use super::Get;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Get {}) Ok(test_examples(Get {})?)
} }
} }

View File

@ -1,20 +1,21 @@
use crate::commands::WholeStreamCommand; use crate::commands::WholeStreamCommand;
use crate::prelude::*; use crate::prelude::*;
use crate::utils::suggestions::suggestions;
use indexmap::indexmap; use indexmap::indexmap;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged; use nu_source::Tagged;
use nu_value_ext::as_string; use nu_value_ext::as_string;
pub struct GroupBy; pub struct Command;
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct GroupByArgs { pub struct Arguments {
grouper: Option<Value>, grouper: Option<Value>,
} }
#[async_trait] #[async_trait]
impl WholeStreamCommand for GroupBy { impl WholeStreamCommand for Command {
fn name(&self) -> &str { fn name(&self) -> &str {
"group-by" "group-by"
} }
@ -39,17 +40,45 @@ impl WholeStreamCommand for GroupBy {
group_by(args, registry).await group_by(args, registry).await
} }
#[allow(clippy::unwrap_used)]
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
use nu_data::value::date_naive_from_str as date;
vec![ vec![
Example { Example {
description: "group items by column named \"type\"", description: "group items by column named \"type\"",
example: r#"ls | group-by type"#, example: r#"ls | group-by type"#,
result: None, result: Some(vec![UntaggedValue::row(indexmap! {
}, "File".to_string() => UntaggedValue::Table(vec![
Example { UntaggedValue::row(indexmap! {
description: "blocks can be used for generating a grouping key (same as above)", "modified".to_string() => date("2019-07-23".tagged_unknown()).unwrap().into(),
example: r#"ls | group-by { get type }"#, "name".to_string() => UntaggedValue::string("Andrés.txt").into(),
result: None, "type".to_string() => UntaggedValue::string("File").into(),
"chickens".to_string() => UntaggedValue::int(10).into(),
}).into(),
UntaggedValue::row(indexmap! {
"modified".to_string() => date("2019-09-24".tagged_unknown()).unwrap().into(),
"name".to_string() => UntaggedValue::string("Andrés.txt").into(),
"type".to_string() => UntaggedValue::string("File").into(),
"chickens".to_string() => UntaggedValue::int(20).into(),
}).into(),
]).into(),
"Dir".to_string() => UntaggedValue::Table(vec![
UntaggedValue::row(indexmap! {
"modified".to_string() => date("2019-07-23".tagged_unknown()).unwrap().into(),
"name".to_string() => UntaggedValue::string("Jonathan").into(),
"type".to_string() => UntaggedValue::string("Dir").into(),
"chickens".to_string() => UntaggedValue::int(5).into(),
}).into(),
UntaggedValue::row(indexmap! {
"modified".to_string() => date("2019-09-24".tagged_unknown()).unwrap().into(),
"name".to_string() => UntaggedValue::string("Yehuda").into(),
"type".to_string() => UntaggedValue::string("Dir").into(),
"chickens".to_string() => UntaggedValue::int(4).into(),
}).into(),
]).into(),
})
.into()]),
}, },
Example { Example {
description: "you can also group by raw values by leaving out the argument", description: "you can also group by raw values by leaving out the argument",
@ -74,10 +103,26 @@ impl WholeStreamCommand for GroupBy {
.into()]), .into()]),
}, },
Example { Example {
description: "write pipelines for a more involved grouping key", description:
example: "use the block form to generate a grouping key when each row gets processed",
"echo [1 3 1 3 2 1 1] | group-by { echo `({{$it}} - 1) % 3` | calc | str from }", example: "echo [1 3 1 3 2 1 1] | group-by { = ($it - 1) mod 3 }",
result: None, result: Some(vec![UntaggedValue::row(indexmap! {
"0".to_string() => UntaggedValue::Table(vec![
UntaggedValue::int(1).into(),
UntaggedValue::int(1).into(),
UntaggedValue::int(1).into(),
UntaggedValue::int(1).into(),
]).into(),
"2".to_string() => UntaggedValue::Table(vec![
UntaggedValue::int(3).into(),
UntaggedValue::int(3).into(),
]).into(),
"1".to_string() => UntaggedValue::Table(vec![
UntaggedValue::int(2).into(),
]).into(),
})
.into()]),
}, },
] ]
} }
@ -95,9 +140,9 @@ pub async fn group_by(
let name = args.call_info.name_tag.clone(); let name = args.call_info.name_tag.clone();
let registry = registry.clone(); let registry = registry.clone();
let head = Arc::new(args.call_info.args.head.clone()); let head = Arc::new(args.call_info.args.head.clone());
let scope = Arc::new(args.call_info.scope.clone()); let scope = args.call_info.scope.clone();
let context = Arc::new(EvaluationContext::from_raw(&args, &registry)); let context = Arc::new(EvaluationContext::from_raw(&args, &registry));
let (GroupByArgs { grouper }, input) = args.process(&registry).await?; let (Arguments { grouper }, input) = args.process(&registry).await?;
let values: Vec<Value> = input.collect().await; let values: Vec<Value> = input.collect().await;
let mut keys: Vec<Result<String, ShellError>> = vec![]; let mut keys: Vec<Result<String, ShellError>> = vec![];
@ -167,6 +212,14 @@ pub async fn group_by(
)); ));
} }
let first = values[0].clone();
let name = if first.tag.anchor().is_some() {
first.tag
} else {
name
};
let values = UntaggedValue::table(&values).into_value(&name); let values = UntaggedValue::table(&values).into_value(&name);
let group_value = match group_strategy { let group_value = match group_strategy {
@ -179,39 +232,14 @@ pub async fn group_by(
None => as_string(row), None => as_string(row),
}); });
nu_data::utils::group(&values, &Some(block), &name) nu_data::utils::group(&values, &Some(block), name)
} }
Grouper::ByColumn(column_name) => group(&column_name, &values, name), Grouper::ByColumn(column_name) => group(&column_name, &values, &name),
}; };
Ok(OutputStream::one(ReturnSuccess::value(group_value?))) Ok(OutputStream::one(ReturnSuccess::value(group_value?)))
} }
pub fn suggestions(tried: Tagged<&str>, for_value: &Value) -> ShellError {
let possibilities = for_value.data_descriptors();
let mut possible_matches: Vec<_> = possibilities
.iter()
.map(|x| (natural::distance::levenshtein_distance(x, &tried), x))
.collect();
possible_matches.sort();
if !possible_matches.is_empty() {
ShellError::labeled_error(
"Unknown column",
format!("did you mean '{}'?", possible_matches[0].1),
tried.tag(),
)
} else {
ShellError::labeled_error(
"Unknown column",
"row does not contain this column",
tried.tag(),
)
}
}
pub fn group( pub fn group(
column_name: &Option<Tagged<String>>, column_name: &Option<Tagged<String>>,
values: &Value, values: &Value,
@ -311,12 +339,4 @@ mod tests {
Ok(()) Ok(())
} }
#[test]
fn examples_work_as_expected() {
use super::GroupBy;
use crate::examples::test as test_examples;
test_examples(GroupBy {})
}
} }

View File

@ -1,5 +1,6 @@
use crate::commands::WholeStreamCommand; use crate::commands::WholeStreamCommand;
use crate::prelude::*; use crate::prelude::*;
use crate::utils::suggestions::suggestions;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged; use nu_source::Tagged;
@ -137,39 +138,15 @@ pub async fn group_by_date(
} }
} }
pub fn suggestions(tried: Tagged<&str>, for_value: &Value) -> ShellError {
let possibilities = for_value.data_descriptors();
let mut possible_matches: Vec<_> = possibilities
.iter()
.map(|x| (natural::distance::levenshtein_distance(x, &tried), x))
.collect();
possible_matches.sort();
if !possible_matches.is_empty() {
ShellError::labeled_error(
"Unknown column",
format!("did you mean '{}'?", possible_matches[0].1),
tried.tag(),
)
} else {
ShellError::labeled_error(
"Unknown column",
"row does not contain this column",
tried.tag(),
)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::GroupByDate; use super::GroupByDate;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(GroupByDate {}) Ok(test_examples(GroupByDate {})?)
} }
} }

View File

@ -116,11 +116,12 @@ pub async fn headers(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Headers; use super::Headers;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Headers {}) Ok(test_examples(Headers {})?)
} }
} }

View File

@ -6,7 +6,7 @@ use nu_data::command::signature_dict;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, TaggedDictBuilder, UntaggedValue, Value}; use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, TaggedDictBuilder, UntaggedValue, Value};
use nu_source::{SpannedItem, Tagged}; use nu_source::{SpannedItem, Tagged};
use nu_value_ext::get_data_by_key; use nu_value_ext::ValueExt;
pub struct Help; pub struct Help;
@ -96,7 +96,8 @@ async fn help(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStr
dict.insert_untagged("name", cmd_name); dict.insert_untagged("name", cmd_name);
dict.insert_untagged( dict.insert_untagged(
"description", "description",
get_data_by_key(&value, "usage".spanned_unknown()) value
.get_data_by_key("usage".spanned_unknown())
.ok_or_else(|| { .ok_or_else(|| {
ShellError::labeled_error( ShellError::labeled_error(
"Expected a usage key", "Expected a usage key",
@ -234,11 +235,12 @@ pub fn get_help(cmd: &dyn WholeStreamCommand, registry: &CommandRegistry) -> Str
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Help; use super::Help;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Help {}) Ok(test_examples(Help {})?)
} }
} }

View File

@ -112,8 +112,9 @@ pub async fn histogram(
nu_data::utils::Operation { nu_data::utils::Operation {
grouper: Some(Box::new(move |_, _| Ok(String::from("frequencies")))), grouper: Some(Box::new(move |_, _| Ok(String::from("frequencies")))),
splitter: Some(splitter(column_grouper)), splitter: Some(splitter(column_grouper)),
format: None, format: &None,
eval: &evaluate_with, eval: &evaluate_with,
reduction: &nu_data::utils::Reduction::Count,
}, },
&name, &name,
)?; )?;
@ -123,17 +124,33 @@ pub async fn histogram(
Ok(futures::stream::iter( Ok(futures::stream::iter(
results results
.percentages .data
.table_entries() .table_entries()
.map(move |value| { .cloned()
let values = value.table_entries().cloned().collect::<Vec<_>>();
let occurrences = values.len();
(occurrences, values[occurrences - 1].clone())
})
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into_iter() .into_iter()
.map(move |(occurrences, value)| { .zip(
results
.percentages
.table_entries()
.cloned()
.collect::<Vec<_>>()
.into_iter(),
)
.map(move |(counts, percentages)| {
let percentage = percentages
.table_entries()
.cloned()
.last()
.unwrap_or_else(|| {
UntaggedValue::decimal_from_float(0.0, name.span).into_value(&name)
});
let value = counts
.table_entries()
.cloned()
.last()
.unwrap_or_else(|| UntaggedValue::int(0).into_value(&name));
let mut fact = TaggedDictBuilder::new(&name); let mut fact = TaggedDictBuilder::new(&name);
let column_value = labels let column_value = labels
.get(idx) .get(idx)
@ -147,19 +164,19 @@ pub async fn histogram(
.clone(); .clone();
fact.insert_value(&column.item, column_value); fact.insert_value(&column.item, column_value);
fact.insert_untagged("occurrences", UntaggedValue::int(occurrences)); fact.insert_untagged("count", value);
let percentage = format!( let fmt_percentage = format!(
"{}%", "{}%",
// Some(2) < the number of digits // Some(2) < the number of digits
// true < group the digits // true < group the digits
crate::commands::str_::from::action(&value, &name, Some(2), true)? crate::commands::str_::from::action(&percentage, &name, Some(2), true)?
.as_string()? .as_string()?
); );
fact.insert_untagged("percentage", UntaggedValue::string(percentage)); fact.insert_untagged("percentage", UntaggedValue::string(fmt_percentage));
let string = std::iter::repeat("*") let string = std::iter::repeat("*")
.take(value.as_u64().map_err(|_| { .take(percentage.as_u64().map_err(|_| {
ShellError::labeled_error("expected a number", "expected a number", &name) ShellError::labeled_error("expected a number", "expected a number", &name)
})? as usize) })? as usize)
.collect::<String>(); .collect::<String>();
@ -210,11 +227,12 @@ fn splitter(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Histogram; use super::Histogram;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Histogram {}) Ok(test_examples(Histogram {})?)
} }
} }

View File

@ -79,11 +79,12 @@ fn history(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStrea
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::History; use super::History;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(History {}) Ok(test_examples(History {})?)
} }
} }

View File

@ -4,7 +4,9 @@ use crate::commands::WholeStreamCommand;
use crate::evaluate::evaluate_baseline_expr; use crate::evaluate::evaluate_baseline_expr;
use crate::prelude::*; use crate::prelude::*;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{hir::Block, hir::ClassifiedCommand, Signature, SyntaxShape, UntaggedValue}; use nu_protocol::{
hir::Block, hir::ClassifiedCommand, Scope, Signature, SyntaxShape, UntaggedValue,
};
pub struct If; pub struct If;
@ -72,7 +74,7 @@ async fn if_command(
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = Arc::new(registry.clone()); let registry = Arc::new(registry.clone());
let scope = Arc::new(raw_args.call_info.scope.clone()); let scope = raw_args.call_info.scope.clone();
let tag = raw_args.call_info.name_tag.clone(); let tag = raw_args.call_info.name_tag.clone();
let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry)); let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry));
@ -119,14 +121,12 @@ async fn if_command(
let then_case = then_case.clone(); let then_case = then_case.clone();
let else_case = else_case.clone(); let else_case = else_case.clone();
let registry = registry.clone(); let registry = registry.clone();
let scope = scope.clone(); let scope = Scope::append_it(scope.clone(), input);
let mut context = context.clone(); let mut context = context.clone();
async move { async move {
//FIXME: should we use the scope that's brought in as well? //FIXME: should we use the scope that's brought in as well?
let condition = let condition = evaluate_baseline_expr(&condition, &*registry, scope.clone()).await;
evaluate_baseline_expr(&condition, &*registry, &input, &scope.vars, &scope.env)
.await;
match condition { match condition {
Ok(condition) => match condition.as_bool() { Ok(condition) => match condition.as_bool() {
@ -136,9 +136,7 @@ async fn if_command(
&then_case, &then_case,
Arc::make_mut(&mut context), Arc::make_mut(&mut context),
InputStream::empty(), InputStream::empty(),
&input, scope,
&scope.vars,
&scope.env,
) )
.await .await
{ {
@ -151,9 +149,7 @@ async fn if_command(
&else_case, &else_case,
Arc::make_mut(&mut context), Arc::make_mut(&mut context),
InputStream::empty(), InputStream::empty(),
&input, scope,
&scope.vars,
&scope.env,
) )
.await .await
{ {
@ -178,11 +174,12 @@ async fn if_command(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::If; use super::If;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(If {}) Ok(test_examples(If {})?)
} }
} }

View File

@ -9,16 +9,18 @@ use nu_protocol::{
use nu_value_ext::ValueExt; use nu_value_ext::ValueExt;
use futures::stream::once; use futures::stream::once;
pub struct Insert; use indexmap::indexmap;
pub struct Command;
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct InsertArgs { pub struct Arguments {
column: ColumnPath, column: ColumnPath,
value: Value, value: Value,
} }
#[async_trait] #[async_trait]
impl WholeStreamCommand for Insert { impl WholeStreamCommand for Command {
fn name(&self) -> &str { fn name(&self) -> &str {
"insert" "insert"
} }
@ -44,6 +46,28 @@ impl WholeStreamCommand for Insert {
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
insert(args, registry).await insert(args, registry).await
} }
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Insert a column with a value",
example: "echo [[author, commits]; ['Andrés', 1]] | insert branches 5",
result: Some(vec![UntaggedValue::row(indexmap! {
"author".to_string() => Value::from("Andrés"),
"commits".to_string() => UntaggedValue::int(1).into(),
"branches".to_string() => UntaggedValue::int(5).into(),
})
.into()]),
},Example {
description: "Use in block form for more involved insertion logic",
example: "echo [[author, lucky_number]; ['Yehuda', 4]] | insert success { = $it.lucky_number * 10 }",
result: Some(vec![UntaggedValue::row(indexmap! {
"author".to_string() => Value::from("Yehuda"),
"lucky_number".to_string() => UntaggedValue::int(4).into(),
"success".to_string() => UntaggedValue::int(40).into(),
})
.into()]),
}]
}
} }
async fn process_row( async fn process_row(
@ -63,15 +87,9 @@ async fn process_row(
let for_block = input.clone(); let for_block = input.clone();
let input_stream = once(async { Ok(for_block) }).to_input_stream(); let input_stream = once(async { Ok(for_block) }).to_input_stream();
let result = run_block( let scope = Scope::append_it(scope, input.clone());
&block,
Arc::make_mut(&mut context), let result = run_block(&block, Arc::make_mut(&mut context), input_stream, scope).await;
input_stream,
&input,
&scope.vars,
&scope.env,
)
.await;
match result { match result {
Ok(mut stream) => { Ok(mut stream) => {
@ -85,13 +103,16 @@ async fn process_row(
let result = if values.len() == 1 { let result = if values.len() == 1 {
let value = values let value = values
.get(0) .get(0)
.ok_or_else(|| ShellError::unexpected("No value to insert with"))?; .ok_or_else(|| ShellError::unexpected("No value to insert with."))?;
value.clone() Value {
value: value.value.clone(),
tag: input.tag.clone(),
}
} else if values.is_empty() { } else if values.is_empty() {
UntaggedValue::nothing().into_untagged_value() UntaggedValue::nothing().into_value(&input.tag)
} else { } else {
UntaggedValue::table(&values).into_untagged_value() UntaggedValue::table(&values).into_value(&input.tag)
}; };
match input { match input {
@ -118,7 +139,11 @@ async fn process_row(
Value { Value {
value: UntaggedValue::Primitive(Primitive::Nothing), value: UntaggedValue::Primitive(Primitive::Nothing),
.. ..
} => match scope.it.insert_data_at_column_path(&field, value.clone()) { } => match scope
.it()
.unwrap_or_else(|| UntaggedValue::nothing().into_untagged_value())
.insert_data_at_column_path(&field, value.clone())
{
Ok(v) => OutputStream::one(ReturnSuccess::value(v)), Ok(v) => OutputStream::one(ReturnSuccess::value(v)),
Err(e) => OutputStream::one(Err(e)), Err(e) => OutputStream::one(Err(e)),
}, },
@ -135,9 +160,9 @@ async fn insert(
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = registry.clone(); let registry = registry.clone();
let scope = Arc::new(raw_args.call_info.scope.clone()); let scope = raw_args.call_info.scope.clone();
let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry)); let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry));
let (InsertArgs { column, value }, input) = raw_args.process(&registry).await?; let (Arguments { column, value }, input) = raw_args.process(&registry).await?;
let value = Arc::new(value); let value = Arc::new(value);
let column = Arc::new(column); let column = Arc::new(column);
@ -158,15 +183,3 @@ async fn insert(
.flatten() .flatten()
.to_output_stream()) .to_output_stream())
} }
#[cfg(test)]
mod tests {
use super::Insert;
#[test]
fn examples_work_as_expected() {
use crate::examples::test as test_examples;
test_examples(Insert {})
}
}

View File

@ -78,11 +78,12 @@ async fn into_int(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::IntoInt; use super::IntoInt;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(IntoInt {}) Ok(test_examples(IntoInt {})?)
} }
} }

View File

@ -1,217 +0,0 @@
use crate::command_registry::CommandRegistry;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_errors::ShellError;
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;
use nu_value_ext::ValueExt;
enum IsEmptyFor {
Value,
RowWithFieldsAndFallback(Vec<Tagged<ColumnPath>>, Value),
RowWithField(Tagged<ColumnPath>),
RowWithFieldAndFallback(Box<Tagged<ColumnPath>>, Value),
}
pub struct IsEmpty;
#[derive(Deserialize)]
pub struct IsEmptyArgs {
rest: Vec<Value>,
}
#[async_trait]
impl WholeStreamCommand for IsEmpty {
fn name(&self) -> &str {
"empty?"
}
fn signature(&self) -> Signature {
Signature::build("empty?").rest(
SyntaxShape::Any,
"the names of the columns to check emptiness followed by the replacement value.",
)
}
fn usage(&self) -> &str {
"Checks emptiness. The last value is the replacement value for any empty column(s) given to check against the table."
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
is_empty(args, registry).await
}
}
async fn is_empty(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let name_tag = args.call_info.name_tag.clone();
let registry = registry.clone();
let (IsEmptyArgs { rest }, input) = args.process(&registry).await?;
if input.is_empty() {
return Ok(OutputStream::one(ReturnSuccess::value(
UntaggedValue::boolean(true).into_value(name_tag),
)));
}
Ok(input
.map(move |value| {
let value_tag = value.tag();
let action = if rest.len() <= 2 {
let field = rest.get(0);
let replacement_if_true = rest.get(1);
match (field, replacement_if_true) {
(Some(field), Some(replacement_if_true)) => {
IsEmptyFor::RowWithFieldAndFallback(
Box::new(field.as_column_path()?),
replacement_if_true.clone(),
)
}
(Some(field), None) => IsEmptyFor::RowWithField(field.as_column_path()?),
(_, _) => IsEmptyFor::Value,
}
} else {
let mut arguments = rest.iter().rev();
let replacement_if_true = match arguments.next() {
Some(arg) => arg.clone(),
None => UntaggedValue::boolean(value.is_empty()).into_value(&value_tag),
};
IsEmptyFor::RowWithFieldsAndFallback(
arguments
.map(|a| a.as_column_path())
.filter_map(Result::ok)
.collect(),
replacement_if_true,
)
};
match action {
IsEmptyFor::Value => Ok(ReturnSuccess::Value(
UntaggedValue::boolean(value.is_empty()).into_value(value_tag),
)),
IsEmptyFor::RowWithFieldsAndFallback(fields, default) => {
let mut out = value;
for field in fields.iter() {
let val = crate::commands::get::get_column_path(&field, &out)?;
let emptiness_value = match out {
obj
@
Value {
value: UntaggedValue::Row(_),
..
} => {
if val.is_empty() {
obj.replace_data_at_column_path(&field, default.clone())
.ok_or_else(|| {
ShellError::labeled_error(
"empty? could not find place to check emptiness",
"column name",
&field.tag,
)
})
} else {
Ok(obj)
}
}
_ => Err(ShellError::labeled_error(
"Unrecognized type in stream",
"original value",
&value_tag,
)),
};
out = emptiness_value?;
}
Ok(ReturnSuccess::Value(out))
}
IsEmptyFor::RowWithField(field) => {
let val = crate::commands::get::get_column_path(&field, &value)?;
match &value {
obj
@
Value {
value: UntaggedValue::Row(_),
..
} => {
if val.is_empty() {
match obj.replace_data_at_column_path(
&field,
UntaggedValue::boolean(true).into_value(&value_tag),
) {
Some(v) => Ok(ReturnSuccess::Value(v)),
None => Err(ShellError::labeled_error(
"empty? could not find place to check emptiness",
"column name",
&field.tag,
)),
}
} else {
Ok(ReturnSuccess::Value(value))
}
}
_ => Err(ShellError::labeled_error(
"Unrecognized type in stream",
"original value",
&value_tag,
)),
}
}
IsEmptyFor::RowWithFieldAndFallback(field, default) => {
let val = crate::commands::get::get_column_path(&field, &value)?;
match &value {
obj
@
Value {
value: UntaggedValue::Row(_),
..
} => {
if val.is_empty() {
match obj.replace_data_at_column_path(&field, default) {
Some(v) => Ok(ReturnSuccess::Value(v)),
None => Err(ShellError::labeled_error(
"empty? could not find place to check emptiness",
"column name",
&field.tag,
)),
}
} else {
Ok(ReturnSuccess::Value(value))
}
}
_ => Err(ShellError::labeled_error(
"Unrecognized type in stream",
"original value",
&value_tag,
)),
}
}
}
})
.to_output_stream())
}
#[cfg(test)]
mod tests {
use super::IsEmpty;
#[test]
fn examples_work_as_expected() {
use crate::examples::test as test_examples;
test_examples(IsEmpty {})
}
}

View File

@ -74,11 +74,12 @@ async fn keep(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStr
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Command; use super::Command;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Command {}) Ok(test_examples(Command {})?)
} }
} }

View File

@ -3,7 +3,7 @@ use crate::evaluate::evaluate_baseline_expr;
use crate::prelude::*; use crate::prelude::*;
use log::trace; use log::trace;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{hir::ClassifiedCommand, Signature, SyntaxShape, UntaggedValue, Value}; use nu_protocol::{hir::ClassifiedCommand, Scope, Signature, SyntaxShape, UntaggedValue, Value};
pub struct SubCommand; pub struct SubCommand;
@ -33,7 +33,7 @@ impl WholeStreamCommand for SubCommand {
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = Arc::new(registry.clone()); let registry = Arc::new(registry.clone());
let scope = Arc::new(args.call_info.scope.clone()); let scope = args.call_info.scope.clone();
let call_info = args.evaluate_once(&registry).await?; let call_info = args.evaluate_once(&registry).await?;
@ -85,19 +85,11 @@ impl WholeStreamCommand for SubCommand {
.take_while(move |item| { .take_while(move |item| {
let condition = condition.clone(); let condition = condition.clone();
let registry = registry.clone(); let registry = registry.clone();
let scope = scope.clone(); let scope = Scope::append_it(scope.clone(), item.clone());
let item = item.clone();
trace!("ITEM = {:?}", item); trace!("ITEM = {:?}", item);
async move { async move {
let result = evaluate_baseline_expr( let result = evaluate_baseline_expr(&*condition, &registry, scope).await;
&*condition,
&registry,
&item,
&scope.vars,
&scope.env,
)
.await;
trace!("RESULT = {:?}", result); trace!("RESULT = {:?}", result);
!matches!(result, Ok(ref v) if v.is_true()) !matches!(result, Ok(ref v) if v.is_true())
@ -109,12 +101,13 @@ impl WholeStreamCommand for SubCommand {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::ShellError;
use super::SubCommand; use super::SubCommand;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(SubCommand {}) Ok(test_examples(SubCommand {})?)
} }
} }

View File

@ -3,7 +3,7 @@ use crate::evaluate::evaluate_baseline_expr;
use crate::prelude::*; use crate::prelude::*;
use log::trace; use log::trace;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{hir::ClassifiedCommand, Signature, SyntaxShape, UntaggedValue, Value}; use nu_protocol::{hir::ClassifiedCommand, Scope, Signature, SyntaxShape, UntaggedValue, Value};
pub struct SubCommand; pub struct SubCommand;
@ -33,7 +33,7 @@ impl WholeStreamCommand for SubCommand {
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = Arc::new(registry.clone()); let registry = Arc::new(registry.clone());
let scope = Arc::new(args.call_info.scope.clone()); let scope = args.call_info.scope.clone();
let call_info = args.evaluate_once(&registry).await?; let call_info = args.evaluate_once(&registry).await?;
let block = call_info.args.expect_nth(0)?.clone(); let block = call_info.args.expect_nth(0)?.clone();
@ -84,20 +84,11 @@ impl WholeStreamCommand for SubCommand {
.take_while(move |item| { .take_while(move |item| {
let condition = condition.clone(); let condition = condition.clone();
let registry = registry.clone(); let registry = registry.clone();
let scope = scope.clone(); let scope = Scope::append_it(scope.clone(), item.clone());
let item = item.clone();
trace!("ITEM = {:?}", item); trace!("ITEM = {:?}", item);
async move { async move {
let result = evaluate_baseline_expr( let result = evaluate_baseline_expr(&*condition, &registry, scope).await;
&*condition,
&registry,
&item,
&scope.vars,
&scope.env,
)
.await;
trace!("RESULT = {:?}", result); trace!("RESULT = {:?}", result);
matches!(result, Ok(ref v) if v.is_true()) matches!(result, Ok(ref v) if v.is_true())
@ -109,12 +100,13 @@ impl WholeStreamCommand for SubCommand {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::ShellError;
use super::SubCommand; use super::SubCommand;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(SubCommand {}) Ok(test_examples(SubCommand {})?)
} }
} }

View File

@ -121,11 +121,12 @@ async fn kill(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStr
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Kill; use super::Kill;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Kill {}) Ok(test_examples(Kill {})?)
} }
} }

View File

@ -83,11 +83,12 @@ async fn last(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStr
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Last; use super::Last;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Last {}) Ok(test_examples(Last {})?)
} }
} }

View File

@ -75,9 +75,9 @@ async fn lines(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputSt
} => { } => {
let mut leftover_string = leftover_string.lock(); let mut leftover_string = leftover_string.lock();
let st = (&*leftover_string).clone() + &st; let lo_lines = (&*leftover_string).lines().map(|x| x.to_string());
let st_lines = st.lines().map(|x| x.to_string());
let mut lines: Vec<String> = st.lines().map(|x| x.to_string()).collect(); let mut lines: Vec<String> = lo_lines.chain(st_lines).collect();
leftover_string.clear(); leftover_string.clear();
@ -125,11 +125,12 @@ async fn lines(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputSt
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Lines; use super::Lines;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Lines {}) Ok(test_examples(Lines {})?)
} }
} }

View File

@ -89,11 +89,12 @@ impl WholeStreamCommand for Ls {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Ls; use super::Ls;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Ls {}) Ok(test_examples(Ls {})?)
} }
} }

View File

@ -188,12 +188,13 @@ pub fn average(values: &[Value], name: &Tag) -> Result<Value, ShellError> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::ShellError;
use super::SubCommand; use super::SubCommand;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(SubCommand {}) Ok(test_examples(SubCommand {})?)
} }
} }

View File

@ -44,10 +44,10 @@ mod tests {
use std::str::FromStr; use std::str::FromStr;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Command {}) Ok(test_examples(Command {})?)
} }
#[test] #[test]

View File

@ -100,12 +100,13 @@ pub fn parse<T: Into<Tag>>(math_expression: &str, tag: T) -> Result<Value, Strin
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::ShellError;
use super::SubCommand; use super::SubCommand;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(SubCommand {}) Ok(test_examples(SubCommand {})?)
} }
} }

View File

@ -58,12 +58,13 @@ pub fn maximum(values: &[Value], _name: &Tag) -> Result<Value, ShellError> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::ShellError;
use super::SubCommand; use super::SubCommand;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(SubCommand {}) Ok(test_examples(SubCommand {})?)
} }
} }

View File

@ -186,12 +186,13 @@ fn compute_average(values: &[Value], name: impl Into<Tag>) -> Result<Value, Shel
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::ShellError;
use super::SubCommand; use super::SubCommand;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(SubCommand {}) Ok(test_examples(SubCommand {})?)
} }
} }

View File

@ -58,12 +58,13 @@ pub fn minimum(values: &[Value], _name: &Tag) -> Result<Value, ShellError> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::ShellError;
use super::SubCommand; use super::SubCommand;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(SubCommand {}) Ok(test_examples(SubCommand {})?)
} }
} }

View File

@ -83,12 +83,13 @@ pub fn mode(values: &[Value], name: &Tag) -> Result<Value, ShellError> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::ShellError;
use super::SubCommand; use super::SubCommand;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(SubCommand {}) Ok(test_examples(SubCommand {})?)
} }
} }

View File

@ -115,12 +115,13 @@ pub fn product(values: &[Value], name: &Tag) -> Result<Value, ShellError> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::ShellError;
use super::SubCommand; use super::SubCommand;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(SubCommand {}) Ok(test_examples(SubCommand {})?)
} }
} }

View File

@ -141,12 +141,13 @@ pub fn compute_stddev(values: &[Value], n: usize, name: &Tag) -> Result<Value, S
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::ShellError;
use super::SubCommand; use super::SubCommand;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(SubCommand {}) Ok(test_examples(SubCommand {})?)
} }
} }

View File

@ -125,12 +125,13 @@ pub fn summation(values: &[Value], name: &Tag) -> Result<Value, ShellError> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::ShellError;
use super::SubCommand; use super::SubCommand;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(SubCommand {}) Ok(test_examples(SubCommand {})?)
} }
} }

View File

@ -240,12 +240,13 @@ pub fn compute_variance(values: &[Value], n: usize, name: &Tag) -> Result<Value,
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::ShellError;
use super::SubCommand; use super::SubCommand;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(SubCommand {}) Ok(test_examples(SubCommand {})?)
} }
} }

View File

@ -60,21 +60,13 @@ async fn merge(
let (merge_args, input): (MergeArgs, _) = raw_args.process(&registry).await?; let (merge_args, input): (MergeArgs, _) = raw_args.process(&registry).await?;
let block = merge_args.block; let block = merge_args.block;
let table: Option<Vec<Value>> = match run_block( let table: Option<Vec<Value>> =
&block, match run_block(&block, &mut context, InputStream::empty(), scope).await {
&mut context, Ok(mut stream) => Some(stream.drain_vec().await),
InputStream::empty(), Err(err) => {
&scope.it, return Err(err);
&scope.vars, }
&scope.env, };
)
.await
{
Ok(mut stream) => Some(stream.drain_vec().await),
Err(err) => {
return Err(err);
}
};
let table = table.unwrap_or_else(|| { let table = table.unwrap_or_else(|| {
vec![Value { vec![Value {
@ -109,11 +101,12 @@ async fn merge(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Merge; use super::Merge;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Merge {}) Ok(test_examples(Merge {})?)
} }
} }

View File

@ -60,11 +60,12 @@ async fn mkdir(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputSt
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Mkdir; use super::Mkdir;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Mkdir {}) Ok(test_examples(Mkdir {})?)
} }
} }

View File

@ -218,17 +218,13 @@ fn move_after(
)); ));
}; };
let columns_moved = table let columns_moved = table.data_descriptors().into_iter().map(|name| {
.data_descriptors() if columns.contains(&name) {
.into_iter() None
.map(|name| { } else {
if columns.contains(&name) { Some(name)
None }
} else { });
Some(name)
}
})
.collect::<Vec<_>>();
let mut reordered_columns = vec![]; let mut reordered_columns = vec![];
let mut insert = false; let mut insert = false;
@ -281,17 +277,13 @@ fn move_before(
)); ));
}; };
let columns_moved = table let columns_moved = table.data_descriptors().into_iter().map(|name| {
.data_descriptors() if columns.contains(&name) {
.into_iter() None
.map(|name| { } else {
if columns.contains(&name) { Some(name)
None }
} else { });
Some(name)
}
})
.collect::<Vec<_>>();
let mut reordered_columns = vec![]; let mut reordered_columns = vec![];
let mut inserted = false; let mut inserted = false;
@ -324,12 +316,13 @@ fn move_before(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::ShellError;
use super::SubCommand; use super::SubCommand;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(SubCommand {}) Ok(test_examples(SubCommand {})?)
} }
} }

View File

@ -36,11 +36,12 @@ impl WholeStreamCommand for Command {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Command; use super::Command;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Command {}) Ok(test_examples(Command {})?)
} }
} }

View File

@ -79,11 +79,12 @@ async fn mv(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStrea
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Mv; use super::Mv;
use super::ShellError;
#[test] #[test]
fn examples_work_as_expected() { fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples; use crate::examples::test as test_examples;
test_examples(Mv {}) Ok(test_examples(Mv {})?)
} }
} }

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