mirror of
https://github.com/nushell/nushell.git
synced 2025-07-01 23:22:10 +02:00
Compare commits
102 Commits
Author | SHA1 | Date | |
---|---|---|---|
388973e9ab | |||
2129ec7558 | |||
82f122525c | |||
7c4c00f1e6 | |||
fe6c7dc10a | |||
9bc24e3b12 | |||
833baca66e | |||
9fd92512a2 | |||
b692ca7896 | |||
52dc04a35a | |||
42b1287759 | |||
5a471aa1d0 | |||
a4b8d4a098 | |||
a3be6affa4 | |||
71b99edd48 | |||
64553ddcb7 | |||
2a42482ae9 | |||
11f345a8ae | |||
fec50d8cfe | |||
05e42381df | |||
b435075e09 | |||
430da53f0b | |||
2e6d836dd1 | |||
899d324a9c | |||
576ed6a906 | |||
d744cf8437 | |||
088e662285 | |||
f9b0b81eb2 | |||
c5485c6501 | |||
d8ed01400f | |||
ebc4694e05 | |||
a9441d670e | |||
495d2ebd70 | |||
ad26adc3e3 | |||
63a62e19f9 | |||
4f2ae34df9 | |||
a636f161a4 | |||
dfb1e22559 | |||
dff85a7f70 | |||
3be198d2f5 | |||
d19314fe3a | |||
d06f457b2a | |||
7d07881d96 | |||
3e6e3a207c | |||
481c6d4511 | |||
231a445809 | |||
93e8f6c05e | |||
9de2144fc4 | |||
363dc51ba0 | |||
99117ff2ef | |||
5356cb9fbd | |||
0e13d9fbaa | |||
2dcb16870b | |||
ac9909112f | |||
eb3c2c9e76 | |||
3d29e3efbf | |||
f410fb6689 | |||
eb62fd466e | |||
b50cdd6de8 | |||
f38e2b5c6d | |||
455915ec9e | |||
2333158256 | |||
3ffa804088 | |||
98810d22b1 | |||
5e72b2a797 | |||
7e4e7fa4a6 | |||
d297199d7c | |||
17a433996e | |||
b9bb4692a4 | |||
d05dcdda02 | |||
27fe356214 | |||
fc44df1e45 | |||
77f915befe | |||
a5f7600f6f | |||
7eb8634ad7 | |||
452d8c06e9 | |||
48f535f02e | |||
43c10b0625 | |||
328b09fe04 | |||
15d49e4096 | |||
3ef53fe2cd | |||
7d8e759e98 | |||
69b3be61a4 | |||
79476a5cb2 | |||
f449baf8de | |||
5ff4bcfb7a | |||
98537ce8b7 | |||
d2a00a2daa | |||
f22938fc4a | |||
1e67ae8e94 | |||
c012d648fb | |||
67acaae53c | |||
e3da546e23 | |||
e5b136f70d | |||
058ef69da3 | |||
2a483531a4 | |||
05202671db | |||
8509873043 | |||
57a2d695e2 | |||
0b5ab1ef22 | |||
2eac79569c | |||
ac578b8491 |
25
.github/ISSUE_TEMPLATE/bug_report.md
vendored
25
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -23,8 +23,25 @@ A clear and concise description of what you expected to happen.
|
|||||||
If applicable, add screenshots to help explain your problem.
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
**Configuration (please complete the following information):**
|
**Configuration (please complete the following information):**
|
||||||
- OS (e.g. Windows):
|
|
||||||
- Nu version (you can use the `version` command to find out):
|
|
||||||
- Optional features (if any):
|
|
||||||
|
|
||||||
Add any other context about the problem here.
|
Run `version | pivot` and paste the output to show OS, features, etc.
|
||||||
|
|
||||||
|
```
|
||||||
|
> version | pivot
|
||||||
|
╭───┬────────────────────┬───────────────────────────────────────────────────────────────────────╮
|
||||||
|
│ # │ Column0 │ Column1 │
|
||||||
|
├───┼────────────────────┼───────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ 0 │ version │ 0.24.1 │
|
||||||
|
│ 1 │ build_os │ macos-x86_64 │
|
||||||
|
│ 2 │ rust_version │ rustc 1.48.0 │
|
||||||
|
│ 3 │ cargo_version │ cargo 1.48.0 │
|
||||||
|
│ 4 │ pkg_version │ 0.24.1 │
|
||||||
|
│ 5 │ build_time │ 2020-12-18 09:54:09 │
|
||||||
|
│ 6 │ build_rust_channel │ release │
|
||||||
|
│ 7 │ features │ ctrlc, default, directories, dirs, git, ichwh, ptree, rich-benchmark, │
|
||||||
|
│ │ │ rustyline, term, uuid, which, zip │
|
||||||
|
╰───┴────────────────────┴───────────────────────────────────────────────────────────────────────╯
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
**Add any other context about the problem here.**
|
||||||
|
@ -4,7 +4,7 @@ tasks:
|
|||||||
- name: Clippy
|
- name: Clippy
|
||||||
init: cargo clippy --all --features=stable -- -D clippy::result_unwrap_used -D clippy::option_unwrap_used
|
init: cargo clippy --all --features=stable -- -D clippy::result_unwrap_used -D clippy::option_unwrap_used
|
||||||
- name: Testing
|
- name: Testing
|
||||||
init: cargo test --all --features=stable,test-bins
|
init: cargo test --all --features=stable
|
||||||
- name: Build
|
- name: Build
|
||||||
init: cargo build --features=stable
|
init: cargo build --features=stable
|
||||||
- name: Nu
|
- name: Nu
|
||||||
|
2138
Cargo.lock
generated
2138
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
92
Cargo.toml
92
Cargo.toml
@ -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.24.1"
|
version = "0.26.0"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["crates/*/"]
|
members = ["crates/*/"]
|
||||||
@ -18,65 +18,64 @@ 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.24.1", path = "./crates/nu-cli"}
|
nu-cli = {version = "0.26.0", path = "./crates/nu-cli"}
|
||||||
nu-data = {version = "0.24.1", path = "./crates/nu-data"}
|
nu-command = {version = "0.26.0", path = "./crates/nu-command"}
|
||||||
nu-errors = {version = "0.24.1", path = "./crates/nu-errors"}
|
nu-data = {version = "0.26.0", path = "./crates/nu-data"}
|
||||||
nu-parser = {version = "0.24.1", path = "./crates/nu-parser"}
|
nu-engine = {version = "0.26.0", path = "./crates/nu-engine"}
|
||||||
nu-plugin = {version = "0.24.1", path = "./crates/nu-plugin"}
|
nu-errors = {version = "0.26.0", path = "./crates/nu-errors"}
|
||||||
nu-protocol = {version = "0.24.1", path = "./crates/nu-protocol"}
|
nu-parser = {version = "0.26.0", path = "./crates/nu-parser"}
|
||||||
nu-source = {version = "0.24.1", path = "./crates/nu-source"}
|
nu-plugin = {version = "0.26.0", path = "./crates/nu-plugin"}
|
||||||
nu-value-ext = {version = "0.24.1", path = "./crates/nu-value-ext"}
|
nu-protocol = {version = "0.26.0", path = "./crates/nu-protocol"}
|
||||||
|
nu-source = {version = "0.26.0", path = "./crates/nu-source"}
|
||||||
|
nu-value-ext = {version = "0.26.0", path = "./crates/nu-value-ext"}
|
||||||
|
|
||||||
nu_plugin_binaryview = {version = "0.24.1", path = "./crates/nu_plugin_binaryview", optional = true}
|
nu_plugin_binaryview = {version = "0.26.0", path = "./crates/nu_plugin_binaryview", optional = true}
|
||||||
nu_plugin_chart = {version = "0.24.1", path = "./crates/nu_plugin_chart", optional = true}
|
nu_plugin_chart = {version = "0.26.0", path = "./crates/nu_plugin_chart", optional = true}
|
||||||
nu_plugin_fetch = {version = "0.24.1", path = "./crates/nu_plugin_fetch", optional = true}
|
nu_plugin_fetch = {version = "0.26.0", path = "./crates/nu_plugin_fetch", optional = true}
|
||||||
nu_plugin_from_bson = {version = "0.24.1", path = "./crates/nu_plugin_from_bson", optional = true}
|
nu_plugin_from_bson = {version = "0.26.0", path = "./crates/nu_plugin_from_bson", optional = true}
|
||||||
nu_plugin_from_sqlite = {version = "0.24.1", path = "./crates/nu_plugin_from_sqlite", optional = true}
|
nu_plugin_from_sqlite = {version = "0.26.0", path = "./crates/nu_plugin_from_sqlite", optional = true}
|
||||||
nu_plugin_inc = {version = "0.24.1", path = "./crates/nu_plugin_inc", optional = true}
|
nu_plugin_inc = {version = "0.26.0", path = "./crates/nu_plugin_inc", optional = true}
|
||||||
nu_plugin_match = {version = "0.24.1", path = "./crates/nu_plugin_match", optional = true}
|
nu_plugin_match = {version = "0.26.0", path = "./crates/nu_plugin_match", optional = true}
|
||||||
nu_plugin_post = {version = "0.24.1", path = "./crates/nu_plugin_post", optional = true}
|
nu_plugin_post = {version = "0.26.0", path = "./crates/nu_plugin_post", optional = true}
|
||||||
nu_plugin_ps = {version = "0.24.1", path = "./crates/nu_plugin_ps", optional = true}
|
nu_plugin_ps = {version = "0.26.0", path = "./crates/nu_plugin_ps", optional = true}
|
||||||
nu_plugin_s3 = {version = "0.24.1", path = "./crates/nu_plugin_s3", optional = true}
|
nu_plugin_s3 = {version = "0.26.0", path = "./crates/nu_plugin_s3", optional = true}
|
||||||
nu_plugin_start = {version = "0.24.1", path = "./crates/nu_plugin_start", optional = true}
|
nu_plugin_selector = {version = "0.26.0", path = "./crates/nu_plugin_selector", optional = true}
|
||||||
nu_plugin_sys = {version = "0.24.1", path = "./crates/nu_plugin_sys", optional = true}
|
nu_plugin_start = {version = "0.26.0", path = "./crates/nu_plugin_start", optional = true}
|
||||||
nu_plugin_textview = {version = "0.24.1", path = "./crates/nu_plugin_textview", optional = true}
|
nu_plugin_sys = {version = "0.26.0", path = "./crates/nu_plugin_sys", optional = true}
|
||||||
nu_plugin_to_bson = {version = "0.24.1", path = "./crates/nu_plugin_to_bson", optional = true}
|
nu_plugin_textview = {version = "0.26.0", path = "./crates/nu_plugin_textview", optional = true}
|
||||||
nu_plugin_to_sqlite = {version = "0.24.1", path = "./crates/nu_plugin_to_sqlite", optional = true}
|
nu_plugin_to_bson = {version = "0.26.0", path = "./crates/nu_plugin_to_bson", optional = true}
|
||||||
nu_plugin_tree = {version = "0.24.1", path = "./crates/nu_plugin_tree", optional = true}
|
nu_plugin_to_sqlite = {version = "0.26.0", path = "./crates/nu_plugin_to_sqlite", optional = true}
|
||||||
nu_plugin_xpath = {version = "0.24.1", path = "./crates/nu_plugin_xpath", optional = true}
|
nu_plugin_tree = {version = "0.26.0", path = "./crates/nu_plugin_tree", optional = true}
|
||||||
nu_plugin_selector = {version = "0.24.1", path = "./crates/nu_plugin_selector", optional = true}
|
nu_plugin_xpath = {version = "0.26.0", path = "./crates/nu_plugin_xpath", optional = true}
|
||||||
|
|
||||||
# Required to bootstrap the main binary
|
# Required to bootstrap the main binary
|
||||||
clap = "2.33.3"
|
clap = "2.33.3"
|
||||||
ctrlc = {version = "3.1.6", optional = true}
|
ctrlc = {version = "3.1.6", optional = true}
|
||||||
futures = {version = "0.3.5", features = ["compat", "io-compat"]}
|
futures = {version = "0.3.5", features = ["compat", "io-compat"]}
|
||||||
|
itertools = "0.10.0"
|
||||||
log = "0.4.11"
|
log = "0.4.11"
|
||||||
pretty_env_logger = "0.4.0"
|
pretty_env_logger = "0.4.0"
|
||||||
itertools = "0.9.0"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
dunce = "1.0.1"
|
dunce = "1.0.1"
|
||||||
nu-test-support = {version = "0.24.1", path = "./crates/nu-test-support"}
|
nu-test-support = {version = "0.26.0", path = "./crates/nu-test-support"}
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
ctrlc-support = ["nu-cli/ctrlc"]
|
ctrlc-support = ["nu-cli/ctrlc", "nu-command/ctrlc"]
|
||||||
directories-support = ["nu-cli/directories", "nu-cli/dirs", "nu-data/directories", "nu-data/dirs"]
|
directories-support = ["nu-cli/directories", "nu-cli/dirs", "nu-command/directories", "nu-command/dirs", "nu-data/directories", "nu-data/dirs", "nu-engine/dirs"]
|
||||||
git-support = ["nu-cli/git2"]
|
ptree-support = ["nu-cli/ptree", "nu-command/ptree"]
|
||||||
ptree-support = ["nu-cli/ptree"]
|
rustyline-support = ["nu-cli/rustyline-support", "nu-command/rustyline-support"]
|
||||||
rich-benchmark = ["nu-cli/rich-benchmark"]
|
term-support = ["nu-cli/term", "nu-command/term"]
|
||||||
rustyline-support = ["nu-cli/rustyline-support"]
|
uuid-support = ["nu-cli/uuid_crate", "nu-command/uuid_crate"]
|
||||||
term-support = ["nu-cli/term"]
|
which-support = ["nu-cli/ichwh", "nu-cli/which", "nu-command/ichwh", "nu-command/which"]
|
||||||
uuid-support = ["nu-cli/uuid_crate"]
|
|
||||||
which-support = ["nu-cli/ichwh", "nu-cli/which"]
|
|
||||||
|
|
||||||
default = [
|
default = [
|
||||||
"sys",
|
"sys",
|
||||||
"ps",
|
"ps",
|
||||||
"textview",
|
"textview",
|
||||||
"inc",
|
"inc",
|
||||||
"git-support",
|
|
||||||
"directories-support",
|
"directories-support",
|
||||||
"ctrlc-support",
|
"ctrlc-support",
|
||||||
"which-support",
|
"which-support",
|
||||||
@ -87,8 +86,7 @@ default = [
|
|||||||
"match",
|
"match",
|
||||||
"post",
|
"post",
|
||||||
"fetch",
|
"fetch",
|
||||||
"rich-benchmark",
|
"zip-support",
|
||||||
"zip-support"
|
|
||||||
]
|
]
|
||||||
extra = ["default", "binaryview", "tree", "clipboard-cli", "trash-support", "start", "bson", "sqlite", "s3", "chart", "xpath", "selector"]
|
extra = ["default", "binaryview", "tree", "clipboard-cli", "trash-support", "start", "bson", "sqlite", "s3", "chart", "xpath", "selector"]
|
||||||
stable = ["default"]
|
stable = ["default"]
|
||||||
@ -105,26 +103,26 @@ post = ["nu_plugin_post"]
|
|||||||
ps = ["nu_plugin_ps"]
|
ps = ["nu_plugin_ps"]
|
||||||
sys = ["nu_plugin_sys"]
|
sys = ["nu_plugin_sys"]
|
||||||
textview = ["nu_plugin_textview"]
|
textview = ["nu_plugin_textview"]
|
||||||
zip-support = ["nu-cli/zip"]
|
zip-support = ["nu-cli/zip", "nu-command/zip"]
|
||||||
|
|
||||||
# Extra
|
# Extra
|
||||||
binaryview = ["nu_plugin_binaryview"]
|
binaryview = ["nu_plugin_binaryview"]
|
||||||
bson = ["nu_plugin_from_bson", "nu_plugin_to_bson"]
|
bson = ["nu_plugin_from_bson", "nu_plugin_to_bson"]
|
||||||
chart = ["nu_plugin_chart"]
|
chart = ["nu_plugin_chart"]
|
||||||
clipboard-cli = ["nu-cli/clipboard-cli"]
|
clipboard-cli = ["nu-cli/clipboard-cli", "nu-command/clipboard-cli"]
|
||||||
s3 = ["nu_plugin_s3"]
|
s3 = ["nu_plugin_s3"]
|
||||||
|
selector = ["nu_plugin_selector"]
|
||||||
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"]
|
||||||
trash-support = ["nu-cli/trash-support"]
|
trash-support = ["nu-cli/trash-support", "nu-command/trash-support"]
|
||||||
tree = ["nu_plugin_tree"]
|
tree = ["nu_plugin_tree"]
|
||||||
xpath = ["nu_plugin_xpath"]
|
xpath = ["nu_plugin_xpath"]
|
||||||
selector = ["nu_plugin_selector"]
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
#strip = "symbols" #Couldn't get working +nightly
|
#strip = "symbols" #Couldn't get working +nightly
|
||||||
opt-level = 'z' #Optimize for size
|
|
||||||
lto = true #Link Time Optimization
|
|
||||||
codegen-units = 1 #Reduce parallel codegen units
|
codegen-units = 1 #Reduce parallel codegen units
|
||||||
|
lto = true #Link Time Optimization
|
||||||
|
opt-level = 'z' #Optimize for size
|
||||||
|
|
||||||
# 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
|
||||||
|
10
README.md
10
README.md
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
A new type of shell.
|
A new type of shell.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ To install Nu via cargo (make sure you have installed [rustup](https://rustup.rs
|
|||||||
cargo install nu
|
cargo install nu
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also build Nu yourself with all the bells and whistles (be sure to have installed the [dependencies](https://www.nushell.sh/book/en/installation.html#dependencies) for your platform), once you have checked out this repo with git:
|
You can also build Nu yourself with all the bells and whistles (be sure to have installed the [dependencies](https://www.nushell.sh/book/installation.html#dependencies) for your platform), once you have checked out this repo with git:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo build --workspace --features=extra
|
cargo build --workspace --features=extra
|
||||||
@ -234,7 +234,7 @@ Here we use the variable `$it` to refer to the value being piped to the external
|
|||||||
|
|
||||||
### Configuration
|
### Configuration
|
||||||
|
|
||||||
Nu has early support for configuring the shell. You can refer to the book for a list of [all supported variables](https://www.nushell.sh/book/en/configuration.html).
|
Nu has early support for configuring the shell. You can refer to the book for a list of [all supported variables](https://www.nushell.sh/book/configuration.html).
|
||||||
|
|
||||||
To set one of these variables, you can use `config set`. For example:
|
To set one of these variables, you can use `config set`. For example:
|
||||||
|
|
||||||
@ -300,8 +300,8 @@ Nu is in heavy development, and will naturally change as it matures and people u
|
|||||||
| Errors | | | X | | | Error reporting works, but could use usability polish
|
| Errors | | | X | | | Error reporting works, but could use usability polish
|
||||||
| Documentation | | X | | | | Book and related are barebones and lack task-based lessons
|
| Documentation | | X | | | | Book and related are barebones and lack task-based lessons
|
||||||
| Paging | | X | | | | Textview has paging, but we'd like paging for tables
|
| Paging | | X | | | | Textview has paging, but we'd like paging for tables
|
||||||
| Functions| X | | | | | No functions, yet, only aliases
|
| Functions | | X | | | | No functions, yet, only aliases
|
||||||
| Variables| X | | | | | Nu doesn't yet support variables
|
| Variables| | X | | | | Nu doesn't yet support variables
|
||||||
| Completions | | X | | | | Completions are currently barebones, at best
|
| Completions | | X | | | | Completions are currently barebones, at best
|
||||||
| Type-checking | | X | | | | Commands check basic types, but input/output isn't checked
|
| Type-checking | | X | | | | Commands check basic types, but input/output isn't checked
|
||||||
|
|
||||||
|
@ -1,28 +1,33 @@
|
|||||||
[package]
|
[package]
|
||||||
authors = ["The Nu Project Contributors"]
|
authors = ["The Nu Project Contributors"]
|
||||||
|
build = "build.rs"
|
||||||
description = "CLI for nushell"
|
description = "CLI for nushell"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
name = "nu-cli"
|
name = "nu-cli"
|
||||||
version = "0.24.1"
|
version = "0.26.0"
|
||||||
build = "build.rs"
|
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nu-data = {version = "0.24.1", path = "../nu-data"}
|
nu-command = { version = "0.26.0", path = "../nu-command" }
|
||||||
nu-errors = {version = "0.24.1", path = "../nu-errors"}
|
nu-data = { version = "0.26.0", path = "../nu-data" }
|
||||||
nu-json = {version = "0.24.1", path = "../nu-json"}
|
nu-engine = { version = "0.26.0", path = "../nu-engine" }
|
||||||
nu-parser = {version = "0.24.1", path = "../nu-parser"}
|
nu-errors = { version = "0.26.0", path = "../nu-errors" }
|
||||||
nu-plugin = {version = "0.24.1", path = "../nu-plugin"}
|
nu-json = { version = "0.26.0", path = "../nu-json" }
|
||||||
nu-protocol = {version = "0.24.1", path = "../nu-protocol"}
|
nu-parser = { version = "0.26.0", path = "../nu-parser" }
|
||||||
nu-source = {version = "0.24.1", path = "../nu-source"}
|
nu-plugin = { version = "0.26.0", path = "../nu-plugin" }
|
||||||
nu-table = {version = "0.24.1", path = "../nu-table"}
|
nu-protocol = { version = "0.26.0", path = "../nu-protocol" }
|
||||||
nu-test-support = {version = "0.24.1", path = "../nu-test-support"}
|
nu-source = { version = "0.26.0", path = "../nu-source" }
|
||||||
nu-value-ext = {version = "0.24.1", path = "../nu-value-ext"}
|
nu-stream = { version = "0.26.0", path = "../nu-stream" }
|
||||||
|
nu-table = { version = "0.26.0", path = "../nu-table" }
|
||||||
|
nu-test-support = { version = "0.26.0", path = "../nu-test-support" }
|
||||||
|
nu-value-ext = { version = "0.26.0", path = "../nu-value-ext" }
|
||||||
|
|
||||||
|
Inflector = "0.11"
|
||||||
ansi_term = "0.12.1"
|
ansi_term = "0.12.1"
|
||||||
|
arboard = { version = "1.1.0", optional = true }
|
||||||
async-recursion = "0.3.1"
|
async-recursion = "0.3.1"
|
||||||
async-trait = "0.1.40"
|
async-trait = "0.1.40"
|
||||||
base64 = "0.13.0"
|
base64 = "0.13.0"
|
||||||
@ -33,13 +38,12 @@ calamine = "0.16.1"
|
|||||||
chrono = { version = "0.4.15", features = ["serde"] }
|
chrono = { version = "0.4.15", features = ["serde"] }
|
||||||
chrono-tz = "0.5.3"
|
chrono-tz = "0.5.3"
|
||||||
clap = "2.33.3"
|
clap = "2.33.3"
|
||||||
clipboard = {version = "0.5.0", optional = true}
|
codespan-reporting = "0.11.0"
|
||||||
codespan-reporting = "0.9.5"
|
|
||||||
csv = "1.1.3"
|
csv = "1.1.3"
|
||||||
ctrlc = { version = "3.1.6", optional = true }
|
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-next = { version = "2.0.0", optional = true }
|
||||||
dirs = {version = "3.0.1", optional = true}
|
dirs-next = { version = "2.0.0", optional = true }
|
||||||
dtparse = "1.2.0"
|
dtparse = "1.2.0"
|
||||||
dunce = "1.0.1"
|
dunce = "1.0.1"
|
||||||
eml-parser = "0.1.0"
|
eml-parser = "0.1.0"
|
||||||
@ -47,18 +51,15 @@ encoding_rs = "0.8.24"
|
|||||||
filesize = "0.2.0"
|
filesize = "0.2.0"
|
||||||
fs_extra = "1.2.0"
|
fs_extra = "1.2.0"
|
||||||
futures = { version = "0.3.5", features = ["compat", "io-compat"] }
|
futures = { version = "0.3.5", features = ["compat", "io-compat"] }
|
||||||
|
futures-util = "0.3.8"
|
||||||
futures_codec = "0.4.1"
|
futures_codec = "0.4.1"
|
||||||
futures-util = "0.3.5"
|
|
||||||
getset = "0.1.1"
|
getset = "0.1.1"
|
||||||
git2 = {version = "0.13.11", default_features = false, optional = true}
|
|
||||||
glob = "0.3.0"
|
glob = "0.3.0"
|
||||||
heim = {version = "0.1.0-rc.1", optional = true}
|
|
||||||
htmlescape = "0.3.1"
|
htmlescape = "0.3.1"
|
||||||
ical = "0.6.0"
|
ical = "0.7.0"
|
||||||
ichwh = { version = "0.3.4", optional = true }
|
ichwh = { version = "0.3.4", optional = true }
|
||||||
indexmap = { version = "1.6.0", features = ["serde-1"] }
|
indexmap = { version = "1.6.0", features = ["serde-1"] }
|
||||||
Inflector = "0.11"
|
itertools = "0.10.0"
|
||||||
itertools = "0.9.0"
|
|
||||||
lazy_static = "1.*"
|
lazy_static = "1.*"
|
||||||
log = "0.4.11"
|
log = "0.4.11"
|
||||||
meval = "0.2.0"
|
meval = "0.2.0"
|
||||||
@ -70,12 +71,12 @@ 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"
|
quick-xml = "0.20.0"
|
||||||
rand = "0.7.3"
|
rand = "0.7.3"
|
||||||
rayon = "1.4.0"
|
rayon = "1.4.0"
|
||||||
regex = "1.3.9"
|
regex = "1.3.9"
|
||||||
roxmltree = "0.13.0"
|
roxmltree = "0.14.0"
|
||||||
rust-embed = "5.6.0"
|
rust-embed = "5.8.0"
|
||||||
rustyline = { version = "6.3.0", optional = true }
|
rustyline = { version = "6.3.0", optional = true }
|
||||||
serde = { version = "1.0.115", features = ["derive"] }
|
serde = { version = "1.0.115", features = ["derive"] }
|
||||||
serde_bytes = "0.11.5"
|
serde_bytes = "0.11.5"
|
||||||
@ -96,11 +97,11 @@ titlecase = "1.0"
|
|||||||
toml = "0.5.6"
|
toml = "0.5.6"
|
||||||
trash = { version = "1.2.0", optional = true }
|
trash = { version = "1.2.0", optional = true }
|
||||||
unicode-segmentation = "1.6.0"
|
unicode-segmentation = "1.6.0"
|
||||||
uom = {version = "0.30.0", features = ["f64", "try-from"]}
|
|
||||||
url = "2.1.1"
|
url = "2.1.1"
|
||||||
uuid_crate = { package = "uuid", version = "0.8.1", features = ["v4"], optional = true }
|
uuid_crate = { package = "uuid", version = "0.8.1", features = ["v4"], optional = true }
|
||||||
which = { version = "4.0.2", optional = true }
|
which = { version = "4.0.2", optional = true }
|
||||||
zip = { version = "0.5.7", optional = true }
|
zip = { version = "0.5.7", optional = true }
|
||||||
|
shadow-rs = { version = "0.5", default-features = false, optional = true }
|
||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
umask = "1.0.0"
|
umask = "1.0.0"
|
||||||
@ -115,18 +116,20 @@ users = "0.10.0"
|
|||||||
[dependencies.rusqlite]
|
[dependencies.rusqlite]
|
||||||
features = ["bundled", "blob"]
|
features = ["bundled", "blob"]
|
||||||
optional = true
|
optional = true
|
||||||
version = "0.24.1"
|
version = "0.24.2"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
shadow-rs = "0.3.20"
|
shadow-rs = "0.5"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
quickcheck = "0.9.2"
|
quickcheck = "0.9.2"
|
||||||
quickcheck_macros = "0.9.1"
|
quickcheck_macros = "0.9.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
clipboard-cli = ["clipboard"]
|
default = ["shadow-rs"]
|
||||||
rich-benchmark = ["heim"]
|
clipboard-cli = ["arboard"]
|
||||||
rustyline-support = ["rustyline"]
|
rustyline-support = ["rustyline", "nu-engine/rustyline-support"]
|
||||||
stable = []
|
stable = []
|
||||||
trash-support = ["trash"]
|
trash-support = ["trash"]
|
||||||
|
dirs = ["dirs-next"]
|
||||||
|
directories = ["directories-next"]
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
fn main() -> shadow_rs::SdResult<()> {
|
fn main() -> shadow_rs::SdResult<()> {
|
||||||
let src_path = std::env::var("CARGO_MANIFEST_DIR")?;
|
shadow_rs::new()
|
||||||
let out_path = std::env::var("OUT_DIR")?;
|
|
||||||
shadow_rs::Shadow::build(src_path, out_path)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,64 +0,0 @@
|
|||||||
use crate::commands::Command;
|
|
||||||
use indexmap::IndexMap;
|
|
||||||
use nu_errors::ShellError;
|
|
||||||
use nu_parser::SignatureRegistry;
|
|
||||||
use nu_protocol::Signature;
|
|
||||||
use parking_lot::Mutex;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
|
||||||
pub struct CommandRegistry {
|
|
||||||
registry: Arc<Mutex<IndexMap<String, Command>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SignatureRegistry for CommandRegistry {
|
|
||||||
fn has(&self, name: &str) -> bool {
|
|
||||||
let registry = self.registry.lock();
|
|
||||||
registry.contains_key(name)
|
|
||||||
}
|
|
||||||
fn get(&self, name: &str) -> Option<Signature> {
|
|
||||||
let registry = self.registry.lock();
|
|
||||||
registry.get(name).map(|command| command.signature())
|
|
||||||
}
|
|
||||||
fn clone_box(&self) -> Box<dyn SignatureRegistry> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRegistry {
|
|
||||||
pub fn new() -> CommandRegistry {
|
|
||||||
CommandRegistry {
|
|
||||||
registry: Arc::new(Mutex::new(IndexMap::default())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRegistry {
|
|
||||||
pub fn get_command(&self, name: &str) -> Option<Command> {
|
|
||||||
let registry = self.registry.lock();
|
|
||||||
|
|
||||||
registry.get(name).cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn expect_command(&self, name: &str) -> Result<Command, ShellError> {
|
|
||||||
self.get_command(name).ok_or_else(|| {
|
|
||||||
ShellError::untagged_runtime_error(format!("Could not load command: {}", name))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn has(&self, name: &str) -> bool {
|
|
||||||
let registry = self.registry.lock();
|
|
||||||
|
|
||||||
registry.contains_key(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert(&mut self, name: impl Into<String>, command: Command) {
|
|
||||||
let mut registry = self.registry.lock();
|
|
||||||
registry.insert(name.into(), command);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn names(&self) -> Vec<String> {
|
|
||||||
let registry = self.registry.lock();
|
|
||||||
registry.keys().cloned().collect()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,221 +0,0 @@
|
|||||||
use crate::command_registry::CommandRegistry;
|
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
use crate::types::deduction::{VarDeclaration, VarSyntaxShapeDeductor};
|
|
||||||
use deduction_to_signature::DeductionToSignature;
|
|
||||||
use log::trace;
|
|
||||||
use nu_data::config;
|
|
||||||
use nu_errors::ShellError;
|
|
||||||
use nu_protocol::{
|
|
||||||
hir::Block, CommandAction, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
|
||||||
};
|
|
||||||
use nu_source::Tagged;
|
|
||||||
|
|
||||||
pub struct Alias;
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
pub struct AliasArgs {
|
|
||||||
pub name: Tagged<String>,
|
|
||||||
pub args: Vec<Value>,
|
|
||||||
pub block: Block,
|
|
||||||
pub infer: Option<bool>,
|
|
||||||
pub save: Option<bool>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl WholeStreamCommand for Alias {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"alias"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build("alias")
|
|
||||||
.required("name", SyntaxShape::String, "the name of the alias")
|
|
||||||
.required("args", SyntaxShape::Table, "the arguments to the alias")
|
|
||||||
.required(
|
|
||||||
"block",
|
|
||||||
SyntaxShape::Block,
|
|
||||||
"the block to run as the body of the alias",
|
|
||||||
)
|
|
||||||
.switch("infer", "infer argument types (experimental)", Some('i'))
|
|
||||||
.switch("save", "save the alias to your config", Some('s'))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Define a shortcut for another command."
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn run(
|
|
||||||
&self,
|
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
alias(args, registry).await
|
|
||||||
}
|
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
|
||||||
vec![
|
|
||||||
Example {
|
|
||||||
description: "An alias without parameters",
|
|
||||||
example: "alias say-hi [] { echo 'Hello!' }",
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
description: "An alias with a single parameter",
|
|
||||||
example: "alias l [x] { ls $x }",
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn alias(
|
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let registry = registry.clone();
|
|
||||||
let mut raw_input = args.raw_input.clone();
|
|
||||||
let (
|
|
||||||
AliasArgs {
|
|
||||||
name,
|
|
||||||
args: list,
|
|
||||||
block,
|
|
||||||
infer,
|
|
||||||
save,
|
|
||||||
},
|
|
||||||
_ctx,
|
|
||||||
) = args.process(®istry).await?;
|
|
||||||
|
|
||||||
if let Some(true) = save {
|
|
||||||
let mut result = nu_data::config::read(name.clone().tag, &None)?;
|
|
||||||
|
|
||||||
// process the alias to remove the --save flag
|
|
||||||
let left_brace = raw_input.find('{').unwrap_or(0);
|
|
||||||
let right_brace = raw_input.rfind('}').unwrap_or_else(|| raw_input.len());
|
|
||||||
let left = raw_input[..left_brace]
|
|
||||||
.replace("--save", "") // TODO using regex (or reconstruct string from AST?)
|
|
||||||
.replace("-si", "-i")
|
|
||||||
.replace("-s ", "")
|
|
||||||
.replace("-is", "-i");
|
|
||||||
let right = raw_input[right_brace..]
|
|
||||||
.replace("--save", "")
|
|
||||||
.replace("-si", "-i")
|
|
||||||
.replace("-s ", "")
|
|
||||||
.replace("-is", "-i");
|
|
||||||
raw_input = format!("{}{}{}", left, &raw_input[left_brace..right_brace], right);
|
|
||||||
|
|
||||||
// create a value from raw_input alias
|
|
||||||
let alias: Value = raw_input.trim().to_string().into();
|
|
||||||
let alias_start = raw_input.find('[').unwrap_or(0); // used to check if the same alias already exists
|
|
||||||
|
|
||||||
// add to startup if alias doesn't exist and replace if it does
|
|
||||||
match result.get_mut("startup") {
|
|
||||||
Some(startup) => {
|
|
||||||
if let UntaggedValue::Table(ref mut commands) = startup.value {
|
|
||||||
if let Some(command) = commands.iter_mut().find(|command| {
|
|
||||||
let cmd_str = command.as_string().unwrap_or_default();
|
|
||||||
cmd_str.starts_with(&raw_input[..alias_start])
|
|
||||||
}) {
|
|
||||||
*command = alias;
|
|
||||||
} else {
|
|
||||||
commands.push(alias);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
let table = UntaggedValue::table(&[alias]);
|
|
||||||
result.insert("startup".to_string(), table.into_value(Tag::default()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
config::write(&result, &None)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut processed_args: Vec<VarDeclaration> = vec![];
|
|
||||||
for (_, item) in list.iter().enumerate() {
|
|
||||||
match item.as_string() {
|
|
||||||
Ok(var_name) => {
|
|
||||||
let dollar_var_name = format!("${}", var_name);
|
|
||||||
processed_args.push(VarDeclaration {
|
|
||||||
name: dollar_var_name,
|
|
||||||
// type_decl: None,
|
|
||||||
span: item.tag.span,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
return Err(ShellError::labeled_error(
|
|
||||||
"Expected a string",
|
|
||||||
"expected a string",
|
|
||||||
item.tag(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
trace!("Found vars: {:?}", processed_args);
|
|
||||||
|
|
||||||
let inferred_shapes = {
|
|
||||||
if let Some(true) = infer {
|
|
||||||
VarSyntaxShapeDeductor::infer_vars(&processed_args, &block, ®istry)?
|
|
||||||
} else {
|
|
||||||
processed_args.into_iter().map(|arg| (arg, None)).collect()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let signature = DeductionToSignature::get(&name.item, &inferred_shapes);
|
|
||||||
trace!("Inferred signature: {:?}", signature);
|
|
||||||
|
|
||||||
Ok(OutputStream::one(ReturnSuccess::action(
|
|
||||||
CommandAction::AddAlias(Box::new(signature), block),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::Alias;
|
|
||||||
use super::ShellError;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
|
||||||
use crate::examples::test as test_examples;
|
|
||||||
|
|
||||||
Ok(test_examples(Alias {})?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod deduction_to_signature {
|
|
||||||
//For now this logic is relativly simple.
|
|
||||||
//For each var, one mandatory positional is added.
|
|
||||||
//As soon as more support for optional positional arguments is arrived,
|
|
||||||
//this logic might be a little bit more tricky.
|
|
||||||
use crate::types::deduction::{Deduction, VarDeclaration};
|
|
||||||
use nu_protocol::{PositionalType, Signature, SyntaxShape};
|
|
||||||
|
|
||||||
pub struct DeductionToSignature {}
|
|
||||||
impl DeductionToSignature {
|
|
||||||
pub fn get(
|
|
||||||
cmd_name: &str,
|
|
||||||
deductions: &[(VarDeclaration, Option<Deduction>)],
|
|
||||||
) -> Signature {
|
|
||||||
let mut signature = Signature::build(cmd_name);
|
|
||||||
for (decl, deduction) in deductions {
|
|
||||||
match deduction {
|
|
||||||
None => signature.positional.push((
|
|
||||||
PositionalType::optional(&decl.name, SyntaxShape::Any),
|
|
||||||
decl.name.clone(),
|
|
||||||
)),
|
|
||||||
Some(deduction) => match deduction {
|
|
||||||
Deduction::VarShapeDeduction(normal_var_deduction) => {
|
|
||||||
signature.positional.push((
|
|
||||||
PositionalType::optional(
|
|
||||||
&decl.name,
|
|
||||||
normal_var_deduction[0].deduction,
|
|
||||||
),
|
|
||||||
decl.name.clone(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
signature
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,88 +0,0 @@
|
|||||||
use crate::commands::classified::expr::run_expression_block;
|
|
||||||
use crate::commands::classified::internal::run_internal_command;
|
|
||||||
use crate::evaluation_context::EvaluationContext;
|
|
||||||
use crate::prelude::*;
|
|
||||||
use crate::stream::InputStream;
|
|
||||||
use futures::stream::TryStreamExt;
|
|
||||||
use nu_errors::ShellError;
|
|
||||||
use nu_protocol::hir::{Block, ClassifiedCommand, Commands};
|
|
||||||
use nu_protocol::{ReturnSuccess, Scope, UntaggedValue, Value};
|
|
||||||
use std::sync::atomic::Ordering;
|
|
||||||
|
|
||||||
pub async fn run_block(
|
|
||||||
block: &Block,
|
|
||||||
ctx: &mut EvaluationContext,
|
|
||||||
mut input: InputStream,
|
|
||||||
scope: Arc<Scope>,
|
|
||||||
) -> Result<InputStream, ShellError> {
|
|
||||||
let mut output: Result<InputStream, ShellError> = Ok(InputStream::empty());
|
|
||||||
for pipeline in &block.block {
|
|
||||||
match output {
|
|
||||||
Ok(inp) if inp.is_empty() => {}
|
|
||||||
Ok(inp) => {
|
|
||||||
let mut output_stream = inp.to_output_stream();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match output_stream.try_next().await {
|
|
||||||
Ok(Some(ReturnSuccess::Value(Value {
|
|
||||||
value: UntaggedValue::Error(e),
|
|
||||||
..
|
|
||||||
}))) => return Err(e),
|
|
||||||
Ok(Some(_item)) => {
|
|
||||||
if let Some(err) = ctx.get_errors().get(0) {
|
|
||||||
ctx.clear_errors();
|
|
||||||
return Err(err.clone());
|
|
||||||
}
|
|
||||||
if ctx.ctrl_c.load(Ordering::SeqCst) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(None) => {
|
|
||||||
if let Some(err) = ctx.get_errors().get(0) {
|
|
||||||
ctx.clear_errors();
|
|
||||||
return Err(err.clone());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
output = run_pipeline(pipeline, ctx, input, scope.clone()).await;
|
|
||||||
|
|
||||||
input = InputStream::empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
output
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn run_pipeline(
|
|
||||||
commands: &Commands,
|
|
||||||
ctx: &mut EvaluationContext,
|
|
||||||
mut input: InputStream,
|
|
||||||
scope: Arc<Scope>,
|
|
||||||
) -> Result<InputStream, ShellError> {
|
|
||||||
for item in commands.list.clone() {
|
|
||||||
input = match item {
|
|
||||||
ClassifiedCommand::Dynamic(_) => {
|
|
||||||
return Err(ShellError::unimplemented("Dynamic commands"))
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassifiedCommand::Expr(expr) => {
|
|
||||||
run_expression_block(*expr, ctx, scope.clone()).await?
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassifiedCommand::Error(err) => return Err(err.into()),
|
|
||||||
|
|
||||||
ClassifiedCommand::Internal(left) => {
|
|
||||||
run_internal_command(left, ctx, input, scope.clone()).await?
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(input)
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
pub(crate) mod block;
|
|
||||||
mod dynamic;
|
|
||||||
pub(crate) mod expr;
|
|
||||||
pub(crate) mod external;
|
|
||||||
pub(crate) mod internal;
|
|
||||||
pub(crate) mod maybe_text_codec;
|
|
||||||
pub(crate) mod plugin;
|
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
|
||||||
pub(crate) use dynamic::Command as DynamicCommand;
|
|
@ -1,340 +0,0 @@
|
|||||||
use crate::command_registry::CommandRegistry;
|
|
||||||
use crate::commands::help::get_help;
|
|
||||||
use crate::deserializer::ConfigDeserializer;
|
|
||||||
use crate::evaluate::evaluate_args::evaluate_args;
|
|
||||||
use crate::prelude::*;
|
|
||||||
use derive_new::new;
|
|
||||||
use getset::Getters;
|
|
||||||
use nu_errors::ShellError;
|
|
||||||
use nu_protocol::hir;
|
|
||||||
use nu_protocol::{CallInfo, EvaluatedArgs, ReturnSuccess, Scope, Signature, UntaggedValue, Value};
|
|
||||||
use parking_lot::Mutex;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::ops::Deref;
|
|
||||||
use std::sync::atomic::AtomicBool;
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
|
||||||
pub struct UnevaluatedCallInfo {
|
|
||||||
pub args: hir::Call,
|
|
||||||
pub name_tag: Tag,
|
|
||||||
pub scope: Arc<Scope>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UnevaluatedCallInfo {
|
|
||||||
pub async fn evaluate(self, registry: &CommandRegistry) -> Result<CallInfo, ShellError> {
|
|
||||||
let args = evaluate_args(&self.args, registry, self.scope.clone()).await?;
|
|
||||||
|
|
||||||
Ok(CallInfo {
|
|
||||||
args,
|
|
||||||
name_tag: self.name_tag,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn switch_present(&self, switch: &str) -> bool {
|
|
||||||
self.args.switch_preset(switch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Getters)]
|
|
||||||
#[get = "pub(crate)"]
|
|
||||||
pub struct CommandArgs {
|
|
||||||
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
|
|
||||||
pub ctrl_c: Arc<AtomicBool>,
|
|
||||||
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
|
|
||||||
pub shell_manager: ShellManager,
|
|
||||||
pub call_info: UnevaluatedCallInfo,
|
|
||||||
pub input: InputStream,
|
|
||||||
pub raw_input: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Getters, Clone)]
|
|
||||||
#[get = "pub(crate)"]
|
|
||||||
pub struct RawCommandArgs {
|
|
||||||
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
|
|
||||||
pub ctrl_c: Arc<AtomicBool>,
|
|
||||||
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
|
|
||||||
pub shell_manager: ShellManager,
|
|
||||||
pub call_info: UnevaluatedCallInfo,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RawCommandArgs {
|
|
||||||
pub fn with_input(self, input: impl Into<InputStream>) -> CommandArgs {
|
|
||||||
CommandArgs {
|
|
||||||
host: self.host,
|
|
||||||
ctrl_c: self.ctrl_c,
|
|
||||||
current_errors: self.current_errors,
|
|
||||||
shell_manager: self.shell_manager,
|
|
||||||
call_info: self.call_info,
|
|
||||||
input: input.into(),
|
|
||||||
raw_input: String::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Debug for CommandArgs {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
self.call_info.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandArgs {
|
|
||||||
pub async fn evaluate_once(
|
|
||||||
self,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<EvaluatedWholeStreamCommandArgs, ShellError> {
|
|
||||||
let host = self.host.clone();
|
|
||||||
let ctrl_c = self.ctrl_c.clone();
|
|
||||||
let shell_manager = self.shell_manager.clone();
|
|
||||||
let input = self.input;
|
|
||||||
let call_info = self.call_info.evaluate(registry).await?;
|
|
||||||
|
|
||||||
Ok(EvaluatedWholeStreamCommandArgs::new(
|
|
||||||
host,
|
|
||||||
ctrl_c,
|
|
||||||
shell_manager,
|
|
||||||
call_info,
|
|
||||||
input,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn evaluate_once_with_scope(
|
|
||||||
self,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
scope: Arc<Scope>,
|
|
||||||
) -> Result<EvaluatedWholeStreamCommandArgs, ShellError> {
|
|
||||||
let host = self.host.clone();
|
|
||||||
let ctrl_c = self.ctrl_c.clone();
|
|
||||||
let shell_manager = self.shell_manager.clone();
|
|
||||||
let input = self.input;
|
|
||||||
let call_info = UnevaluatedCallInfo {
|
|
||||||
name_tag: self.call_info.name_tag,
|
|
||||||
args: self.call_info.args,
|
|
||||||
scope: scope.clone(),
|
|
||||||
};
|
|
||||||
let call_info = call_info.evaluate(registry).await?;
|
|
||||||
|
|
||||||
Ok(EvaluatedWholeStreamCommandArgs::new(
|
|
||||||
host,
|
|
||||||
ctrl_c,
|
|
||||||
shell_manager,
|
|
||||||
call_info,
|
|
||||||
input,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn process<'de, T: Deserialize<'de>>(
|
|
||||||
self,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<(T, InputStream), ShellError> {
|
|
||||||
let args = self.evaluate_once(registry).await?;
|
|
||||||
let call_info = args.call_info.clone();
|
|
||||||
|
|
||||||
let mut deserializer = ConfigDeserializer::from_call_info(call_info);
|
|
||||||
|
|
||||||
Ok((T::deserialize(&mut deserializer)?, args.input))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct RunnableContext {
|
|
||||||
pub input: InputStream,
|
|
||||||
pub shell_manager: ShellManager,
|
|
||||||
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
|
|
||||||
pub ctrl_c: Arc<AtomicBool>,
|
|
||||||
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
|
|
||||||
pub registry: CommandRegistry,
|
|
||||||
pub name: Tag,
|
|
||||||
pub raw_input: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RunnableContext {
|
|
||||||
pub fn get_command(&self, name: &str) -> Option<Command> {
|
|
||||||
self.registry.get_command(name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct EvaluatedWholeStreamCommandArgs {
|
|
||||||
pub args: EvaluatedCommandArgs,
|
|
||||||
pub input: InputStream,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for EvaluatedWholeStreamCommandArgs {
|
|
||||||
type Target = EvaluatedCommandArgs;
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.args
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EvaluatedWholeStreamCommandArgs {
|
|
||||||
pub fn new(
|
|
||||||
host: Arc<parking_lot::Mutex<dyn Host>>,
|
|
||||||
ctrl_c: Arc<AtomicBool>,
|
|
||||||
shell_manager: ShellManager,
|
|
||||||
call_info: CallInfo,
|
|
||||||
input: impl Into<InputStream>,
|
|
||||||
) -> EvaluatedWholeStreamCommandArgs {
|
|
||||||
EvaluatedWholeStreamCommandArgs {
|
|
||||||
args: EvaluatedCommandArgs {
|
|
||||||
host,
|
|
||||||
ctrl_c,
|
|
||||||
shell_manager,
|
|
||||||
call_info,
|
|
||||||
},
|
|
||||||
input: input.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name_tag(&self) -> Tag {
|
|
||||||
self.args.call_info.name_tag.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parts(self) -> (InputStream, EvaluatedArgs) {
|
|
||||||
let EvaluatedWholeStreamCommandArgs { args, input } = self;
|
|
||||||
|
|
||||||
(input, args.call_info.args)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn split(self) -> (InputStream, EvaluatedCommandArgs) {
|
|
||||||
let EvaluatedWholeStreamCommandArgs { args, input } = self;
|
|
||||||
|
|
||||||
(input, args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Getters, new)]
|
|
||||||
#[get = "pub(crate)"]
|
|
||||||
pub struct EvaluatedCommandArgs {
|
|
||||||
pub host: Arc<parking_lot::Mutex<dyn Host>>,
|
|
||||||
pub ctrl_c: Arc<AtomicBool>,
|
|
||||||
pub shell_manager: ShellManager,
|
|
||||||
pub call_info: CallInfo,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EvaluatedCommandArgs {
|
|
||||||
pub fn nth(&self, pos: usize) -> Option<&Value> {
|
|
||||||
self.call_info.args.nth(pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the nth positional argument, error if not possible
|
|
||||||
pub fn expect_nth(&self, pos: usize) -> Result<&Value, ShellError> {
|
|
||||||
self.call_info
|
|
||||||
.args
|
|
||||||
.nth(pos)
|
|
||||||
.ok_or_else(|| ShellError::unimplemented("Better error: expect_nth"))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(&self, name: &str) -> Option<&Value> {
|
|
||||||
self.call_info.args.get(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn has(&self, name: &str) -> bool {
|
|
||||||
self.call_info.args.has(name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Example {
|
|
||||||
pub example: &'static str,
|
|
||||||
pub description: &'static str,
|
|
||||||
pub result: Option<Vec<Value>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait WholeStreamCommand: Send + Sync {
|
|
||||||
fn name(&self) -> &str;
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::new(self.name()).desc(self.usage()).filter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str;
|
|
||||||
|
|
||||||
async fn run(
|
|
||||||
&self,
|
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError>;
|
|
||||||
|
|
||||||
fn is_binary(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Commands that are not meant to be run by users
|
|
||||||
fn is_internal(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Command(Arc<dyn WholeStreamCommand>);
|
|
||||||
|
|
||||||
impl PrettyDebugWithSource for Command {
|
|
||||||
fn pretty_debug(&self, source: &str) -> DebugDocBuilder {
|
|
||||||
b::typed(
|
|
||||||
"whole stream command",
|
|
||||||
b::description(self.name())
|
|
||||||
+ b::space()
|
|
||||||
+ b::equals()
|
|
||||||
+ b::space()
|
|
||||||
+ self.signature().pretty_debug(source),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Debug for Command {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "Command({})", self.name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command {
|
|
||||||
pub fn name(&self) -> &str {
|
|
||||||
self.0.name()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn signature(&self) -> Signature {
|
|
||||||
self.0.signature()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn usage(&self) -> &str {
|
|
||||||
self.0.usage()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn examples(&self) -> Vec<Example> {
|
|
||||||
self.0.examples()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn run(
|
|
||||||
&self,
|
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
if args.call_info.switch_present("help") {
|
|
||||||
let cl = self.0.clone();
|
|
||||||
let registry = registry.clone();
|
|
||||||
Ok(OutputStream::one(Ok(ReturnSuccess::Value(
|
|
||||||
UntaggedValue::string(get_help(&*cl, ®istry)).into_value(Tag::unknown()),
|
|
||||||
))))
|
|
||||||
} else {
|
|
||||||
self.0.run(args, registry).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_binary(&self) -> bool {
|
|
||||||
self.0.is_binary()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_internal(&self) -> bool {
|
|
||||||
self.0.is_internal()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn stream_command(&self) -> &dyn WholeStreamCommand {
|
|
||||||
&*self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn whole_stream_command(command: impl WholeStreamCommand + 'static) -> Command {
|
|
||||||
Command(Arc::new(command))
|
|
||||||
}
|
|
@ -1,185 +0,0 @@
|
|||||||
use crate::command_registry::CommandRegistry;
|
|
||||||
use crate::commands::classified::block::run_block;
|
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::evaluate::evaluate_baseline_expr;
|
|
||||||
use crate::prelude::*;
|
|
||||||
use nu_errors::ShellError;
|
|
||||||
use nu_protocol::{
|
|
||||||
hir::Block, hir::ClassifiedCommand, Scope, Signature, SyntaxShape, UntaggedValue,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct If;
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
pub struct IfArgs {
|
|
||||||
condition: Block,
|
|
||||||
then_case: Block,
|
|
||||||
else_case: Block,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl WholeStreamCommand for If {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"if"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build("if")
|
|
||||||
.required(
|
|
||||||
"condition",
|
|
||||||
SyntaxShape::Math,
|
|
||||||
"the condition that must match",
|
|
||||||
)
|
|
||||||
.required(
|
|
||||||
"then_case",
|
|
||||||
SyntaxShape::Block,
|
|
||||||
"block to run if condition is true",
|
|
||||||
)
|
|
||||||
.required(
|
|
||||||
"else_case",
|
|
||||||
SyntaxShape::Block,
|
|
||||||
"block to run if condition is false",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Run blocks if a condition is true or false."
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn run(
|
|
||||||
&self,
|
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
if_command(args, registry).await
|
|
||||||
}
|
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
|
||||||
vec![
|
|
||||||
Example {
|
|
||||||
description: "Run a block if a condition is true",
|
|
||||||
example: "echo 10 | if $it > 5 { echo 'greater than 5' } { echo 'less than or equal to 5' }",
|
|
||||||
result: Some(vec![UntaggedValue::string("greater than 5").into()]),
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
description: "Run a block if a condition is false",
|
|
||||||
example: "echo 1 | if $it > 5 { echo 'greater than 5' } { echo 'less than or equal to 5' }",
|
|
||||||
result: Some(vec![UntaggedValue::string("less than or equal to 5").into()]),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async fn if_command(
|
|
||||||
raw_args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let registry = Arc::new(registry.clone());
|
|
||||||
let scope = raw_args.call_info.scope.clone();
|
|
||||||
let tag = raw_args.call_info.name_tag.clone();
|
|
||||||
let context = Arc::new(EvaluationContext::from_raw(&raw_args, ®istry));
|
|
||||||
|
|
||||||
let (
|
|
||||||
IfArgs {
|
|
||||||
condition,
|
|
||||||
then_case,
|
|
||||||
else_case,
|
|
||||||
},
|
|
||||||
input,
|
|
||||||
) = raw_args.process(®istry).await?;
|
|
||||||
let condition = {
|
|
||||||
if condition.block.len() != 1 {
|
|
||||||
return Err(ShellError::labeled_error(
|
|
||||||
"Expected a condition",
|
|
||||||
"expected a condition",
|
|
||||||
tag,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
match condition.block[0].list.get(0) {
|
|
||||||
Some(item) => match item {
|
|
||||||
ClassifiedCommand::Expr(expr) => expr.clone(),
|
|
||||||
_ => {
|
|
||||||
return Err(ShellError::labeled_error(
|
|
||||||
"Expected a condition",
|
|
||||||
"expected a condition",
|
|
||||||
tag,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
return Err(ShellError::labeled_error(
|
|
||||||
"Expected a condition",
|
|
||||||
"expected a condition",
|
|
||||||
tag,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(input
|
|
||||||
.then(move |input| {
|
|
||||||
let condition = condition.clone();
|
|
||||||
let then_case = then_case.clone();
|
|
||||||
let else_case = else_case.clone();
|
|
||||||
let registry = registry.clone();
|
|
||||||
let scope = Scope::append_var(scope.clone(), "$it", input);
|
|
||||||
let mut context = context.clone();
|
|
||||||
|
|
||||||
async move {
|
|
||||||
//FIXME: should we use the scope that's brought in as well?
|
|
||||||
let condition = evaluate_baseline_expr(&condition, &*registry, scope.clone()).await;
|
|
||||||
|
|
||||||
match condition {
|
|
||||||
Ok(condition) => match condition.as_bool() {
|
|
||||||
Ok(b) => {
|
|
||||||
if b {
|
|
||||||
match run_block(
|
|
||||||
&then_case,
|
|
||||||
Arc::make_mut(&mut context),
|
|
||||||
InputStream::empty(),
|
|
||||||
scope,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(stream) => stream.to_output_stream(),
|
|
||||||
Err(e) => futures::stream::iter(vec![Err(e)].into_iter())
|
|
||||||
.to_output_stream(),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match run_block(
|
|
||||||
&else_case,
|
|
||||||
Arc::make_mut(&mut context),
|
|
||||||
InputStream::empty(),
|
|
||||||
scope,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(stream) => stream.to_output_stream(),
|
|
||||||
Err(e) => futures::stream::iter(vec![Err(e)].into_iter())
|
|
||||||
.to_output_stream(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
futures::stream::iter(vec![Err(e)].into_iter()).to_output_stream()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => futures::stream::iter(vec![Err(e)].into_iter()).to_output_stream(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.flatten()
|
|
||||||
.to_output_stream())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::If;
|
|
||||||
use super::ShellError;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
|
||||||
use crate::examples::test as test_examples;
|
|
||||||
|
|
||||||
Ok(test_examples(If {})?)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
use crate::commands::classified::block::run_block;
|
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
use derive_new::new;
|
|
||||||
use nu_errors::ShellError;
|
|
||||||
use nu_protocol::{hir::Block, PositionalType, Scope, Signature, UntaggedValue};
|
|
||||||
|
|
||||||
#[derive(new, Clone)]
|
|
||||||
pub struct AliasCommand {
|
|
||||||
sig: Signature,
|
|
||||||
block: Block,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl WholeStreamCommand for AliasCommand {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
&self.sig.name
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
self.sig.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
""
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn run(
|
|
||||||
&self,
|
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let call_info = args.call_info.clone();
|
|
||||||
let registry = registry.clone();
|
|
||||||
let mut block = self.block.clone();
|
|
||||||
block.set_redirect(call_info.args.external_redirection);
|
|
||||||
|
|
||||||
// let alias_command = self.clone();
|
|
||||||
let mut context = EvaluationContext::from_args(&args, ®istry);
|
|
||||||
let input = args.input;
|
|
||||||
|
|
||||||
let scope = call_info.scope.clone();
|
|
||||||
let evaluated = call_info.evaluate(®istry).await?;
|
|
||||||
|
|
||||||
let mut vars = IndexMap::new();
|
|
||||||
let mut num_positionals = 0;
|
|
||||||
if let Some(positional) = &evaluated.args.positional {
|
|
||||||
num_positionals = positional.len();
|
|
||||||
for (idx, arg) in positional.iter().enumerate() {
|
|
||||||
let pos_type = &self.sig.positional[idx].0;
|
|
||||||
match pos_type {
|
|
||||||
PositionalType::Mandatory(name, _) | PositionalType::Optional(name, _) => {
|
|
||||||
vars.insert(name.clone(), arg.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Fill out every missing argument with empty value
|
|
||||||
if self.sig.positional.len() > num_positionals {
|
|
||||||
for idx in num_positionals..self.sig.positional.len() {
|
|
||||||
let pos_type = &self.sig.positional[idx].0;
|
|
||||||
match pos_type {
|
|
||||||
PositionalType::Mandatory(name, _) | PositionalType::Optional(name, _) => {
|
|
||||||
vars.insert(name.clone(), UntaggedValue::nothing().into_untagged_value());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let scope = Scope::append_vars(scope, vars);
|
|
||||||
|
|
||||||
// FIXME: we need to patch up the spans to point at the top-level error
|
|
||||||
Ok(run_block(&block, &mut context, input, scope)
|
|
||||||
.await?
|
|
||||||
.to_output_stream())
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
|
||||||
use nu_errors::ShellError;
|
|
||||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
|
||||||
use nu_source::Tagged;
|
|
||||||
|
|
||||||
pub struct SubCommand;
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
pub struct SubCommandArgs {
|
|
||||||
separator: Option<Tagged<String>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl WholeStreamCommand for SubCommand {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"str collect"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build("str collect").desc(self.usage()).optional(
|
|
||||||
"separator",
|
|
||||||
SyntaxShape::String,
|
|
||||||
"the separator to put between the different values",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"collects a list of strings into a string"
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn run(
|
|
||||||
&self,
|
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
collect(args, registry).await
|
|
||||||
}
|
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
|
||||||
vec![Example {
|
|
||||||
description: "Collect a list of string",
|
|
||||||
example: "echo ['a' 'b' 'c'] | str collect",
|
|
||||||
result: Some(vec![Value::from("abc")]),
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn collect(
|
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let tag = args.call_info.name_tag.clone();
|
|
||||||
let (SubCommandArgs { separator }, input) = args.process(registry).await?;
|
|
||||||
let separator = separator.map(|tagged| tagged.item).unwrap_or_default();
|
|
||||||
|
|
||||||
let strings: Vec<Result<String, ShellError>> =
|
|
||||||
input.map(|value| value.as_string()).collect().await;
|
|
||||||
let strings: Vec<String> = strings.into_iter().collect::<Result<_, _>>()?;
|
|
||||||
let output = strings.join(&separator);
|
|
||||||
|
|
||||||
Ok(OutputStream::one(ReturnSuccess::value(
|
|
||||||
UntaggedValue::string(output).into_value(tag),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::ShellError;
|
|
||||||
use super::SubCommand;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
|
||||||
use crate::examples::test as test_examples;
|
|
||||||
|
|
||||||
Ok(test_examples(SubCommand {})?)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
|
||||||
use nu_errors::ShellError;
|
|
||||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
|
||||||
|
|
||||||
pub struct SubCommand;
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl WholeStreamCommand for SubCommand {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"str length"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build("str length")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"outputs the lengths of the strings in the pipeline"
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn run(
|
|
||||||
&self,
|
|
||||||
args: CommandArgs,
|
|
||||||
_registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
Ok(args
|
|
||||||
.input
|
|
||||||
.map(move |x| match x.as_string() {
|
|
||||||
Ok(s) => ReturnSuccess::value(UntaggedValue::int(s.len()).into_untagged_value()),
|
|
||||||
Err(err) => Err(err),
|
|
||||||
})
|
|
||||||
.to_output_stream())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
|
||||||
vec![
|
|
||||||
Example {
|
|
||||||
description: "Return the lengths of multiple strings",
|
|
||||||
example: "echo 'hello' | str length",
|
|
||||||
result: Some(vec![UntaggedValue::int(5).into_untagged_value()]),
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
description: "Return the lengths of multiple strings",
|
|
||||||
example: "echo 'hi' 'there' | str length",
|
|
||||||
result: Some(vec![
|
|
||||||
UntaggedValue::int(2).into_untagged_value(),
|
|
||||||
UntaggedValue::int(5).into_untagged_value(),
|
|
||||||
]),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::ShellError;
|
|
||||||
use super::SubCommand;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
|
||||||
use crate::examples::test as test_examples;
|
|
||||||
|
|
||||||
Ok(test_examples(SubCommand {})?)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
|
||||||
use nu_errors::ShellError;
|
|
||||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
|
||||||
|
|
||||||
pub struct SubCommand;
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl WholeStreamCommand for SubCommand {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"str reverse"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build("str reverse")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"outputs the reversals of the strings in the pipeline"
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn run(
|
|
||||||
&self,
|
|
||||||
args: CommandArgs,
|
|
||||||
_registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
Ok(args
|
|
||||||
.input
|
|
||||||
.map(move |x| match x.as_string() {
|
|
||||||
Ok(s) => ReturnSuccess::value(
|
|
||||||
UntaggedValue::string(s.chars().rev().collect::<String>())
|
|
||||||
.into_untagged_value(),
|
|
||||||
),
|
|
||||||
Err(err) => Err(err),
|
|
||||||
})
|
|
||||||
.to_output_stream())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
|
||||||
vec![Example {
|
|
||||||
description: "Return the reversals of multiple strings",
|
|
||||||
example: "echo 'Nushell' | str reverse",
|
|
||||||
result: Some(vec![UntaggedValue::string("llehsuN").into_untagged_value()]),
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::ShellError;
|
|
||||||
use super::SubCommand;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
|
||||||
use crate::examples::test as test_examples;
|
|
||||||
|
|
||||||
Ok(test_examples(SubCommand {})?)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,124 +0,0 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
|
||||||
use nu_errors::ShellError;
|
|
||||||
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
|
||||||
use nu_source::{Tag, Tagged};
|
|
||||||
use nu_value_ext::ValueExt;
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Arguments {
|
|
||||||
replace: Tagged<String>,
|
|
||||||
rest: Vec<ColumnPath>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SubCommand;
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl WholeStreamCommand for SubCommand {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"str set"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build("str set")
|
|
||||||
.required("set", SyntaxShape::String, "the new string to set")
|
|
||||||
.rest(
|
|
||||||
SyntaxShape::ColumnPath,
|
|
||||||
"optionally set text by column paths",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"sets text"
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn run(
|
|
||||||
&self,
|
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
operate(args, registry).await
|
|
||||||
}
|
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
|
||||||
vec![
|
|
||||||
Example {
|
|
||||||
description: "Set contents with preferred string",
|
|
||||||
example: "echo 'good day' | str set 'good bye'",
|
|
||||||
result: Some(vec![Value::from("good bye")]),
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
description: "Set the contents on preferred column paths",
|
|
||||||
example: "open Cargo.toml | str set '255' package.version",
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct Replace(String);
|
|
||||||
|
|
||||||
async fn operate(
|
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let registry = registry.clone();
|
|
||||||
|
|
||||||
let (Arguments { replace, rest }, input) = args.process(®istry).await?;
|
|
||||||
let options = Replace(replace.item);
|
|
||||||
|
|
||||||
let column_paths: Vec<_> = rest;
|
|
||||||
|
|
||||||
Ok(input
|
|
||||||
.map(move |v| {
|
|
||||||
if column_paths.is_empty() {
|
|
||||||
ReturnSuccess::value(action(&v, &options, v.tag())?)
|
|
||||||
} else {
|
|
||||||
let mut ret = v;
|
|
||||||
|
|
||||||
for path in &column_paths {
|
|
||||||
let options = options.clone();
|
|
||||||
|
|
||||||
ret = ret.swap_data_by_column_path(
|
|
||||||
path,
|
|
||||||
Box::new(move |old| action(old, &options, old.tag())),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnSuccess::value(ret)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.to_output_stream())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn action(_input: &Value, options: &Replace, tag: impl Into<Tag>) -> Result<Value, ShellError> {
|
|
||||||
let replacement = &options.0;
|
|
||||||
Ok(UntaggedValue::string(replacement.as_str()).into_value(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::ShellError;
|
|
||||||
use super::{action, Replace, SubCommand};
|
|
||||||
use nu_source::Tag;
|
|
||||||
use nu_test_support::value::string;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
|
||||||
use crate::examples::test as test_examples;
|
|
||||||
|
|
||||||
Ok(test_examples(SubCommand {})?)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn sets() {
|
|
||||||
let word = string("andres");
|
|
||||||
let expected = string("robalino");
|
|
||||||
|
|
||||||
let set_options = Replace(String::from("robalino"));
|
|
||||||
|
|
||||||
let actual = action(&word, &set_options, Tag::unknown()).unwrap();
|
|
||||||
assert_eq!(actual, expected);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,134 +0,0 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
|
||||||
use indexmap::map::IndexMap;
|
|
||||||
use nu_errors::ShellError;
|
|
||||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
|
||||||
use nu_source::Tagged;
|
|
||||||
|
|
||||||
pub struct Which;
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl WholeStreamCommand for Which {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"which"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build("which")
|
|
||||||
.required("application", SyntaxShape::String, "application")
|
|
||||||
.switch("all", "list all executables", Some('a'))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Finds a program file."
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn run(
|
|
||||||
&self,
|
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
which(args, registry).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Shortcuts for creating an entry to the output table
|
|
||||||
fn entry(arg: impl Into<String>, path: Value, builtin: bool, tag: Tag) -> Value {
|
|
||||||
let mut map = IndexMap::new();
|
|
||||||
map.insert(
|
|
||||||
"arg".to_string(),
|
|
||||||
UntaggedValue::Primitive(Primitive::String(arg.into())).into_value(tag.clone()),
|
|
||||||
);
|
|
||||||
map.insert("path".to_string(), path);
|
|
||||||
map.insert(
|
|
||||||
"builtin".to_string(),
|
|
||||||
UntaggedValue::boolean(builtin).into_value(tag.clone()),
|
|
||||||
);
|
|
||||||
|
|
||||||
UntaggedValue::row(map).into_value(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! entry_builtin {
|
|
||||||
($arg:expr, $tag:expr) => {
|
|
||||||
entry(
|
|
||||||
$arg.clone(),
|
|
||||||
UntaggedValue::Primitive(Primitive::String("nushell built-in command".to_string()))
|
|
||||||
.into_value($tag.clone()),
|
|
||||||
true,
|
|
||||||
$tag,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
macro_rules! entry_path {
|
|
||||||
($arg:expr, $path:expr, $tag:expr) => {
|
|
||||||
entry(
|
|
||||||
$arg.clone(),
|
|
||||||
UntaggedValue::Primitive(Primitive::Path($path)).into_value($tag.clone()),
|
|
||||||
false,
|
|
||||||
$tag,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
struct WhichArgs {
|
|
||||||
application: Tagged<String>,
|
|
||||||
all: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn which(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
|
||||||
let registry = registry.clone();
|
|
||||||
|
|
||||||
let mut output = vec![];
|
|
||||||
|
|
||||||
let (WhichArgs { application, all }, _) = args.process(®istry).await?;
|
|
||||||
let external = application.starts_with('^');
|
|
||||||
let item = if external {
|
|
||||||
application.item[1..].to_string()
|
|
||||||
} else {
|
|
||||||
application.item.clone()
|
|
||||||
};
|
|
||||||
if !external {
|
|
||||||
let builtin = registry.has(&item);
|
|
||||||
if builtin {
|
|
||||||
output.push(ReturnSuccess::value(entry_builtin!(
|
|
||||||
item,
|
|
||||||
application.tag.clone()
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "ichwh")]
|
|
||||||
{
|
|
||||||
if let Ok(paths) = ichwh::which_all(&item).await {
|
|
||||||
for path in paths {
|
|
||||||
output.push(ReturnSuccess::value(entry_path!(
|
|
||||||
item,
|
|
||||||
path.into(),
|
|
||||||
application.tag.clone()
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if all {
|
|
||||||
Ok(futures::stream::iter(output.into_iter()).to_output_stream())
|
|
||||||
} else {
|
|
||||||
Ok(futures::stream::iter(output.into_iter().take(1)).to_output_stream())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::ShellError;
|
|
||||||
use super::Which;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
|
||||||
use crate::examples::test as test_examples;
|
|
||||||
|
|
||||||
Ok(test_examples(Which {})?)
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,7 +5,7 @@ use indexmap::set::IndexSet;
|
|||||||
|
|
||||||
use super::matchers::Matcher;
|
use super::matchers::Matcher;
|
||||||
use crate::completion::{Completer, CompletionContext, Suggestion};
|
use crate::completion::{Completer, CompletionContext, Suggestion};
|
||||||
use crate::evaluation_context::EvaluationContext;
|
use nu_engine::EvaluationContext;
|
||||||
|
|
||||||
pub struct CommandCompleter;
|
pub struct CommandCompleter;
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ impl Completer for CommandCompleter {
|
|||||||
matcher: &dyn Matcher,
|
matcher: &dyn Matcher,
|
||||||
) -> Vec<Suggestion> {
|
) -> Vec<Suggestion> {
|
||||||
let context: &EvaluationContext = ctx.as_ref();
|
let context: &EvaluationContext = ctx.as_ref();
|
||||||
let mut commands: IndexSet<String> = IndexSet::from_iter(context.registry.names());
|
let mut commands: IndexSet<String> = IndexSet::from_iter(context.scope.get_command_names());
|
||||||
|
|
||||||
// Command suggestions can come from three possible sets:
|
// Command suggestions can come from three possible sets:
|
||||||
// 1. internal command names,
|
// 1. internal command names,
|
||||||
@ -38,7 +38,7 @@ impl Completer for CommandCompleter {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if partial != "" {
|
if !partial.is_empty() {
|
||||||
let path_completer = crate::completion::path::PathCompleter;
|
let path_completer = crate::completion::path::PathCompleter;
|
||||||
let path_results = path_completer.path_suggestions(partial, matcher);
|
let path_results = path_completer.path_suggestions(partial, matcher);
|
||||||
let iter = path_results.into_iter().filter_map(|path_suggestion| {
|
let iter = path_results.into_iter().filter_map(|path_suggestion| {
|
||||||
|
@ -138,7 +138,7 @@ impl<'s> Flatten<'s> {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pipeline(&self, pipeline: &Commands) -> Vec<CompletionLocation> {
|
fn pipeline(&self, pipeline: &Pipeline) -> Vec<CompletionLocation> {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
|
|
||||||
for command in &pipeline.list {
|
for command in &pipeline.list {
|
||||||
@ -158,7 +158,11 @@ impl<'s> Flatten<'s> {
|
|||||||
|
|
||||||
/// Flattens the block into a Vec of completion locations
|
/// Flattens the block into a Vec of completion locations
|
||||||
pub fn completion_locations(&self, block: &Block) -> Vec<CompletionLocation> {
|
pub fn completion_locations(&self, block: &Block) -> Vec<CompletionLocation> {
|
||||||
block.block.iter().flat_map(|v| self.pipeline(v)).collect()
|
block
|
||||||
|
.block
|
||||||
|
.iter()
|
||||||
|
.flat_map(|g| g.pipelines.iter().flat_map(|v| self.pipeline(v)))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(line: &'s str) -> Flatten<'s> {
|
pub fn new(line: &'s str) -> Flatten<'s> {
|
||||||
@ -252,7 +256,7 @@ pub fn completion_location(line: &str, block: &Block, pos: usize) -> Vec<Complet
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use nu_parser::SignatureRegistry;
|
use nu_parser::{block, classify_block, lex, ParserScope};
|
||||||
use nu_protocol::{Signature, SyntaxShape};
|
use nu_protocol::{Signature, SyntaxShape};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -264,35 +268,52 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SignatureRegistry for VecRegistry {
|
impl ParserScope for VecRegistry {
|
||||||
fn has(&self, name: &str) -> bool {
|
fn has_signature(&self, name: &str) -> bool {
|
||||||
self.0.iter().any(|v| v.name == name)
|
self.0.iter().any(|v| v.name == name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self, name: &str) -> Option<nu_protocol::Signature> {
|
fn get_signature(&self, name: &str) -> Option<nu_protocol::Signature> {
|
||||||
self.0.iter().find(|v| v.name == name).map(Clone::clone)
|
self.0.iter().find(|v| v.name == name).map(Clone::clone)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn SignatureRegistry> {
|
fn get_alias(&self, _name: &str) -> Option<Vec<Spanned<String>>> {
|
||||||
Box::new(self.clone())
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_alias(&self, _name: &str, _replacement: Vec<Spanned<String>>) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_definition(&self, _block: Block) {}
|
||||||
|
|
||||||
|
fn get_definitions(&self) -> Vec<Block> {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enter_scope(&self) {}
|
||||||
|
|
||||||
|
fn exit_scope(&self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod completion_location {
|
mod completion_location {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use nu_parser::{classify_block, lite_parse, SignatureRegistry};
|
use nu_parser::ParserScope;
|
||||||
|
|
||||||
fn completion_location(
|
fn completion_location(
|
||||||
line: &str,
|
line: &str,
|
||||||
registry: &dyn SignatureRegistry,
|
scope: &dyn ParserScope,
|
||||||
pos: usize,
|
pos: usize,
|
||||||
) -> Vec<LocationType> {
|
) -> Vec<LocationType> {
|
||||||
let (lite_block, _) = lite_parse(line, 0);
|
let (tokens, _) = lex(line, 0);
|
||||||
|
let (lite_block, _) = block(tokens);
|
||||||
|
|
||||||
let block = classify_block(&lite_block, registry);
|
scope.enter_scope();
|
||||||
|
let (block, _) = classify_block(&lite_block, scope);
|
||||||
|
scope.exit_scope();
|
||||||
|
|
||||||
super::completion_location(line, &block.block, pos)
|
super::completion_location(line, &block, pos)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|v| v.item)
|
.map(|v| v.item)
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use super::matchers::Matcher;
|
use super::matchers::Matcher;
|
||||||
use crate::completion::{Completer, CompletionContext, Suggestion};
|
use crate::completion::{Completer, CompletionContext, Suggestion};
|
||||||
use crate::evaluation_context::EvaluationContext;
|
use nu_engine::EvaluationContext;
|
||||||
|
|
||||||
pub struct FlagCompleter {
|
pub struct FlagCompleter {
|
||||||
pub(crate) cmd: String,
|
pub(crate) cmd: String,
|
||||||
@ -15,7 +15,7 @@ impl Completer for FlagCompleter {
|
|||||||
) -> Vec<Suggestion> {
|
) -> Vec<Suggestion> {
|
||||||
let context: &EvaluationContext = ctx.as_ref();
|
let context: &EvaluationContext = ctx.as_ref();
|
||||||
|
|
||||||
if let Some(cmd) = context.registry.get_command(&self.cmd) {
|
if let Some(cmd) = context.scope.get_command(&self.cmd) {
|
||||||
let sig = cmd.signature();
|
let sig = cmd.signature();
|
||||||
let mut suggestions = Vec::new();
|
let mut suggestions = Vec::new();
|
||||||
for (name, (named_type, _desc)) in sig.named.iter() {
|
for (name, (named_type, _desc)) in sig.named.iter() {
|
||||||
|
@ -4,8 +4,8 @@ pub(crate) mod flag;
|
|||||||
pub(crate) mod matchers;
|
pub(crate) mod matchers;
|
||||||
pub(crate) mod path;
|
pub(crate) mod path;
|
||||||
|
|
||||||
use crate::evaluation_context::EvaluationContext;
|
|
||||||
use matchers::Matcher;
|
use matchers::Matcher;
|
||||||
|
use nu_engine::EvaluationContext;
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub struct Suggestion {
|
pub struct Suggestion {
|
||||||
|
@ -22,14 +22,14 @@ impl PathCompleter {
|
|||||||
None => ("", expanded),
|
None => ("", expanded),
|
||||||
};
|
};
|
||||||
|
|
||||||
let base_dir = if base_dir_name == "" {
|
let base_dir = if base_dir_name.is_empty() {
|
||||||
PathBuf::from(".")
|
PathBuf::from(".")
|
||||||
} else {
|
} else {
|
||||||
#[cfg(feature = "directories")]
|
#[cfg(feature = "directories")]
|
||||||
{
|
{
|
||||||
let home_prefix = format!("~{}", SEP);
|
let home_prefix = format!("~{}", SEP);
|
||||||
if base_dir_name.starts_with(&home_prefix) {
|
if base_dir_name.starts_with(&home_prefix) {
|
||||||
let mut home_dir = dirs::home_dir().unwrap_or_else(|| PathBuf::from("~"));
|
let mut home_dir = dirs_next::home_dir().unwrap_or_else(|| PathBuf::from("~"));
|
||||||
home_dir.push(&base_dir_name[2..]);
|
home_dir.push(&base_dir_name[2..]);
|
||||||
home_dir
|
home_dir
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
pub(crate) mod directory_specific_environment;
|
pub(crate) mod directory_specific_environment;
|
||||||
pub(crate) mod environment;
|
pub(crate) mod environment;
|
||||||
pub(crate) mod environment_syncer;
|
pub(crate) mod environment_syncer;
|
||||||
pub(crate) mod host;
|
|
||||||
|
|
||||||
pub(crate) use self::host::Host;
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use crate::commands;
|
|
||||||
use commands::autoenv;
|
|
||||||
use indexmap::{IndexMap, IndexSet};
|
use indexmap::{IndexMap, IndexSet};
|
||||||
|
use nu_command::commands::autoenv;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::env::*;
|
use std::env::*;
|
||||||
|
33
crates/nu-cli/src/env/environment.rs
vendored
33
crates/nu-cli/src/env/environment.rs
vendored
@ -1,38 +1,9 @@
|
|||||||
use crate::env::directory_specific_environment::*;
|
use crate::env::directory_specific_environment::*;
|
||||||
use indexmap::{indexmap, IndexSet};
|
use indexmap::{indexmap, IndexSet};
|
||||||
use nu_data::config::Conf;
|
use nu_data::config::Conf;
|
||||||
|
use nu_engine::Env;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{UntaggedValue, Value};
|
use nu_protocol::{UntaggedValue, Value};
|
||||||
use std::env::*;
|
|
||||||
use std::ffi::OsString;
|
|
||||||
|
|
||||||
use std::fmt::Debug;
|
|
||||||
|
|
||||||
pub trait Env: Debug + Send {
|
|
||||||
fn env(&self) -> Option<Value>;
|
|
||||||
fn path(&self) -> Option<Value>;
|
|
||||||
|
|
||||||
fn add_env(&mut self, key: &str, value: &str);
|
|
||||||
fn add_path(&mut self, new_path: OsString);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Env for Box<dyn Env> {
|
|
||||||
fn env(&self) -> Option<Value> {
|
|
||||||
(**self).env()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn path(&self) -> Option<Value> {
|
|
||||||
(**self).path()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_env(&mut self, key: &str, value: &str) {
|
|
||||||
(**self).add_env(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_path(&mut self, new_path: OsString) {
|
|
||||||
(**self).add_path(new_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Environment {
|
pub struct Environment {
|
||||||
@ -128,7 +99,7 @@ impl Env for Environment {
|
|||||||
{
|
{
|
||||||
let mut new_paths = current_paths.clone();
|
let mut new_paths = current_paths.clone();
|
||||||
|
|
||||||
let new_path_candidates = split_paths(&paths).map(|path| {
|
let new_path_candidates = std::env::split_paths(&paths).map(|path| {
|
||||||
UntaggedValue::string(path.to_string_lossy()).into_value(tag.clone())
|
UntaggedValue::string(path.to_string_lossy()).into_value(tag.clone())
|
||||||
});
|
});
|
||||||
|
|
||||||
|
41
crates/nu-cli/src/env/environment_syncer.rs
vendored
41
crates/nu-cli/src/env/environment_syncer.rs
vendored
@ -1,9 +1,10 @@
|
|||||||
use crate::env::environment::{Env, Environment};
|
use crate::env::environment::Environment;
|
||||||
use crate::evaluation_context::EvaluationContext;
|
|
||||||
use nu_data::config::{Conf, NuConfig};
|
use nu_data::config::{Conf, NuConfig};
|
||||||
|
use nu_engine::Env;
|
||||||
|
use nu_engine::EvaluationContext;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::sync::Arc;
|
use std::sync::{atomic::Ordering, Arc};
|
||||||
|
|
||||||
pub struct EnvironmentSyncer {
|
pub struct EnvironmentSyncer {
|
||||||
pub env: Arc<Mutex<Box<Environment>>>,
|
pub env: Arc<Mutex<Box<Environment>>>,
|
||||||
@ -63,8 +64,12 @@ impl EnvironmentSyncer {
|
|||||||
|
|
||||||
pub fn autoenv(&self, ctx: &mut EvaluationContext) -> Result<(), ShellError> {
|
pub fn autoenv(&self, ctx: &mut EvaluationContext) -> Result<(), ShellError> {
|
||||||
let mut environment = self.env.lock();
|
let mut environment = self.env.lock();
|
||||||
let auto = environment.autoenv(ctx.user_recently_used_autoenv_untrust);
|
let recently_used = ctx
|
||||||
ctx.user_recently_used_autoenv_untrust = false;
|
.user_recently_used_autoenv_untrust
|
||||||
|
.load(Ordering::SeqCst);
|
||||||
|
let auto = environment.autoenv(recently_used);
|
||||||
|
ctx.user_recently_used_autoenv_untrust
|
||||||
|
.store(false, Ordering::SeqCst);
|
||||||
auto
|
auto
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,10 +153,10 @@ impl EnvironmentSyncer {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::EnvironmentSyncer;
|
use super::EnvironmentSyncer;
|
||||||
use crate::env::environment::Env;
|
|
||||||
use crate::evaluation_context::EvaluationContext;
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use nu_data::config::tests::FakeConfig;
|
use nu_data::config::tests::FakeConfig;
|
||||||
|
use nu_engine::basic_evaluation_context;
|
||||||
|
use nu_engine::Env;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_test_support::fs::Stub::FileWithContent;
|
use nu_test_support::fs::Stub::FileWithContent;
|
||||||
use nu_test_support::playground::Playground;
|
use nu_test_support::playground::Playground;
|
||||||
@ -166,8 +171,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn syncs_env_if_new_env_entry_is_added_to_an_existing_configuration() -> Result<(), ShellError>
|
fn syncs_env_if_new_env_entry_is_added_to_an_existing_configuration() -> Result<(), ShellError>
|
||||||
{
|
{
|
||||||
let mut ctx = EvaluationContext::basic()?;
|
let mut ctx = basic_evaluation_context()?;
|
||||||
ctx.host = Arc::new(Mutex::new(Box::new(crate::env::host::FakeHost::new())));
|
ctx.host = Arc::new(Mutex::new(Box::new(nu_engine::FakeHost::new())));
|
||||||
|
|
||||||
let mut expected = IndexMap::new();
|
let mut expected = IndexMap::new();
|
||||||
expected.insert(
|
expected.insert(
|
||||||
@ -198,7 +203,7 @@ mod tests {
|
|||||||
let new_file = dirs.test().join("updated_configuration.toml");
|
let new_file = dirs.test().join("updated_configuration.toml");
|
||||||
|
|
||||||
let fake_config = FakeConfig::new(&file);
|
let fake_config = FakeConfig::new(&file);
|
||||||
let mut actual = EnvironmentSyncer::with_config(Box::new(fake_config.clone()));
|
let mut actual = EnvironmentSyncer::with_config(Box::new(fake_config));
|
||||||
|
|
||||||
// Here, the environment variables from the current session
|
// Here, the environment variables from the current session
|
||||||
// are cleared since we will load and set them from the
|
// are cleared since we will load and set them from the
|
||||||
@ -269,8 +274,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn syncs_env_if_new_env_entry_in_session_is_not_in_configuration_file() -> Result<(), ShellError>
|
fn syncs_env_if_new_env_entry_in_session_is_not_in_configuration_file() -> Result<(), ShellError>
|
||||||
{
|
{
|
||||||
let mut ctx = EvaluationContext::basic()?;
|
let mut ctx = basic_evaluation_context()?;
|
||||||
ctx.host = Arc::new(Mutex::new(Box::new(crate::env::host::FakeHost::new())));
|
ctx.host = Arc::new(Mutex::new(Box::new(nu_engine::FakeHost::new())));
|
||||||
|
|
||||||
let mut expected = IndexMap::new();
|
let mut expected = IndexMap::new();
|
||||||
expected.insert(
|
expected.insert(
|
||||||
@ -368,8 +373,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn nu_envs_have_higher_priority_and_does_not_get_overwritten() -> Result<(), ShellError> {
|
fn nu_envs_have_higher_priority_and_does_not_get_overwritten() -> Result<(), ShellError> {
|
||||||
let mut ctx = EvaluationContext::basic()?;
|
let mut ctx = basic_evaluation_context()?;
|
||||||
ctx.host = Arc::new(Mutex::new(Box::new(crate::env::host::FakeHost::new())));
|
ctx.host = Arc::new(Mutex::new(Box::new(nu_engine::FakeHost::new())));
|
||||||
|
|
||||||
let mut expected = IndexMap::new();
|
let mut expected = IndexMap::new();
|
||||||
expected.insert(
|
expected.insert(
|
||||||
@ -444,8 +449,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn syncs_path_if_new_path_entry_in_session_is_not_in_configuration_file(
|
fn syncs_path_if_new_path_entry_in_session_is_not_in_configuration_file(
|
||||||
) -> Result<(), ShellError> {
|
) -> Result<(), ShellError> {
|
||||||
let mut ctx = EvaluationContext::basic()?;
|
let mut ctx = basic_evaluation_context()?;
|
||||||
ctx.host = Arc::new(Mutex::new(Box::new(crate::env::host::FakeHost::new())));
|
ctx.host = Arc::new(Mutex::new(Box::new(nu_engine::FakeHost::new())));
|
||||||
|
|
||||||
let expected = std::env::join_paths(vec![
|
let expected = std::env::join_paths(vec![
|
||||||
PathBuf::from("/Users/andresrobalino/.volta/bin"),
|
PathBuf::from("/Users/andresrobalino/.volta/bin"),
|
||||||
@ -531,8 +536,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn nu_paths_have_higher_priority_and_new_paths_get_appended_to_the_end(
|
fn nu_paths_have_higher_priority_and_new_paths_get_appended_to_the_end(
|
||||||
) -> Result<(), ShellError> {
|
) -> Result<(), ShellError> {
|
||||||
let mut ctx = EvaluationContext::basic()?;
|
let mut ctx = basic_evaluation_context()?;
|
||||||
ctx.host = Arc::new(Mutex::new(Box::new(crate::env::host::FakeHost::new())));
|
ctx.host = Arc::new(Mutex::new(Box::new(nu_engine::FakeHost::new())));
|
||||||
|
|
||||||
let expected = std::env::join_paths(vec![
|
let expected = std::env::join_paths(vec![
|
||||||
PathBuf::from("/Users/andresrobalino/.volta/bin"),
|
PathBuf::from("/Users/andresrobalino/.volta/bin"),
|
||||||
|
@ -1,195 +0,0 @@
|
|||||||
use crate::command_registry::CommandRegistry;
|
|
||||||
use crate::commands::{command::CommandArgs, Command, UnevaluatedCallInfo};
|
|
||||||
use crate::env::host::Host;
|
|
||||||
use crate::shell::shell_manager::ShellManager;
|
|
||||||
use crate::stream::{InputStream, OutputStream};
|
|
||||||
use indexmap::IndexMap;
|
|
||||||
use nu_errors::ShellError;
|
|
||||||
use nu_protocol::{hir, Scope};
|
|
||||||
use nu_source::{Tag, Text};
|
|
||||||
use parking_lot::Mutex;
|
|
||||||
use std::error::Error;
|
|
||||||
use std::sync::atomic::AtomicBool;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct EvaluationContext {
|
|
||||||
pub registry: CommandRegistry,
|
|
||||||
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
|
|
||||||
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
|
|
||||||
pub ctrl_c: Arc<AtomicBool>,
|
|
||||||
pub raw_input: String,
|
|
||||||
pub user_recently_used_autoenv_untrust: bool,
|
|
||||||
pub(crate) shell_manager: ShellManager,
|
|
||||||
|
|
||||||
/// Windows-specific: keep track of previous cwd on each drive
|
|
||||||
pub windows_drives_previous_cwd: Arc<Mutex<std::collections::HashMap<String, String>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EvaluationContext {
|
|
||||||
pub fn registry(&self) -> &CommandRegistry {
|
|
||||||
&self.registry
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn from_raw(
|
|
||||||
raw_args: &CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> EvaluationContext {
|
|
||||||
EvaluationContext {
|
|
||||||
registry: registry.clone(),
|
|
||||||
host: raw_args.host.clone(),
|
|
||||||
current_errors: raw_args.current_errors.clone(),
|
|
||||||
ctrl_c: raw_args.ctrl_c.clone(),
|
|
||||||
shell_manager: raw_args.shell_manager.clone(),
|
|
||||||
user_recently_used_autoenv_untrust: false,
|
|
||||||
windows_drives_previous_cwd: Arc::new(Mutex::new(std::collections::HashMap::new())),
|
|
||||||
raw_input: String::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn from_args(args: &CommandArgs, registry: &CommandRegistry) -> EvaluationContext {
|
|
||||||
EvaluationContext {
|
|
||||||
registry: registry.clone(),
|
|
||||||
host: args.host.clone(),
|
|
||||||
current_errors: args.current_errors.clone(),
|
|
||||||
ctrl_c: args.ctrl_c.clone(),
|
|
||||||
shell_manager: args.shell_manager.clone(),
|
|
||||||
user_recently_used_autoenv_untrust: false,
|
|
||||||
windows_drives_previous_cwd: Arc::new(Mutex::new(std::collections::HashMap::new())),
|
|
||||||
raw_input: String::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn basic() -> Result<EvaluationContext, Box<dyn Error>> {
|
|
||||||
let registry = CommandRegistry::new();
|
|
||||||
|
|
||||||
Ok(EvaluationContext {
|
|
||||||
registry,
|
|
||||||
host: Arc::new(parking_lot::Mutex::new(Box::new(
|
|
||||||
crate::env::host::BasicHost,
|
|
||||||
))),
|
|
||||||
current_errors: Arc::new(Mutex::new(vec![])),
|
|
||||||
ctrl_c: Arc::new(AtomicBool::new(false)),
|
|
||||||
user_recently_used_autoenv_untrust: false,
|
|
||||||
shell_manager: ShellManager::basic()?,
|
|
||||||
windows_drives_previous_cwd: Arc::new(Mutex::new(std::collections::HashMap::new())),
|
|
||||||
raw_input: String::default(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn error(&mut self, error: ShellError) {
|
|
||||||
self.with_errors(|errors| errors.push(error))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn clear_errors(&mut self) {
|
|
||||||
self.current_errors.lock().clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn get_errors(&self) -> Vec<ShellError> {
|
|
||||||
self.current_errors.lock().clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn add_error(&self, err: ShellError) {
|
|
||||||
self.current_errors.lock().push(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn maybe_print_errors(&mut self, source: Text) -> bool {
|
|
||||||
let errors = self.current_errors.clone();
|
|
||||||
let mut errors = errors.lock();
|
|
||||||
|
|
||||||
if errors.len() > 0 {
|
|
||||||
let error = errors[0].clone();
|
|
||||||
*errors = vec![];
|
|
||||||
|
|
||||||
crate::cli::print_err(error, &source);
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn configure<T>(
|
|
||||||
&mut self,
|
|
||||||
config: &dyn nu_data::config::Conf,
|
|
||||||
block: impl FnOnce(&dyn nu_data::config::Conf, &mut Self) -> T,
|
|
||||||
) {
|
|
||||||
block(config, &mut *self);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn with_host<T>(&mut self, block: impl FnOnce(&mut dyn Host) -> T) -> T {
|
|
||||||
let mut host = self.host.lock();
|
|
||||||
|
|
||||||
block(&mut *host)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn with_errors<T>(&mut self, block: impl FnOnce(&mut Vec<ShellError>) -> T) -> T {
|
|
||||||
let mut errors = self.current_errors.lock();
|
|
||||||
|
|
||||||
block(&mut *errors)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_commands(&mut self, commands: Vec<Command>) {
|
|
||||||
for command in commands {
|
|
||||||
self.registry.insert(command.name().to_string(), command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
pub(crate) fn get_command(&self, name: &str) -> Option<Command> {
|
|
||||||
self.registry.get_command(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn is_command_registered(&self, name: &str) -> bool {
|
|
||||||
self.registry.has(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn expect_command(&self, name: &str) -> Result<Command, ShellError> {
|
|
||||||
self.registry.expect_command(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) async fn run_command(
|
|
||||||
&mut self,
|
|
||||||
command: Command,
|
|
||||||
name_tag: Tag,
|
|
||||||
args: hir::Call,
|
|
||||||
scope: Arc<Scope>,
|
|
||||||
input: InputStream,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let command_args = self.command_args(args, input, name_tag, scope);
|
|
||||||
command.run(command_args, self.registry()).await
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call_info(&self, args: hir::Call, name_tag: Tag, scope: Arc<Scope>) -> UnevaluatedCallInfo {
|
|
||||||
UnevaluatedCallInfo {
|
|
||||||
args,
|
|
||||||
name_tag,
|
|
||||||
scope,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn command_args(
|
|
||||||
&self,
|
|
||||||
args: hir::Call,
|
|
||||||
input: InputStream,
|
|
||||||
name_tag: Tag,
|
|
||||||
scope: Arc<Scope>,
|
|
||||||
) -> CommandArgs {
|
|
||||||
CommandArgs {
|
|
||||||
host: self.host.clone(),
|
|
||||||
ctrl_c: self.ctrl_c.clone(),
|
|
||||||
current_errors: self.current_errors.clone(),
|
|
||||||
shell_manager: self.shell_manager.clone(),
|
|
||||||
call_info: self.call_info(args, name_tag, scope),
|
|
||||||
input,
|
|
||||||
raw_input: self.raw_input.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_env(&self) -> IndexMap<String, String> {
|
|
||||||
let mut output = IndexMap::new();
|
|
||||||
for (var, value) in self.host.lock().vars() {
|
|
||||||
output.insert(var, value);
|
|
||||||
}
|
|
||||||
output
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,492 +0,0 @@
|
|||||||
use nu_errors::ShellError;
|
|
||||||
use nu_protocol::hir::ClassifiedBlock;
|
|
||||||
use nu_protocol::{
|
|
||||||
Primitive, ReturnSuccess, Scope, ShellTypeName, Signature, SyntaxShape, UntaggedValue, Value,
|
|
||||||
};
|
|
||||||
use nu_source::{AnchorLocation, TaggedItem};
|
|
||||||
|
|
||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
use num_bigint::BigInt;
|
|
||||||
|
|
||||||
use crate::command_registry::CommandRegistry;
|
|
||||||
use crate::commands::classified::block::run_block;
|
|
||||||
use crate::commands::command::CommandArgs;
|
|
||||||
use crate::commands::{
|
|
||||||
whole_stream_command, BuildString, Command, Each, Echo, First, Get, Keep, Last, Nth,
|
|
||||||
StrCollect, WholeStreamCommand, Wrap,
|
|
||||||
};
|
|
||||||
use crate::evaluation_context::EvaluationContext;
|
|
||||||
use crate::stream::{InputStream, OutputStream};
|
|
||||||
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use futures::executor::block_on;
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
pub fn test_examples(cmd: Command) -> Result<(), ShellError> {
|
|
||||||
let examples = cmd.examples();
|
|
||||||
|
|
||||||
let mut base_context = EvaluationContext::basic()?;
|
|
||||||
|
|
||||||
base_context.add_commands(vec![
|
|
||||||
// Mocks
|
|
||||||
whole_stream_command(MockLs {}),
|
|
||||||
// Minimal restricted commands to aid in testing
|
|
||||||
whole_stream_command(Echo {}),
|
|
||||||
whole_stream_command(BuildString {}),
|
|
||||||
whole_stream_command(First {}),
|
|
||||||
whole_stream_command(Get {}),
|
|
||||||
whole_stream_command(Keep {}),
|
|
||||||
whole_stream_command(Each {}),
|
|
||||||
whole_stream_command(Last {}),
|
|
||||||
whole_stream_command(Nth {}),
|
|
||||||
whole_stream_command(StrCollect),
|
|
||||||
whole_stream_command(Wrap),
|
|
||||||
cmd,
|
|
||||||
]);
|
|
||||||
|
|
||||||
for sample_pipeline in examples {
|
|
||||||
let mut ctx = base_context.clone();
|
|
||||||
|
|
||||||
let block = parse_line(sample_pipeline.example, &mut ctx)?;
|
|
||||||
|
|
||||||
if let Some(expected) = &sample_pipeline.result {
|
|
||||||
let result = block_on(evaluate_block(block, &mut ctx))?;
|
|
||||||
|
|
||||||
ctx.with_errors(|reasons| reasons.iter().cloned().take(1).next())
|
|
||||||
.map_or(Ok(()), Err)?;
|
|
||||||
|
|
||||||
if expected.len() != result.len() {
|
|
||||||
let rows_returned =
|
|
||||||
format!("expected: {}\nactual: {}", expected.len(), result.len());
|
|
||||||
let failed_call = format!("command: {}\n", sample_pipeline.example);
|
|
||||||
|
|
||||||
panic!(
|
|
||||||
"example command produced unexpected number of results.\n {} {}",
|
|
||||||
failed_call, rows_returned
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (e, a) in expected.iter().zip(result.iter()) {
|
|
||||||
if !values_equal(e, a) {
|
|
||||||
let row_errored = format!("expected: {:#?}\nactual: {:#?}", e, a);
|
|
||||||
let failed_call = format!("command: {}\n", sample_pipeline.example);
|
|
||||||
|
|
||||||
panic!(
|
|
||||||
"example command produced unexpected result.\n {} {}",
|
|
||||||
failed_call, row_errored
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn test(cmd: impl WholeStreamCommand + 'static) -> Result<(), ShellError> {
|
|
||||||
let examples = cmd.examples();
|
|
||||||
|
|
||||||
let mut base_context = EvaluationContext::basic()?;
|
|
||||||
|
|
||||||
base_context.add_commands(vec![
|
|
||||||
whole_stream_command(Echo {}),
|
|
||||||
whole_stream_command(BuildString {}),
|
|
||||||
whole_stream_command(Get {}),
|
|
||||||
whole_stream_command(Keep {}),
|
|
||||||
whole_stream_command(Each {}),
|
|
||||||
whole_stream_command(cmd),
|
|
||||||
whole_stream_command(StrCollect),
|
|
||||||
whole_stream_command(Wrap),
|
|
||||||
]);
|
|
||||||
|
|
||||||
for sample_pipeline in examples {
|
|
||||||
let mut ctx = base_context.clone();
|
|
||||||
|
|
||||||
let block = parse_line(sample_pipeline.example, &mut ctx)?;
|
|
||||||
|
|
||||||
if let Some(expected) = &sample_pipeline.result {
|
|
||||||
let result = block_on(evaluate_block(block, &mut ctx))?;
|
|
||||||
|
|
||||||
ctx.with_errors(|reasons| reasons.iter().cloned().take(1).next())
|
|
||||||
.map_or(Ok(()), Err)?;
|
|
||||||
|
|
||||||
if expected.len() != result.len() {
|
|
||||||
let rows_returned =
|
|
||||||
format!("expected: {}\nactual: {}", expected.len(), result.len());
|
|
||||||
let failed_call = format!("command: {}\n", sample_pipeline.example);
|
|
||||||
|
|
||||||
panic!(
|
|
||||||
"example command produced unexpected number of results.\n {} {}",
|
|
||||||
failed_call, rows_returned
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (e, a) in expected.iter().zip(result.iter()) {
|
|
||||||
if !values_equal(e, a) {
|
|
||||||
let row_errored = format!("expected: {:#?}\nactual: {:#?}", e, a);
|
|
||||||
let failed_call = format!("command: {}\n", sample_pipeline.example);
|
|
||||||
|
|
||||||
panic!(
|
|
||||||
"example command produced unexpected result.\n {} {}",
|
|
||||||
failed_call, row_errored
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn test_anchors(cmd: Command) -> Result<(), ShellError> {
|
|
||||||
let examples = cmd.examples();
|
|
||||||
|
|
||||||
let mut base_context = EvaluationContext::basic()?;
|
|
||||||
|
|
||||||
base_context.add_commands(vec![
|
|
||||||
// Minimal restricted commands to aid in testing
|
|
||||||
whole_stream_command(MockCommand {}),
|
|
||||||
whole_stream_command(MockEcho {}),
|
|
||||||
whole_stream_command(MockLs {}),
|
|
||||||
whole_stream_command(BuildString {}),
|
|
||||||
whole_stream_command(First {}),
|
|
||||||
whole_stream_command(Get {}),
|
|
||||||
whole_stream_command(Keep {}),
|
|
||||||
whole_stream_command(Each {}),
|
|
||||||
whole_stream_command(Last {}),
|
|
||||||
whole_stream_command(Nth {}),
|
|
||||||
whole_stream_command(StrCollect),
|
|
||||||
whole_stream_command(Wrap),
|
|
||||||
cmd,
|
|
||||||
]);
|
|
||||||
|
|
||||||
for sample_pipeline in examples {
|
|
||||||
let pipeline_with_anchor = format!("mock --open --path | {}", sample_pipeline.example);
|
|
||||||
|
|
||||||
let mut ctx = base_context.clone();
|
|
||||||
|
|
||||||
let block = parse_line(&pipeline_with_anchor, &mut ctx)?;
|
|
||||||
let result = block_on(evaluate_block(block, &mut ctx))?;
|
|
||||||
|
|
||||||
ctx.with_errors(|reasons| reasons.iter().cloned().take(1).next())
|
|
||||||
.map_or(Ok(()), Err)?;
|
|
||||||
|
|
||||||
for actual in result.iter() {
|
|
||||||
if !is_anchor_carried(actual, mock_path()) {
|
|
||||||
let failed_call = format!("command: {}\n", pipeline_with_anchor);
|
|
||||||
|
|
||||||
panic!(
|
|
||||||
"example command didn't carry anchor tag correctly.\n {} {:#?} {:#?}",
|
|
||||||
failed_call,
|
|
||||||
actual,
|
|
||||||
mock_path()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse and run a nushell pipeline
|
|
||||||
fn parse_line(line: &str, ctx: &mut EvaluationContext) -> Result<ClassifiedBlock, ShellError> {
|
|
||||||
let line = if let Some(line) = line.strip_suffix('\n') {
|
|
||||||
line
|
|
||||||
} else {
|
|
||||||
line
|
|
||||||
};
|
|
||||||
|
|
||||||
let (lite_result, err) = nu_parser::lite_parse(&line, 0);
|
|
||||||
if let Some(err) = err {
|
|
||||||
return Err(err.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO ensure the command whose examples we're testing is actually in the pipeline
|
|
||||||
let classified_block = nu_parser::classify_block(&lite_result, ctx.registry());
|
|
||||||
Ok(classified_block)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn evaluate_block(
|
|
||||||
block: ClassifiedBlock,
|
|
||||||
ctx: &mut EvaluationContext,
|
|
||||||
) -> Result<Vec<Value>, ShellError> {
|
|
||||||
let input_stream = InputStream::empty();
|
|
||||||
let env = ctx.get_env();
|
|
||||||
|
|
||||||
let scope = Scope::from_env(env);
|
|
||||||
|
|
||||||
Ok(run_block(&block.block, ctx, input_stream, scope)
|
|
||||||
.await?
|
|
||||||
.drain_vec()
|
|
||||||
.await)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO probably something already available to do this
|
|
||||||
// TODO perhaps better panic messages when things don't compare
|
|
||||||
|
|
||||||
// Deep value comparisons that ignore tags
|
|
||||||
fn values_equal(expected: &Value, actual: &Value) -> bool {
|
|
||||||
use nu_protocol::UntaggedValue::*;
|
|
||||||
|
|
||||||
match (&expected.value, &actual.value) {
|
|
||||||
(Primitive(e), Primitive(a)) => e == a,
|
|
||||||
(Row(e), Row(a)) => {
|
|
||||||
if e.entries.len() != a.entries.len() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
e.entries
|
|
||||||
.iter()
|
|
||||||
.zip(a.entries.iter())
|
|
||||||
.all(|((ek, ev), (ak, av))| ek == ak && values_equal(ev, av))
|
|
||||||
}
|
|
||||||
(Table(e), Table(a)) => e.iter().zip(a.iter()).all(|(e, a)| values_equal(e, a)),
|
|
||||||
(e, a) => unimplemented!("{} {}", e.type_name(), a.type_name()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_anchor_carried(actual: &Value, anchor: AnchorLocation) -> bool {
|
|
||||||
actual.tag.anchor() == Some(anchor)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Arguments {
|
|
||||||
path: Option<bool>,
|
|
||||||
open: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MockCommand;
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl WholeStreamCommand for MockCommand {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"mock"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build("mock")
|
|
||||||
.switch("open", "fake opening sources", Some('o'))
|
|
||||||
.switch("path", "file open", Some('p'))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Generates tables and metadata that mimics behavior of real commands in controlled ways."
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn run(
|
|
||||||
&self,
|
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let name_tag = args.call_info.name_tag.clone();
|
|
||||||
|
|
||||||
let (
|
|
||||||
Arguments {
|
|
||||||
path: mocked_path,
|
|
||||||
open: open_mock,
|
|
||||||
},
|
|
||||||
_input,
|
|
||||||
) = args.process(®istry).await?;
|
|
||||||
|
|
||||||
let out = UntaggedValue::string("Yehuda Katz in Ecuador");
|
|
||||||
|
|
||||||
if open_mock {
|
|
||||||
if let Some(true) = mocked_path {
|
|
||||||
return Ok(OutputStream::one(Ok(ReturnSuccess::Value(Value {
|
|
||||||
value: out,
|
|
||||||
tag: Tag {
|
|
||||||
anchor: Some(mock_path()),
|
|
||||||
span: name_tag.span,
|
|
||||||
},
|
|
||||||
}))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(OutputStream::one(Ok(ReturnSuccess::Value(
|
|
||||||
out.into_value(name_tag),
|
|
||||||
))))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MockEcho;
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct MockEchoArgs {
|
|
||||||
pub rest: Vec<Value>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl WholeStreamCommand for MockEcho {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"echo"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build("echo").rest(SyntaxShape::Any, "the values to echo")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Mock echo."
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn run(
|
|
||||||
&self,
|
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let name_tag = args.call_info.name_tag.clone();
|
|
||||||
let (MockEchoArgs { rest }, input) = args.process(®istry).await?;
|
|
||||||
|
|
||||||
let mut base_value = UntaggedValue::string("Yehuda Katz in Ecuador").into_value(name_tag);
|
|
||||||
let input: Vec<Value> = input.collect().await;
|
|
||||||
|
|
||||||
if let Some(first) = input.get(0) {
|
|
||||||
base_value = first.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
let stream = rest.into_iter().map(move |i| {
|
|
||||||
let base_value = base_value.clone();
|
|
||||||
match i.as_string() {
|
|
||||||
Ok(s) => OutputStream::one(Ok(ReturnSuccess::Value(Value {
|
|
||||||
value: UntaggedValue::Primitive(Primitive::String(s)),
|
|
||||||
tag: base_value.tag,
|
|
||||||
}))),
|
|
||||||
_ => match i {
|
|
||||||
Value {
|
|
||||||
value: UntaggedValue::Table(table),
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
if table.len() == 1 && table[0].is_table() {
|
|
||||||
let mut values: Vec<Value> =
|
|
||||||
table[0].table_entries().map(Clone::clone).collect();
|
|
||||||
|
|
||||||
for v in values.iter_mut() {
|
|
||||||
v.tag = base_value.tag();
|
|
||||||
}
|
|
||||||
|
|
||||||
let subtable =
|
|
||||||
vec![UntaggedValue::Table(values).into_value(base_value.tag())];
|
|
||||||
|
|
||||||
futures::stream::iter(subtable.into_iter().map(ReturnSuccess::value))
|
|
||||||
.to_output_stream()
|
|
||||||
} else {
|
|
||||||
futures::stream::iter(
|
|
||||||
table
|
|
||||||
.into_iter()
|
|
||||||
.map(move |mut v| {
|
|
||||||
v.tag = base_value.tag();
|
|
||||||
v
|
|
||||||
})
|
|
||||||
.map(ReturnSuccess::value),
|
|
||||||
)
|
|
||||||
.to_output_stream()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => OutputStream::one(Ok(ReturnSuccess::Value(Value {
|
|
||||||
value: i.value.clone(),
|
|
||||||
tag: base_value.tag,
|
|
||||||
}))),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(futures::stream::iter(stream).flatten().to_output_stream())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MockLs;
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl WholeStreamCommand for MockLs {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"ls"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build("ls")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Mock ls."
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn run(
|
|
||||||
&self,
|
|
||||||
args: CommandArgs,
|
|
||||||
_: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let name_tag = args.call_info.name_tag.clone();
|
|
||||||
|
|
||||||
let mut base_value =
|
|
||||||
UntaggedValue::string("Andrés N. Robalino in Portland").into_value(name_tag);
|
|
||||||
let input: Vec<Value> = args.input.collect().await;
|
|
||||||
|
|
||||||
if let Some(first) = input.get(0) {
|
|
||||||
base_value = first.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(futures::stream::iter(
|
|
||||||
file_listing()
|
|
||||||
.iter()
|
|
||||||
.map(|row| Value {
|
|
||||||
value: row.value.clone(),
|
|
||||||
tag: base_value.tag.clone(),
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.into_iter()
|
|
||||||
.map(ReturnSuccess::value),
|
|
||||||
)
|
|
||||||
.to_output_stream())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn int(s: impl Into<BigInt>) -> Value {
|
|
||||||
UntaggedValue::int(s).into_untagged_value()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn string(input: impl Into<String>) -> Value {
|
|
||||||
UntaggedValue::string(input.into()).into_untagged_value()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn date(input: impl Into<String>) -> Value {
|
|
||||||
let key = input.into().tagged_unknown();
|
|
||||||
crate::value::Date::naive_from_str(key.borrow_tagged())
|
|
||||||
.expect("date from string failed")
|
|
||||||
.into_untagged_value()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn file_listing() -> Vec<Value> {
|
|
||||||
vec![
|
|
||||||
row! {
|
|
||||||
"name".to_string() => string("Andrés.txt"),
|
|
||||||
"type".to_string() => string("File"),
|
|
||||||
"chickens".to_string() => int(10),
|
|
||||||
"modified".to_string() => date("2019-07-23")
|
|
||||||
},
|
|
||||||
row! {
|
|
||||||
"name".to_string() => string("Jonathan"),
|
|
||||||
"type".to_string() => string("Dir"),
|
|
||||||
"chickens".to_string() => int(5),
|
|
||||||
"modified".to_string() => date("2019-07-23")
|
|
||||||
},
|
|
||||||
row! {
|
|
||||||
"name".to_string() => string("Andrés.txt"),
|
|
||||||
"type".to_string() => string("File"),
|
|
||||||
"chickens".to_string() => int(20),
|
|
||||||
"modified".to_string() => date("2019-09-24")
|
|
||||||
},
|
|
||||||
row! {
|
|
||||||
"name".to_string() => string("Yehuda"),
|
|
||||||
"type".to_string() => string("Dir"),
|
|
||||||
"chickens".to_string() => int(4),
|
|
||||||
"modified".to_string() => date("2019-09-24")
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mock_path() -> AnchorLocation {
|
|
||||||
let path = String::from("path/to/las_best_arepas_in_the_world.txt");
|
|
||||||
|
|
||||||
AnchorLocation::File(path)
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
pub fn current_branch() -> Option<String> {
|
|
||||||
#[cfg(feature = "git2")]
|
|
||||||
{
|
|
||||||
use git2::{Repository, RepositoryOpenFlags};
|
|
||||||
use std::ffi::OsString;
|
|
||||||
|
|
||||||
let v: Vec<OsString> = vec![];
|
|
||||||
match Repository::open_ext(".", RepositoryOpenFlags::empty(), v) {
|
|
||||||
Ok(repo) => {
|
|
||||||
let r = repo.head();
|
|
||||||
match r {
|
|
||||||
Ok(r) => match r.shorthand() {
|
|
||||||
Some(s) => Some(s.to_string()),
|
|
||||||
None => None,
|
|
||||||
},
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(not(feature = "git2"))]
|
|
||||||
{
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
@ -405,14 +405,10 @@ pub struct Keybinding {
|
|||||||
|
|
||||||
type Keybindings = Vec<Keybinding>;
|
type Keybindings = Vec<Keybinding>;
|
||||||
|
|
||||||
pub(crate) fn keybinding_path() -> Result<std::path::PathBuf, nu_errors::ShellError> {
|
|
||||||
nu_data::config::default_path_for(&Some(std::path::PathBuf::from("keybindings.yml")))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn load_keybindings(
|
pub(crate) fn load_keybindings(
|
||||||
rl: &mut rustyline::Editor<crate::shell::Helper>,
|
rl: &mut rustyline::Editor<crate::shell::Helper>,
|
||||||
) -> Result<(), nu_errors::ShellError> {
|
) -> Result<(), nu_errors::ShellError> {
|
||||||
let filename = keybinding_path()?;
|
let filename = nu_data::keybinding::keybinding_path()?;
|
||||||
let contents = std::fs::read_to_string(filename);
|
let contents = std::fs::read_to_string(filename);
|
||||||
|
|
||||||
// Silently fail if there is no file there
|
// Silently fail if there is no file there
|
||||||
|
@ -14,53 +14,28 @@ extern crate quickcheck;
|
|||||||
extern crate quickcheck_macros;
|
extern crate quickcheck_macros;
|
||||||
|
|
||||||
mod cli;
|
mod cli;
|
||||||
mod command_registry;
|
|
||||||
mod commands;
|
|
||||||
#[cfg(feature = "rustyline-support")]
|
#[cfg(feature = "rustyline-support")]
|
||||||
mod completion;
|
mod completion;
|
||||||
mod deserializer;
|
|
||||||
mod documentation;
|
|
||||||
mod env;
|
mod env;
|
||||||
mod evaluate;
|
|
||||||
mod evaluation_context;
|
|
||||||
mod format;
|
mod format;
|
||||||
mod futures;
|
|
||||||
#[cfg(feature = "rustyline-support")]
|
|
||||||
mod git;
|
|
||||||
#[cfg(feature = "rustyline-support")]
|
#[cfg(feature = "rustyline-support")]
|
||||||
mod keybinding;
|
mod keybinding;
|
||||||
mod path;
|
mod line_editor;
|
||||||
mod plugin;
|
|
||||||
mod shell;
|
mod shell;
|
||||||
mod stream;
|
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub mod utils;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod examples;
|
|
||||||
|
|
||||||
#[cfg(feature = "rustyline-support")]
|
#[cfg(feature = "rustyline-support")]
|
||||||
pub use crate::cli::cli;
|
pub use crate::cli::cli;
|
||||||
|
|
||||||
pub use crate::cli::{
|
pub use crate::cli::{parse_and_eval, register_plugins, run_script_file};
|
||||||
create_default_context, parse_and_eval, process_line, register_plugins,
|
|
||||||
run_pipeline_standalone, run_vec_of_pipelines, LineResult,
|
|
||||||
};
|
|
||||||
pub use crate::command_registry::CommandRegistry;
|
|
||||||
pub use crate::commands::classified::block::run_block;
|
|
||||||
pub use crate::commands::command::{
|
|
||||||
whole_stream_command, CommandArgs, EvaluatedWholeStreamCommandArgs, Example, WholeStreamCommand,
|
|
||||||
};
|
|
||||||
pub use crate::commands::help::get_help;
|
|
||||||
pub use crate::env::environment_syncer::EnvironmentSyncer;
|
pub use crate::env::environment_syncer::EnvironmentSyncer;
|
||||||
pub use crate::env::host::BasicHost;
|
pub use nu_command::commands::default_context::create_default_context;
|
||||||
pub use crate::evaluation_context::EvaluationContext;
|
|
||||||
pub use crate::prelude::ToOutputStream;
|
|
||||||
pub use crate::stream::{InputStream, InterruptibleStream, OutputStream};
|
|
||||||
pub use nu_data::config;
|
pub use nu_data::config;
|
||||||
pub use nu_data::dict::TaggedListBuilder;
|
pub use nu_data::dict::TaggedListBuilder;
|
||||||
pub use nu_data::primitive;
|
pub use nu_data::primitive;
|
||||||
pub use nu_data::value;
|
pub use nu_data::value;
|
||||||
|
pub use nu_stream::{InputStream, InterruptibleStream, OutputStream};
|
||||||
pub use nu_value_ext::ValueExt;
|
pub use nu_value_ext::ValueExt;
|
||||||
pub use num_traits::cast::ToPrimitive;
|
pub use num_traits::cast::ToPrimitive;
|
||||||
|
|
||||||
|
234
crates/nu-cli/src/line_editor.rs
Normal file
234
crates/nu-cli/src/line_editor.rs
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
use nu_engine::EvaluationContext;
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use nu_command::script::LineResult;
|
||||||
|
|
||||||
|
#[cfg(feature = "rustyline-support")]
|
||||||
|
use crate::shell::Helper;
|
||||||
|
|
||||||
|
#[cfg(feature = "rustyline-support")]
|
||||||
|
use rustyline::{
|
||||||
|
self,
|
||||||
|
config::Configurer,
|
||||||
|
config::{ColorMode, CompletionType, Config},
|
||||||
|
error::ReadlineError,
|
||||||
|
At, Cmd, Editor, KeyPress, Movement, Word,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "rustyline-support")]
|
||||||
|
pub fn convert_rustyline_result_to_string(input: Result<String, ReadlineError>) -> LineResult {
|
||||||
|
match input {
|
||||||
|
Ok(s) if s == "history -c" || s == "history --clear" => LineResult::ClearHistory,
|
||||||
|
Ok(s) => LineResult::Success(s),
|
||||||
|
Err(ReadlineError::Interrupted) => LineResult::CtrlC,
|
||||||
|
Err(ReadlineError::Eof) => LineResult::CtrlD,
|
||||||
|
Err(err) => {
|
||||||
|
outln!("Error: {:?}", err);
|
||||||
|
LineResult::Break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rustyline-support")]
|
||||||
|
pub fn default_rustyline_editor_configuration() -> Editor<Helper> {
|
||||||
|
#[cfg(windows)]
|
||||||
|
const DEFAULT_COMPLETION_MODE: CompletionType = CompletionType::Circular;
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
const DEFAULT_COMPLETION_MODE: CompletionType = CompletionType::List;
|
||||||
|
|
||||||
|
let config = Config::builder().color_mode(ColorMode::Forced).build();
|
||||||
|
let mut rl: Editor<_> = Editor::with_config(config);
|
||||||
|
|
||||||
|
// add key bindings to move over a whole word with Ctrl+ArrowLeft and Ctrl+ArrowRight
|
||||||
|
rl.bind_sequence(
|
||||||
|
KeyPress::ControlLeft,
|
||||||
|
Cmd::Move(Movement::BackwardWord(1, Word::Vi)),
|
||||||
|
);
|
||||||
|
rl.bind_sequence(
|
||||||
|
KeyPress::ControlRight,
|
||||||
|
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
|
||||||
|
// defaults taken from here https://github.com/kkawakam/rustyline/blob/2fe886c9576c1ea13ca0e5808053ad491a6fe049/src/config.rs#L150-L167
|
||||||
|
rl.set_max_history_size(100);
|
||||||
|
rl.set_history_ignore_dups(true);
|
||||||
|
rl.set_history_ignore_space(false);
|
||||||
|
rl.set_completion_type(DEFAULT_COMPLETION_MODE);
|
||||||
|
rl.set_completion_prompt_limit(100);
|
||||||
|
rl.set_keyseq_timeout(-1);
|
||||||
|
rl.set_edit_mode(rustyline::config::EditMode::Emacs);
|
||||||
|
rl.set_auto_add_history(false);
|
||||||
|
rl.set_bell_style(rustyline::config::BellStyle::default());
|
||||||
|
rl.set_color_mode(rustyline::ColorMode::Enabled);
|
||||||
|
rl.set_tab_stop(8);
|
||||||
|
|
||||||
|
if let Err(e) = crate::keybinding::load_keybindings(&mut rl) {
|
||||||
|
println!("Error loading keybindings: {:?}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
rl
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rustyline-support")]
|
||||||
|
pub fn configure_rustyline_editor(
|
||||||
|
rl: &mut Editor<Helper>,
|
||||||
|
config: &dyn nu_data::config::Conf,
|
||||||
|
) -> Result<(), ShellError> {
|
||||||
|
#[cfg(windows)]
|
||||||
|
const DEFAULT_COMPLETION_MODE: CompletionType = CompletionType::Circular;
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
const DEFAULT_COMPLETION_MODE: CompletionType = CompletionType::List;
|
||||||
|
|
||||||
|
if let Some(line_editor_vars) = config.var("line_editor") {
|
||||||
|
for (idx, value) in line_editor_vars.row_entries() {
|
||||||
|
match idx.as_ref() {
|
||||||
|
"max_history_size" => {
|
||||||
|
if let Ok(max_history_size) = value.as_u64() {
|
||||||
|
rl.set_max_history_size(max_history_size as usize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"history_duplicates" => {
|
||||||
|
// history_duplicates = match value.as_string() {
|
||||||
|
// Ok(s) if s.to_lowercase() == "alwaysadd" => {
|
||||||
|
// rustyline::config::HistoryDuplicates::AlwaysAdd
|
||||||
|
// }
|
||||||
|
// Ok(s) if s.to_lowercase() == "ignoreconsecutive" => {
|
||||||
|
// rustyline::config::HistoryDuplicates::IgnoreConsecutive
|
||||||
|
// }
|
||||||
|
// _ => rustyline::config::HistoryDuplicates::AlwaysAdd,
|
||||||
|
// };
|
||||||
|
if let Ok(history_duplicates) = value.as_bool() {
|
||||||
|
rl.set_history_ignore_dups(history_duplicates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"history_ignore_space" => {
|
||||||
|
if let Ok(history_ignore_space) = value.as_bool() {
|
||||||
|
rl.set_history_ignore_space(history_ignore_space);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"completion_type" => {
|
||||||
|
let completion_type = match value.as_string() {
|
||||||
|
Ok(s) if s.to_lowercase() == "circular" => {
|
||||||
|
rustyline::config::CompletionType::Circular
|
||||||
|
}
|
||||||
|
Ok(s) if s.to_lowercase() == "list" => {
|
||||||
|
rustyline::config::CompletionType::List
|
||||||
|
}
|
||||||
|
#[cfg(all(unix, feature = "with-fuzzy"))]
|
||||||
|
Ok(s) if s.to_lowercase() == "fuzzy" => {
|
||||||
|
rustyline::config::CompletionType::Fuzzy
|
||||||
|
}
|
||||||
|
_ => DEFAULT_COMPLETION_MODE,
|
||||||
|
};
|
||||||
|
rl.set_completion_type(completion_type);
|
||||||
|
}
|
||||||
|
"completion_prompt_limit" => {
|
||||||
|
if let Ok(completion_prompt_limit) = value.as_u64() {
|
||||||
|
rl.set_completion_prompt_limit(completion_prompt_limit as usize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"keyseq_timeout_ms" => {
|
||||||
|
if let Ok(keyseq_timeout_ms) = value.as_u64() {
|
||||||
|
rl.set_keyseq_timeout(keyseq_timeout_ms as i32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"edit_mode" => {
|
||||||
|
let edit_mode = match value.as_string() {
|
||||||
|
Ok(s) if s.to_lowercase() == "vi" => rustyline::config::EditMode::Vi,
|
||||||
|
Ok(s) if s.to_lowercase() == "emacs" => rustyline::config::EditMode::Emacs,
|
||||||
|
_ => rustyline::config::EditMode::Emacs,
|
||||||
|
};
|
||||||
|
rl.set_edit_mode(edit_mode);
|
||||||
|
// Note: When edit_mode is Emacs, the keyseq_timeout_ms is set to -1
|
||||||
|
// no matter what you may have configured. This is so that key chords
|
||||||
|
// can be applied without having to do them in a given timeout. So,
|
||||||
|
// it essentially turns off the keyseq timeout.
|
||||||
|
}
|
||||||
|
"auto_add_history" => {
|
||||||
|
if let Ok(auto_add_history) = value.as_bool() {
|
||||||
|
rl.set_auto_add_history(auto_add_history);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"bell_style" => {
|
||||||
|
let bell_style = match value.as_string() {
|
||||||
|
Ok(s) if s.to_lowercase() == "audible" => {
|
||||||
|
rustyline::config::BellStyle::Audible
|
||||||
|
}
|
||||||
|
Ok(s) if s.to_lowercase() == "none" => rustyline::config::BellStyle::None,
|
||||||
|
Ok(s) if s.to_lowercase() == "visible" => {
|
||||||
|
rustyline::config::BellStyle::Visible
|
||||||
|
}
|
||||||
|
_ => rustyline::config::BellStyle::default(),
|
||||||
|
};
|
||||||
|
rl.set_bell_style(bell_style);
|
||||||
|
}
|
||||||
|
"color_mode" => {
|
||||||
|
let color_mode = match value.as_string() {
|
||||||
|
Ok(s) if s.to_lowercase() == "enabled" => rustyline::ColorMode::Enabled,
|
||||||
|
Ok(s) if s.to_lowercase() == "forced" => rustyline::ColorMode::Forced,
|
||||||
|
Ok(s) if s.to_lowercase() == "disabled" => rustyline::ColorMode::Disabled,
|
||||||
|
_ => rustyline::ColorMode::Enabled,
|
||||||
|
};
|
||||||
|
rl.set_color_mode(color_mode);
|
||||||
|
}
|
||||||
|
"tab_stop" => {
|
||||||
|
if let Ok(tab_stop) = value.as_u64() {
|
||||||
|
rl.set_tab_stop(tab_stop as usize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rustyline-support")]
|
||||||
|
pub fn nu_line_editor_helper(
|
||||||
|
context: &mut EvaluationContext,
|
||||||
|
config: &dyn nu_data::config::Conf,
|
||||||
|
) -> crate::shell::Helper {
|
||||||
|
let hinter = rustyline_hinter(config);
|
||||||
|
crate::shell::Helper::new(context.clone(), hinter)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rustyline-support")]
|
||||||
|
pub fn rustyline_hinter(
|
||||||
|
config: &dyn nu_data::config::Conf,
|
||||||
|
) -> Option<rustyline::hint::HistoryHinter> {
|
||||||
|
if let Some(line_editor_vars) = config.var("line_editor") {
|
||||||
|
for (idx, value) in line_editor_vars.row_entries() {
|
||||||
|
if idx == "show_hints" && value.expect_string() == "false" {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(rustyline::hint::HistoryHinter {})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn configure_ctrl_c(_context: &mut EvaluationContext) -> Result<(), Box<dyn Error>> {
|
||||||
|
#[cfg(feature = "ctrlc")]
|
||||||
|
{
|
||||||
|
let cc = _context.ctrl_c.clone();
|
||||||
|
|
||||||
|
ctrlc::set_handler(move || {
|
||||||
|
cc.store(true, Ordering::SeqCst);
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if _context.ctrl_c.load(Ordering::SeqCst) {
|
||||||
|
_context.ctrl_c.store(false, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -21,28 +21,6 @@ macro_rules! stream {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! trace_stream {
|
|
||||||
(target: $target:tt, $desc:tt = $expr:expr) => {{
|
|
||||||
if log::log_enabled!(target: $target, log::Level::Trace) {
|
|
||||||
use futures::stream::StreamExt;
|
|
||||||
|
|
||||||
let objects = $expr.inspect(move |o| {
|
|
||||||
trace!(
|
|
||||||
target: $target,
|
|
||||||
"{} = {}",
|
|
||||||
$desc,
|
|
||||||
nu_source::PrettyDebug::plain_string(o, 70)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
$crate::stream::InputStream::from_stream(objects.boxed())
|
|
||||||
} else {
|
|
||||||
$expr
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! trace_out_stream {
|
macro_rules! trace_out_stream {
|
||||||
(target: $target:tt, $desc:tt = $expr:expr) => {{
|
(target: $target:tt, $desc:tt = $expr:expr) => {{
|
||||||
@ -61,48 +39,24 @@ macro_rules! trace_out_stream {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
$crate::stream::OutputStream::new(objects)
|
nu_stream::OutputStream::new(objects)
|
||||||
} else {
|
} else {
|
||||||
$expr
|
$expr
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) use nu_protocol::{errln, out, outln, row};
|
|
||||||
use nu_source::HasFallibleSpan;
|
|
||||||
|
|
||||||
pub(crate) use crate::command_registry::CommandRegistry;
|
|
||||||
pub(crate) use crate::commands::command::{CommandArgs, RawCommandArgs, RunnableContext};
|
|
||||||
pub(crate) use crate::commands::Example;
|
|
||||||
pub(crate) use crate::evaluation_context::EvaluationContext;
|
|
||||||
pub(crate) use nu_data::config;
|
|
||||||
pub(crate) use nu_data::value;
|
|
||||||
// pub(crate) use crate::env::host::handle_unexpected;
|
|
||||||
pub(crate) use crate::env::Host;
|
|
||||||
pub(crate) use crate::shell::filesystem_shell::FilesystemShell;
|
|
||||||
pub(crate) use crate::shell::help_shell::HelpShell;
|
|
||||||
pub(crate) use crate::shell::shell_manager::ShellManager;
|
|
||||||
pub(crate) use crate::shell::value_shell::ValueShell;
|
|
||||||
pub(crate) use crate::stream::{InputStream, InterruptibleStream, OutputStream};
|
|
||||||
pub(crate) use bigdecimal::BigDecimal;
|
|
||||||
pub(crate) use futures::stream::BoxStream;
|
|
||||||
pub(crate) use futures::{Stream, StreamExt};
|
pub(crate) use futures::{Stream, StreamExt};
|
||||||
pub(crate) use nu_source::{
|
pub(crate) use nu_engine::Host;
|
||||||
b, AnchorLocation, DebugDocBuilder, PrettyDebug, PrettyDebugWithSource, Span, SpannedItem, Tag,
|
#[allow(unused_imports)]
|
||||||
TaggedItem, Text,
|
pub(crate) use nu_errors::ShellError;
|
||||||
};
|
#[allow(unused_imports)]
|
||||||
|
pub(crate) use nu_protocol::outln;
|
||||||
|
pub(crate) use nu_stream::OutputStream;
|
||||||
|
#[allow(unused_imports)]
|
||||||
pub(crate) use nu_value_ext::ValueExt;
|
pub(crate) use nu_value_ext::ValueExt;
|
||||||
pub(crate) use num_bigint::BigInt;
|
#[allow(unused_imports)]
|
||||||
pub(crate) use num_traits::cast::ToPrimitive;
|
pub(crate) use std::sync::atomic::Ordering;
|
||||||
pub(crate) use serde::Deserialize;
|
|
||||||
pub(crate) use std::collections::VecDeque;
|
|
||||||
pub(crate) use std::future::Future;
|
|
||||||
pub(crate) use std::sync::atomic::AtomicBool;
|
|
||||||
pub(crate) use std::sync::Arc;
|
|
||||||
|
|
||||||
pub(crate) use async_trait::async_trait;
|
|
||||||
pub(crate) use indexmap::IndexMap;
|
|
||||||
pub(crate) use itertools::Itertools;
|
|
||||||
|
|
||||||
pub trait FromInputStream {
|
pub trait FromInputStream {
|
||||||
fn from_input_stream(self) -> OutputStream;
|
fn from_input_stream(self) -> OutputStream;
|
||||||
@ -119,26 +73,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToInputStream {
|
|
||||||
fn to_input_stream(self) -> InputStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, U> ToInputStream for T
|
|
||||||
where
|
|
||||||
T: Stream<Item = U> + Send + 'static,
|
|
||||||
U: Into<Result<nu_protocol::Value, nu_errors::ShellError>>,
|
|
||||||
{
|
|
||||||
fn to_input_stream(self) -> InputStream {
|
|
||||||
InputStream::from_stream(self.map(|item| match item.into() {
|
|
||||||
Ok(result) => result,
|
|
||||||
Err(err) => match HasFallibleSpan::maybe_span(&err) {
|
|
||||||
Some(span) => nu_protocol::UntaggedValue::Error(err).into_value(span),
|
|
||||||
None => nu_protocol::UntaggedValue::Error(err).into_untagged_value(),
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ToOutputStream {
|
pub trait ToOutputStream {
|
||||||
fn to_output_stream(self) -> OutputStream;
|
fn to_output_stream(self) -> OutputStream;
|
||||||
}
|
}
|
||||||
@ -154,16 +88,3 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Interruptible<V> {
|
|
||||||
fn interruptible(self, ctrl_c: Arc<AtomicBool>) -> InterruptibleStream<V>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S, V> Interruptible<V> for S
|
|
||||||
where
|
|
||||||
S: Stream<Item = V> + Send + 'static,
|
|
||||||
{
|
|
||||||
fn interruptible(self, ctrl_c: Arc<AtomicBool>) -> InterruptibleStream<V> {
|
|
||||||
InterruptibleStream::new(self, ctrl_c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -2,15 +2,8 @@
|
|||||||
|
|
||||||
#[cfg(feature = "rustyline-support")]
|
#[cfg(feature = "rustyline-support")]
|
||||||
pub(crate) mod completer;
|
pub(crate) mod completer;
|
||||||
pub(crate) mod filesystem_shell;
|
|
||||||
pub(crate) mod help_shell;
|
|
||||||
#[cfg(feature = "rustyline-support")]
|
#[cfg(feature = "rustyline-support")]
|
||||||
pub(crate) mod helper;
|
pub(crate) mod helper;
|
||||||
pub(crate) mod painter;
|
|
||||||
pub(crate) mod palette;
|
|
||||||
pub(crate) mod shell;
|
|
||||||
pub(crate) mod shell_manager;
|
|
||||||
pub(crate) mod value_shell;
|
|
||||||
|
|
||||||
#[cfg(feature = "rustyline-support")]
|
#[cfg(feature = "rustyline-support")]
|
||||||
pub(crate) use helper::Helper;
|
pub(crate) use helper::Helper;
|
||||||
|
@ -4,7 +4,8 @@ use crate::completion::matchers;
|
|||||||
use crate::completion::matchers::Matcher;
|
use crate::completion::matchers::Matcher;
|
||||||
use crate::completion::path::{PathCompleter, PathSuggestion};
|
use crate::completion::path::{PathCompleter, PathSuggestion};
|
||||||
use crate::completion::{self, Completer, Suggestion};
|
use crate::completion::{self, Completer, Suggestion};
|
||||||
use crate::evaluation_context::EvaluationContext;
|
use nu_engine::EvaluationContext;
|
||||||
|
use nu_parser::ParserScope;
|
||||||
use nu_source::Tag;
|
use nu_source::Tag;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
@ -23,10 +24,12 @@ impl NuCompleter {
|
|||||||
use completion::engine::LocationType;
|
use completion::engine::LocationType;
|
||||||
|
|
||||||
let nu_context: &EvaluationContext = context.as_ref();
|
let nu_context: &EvaluationContext = context.as_ref();
|
||||||
let (lite_block, _) = nu_parser::lite_parse(line, 0);
|
|
||||||
|
|
||||||
let classified_block = nu_parser::classify_block(&lite_block, &nu_context.registry);
|
nu_context.scope.enter_scope();
|
||||||
let locations = completion::engine::completion_location(line, &classified_block.block, pos);
|
let (block, _) = nu_parser::parse(line, 0, &nu_context.scope);
|
||||||
|
nu_context.scope.exit_scope();
|
||||||
|
|
||||||
|
let locations = completion::engine::completion_location(line, &block, pos);
|
||||||
|
|
||||||
let matcher = nu_data::config::config(Tag::unknown())
|
let matcher = nu_data::config::config(Tag::unknown())
|
||||||
.ok()
|
.ok()
|
||||||
|
@ -1,13 +1,8 @@
|
|||||||
use std::borrow::Cow::{self, Owned};
|
|
||||||
|
|
||||||
use nu_parser::SignatureRegistry;
|
|
||||||
use nu_source::{Tag, Tagged};
|
|
||||||
|
|
||||||
use crate::completion;
|
use crate::completion;
|
||||||
use crate::evaluation_context::EvaluationContext;
|
|
||||||
use crate::shell::completer::NuCompleter;
|
use crate::shell::completer::NuCompleter;
|
||||||
use crate::shell::painter::Painter;
|
use nu_engine::{DefaultPalette, EvaluationContext, Painter};
|
||||||
use crate::shell::palette::DefaultPalette;
|
use nu_source::{Tag, Tagged};
|
||||||
|
use std::borrow::Cow::{self, Owned};
|
||||||
|
|
||||||
pub struct Helper {
|
pub struct Helper {
|
||||||
completer: NuCompleter,
|
completer: NuCompleter,
|
||||||
@ -87,11 +82,7 @@ impl rustyline::highlight::Highlighter for Helper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn highlight<'l>(&self, line: &'l str, _pos: usize) -> Cow<'l, str> {
|
fn highlight<'l>(&self, line: &'l str, _pos: usize) -> Cow<'l, str> {
|
||||||
Painter::paint_string(
|
Painter::paint_string(line, &self.context.scope, &DefaultPalette {})
|
||||||
line,
|
|
||||||
&self.context.registry().clone_box(),
|
|
||||||
&DefaultPalette {},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn highlight_char(&self, _line: &str, _pos: usize) -> bool {
|
fn highlight_char(&self, _line: &str, _pos: usize) -> bool {
|
||||||
@ -121,7 +112,14 @@ impl rustyline::validate::Validator for NuValidator {
|
|||||||
) -> rustyline::Result<rustyline::validate::ValidationResult> {
|
) -> rustyline::Result<rustyline::validate::ValidationResult> {
|
||||||
let src = ctx.input();
|
let src = ctx.input();
|
||||||
|
|
||||||
let (_, err) = nu_parser::lite_parse(src, 0);
|
let (tokens, err) = nu_parser::lex(src, 0);
|
||||||
|
if let Some(err) = err {
|
||||||
|
if let nu_errors::ParseErrorReason::Eof { .. } = err.reason() {
|
||||||
|
return Ok(rustyline::validate::ValidationResult::Incomplete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let (_, err) = nu_parser::block(tokens);
|
||||||
|
|
||||||
if let Some(err) = err {
|
if let Some(err) = err {
|
||||||
if let nu_errors::ParseErrorReason::Eof { .. } = err.reason() {
|
if let nu_errors::ParseErrorReason::Eof { .. } = err.reason() {
|
||||||
@ -146,3 +144,51 @@ fn vec_tag<T>(input: Vec<Tagged<T>>) -> Option<Tag> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl rustyline::Helper for Helper {}
|
impl rustyline::Helper for Helper {}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use nu_engine::basic_evaluation_context;
|
||||||
|
use rustyline::completion::Completer;
|
||||||
|
use rustyline::line_buffer::LineBuffer;
|
||||||
|
|
||||||
|
#[ignore]
|
||||||
|
#[test]
|
||||||
|
fn closing_quote_should_replaced() {
|
||||||
|
let text = "cd \"folder with spaces\\subdirectory\\\"";
|
||||||
|
let replacement = "\"folder with spaces\\subdirectory\\subsubdirectory\\\"";
|
||||||
|
|
||||||
|
let mut buffer = LineBuffer::with_capacity(256);
|
||||||
|
buffer.insert_str(0, text);
|
||||||
|
buffer.set_pos(text.len() - 1);
|
||||||
|
|
||||||
|
let helper = Helper::new(basic_evaluation_context().unwrap(), None);
|
||||||
|
|
||||||
|
helper.update(&mut buffer, "cd ".len(), &replacement);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
buffer.as_str(),
|
||||||
|
"cd \"folder with spaces\\subdirectory\\subsubdirectory\\\""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[ignore]
|
||||||
|
#[test]
|
||||||
|
fn replacement_with_cursor_in_text() {
|
||||||
|
let text = "cd \"folder with spaces\\subdirectory\\\"";
|
||||||
|
let replacement = "\"folder with spaces\\subdirectory\\subsubdirectory\\\"";
|
||||||
|
|
||||||
|
let mut buffer = LineBuffer::with_capacity(256);
|
||||||
|
buffer.insert_str(0, text);
|
||||||
|
buffer.set_pos(text.len() - 30);
|
||||||
|
|
||||||
|
let helper = Helper::new(basic_evaluation_context().unwrap(), None);
|
||||||
|
|
||||||
|
helper.update(&mut buffer, "cd ".len(), &replacement);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
buffer.as_str(),
|
||||||
|
"cd \"folder with spaces\\subdirectory\\subsubdirectory\\\""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
use crate::CommandRegistry;
|
#![allow(dead_code)]
|
||||||
|
use itertools::{merge_join_by, EitherOrBoth, Itertools};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
use log::trace;
|
||||||
|
use nu_engine::Scope;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_parser::SignatureRegistry;
|
use nu_parser::ParserScope;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
hir::{
|
hir::{
|
||||||
Binary, Block, ClassifiedCommand, Commands, Expression, Literal, NamedArguments,
|
Binary, Block, ClassifiedCommand, Expression, Literal, NamedArguments, NamedValue,
|
||||||
NamedValue, Operator, SpannedExpression,
|
Operator, Pipeline, SpannedExpression,
|
||||||
},
|
},
|
||||||
NamedType, PositionalType, Signature, SyntaxShape,
|
NamedType, PositionalType, Signature, SyntaxShape,
|
||||||
};
|
};
|
||||||
@ -14,9 +16,6 @@ use nu_source::Span;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{collections::HashMap, hash::Hash};
|
use std::{collections::HashMap, hash::Hash};
|
||||||
|
|
||||||
use itertools::{merge_join_by, EitherOrBoth, Itertools};
|
|
||||||
use log::trace;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct VarDeclaration {
|
pub struct VarDeclaration {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@ -290,13 +289,13 @@ fn get_shape_of_expr(expr: &SpannedExpression) -> Option<SyntaxShape> {
|
|||||||
Expression::ExternalWord => Some(SyntaxShape::String),
|
Expression::ExternalWord => Some(SyntaxShape::String),
|
||||||
Expression::Synthetic(_) => Some(SyntaxShape::String),
|
Expression::Synthetic(_) => Some(SyntaxShape::String),
|
||||||
|
|
||||||
Expression::Binary(_) => Some(SyntaxShape::Math),
|
Expression::Binary(_) => Some(SyntaxShape::RowCondition),
|
||||||
Expression::Range(_) => Some(SyntaxShape::Range),
|
Expression::Range(_) => Some(SyntaxShape::Range),
|
||||||
Expression::List(_) => Some(SyntaxShape::Table),
|
Expression::List(_) => Some(SyntaxShape::Table),
|
||||||
Expression::Boolean(_) => Some(SyntaxShape::String),
|
Expression::Boolean(_) => Some(SyntaxShape::String),
|
||||||
|
|
||||||
Expression::Path(_) => Some(SyntaxShape::ColumnPath),
|
Expression::Path(_) => Some(SyntaxShape::ColumnPath),
|
||||||
Expression::FilePath(_) => Some(SyntaxShape::Path),
|
Expression::FilePath(_) => Some(SyntaxShape::FilePath),
|
||||||
Expression::Block(_) => Some(SyntaxShape::Block),
|
Expression::Block(_) => Some(SyntaxShape::Block),
|
||||||
Expression::ExternalCommand(_) => Some(SyntaxShape::String),
|
Expression::ExternalCommand(_) => Some(SyntaxShape::String),
|
||||||
Expression::Table(_, _) => Some(SyntaxShape::Table),
|
Expression::Table(_, _) => Some(SyntaxShape::Table),
|
||||||
@ -318,14 +317,14 @@ fn spanned_to_binary(bin_spanned: &SpannedExpression) -> &Binary {
|
|||||||
///Returns result shape of this math expr otherwise
|
///Returns result shape of this math expr otherwise
|
||||||
fn get_result_shape_of_math_expr(
|
fn get_result_shape_of_math_expr(
|
||||||
bin: &Binary,
|
bin: &Binary,
|
||||||
(pipeline_idx, pipeline): (usize, &Commands),
|
(pipeline_idx, pipeline): (usize, &Pipeline),
|
||||||
registry: &CommandRegistry,
|
scope: &Scope,
|
||||||
) -> Result<Option<SyntaxShape>, ShellError> {
|
) -> Result<Option<SyntaxShape>, ShellError> {
|
||||||
let mut shapes: Vec<Option<SyntaxShape>> = vec![];
|
let mut shapes: Vec<Option<SyntaxShape>> = vec![];
|
||||||
for expr in &[&bin.left, &bin.right] {
|
for expr in &[&bin.left, &bin.right] {
|
||||||
let shape = match &expr.expr {
|
let shape = match &expr.expr {
|
||||||
Expression::Binary(deep_binary) => {
|
Expression::Binary(deep_binary) => {
|
||||||
get_result_shape_of_math_expr(&deep_binary, (pipeline_idx, pipeline), registry)?
|
get_result_shape_of_math_expr(&deep_binary, (pipeline_idx, pipeline), scope)?
|
||||||
}
|
}
|
||||||
_ => get_shape_of_expr(expr),
|
_ => get_shape_of_expr(expr),
|
||||||
};
|
};
|
||||||
@ -356,7 +355,7 @@ impl VarSyntaxShapeDeductor {
|
|||||||
pub fn infer_vars(
|
pub fn infer_vars(
|
||||||
vars_to_find: &[VarDeclaration],
|
vars_to_find: &[VarDeclaration],
|
||||||
block: &Block,
|
block: &Block,
|
||||||
registry: &CommandRegistry,
|
scope: &Scope,
|
||||||
) -> Result<Vec<(VarDeclaration, Option<Deduction>)>, ShellError> {
|
) -> Result<Vec<(VarDeclaration, Option<Deduction>)>, ShellError> {
|
||||||
trace!("Deducing shapes for vars: {:?}", vars_to_find);
|
trace!("Deducing shapes for vars: {:?}", vars_to_find);
|
||||||
|
|
||||||
@ -367,7 +366,7 @@ impl VarSyntaxShapeDeductor {
|
|||||||
dependencies: Vec::new(),
|
dependencies: Vec::new(),
|
||||||
dependencies_on_result_type: Vec::new(),
|
dependencies_on_result_type: Vec::new(),
|
||||||
};
|
};
|
||||||
deducer.infer_shape(block, registry)?;
|
deducer.infer_shape(block, scope)?;
|
||||||
|
|
||||||
deducer.solve_dependencies();
|
deducer.solve_dependencies();
|
||||||
trace!("Found shapes for vars: {:?}", deducer.inferences);
|
trace!("Found shapes for vars: {:?}", deducer.inferences);
|
||||||
@ -386,24 +385,22 @@ impl VarSyntaxShapeDeductor {
|
|||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_shape(&mut self, block: &Block, registry: &CommandRegistry) -> Result<(), ShellError> {
|
fn infer_shape(&mut self, block: &Block, scope: &Scope) -> Result<(), ShellError> {
|
||||||
trace!("Infering vars in shape");
|
trace!("Infering vars in shape");
|
||||||
for pipeline in &block.block {
|
for group in &block.block {
|
||||||
self.infer_pipeline(pipeline, registry)?;
|
for pipeline in &group.pipelines {
|
||||||
|
self.infer_pipeline(pipeline, scope)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn infer_pipeline(
|
pub fn infer_pipeline(&mut self, pipeline: &Pipeline, scope: &Scope) -> Result<(), ShellError> {
|
||||||
&mut self,
|
|
||||||
pipeline: &Commands,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<(), ShellError> {
|
|
||||||
trace!("Infering vars in pipeline");
|
trace!("Infering vars in pipeline");
|
||||||
for (cmd_pipeline_idx, classified) in pipeline.list.iter().enumerate() {
|
for (cmd_pipeline_idx, classified) in pipeline.list.iter().enumerate() {
|
||||||
match &classified {
|
match &classified {
|
||||||
ClassifiedCommand::Internal(internal) => {
|
ClassifiedCommand::Internal(internal) => {
|
||||||
if let Some(signature) = registry.get(&internal.name) {
|
if let Some(signature) = scope.get_signature(&internal.name) {
|
||||||
//When the signature is given vars directly used as named or positional
|
//When the signature is given vars directly used as named or positional
|
||||||
//arguments can be deduced
|
//arguments can be deduced
|
||||||
//e.G. cp $var1 $var2
|
//e.G. cp $var1 $var2
|
||||||
@ -426,7 +423,7 @@ impl VarSyntaxShapeDeductor {
|
|||||||
self.infer_shapes_in_expr(
|
self.infer_shapes_in_expr(
|
||||||
(cmd_pipeline_idx, pipeline),
|
(cmd_pipeline_idx, pipeline),
|
||||||
pos_expr,
|
pos_expr,
|
||||||
registry,
|
scope,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -437,7 +434,7 @@ impl VarSyntaxShapeDeductor {
|
|||||||
self.infer_shapes_in_expr(
|
self.infer_shapes_in_expr(
|
||||||
(cmd_pipeline_idx, pipeline),
|
(cmd_pipeline_idx, pipeline),
|
||||||
named_expr,
|
named_expr,
|
||||||
registry,
|
scope,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -448,11 +445,7 @@ impl VarSyntaxShapeDeductor {
|
|||||||
"Infering shapes in ClassifiedCommand::Expr: {:?}",
|
"Infering shapes in ClassifiedCommand::Expr: {:?}",
|
||||||
spanned_expr
|
spanned_expr
|
||||||
);
|
);
|
||||||
self.infer_shapes_in_expr(
|
self.infer_shapes_in_expr((cmd_pipeline_idx, pipeline), spanned_expr, scope)?;
|
||||||
(cmd_pipeline_idx, pipeline),
|
|
||||||
spanned_expr,
|
|
||||||
registry,
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
ClassifiedCommand::Dynamic(_) | ClassifiedCommand::Error(_) => unimplemented!(),
|
ClassifiedCommand::Dynamic(_) | ClassifiedCommand::Error(_) => unimplemented!(),
|
||||||
}
|
}
|
||||||
@ -534,25 +527,25 @@ impl VarSyntaxShapeDeductor {
|
|||||||
|
|
||||||
fn infer_shapes_in_expr(
|
fn infer_shapes_in_expr(
|
||||||
&mut self,
|
&mut self,
|
||||||
(pipeline_idx, pipeline): (usize, &Commands),
|
(pipeline_idx, pipeline): (usize, &Pipeline),
|
||||||
spanned_expr: &SpannedExpression,
|
spanned_expr: &SpannedExpression,
|
||||||
registry: &CommandRegistry,
|
scope: &Scope,
|
||||||
) -> Result<(), ShellError> {
|
) -> Result<(), ShellError> {
|
||||||
match &spanned_expr.expr {
|
match &spanned_expr.expr {
|
||||||
Expression::Binary(_) => {
|
Expression::Binary(_) => {
|
||||||
trace!("Infering vars in bin expr");
|
trace!("Infering vars in bin expr");
|
||||||
self.infer_shapes_in_binary_expr((pipeline_idx, pipeline), spanned_expr, registry)?;
|
self.infer_shapes_in_binary_expr((pipeline_idx, pipeline), spanned_expr, scope)?;
|
||||||
}
|
}
|
||||||
Expression::Block(b) => {
|
Expression::Block(b) => {
|
||||||
trace!("Infering vars in block");
|
trace!("Infering vars in block");
|
||||||
self.infer_shape(&b, registry)?;
|
self.infer_shape(&b, scope)?;
|
||||||
}
|
}
|
||||||
Expression::Path(path) => {
|
Expression::Path(path) => {
|
||||||
trace!("Infering vars in path");
|
trace!("Infering vars in path");
|
||||||
match &path.head.expr {
|
match &path.head.expr {
|
||||||
//PathMember can't be var yet (?)
|
//PathMember can't be var yet (?)
|
||||||
//TODO Iterate over path parts and find var when implemented
|
//TODO Iterate over path parts and find var when implemented
|
||||||
Expression::Invocation(b) => self.infer_shape(&b, registry)?,
|
Expression::Invocation(b) => self.infer_shape(&b, scope)?,
|
||||||
Expression::Variable(var_name, span) => {
|
Expression::Variable(var_name, span) => {
|
||||||
self.checked_insert(
|
self.checked_insert(
|
||||||
&VarUsage::new(var_name, span),
|
&VarUsage::new(var_name, span),
|
||||||
@ -593,12 +586,12 @@ impl VarSyntaxShapeDeductor {
|
|||||||
Expression::List(inner_exprs) => {
|
Expression::List(inner_exprs) => {
|
||||||
trace!("Infering vars in list");
|
trace!("Infering vars in list");
|
||||||
for expr in inner_exprs {
|
for expr in inner_exprs {
|
||||||
self.infer_shapes_in_expr((pipeline_idx, pipeline), expr, registry)?;
|
self.infer_shapes_in_expr((pipeline_idx, pipeline), expr, scope)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::Invocation(invoc) => {
|
Expression::Invocation(invoc) => {
|
||||||
trace!("Infering vars in invocation: {:?}", invoc);
|
trace!("Infering vars in invocation: {:?}", invoc);
|
||||||
self.infer_shape(invoc, registry)?;
|
self.infer_shape(invoc, scope)?;
|
||||||
}
|
}
|
||||||
Expression::Table(header, _rows) => {
|
Expression::Table(header, _rows) => {
|
||||||
self.infer_shapes_in_table_header(header)?;
|
self.infer_shapes_in_table_header(header)?;
|
||||||
@ -660,11 +653,11 @@ impl VarSyntaxShapeDeductor {
|
|||||||
(var, expr): (&VarUsage, &SpannedExpression),
|
(var, expr): (&VarUsage, &SpannedExpression),
|
||||||
//source_bin is binary having var on one and expr on other side
|
//source_bin is binary having var on one and expr on other side
|
||||||
source_bin: &SpannedExpression,
|
source_bin: &SpannedExpression,
|
||||||
(pipeline_idx, pipeline): (usize, &Commands),
|
(pipeline_idx, pipeline): (usize, &Pipeline),
|
||||||
registry: &CommandRegistry,
|
scope: &Scope,
|
||||||
) -> Result<Option<SyntaxShape>, ShellError> {
|
) -> Result<Option<SyntaxShape>, ShellError> {
|
||||||
get_result_shape_of_math_expr(spanned_to_binary(expr), (pipeline_idx, pipeline), registry)
|
get_result_shape_of_math_expr(spanned_to_binary(expr), (pipeline_idx, pipeline), scope).map(
|
||||||
.map(|shape| {
|
|shape| {
|
||||||
if shape == None {
|
if shape == None {
|
||||||
self.dependencies_on_result_type.push((
|
self.dependencies_on_result_type.push((
|
||||||
var.clone(),
|
var.clone(),
|
||||||
@ -673,7 +666,8 @@ impl VarSyntaxShapeDeductor {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
shape
|
shape
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_shape_of_binary_arg_or_insert_dependency(
|
fn get_shape_of_binary_arg_or_insert_dependency(
|
||||||
@ -682,8 +676,8 @@ impl VarSyntaxShapeDeductor {
|
|||||||
(var, expr): (&VarUsage, &SpannedExpression),
|
(var, expr): (&VarUsage, &SpannedExpression),
|
||||||
//source_bin is binary having var on one and expr on other side
|
//source_bin is binary having var on one and expr on other side
|
||||||
source_bin: &SpannedExpression,
|
source_bin: &SpannedExpression,
|
||||||
(pipeline_idx, pipeline): (usize, &Commands),
|
(pipeline_idx, pipeline): (usize, &Pipeline),
|
||||||
registry: &CommandRegistry,
|
scope: &Scope,
|
||||||
) -> Result<Option<SyntaxShape>, ShellError> {
|
) -> Result<Option<SyntaxShape>, ShellError> {
|
||||||
trace!("Getting shape of binary arg {:?} for var {:?}", expr, var);
|
trace!("Getting shape of binary arg {:?} for var {:?}", expr, var);
|
||||||
if let Some(shape) = self.get_shape_of_expr_or_insert_dependency(
|
if let Some(shape) = self.get_shape_of_expr_or_insert_dependency(
|
||||||
@ -695,11 +689,12 @@ impl VarSyntaxShapeDeductor {
|
|||||||
match shape {
|
match shape {
|
||||||
//If the shape of expr is math, we return the result shape of this math expr if
|
//If the shape of expr is math, we return the result shape of this math expr if
|
||||||
//possible
|
//possible
|
||||||
SyntaxShape::Math => self.get_result_shape_of_math_expr_or_insert_dependency(
|
SyntaxShape::RowCondition => self
|
||||||
|
.get_result_shape_of_math_expr_or_insert_dependency(
|
||||||
(var, expr),
|
(var, expr),
|
||||||
source_bin,
|
source_bin,
|
||||||
(pipeline_idx, pipeline),
|
(pipeline_idx, pipeline),
|
||||||
registry,
|
scope,
|
||||||
),
|
),
|
||||||
_ => Ok(Some(shape)),
|
_ => Ok(Some(shape)),
|
||||||
}
|
}
|
||||||
@ -714,8 +709,7 @@ impl VarSyntaxShapeDeductor {
|
|||||||
var: &VarUsage,
|
var: &VarUsage,
|
||||||
bin_spanned: &SpannedExpression,
|
bin_spanned: &SpannedExpression,
|
||||||
list: &[SpannedExpression],
|
list: &[SpannedExpression],
|
||||||
(_pipeline_idx, _pipeline): (usize, &Commands),
|
(_pipeline_idx, _pipeline): (usize, &Pipeline),
|
||||||
_registry: &CommandRegistry,
|
|
||||||
) -> Option<Vec<SyntaxShape>> {
|
) -> Option<Vec<SyntaxShape>> {
|
||||||
let shapes_in_list = list
|
let shapes_in_list = list
|
||||||
.iter()
|
.iter()
|
||||||
@ -740,8 +734,8 @@ impl VarSyntaxShapeDeductor {
|
|||||||
var_side: BinarySide,
|
var_side: BinarySide,
|
||||||
//Binary having expr on one side and var on other
|
//Binary having expr on one side and var on other
|
||||||
bin_spanned: &SpannedExpression,
|
bin_spanned: &SpannedExpression,
|
||||||
(pipeline_idx, pipeline): (usize, &Commands),
|
(pipeline_idx, pipeline): (usize, &Pipeline),
|
||||||
registry: &CommandRegistry,
|
scope: &Scope,
|
||||||
) -> Result<(), ShellError> {
|
) -> Result<(), ShellError> {
|
||||||
trace!("Infering shapes between var {:?} and expr {:?}", var, expr);
|
trace!("Infering shapes between var {:?} and expr {:?}", var, expr);
|
||||||
let bin = spanned_to_binary(bin_spanned);
|
let bin = spanned_to_binary(bin_spanned);
|
||||||
@ -774,7 +768,6 @@ impl VarSyntaxShapeDeductor {
|
|||||||
bin_spanned,
|
bin_spanned,
|
||||||
&list,
|
&list,
|
||||||
(pipeline_idx, pipeline),
|
(pipeline_idx, pipeline),
|
||||||
registry,
|
|
||||||
);
|
);
|
||||||
match shapes_in_list {
|
match shapes_in_list {
|
||||||
None => {}
|
None => {}
|
||||||
@ -839,7 +832,7 @@ impl VarSyntaxShapeDeductor {
|
|||||||
(var, expr),
|
(var, expr),
|
||||||
bin_spanned,
|
bin_spanned,
|
||||||
(pipeline_idx, pipeline),
|
(pipeline_idx, pipeline),
|
||||||
registry,
|
scope,
|
||||||
)? {
|
)? {
|
||||||
match shape {
|
match shape {
|
||||||
SyntaxShape::Int | SyntaxShape::Number => {
|
SyntaxShape::Int | SyntaxShape::Number => {
|
||||||
@ -872,7 +865,7 @@ impl VarSyntaxShapeDeductor {
|
|||||||
(var, expr),
|
(var, expr),
|
||||||
bin_spanned,
|
bin_spanned,
|
||||||
(pipeline_idx, pipeline),
|
(pipeline_idx, pipeline),
|
||||||
registry,
|
scope,
|
||||||
)? {
|
)? {
|
||||||
self.checked_insert(
|
self.checked_insert(
|
||||||
var,
|
var,
|
||||||
@ -892,9 +885,9 @@ impl VarSyntaxShapeDeductor {
|
|||||||
|
|
||||||
fn infer_shapes_in_binary_expr(
|
fn infer_shapes_in_binary_expr(
|
||||||
&mut self,
|
&mut self,
|
||||||
(pipeline_idx, pipeline): (usize, &Commands),
|
(pipeline_idx, pipeline): (usize, &Pipeline),
|
||||||
bin_spanned: &SpannedExpression,
|
bin_spanned: &SpannedExpression,
|
||||||
registry: &CommandRegistry,
|
scope: &Scope,
|
||||||
) -> Result<(), ShellError> {
|
) -> Result<(), ShellError> {
|
||||||
let bin = spanned_to_binary(bin_spanned);
|
let bin = spanned_to_binary(bin_spanned);
|
||||||
if let Expression::Variable(left_var_name, l_span) = &bin.left.expr {
|
if let Expression::Variable(left_var_name, l_span) = &bin.left.expr {
|
||||||
@ -903,7 +896,7 @@ impl VarSyntaxShapeDeductor {
|
|||||||
BinarySide::Left,
|
BinarySide::Left,
|
||||||
bin_spanned,
|
bin_spanned,
|
||||||
(pipeline_idx, pipeline),
|
(pipeline_idx, pipeline),
|
||||||
registry,
|
scope,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -913,13 +906,13 @@ impl VarSyntaxShapeDeductor {
|
|||||||
BinarySide::Right,
|
BinarySide::Right,
|
||||||
bin_spanned,
|
bin_spanned,
|
||||||
(pipeline_idx, pipeline),
|
(pipeline_idx, pipeline),
|
||||||
registry,
|
scope,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
//Descend deeper into bin tree
|
//Descend deeper into bin tree
|
||||||
self.infer_shapes_in_expr((pipeline_idx, pipeline), &bin.right, registry)?;
|
self.infer_shapes_in_expr((pipeline_idx, pipeline), &bin.right, scope)?;
|
||||||
//Descend deeper into bin tree
|
//Descend deeper into bin tree
|
||||||
self.infer_shapes_in_expr((pipeline_idx, pipeline), &bin.left, registry)?;
|
self.infer_shapes_in_expr((pipeline_idx, pipeline), &bin.left, scope)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,299 +0,0 @@
|
|||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use nu_test_support::nu;
|
|
||||||
use nu_test_support::playground::Playground;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn alias_without_args() {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
alias -i e [] {^echo hi nushell | to json}
|
|
||||||
e
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
assert_eq!(actual.out, "\"hi nushell\\n\"");
|
|
||||||
#[cfg(windows)]
|
|
||||||
assert_eq!(actual.out, "\"hi nushell\\r\\n\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn alias_args_work() {
|
|
||||||
Playground::setup("append_test_2", |dirs, _| {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.root(),
|
|
||||||
r#"
|
|
||||||
alias -i double_echo [b] {echo $b | to json}
|
|
||||||
double_echo 1kb
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(actual.out, "1024");
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn alias_args_double_echo() {
|
|
||||||
Playground::setup("append_test_1", |dirs, _| {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.root(),
|
|
||||||
r#"
|
|
||||||
alias -i double_echo [a b] {echo $a $b}
|
|
||||||
double_echo 1 2 | to json
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(actual.out, "[1,2]");
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
fn alias_parses_path_tilde() {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: "tests/fixtures/formats",
|
|
||||||
r#"
|
|
||||||
alias -i new-cd [dir] { cd $dir }
|
|
||||||
new-cd ~
|
|
||||||
pwd
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
//If this fails for you, check for any special unicode characters in your ~ path
|
|
||||||
assert!(actual.out.chars().filter(|c| *c == '/').count() == 2);
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
assert!(actual.out.contains("home"));
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
assert!(actual.out.contains("Users"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn alias_missing_args_work() {
|
|
||||||
Playground::setup("append_test_1", |dirs, _| {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.root(),
|
|
||||||
r#"
|
|
||||||
alias double_echo [a b] {^echo $a $b}
|
|
||||||
double_echo bob
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(actual.out, "bob");
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore]
|
|
||||||
fn alias_with_in_str_var_right() {
|
|
||||||
//Failing
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
alias -i lw [newbie] {echo 1 2 3 | where "hello_world" in $newbie | to json}
|
|
||||||
lw [hello_world_test_repo]
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
assert_eq!(actual.out, "[1,2,3]");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn alias_with_in_str_var_right_mismatch() {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
alias -i lw [rust_newbie] { echo 1 2 3 | where "hello_world" in $rust_newbie | to json }
|
|
||||||
lw [ big_brain_programmer ]
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
assert_eq!(actual.out, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn alias_with_in_err() {
|
|
||||||
//in operator only applicable for strings atm
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
alias -i lw [p] {echo 1 2 3 | where $p in [1 3 2] | to json}
|
|
||||||
lw /root/sys
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
assert!(actual.err.contains("Type"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore]
|
|
||||||
fn alias_with_contains() {
|
|
||||||
//Failing
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
alias -i lw [p] {echo 1 2 3 | where $p in [1 hi 3] | to json}
|
|
||||||
lw 1
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
assert_eq!(actual.out, "[1,2,3]");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore]
|
|
||||||
fn alias_with_contains_and_var_is_right_side() {
|
|
||||||
//Failing
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
alias -i lw [p] {echo 1 2 3 | where 1 in $p | to json}
|
|
||||||
lw [1 2 hi]
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
assert_eq!(actual.out, "[1,2,3]");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn error_alias_wrong_shape_shallow() {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
alias -i round-to [num digits] { echo $num | str from -d $digits }
|
|
||||||
round-to 3.45 a
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(actual.err.contains("Type"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn error_alias_wrong_shape_deep_invocation() {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
alias -i round-to [nums digits] { echo $nums | each {= $(str from -d $digits)}}
|
|
||||||
round-to 3.45 a
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(actual.err.contains("Type"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn error_alias_wrong_shape_deep_binary() {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
alias -i round-plus-one [nums digits] { echo $nums | each {= $(str from -d $digits | str to-decimal) + 1}}
|
|
||||||
round-plus-one 3.45 a
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(actual.err.contains("Type"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn error_alias_wrong_shape_deeper_binary() {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
alias -i round-one-more [num digits] { echo $num | str from -d $(= $digits + 1) }
|
|
||||||
round-one-more 3.45 a
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(actual.err.contains("Type"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn error_alias_syntax_shape_clash() {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
alias -i clash [a] { echo 1.1 2 3 | each { str from -d $a } | range $a }
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(actual.err.contains("Contrary types for variable $a"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore]
|
|
||||||
fn alias_with_math_var() {
|
|
||||||
//Failing
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
alias -i echo_math [math] { echo {= 1 + $math}}
|
|
||||||
echo_math 1 + 1 | to json
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(actual.out, "3");
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
#[ignore]
|
|
||||||
fn alias_with_math_var2() {
|
|
||||||
//Failing
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
alias -i round-plus-one [nums digits math] { echo $nums | each {= $(str from -d $digits | str to-decimal) + $math}}
|
|
||||||
round-plus-one 3.45 2 1 + 1 | to json
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
assert_eq!(actual.out, "5.45");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn alias_with_true_and_false() {
|
|
||||||
//https://github.com/nushell/nushell/issues/2416
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
alias -i is_empty [a] {if $(echo $a | empty?) == $true { echo $true } { echo $false }}
|
|
||||||
is_empty ""
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
assert!(actual.out.contains("true"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn alias_sent_env() {
|
|
||||||
//https://github.com/nushell/nushell/issues/1835
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
alias -i set-env [name value] { echo $nu.env | insert $name $value | get SHELL | to json }
|
|
||||||
set-env SHELL /bin/nu
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
assert_eq!(actual.out, "\"/bin/nu\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore]
|
|
||||||
fn alias_with_math_arg() {
|
|
||||||
//Failing
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
alias -i lswh [math] { echo 1 2 3 | where $math | to json }
|
|
||||||
lswh $it > 2
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
assert_eq!(actual.out, "3");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
fn alias_ls() {
|
|
||||||
//https://github.com/nushell/nushell/issues/1632
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
touch /tmp/nushell_alias_test
|
|
||||||
alias -i l [x] { ls $x }
|
|
||||||
l /tmp | to json
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
assert!(actual.out.contains("nushell_alias_test"));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
use nu_test_support::{nu, pipeline};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn echo_range_is_lazy() {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: "tests/fixtures/formats", pipeline(
|
|
||||||
r#"
|
|
||||||
echo 1..10000000000 | first 3 | to json
|
|
||||||
"#
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(actual.out, "[1,2,3]");
|
|
||||||
}
|
|
132
crates/nu-command/Cargo.toml
Normal file
132
crates/nu-command/Cargo.toml
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
[package]
|
||||||
|
authors = ["The Nu Project Contributors"]
|
||||||
|
build = "build.rs"
|
||||||
|
description = "CLI for nushell"
|
||||||
|
edition = "2018"
|
||||||
|
license = "MIT"
|
||||||
|
name = "nu-command"
|
||||||
|
version = "0.26.0"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
doctest = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
nu-data = { version = "0.26.0", path = "../nu-data" }
|
||||||
|
nu-engine = { version = "0.26.0", path = "../nu-engine" }
|
||||||
|
nu-errors = { version = "0.26.0", path = "../nu-errors" }
|
||||||
|
nu-json = { version = "0.26.0", path = "../nu-json" }
|
||||||
|
nu-parser = { version = "0.26.0", path = "../nu-parser" }
|
||||||
|
nu-plugin = { version = "0.26.0", path = "../nu-plugin" }
|
||||||
|
nu-protocol = { version = "0.26.0", path = "../nu-protocol" }
|
||||||
|
nu-source = { version = "0.26.0", path = "../nu-source" }
|
||||||
|
nu-stream = { version = "0.26.0", path = "../nu-stream" }
|
||||||
|
nu-table = { version = "0.26.0", path = "../nu-table" }
|
||||||
|
nu-test-support = { version = "0.26.0", path = "../nu-test-support" }
|
||||||
|
nu-value-ext = { version = "0.26.0", path = "../nu-value-ext" }
|
||||||
|
|
||||||
|
Inflector = "0.11"
|
||||||
|
ansi_term = "0.12.1"
|
||||||
|
arboard = { version = "1.1.0", optional = true }
|
||||||
|
async-recursion = "0.3.1"
|
||||||
|
async-trait = "0.1.40"
|
||||||
|
base64 = "0.13.0"
|
||||||
|
bigdecimal = { version = "0.2.0", features = ["serde"] }
|
||||||
|
byte-unit = "4.0.9"
|
||||||
|
bytes = "0.5.6"
|
||||||
|
calamine = "0.16.1"
|
||||||
|
chrono = { version = "0.4.15", features = ["serde"] }
|
||||||
|
chrono-tz = "0.5.3"
|
||||||
|
clap = "2.33.3"
|
||||||
|
codespan-reporting = "0.11.0"
|
||||||
|
csv = "1.1.3"
|
||||||
|
ctrlc = { version = "3.1.6", optional = true }
|
||||||
|
derive-new = "0.5.8"
|
||||||
|
directories-next = { version = "2.0.0", optional = true }
|
||||||
|
dirs-next = { version = "2.0.0", optional = true }
|
||||||
|
dtparse = "1.2.0"
|
||||||
|
dunce = "1.0.1"
|
||||||
|
eml-parser = "0.1.0"
|
||||||
|
encoding_rs = "0.8.24"
|
||||||
|
filesize = "0.2.0"
|
||||||
|
fs_extra = "1.2.0"
|
||||||
|
futures = { version = "0.3.5", features = ["compat", "io-compat"] }
|
||||||
|
futures-util = "0.3.8"
|
||||||
|
futures_codec = "0.4.1"
|
||||||
|
getset = "0.1.1"
|
||||||
|
glob = "0.3.0"
|
||||||
|
htmlescape = "0.3.1"
|
||||||
|
ical = "0.7.0"
|
||||||
|
ichwh = { version = "0.3.4", optional = true }
|
||||||
|
indexmap = { version = "1.6.0", features = ["serde-1"] }
|
||||||
|
itertools = "0.10.0"
|
||||||
|
lazy_static = "1.*"
|
||||||
|
log = "0.4.11"
|
||||||
|
meval = "0.2.0"
|
||||||
|
num-bigint = { version = "0.3.0", features = ["serde"] }
|
||||||
|
num-format = { version = "0.4.0", features = ["with-num-bigint"] }
|
||||||
|
num-traits = "0.2.12"
|
||||||
|
parking_lot = "0.11.0"
|
||||||
|
pin-utils = "0.1.0"
|
||||||
|
pretty-hex = "0.2.0"
|
||||||
|
ptree = { version = "0.3.0", optional = true }
|
||||||
|
query_interface = "0.3.5"
|
||||||
|
quick-xml = "0.20.0"
|
||||||
|
rand = "0.7.3"
|
||||||
|
rayon = "1.4.0"
|
||||||
|
regex = "1.3.9"
|
||||||
|
roxmltree = "0.14.0"
|
||||||
|
rust-embed = "5.8.0"
|
||||||
|
rustyline = { version = "6.3.0", optional = true }
|
||||||
|
serde = { version = "1.0.115", features = ["derive"] }
|
||||||
|
serde_bytes = "0.11.5"
|
||||||
|
serde_ini = "0.2.0"
|
||||||
|
serde_json = "1.0.57"
|
||||||
|
serde_urlencoded = "0.7.0"
|
||||||
|
serde_yaml = "0.8.13"
|
||||||
|
sha2 = "0.9.1"
|
||||||
|
shellexpand = "2.0.0"
|
||||||
|
strip-ansi-escapes = "0.1.0"
|
||||||
|
sxd-document = "0.3.2"
|
||||||
|
sxd-xpath = "0.4.2"
|
||||||
|
tempfile = "3.1.0"
|
||||||
|
term = { version = "0.6.1", optional = true }
|
||||||
|
term_size = "0.3.2"
|
||||||
|
termcolor = "1.1.0"
|
||||||
|
titlecase = "1.0"
|
||||||
|
toml = "0.5.6"
|
||||||
|
trash = { version = "1.2.0", optional = true }
|
||||||
|
unicode-segmentation = "1.6.0"
|
||||||
|
url = "2.1.1"
|
||||||
|
uuid_crate = { package = "uuid", version = "0.8.1", features = ["v4"], optional = true }
|
||||||
|
which = { version = "4.0.2", optional = true }
|
||||||
|
zip = { version = "0.5.7", optional = true }
|
||||||
|
|
||||||
|
[target.'cfg(unix)'.dependencies]
|
||||||
|
umask = "1.0.0"
|
||||||
|
users = "0.10.0"
|
||||||
|
|
||||||
|
# TODO this will be possible with new dependency resolver
|
||||||
|
# (currently on nightly behind -Zfeatures=itarget):
|
||||||
|
# https://github.com/rust-lang/cargo/issues/7914
|
||||||
|
#[target.'cfg(not(windows))'.dependencies]
|
||||||
|
#num-format = {version = "0.4", features = ["with-system-locale"]}
|
||||||
|
|
||||||
|
[dependencies.rusqlite]
|
||||||
|
features = ["bundled", "blob"]
|
||||||
|
optional = true
|
||||||
|
version = "0.24.2"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
shadow-rs = "0.5"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
quickcheck = "0.9.2"
|
||||||
|
quickcheck_macros = "0.9.1"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
clipboard-cli = ["arboard"]
|
||||||
|
rustyline-support = ["rustyline"]
|
||||||
|
stable = []
|
||||||
|
trash-support = ["trash"]
|
||||||
|
directories = ["directories-next"]
|
||||||
|
dirs = ["dirs-next"]
|
BIN
crates/nu-command/assets/228_themes.zip
Normal file
BIN
crates/nu-command/assets/228_themes.zip
Normal file
Binary file not shown.
3
crates/nu-command/build.rs
Normal file
3
crates/nu-command/build.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fn main() -> shadow_rs::SdResult<()> {
|
||||||
|
shadow_rs::new()
|
||||||
|
}
|
@ -4,11 +4,10 @@ pub(crate) mod macros;
|
|||||||
mod from_delimited_data;
|
mod from_delimited_data;
|
||||||
mod to_delimited_data;
|
mod to_delimited_data;
|
||||||
|
|
||||||
pub(crate) mod alias;
|
|
||||||
pub(crate) mod ansi;
|
pub(crate) mod ansi;
|
||||||
pub(crate) mod append;
|
pub(crate) mod append;
|
||||||
pub(crate) mod args;
|
pub(crate) mod args;
|
||||||
pub(crate) mod autoenv;
|
pub mod autoenv;
|
||||||
pub(crate) mod autoenv_trust;
|
pub(crate) mod autoenv_trust;
|
||||||
pub(crate) mod autoenv_untrust;
|
pub(crate) mod autoenv_untrust;
|
||||||
pub(crate) mod autoview;
|
pub(crate) mod autoview;
|
||||||
@ -21,7 +20,7 @@ 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;
|
||||||
pub(crate) mod command;
|
pub mod command;
|
||||||
pub(crate) mod compact;
|
pub(crate) mod compact;
|
||||||
pub(crate) mod config;
|
pub(crate) mod config;
|
||||||
pub(crate) mod constants;
|
pub(crate) mod constants;
|
||||||
@ -29,7 +28,9 @@ pub(crate) mod count;
|
|||||||
pub(crate) mod cp;
|
pub(crate) mod cp;
|
||||||
pub(crate) mod date;
|
pub(crate) mod date;
|
||||||
pub(crate) mod debug;
|
pub(crate) mod debug;
|
||||||
|
pub(crate) mod def;
|
||||||
pub(crate) mod default;
|
pub(crate) mod default;
|
||||||
|
pub mod default_context;
|
||||||
pub(crate) mod describe;
|
pub(crate) mod describe;
|
||||||
pub(crate) mod do_;
|
pub(crate) mod do_;
|
||||||
pub(crate) mod drop;
|
pub(crate) mod drop;
|
||||||
@ -72,6 +73,8 @@ pub(crate) mod insert;
|
|||||||
pub(crate) mod into_int;
|
pub(crate) mod into_int;
|
||||||
pub(crate) mod keep;
|
pub(crate) mod keep;
|
||||||
pub(crate) mod last;
|
pub(crate) mod last;
|
||||||
|
pub(crate) mod let_;
|
||||||
|
pub(crate) mod let_env;
|
||||||
pub(crate) mod lines;
|
pub(crate) mod lines;
|
||||||
pub(crate) mod ls;
|
pub(crate) mod ls;
|
||||||
pub(crate) mod math;
|
pub(crate) mod math;
|
||||||
@ -95,7 +98,6 @@ pub(crate) mod reject;
|
|||||||
pub(crate) mod rename;
|
pub(crate) mod rename;
|
||||||
pub(crate) mod reverse;
|
pub(crate) mod reverse;
|
||||||
pub(crate) mod rm;
|
pub(crate) mod rm;
|
||||||
pub(crate) mod run_alias;
|
|
||||||
pub(crate) mod run_external;
|
pub(crate) mod run_external;
|
||||||
pub(crate) mod save;
|
pub(crate) mod save;
|
||||||
pub(crate) mod select;
|
pub(crate) mod select;
|
||||||
@ -107,6 +109,7 @@ pub(crate) mod size;
|
|||||||
pub(crate) mod skip;
|
pub(crate) mod skip;
|
||||||
pub(crate) mod sleep;
|
pub(crate) mod sleep;
|
||||||
pub(crate) mod sort_by;
|
pub(crate) mod sort_by;
|
||||||
|
pub(crate) mod source;
|
||||||
pub(crate) mod split;
|
pub(crate) mod split;
|
||||||
pub(crate) mod split_by;
|
pub(crate) mod split_by;
|
||||||
pub(crate) mod str_;
|
pub(crate) mod str_;
|
||||||
@ -133,11 +136,7 @@ pub(crate) mod wrap;
|
|||||||
|
|
||||||
pub(crate) use autoview::Autoview;
|
pub(crate) use autoview::Autoview;
|
||||||
pub(crate) use cd::Cd;
|
pub(crate) use cd::Cd;
|
||||||
pub(crate) use command::{
|
|
||||||
whole_stream_command, Command, Example, UnevaluatedCallInfo, WholeStreamCommand,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub(crate) use alias::Alias;
|
|
||||||
pub(crate) use ansi::Ansi;
|
pub(crate) use ansi::Ansi;
|
||||||
pub(crate) use append::Command as Append;
|
pub(crate) use append::Command as Append;
|
||||||
pub(crate) use autoenv::Autoenv;
|
pub(crate) use autoenv::Autoenv;
|
||||||
@ -156,6 +155,7 @@ pub(crate) use count::Count;
|
|||||||
pub(crate) use cp::Cpy;
|
pub(crate) use cp::Cpy;
|
||||||
pub(crate) use date::{Date, DateFormat, DateListTimeZone, DateNow, DateToTable, DateToTimeZone};
|
pub(crate) use date::{Date, DateFormat, DateListTimeZone, DateNow, DateToTable, DateToTimeZone};
|
||||||
pub(crate) use debug::Debug;
|
pub(crate) use debug::Debug;
|
||||||
|
pub(crate) use def::Def;
|
||||||
pub(crate) use default::Default;
|
pub(crate) use default::Default;
|
||||||
pub(crate) use describe::Describe;
|
pub(crate) use describe::Describe;
|
||||||
pub(crate) use do_::Do;
|
pub(crate) use do_::Do;
|
||||||
@ -209,6 +209,8 @@ 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;
|
||||||
|
pub(crate) use let_::Let;
|
||||||
|
pub(crate) use let_env::LetEnv;
|
||||||
pub(crate) use lines::Lines;
|
pub(crate) use lines::Lines;
|
||||||
pub(crate) use ls::Ls;
|
pub(crate) use ls::Ls;
|
||||||
pub(crate) use math::{
|
pub(crate) use math::{
|
||||||
@ -252,13 +254,14 @@ pub(crate) use size::Size;
|
|||||||
pub(crate) use skip::{Skip, SkipUntil, SkipWhile};
|
pub(crate) use skip::{Skip, SkipUntil, SkipWhile};
|
||||||
pub(crate) use sleep::Sleep;
|
pub(crate) use sleep::Sleep;
|
||||||
pub(crate) use sort_by::SortBy;
|
pub(crate) use sort_by::SortBy;
|
||||||
|
pub(crate) use source::Source;
|
||||||
pub(crate) use split::{Split, SplitChars, SplitColumn, SplitRow};
|
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, StrLPad, StrLength, StrPascalCase, StrRPad,
|
StrFindReplace, StrFrom, StrIndexOf, StrKebabCase, StrLPad, StrLength, StrPascalCase, StrRPad,
|
||||||
StrReverse, StrScreamingSnakeCase, StrSet, StrSnakeCase, StrStartsWith, StrSubstring,
|
StrReverse, StrScreamingSnakeCase, StrSnakeCase, StrStartsWith, StrSubstring, StrToDatetime,
|
||||||
StrToDatetime, StrToDecimal, StrToInteger, StrTrim, StrTrimLeft, StrTrimRight, StrUpcase,
|
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;
|
||||||
@ -284,8 +287,8 @@ pub(crate) use wrap::Wrap;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::commands::whole_stream_command;
|
|
||||||
use crate::examples::{test_anchors, test_examples};
|
use crate::examples::{test_anchors, test_examples};
|
||||||
|
use nu_engine::{whole_stream_command, Command};
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
|
|
||||||
fn full_tests() -> Vec<Command> {
|
fn full_tests() -> Vec<Command> {
|
||||||
@ -296,6 +299,34 @@ mod tests {
|
|||||||
whole_stream_command(Move),
|
whole_stream_command(Move),
|
||||||
whole_stream_command(Update),
|
whole_stream_command(Update),
|
||||||
whole_stream_command(Empty),
|
whole_stream_command(Empty),
|
||||||
|
// Str Command Suite
|
||||||
|
whole_stream_command(Str),
|
||||||
|
whole_stream_command(StrToDecimal),
|
||||||
|
whole_stream_command(StrToInteger),
|
||||||
|
whole_stream_command(StrDowncase),
|
||||||
|
whole_stream_command(StrUpcase),
|
||||||
|
whole_stream_command(StrCapitalize),
|
||||||
|
whole_stream_command(StrFindReplace),
|
||||||
|
whole_stream_command(StrFrom),
|
||||||
|
whole_stream_command(StrSubstring),
|
||||||
|
whole_stream_command(StrToDatetime),
|
||||||
|
whole_stream_command(StrContains),
|
||||||
|
whole_stream_command(StrIndexOf),
|
||||||
|
whole_stream_command(StrTrim),
|
||||||
|
whole_stream_command(StrTrimLeft),
|
||||||
|
whole_stream_command(StrTrimRight),
|
||||||
|
whole_stream_command(StrStartsWith),
|
||||||
|
whole_stream_command(StrEndsWith),
|
||||||
|
//whole_stream_command(StrCollect),
|
||||||
|
whole_stream_command(StrLength),
|
||||||
|
whole_stream_command(StrLPad),
|
||||||
|
whole_stream_command(StrReverse),
|
||||||
|
whole_stream_command(StrRPad),
|
||||||
|
whole_stream_command(StrCamelCase),
|
||||||
|
whole_stream_command(StrPascalCase),
|
||||||
|
whole_stream_command(StrKebabCase),
|
||||||
|
whole_stream_command(StrSnakeCase),
|
||||||
|
whole_stream_command(StrScreamingSnakeCase),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use ansi_term::Color;
|
use ansi_term::Color;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
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;
|
||||||
@ -9,7 +9,7 @@ pub struct Ansi;
|
|||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct AnsiArgs {
|
struct AnsiArgs {
|
||||||
color: Value,
|
code: Value,
|
||||||
escape: Option<Tagged<String>>,
|
escape: Option<Tagged<String>>,
|
||||||
osc: Option<Tagged<String>>,
|
osc: Option<Tagged<String>>,
|
||||||
}
|
}
|
||||||
@ -23,18 +23,18 @@ impl WholeStreamCommand for Ansi {
|
|||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("ansi")
|
Signature::build("ansi")
|
||||||
.optional(
|
.optional(
|
||||||
"color",
|
"code",
|
||||||
SyntaxShape::Any,
|
SyntaxShape::Any,
|
||||||
"the name of the color to use or 'reset' to reset the color",
|
"the name of the code to use like 'green' or 'reset' to reset the color",
|
||||||
)
|
)
|
||||||
.named(
|
.named(
|
||||||
"escape", // \x1b
|
"escape", // \x1b[
|
||||||
SyntaxShape::Any,
|
SyntaxShape::Any,
|
||||||
"escape sequence without the escape character(s)",
|
"escape sequence without the escape character(s)",
|
||||||
Some('e'),
|
Some('e'),
|
||||||
)
|
)
|
||||||
.named(
|
.named(
|
||||||
"osc",
|
"osc", // \x1b]
|
||||||
SyntaxShape::Any,
|
SyntaxShape::Any,
|
||||||
"operating system command (ocs) escape sequence without the escape character(s)",
|
"operating system command (ocs) escape sequence without the escape character(s)",
|
||||||
Some('o'),
|
Some('o'),
|
||||||
@ -118,12 +118,8 @@ Format: #
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
let (AnsiArgs { code, escape, osc }, _) = args.process().await?;
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let (AnsiArgs { color, escape, osc }, _) = args.process(®istry).await?;
|
|
||||||
|
|
||||||
if let Some(e) = escape {
|
if let Some(e) = escape {
|
||||||
let esc_vec: Vec<char> = e.item.chars().collect();
|
let esc_vec: Vec<char> = e.item.chars().collect();
|
||||||
@ -149,6 +145,7 @@ Format: #
|
|||||||
o.tag(),
|
o.tag(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
//Operating system command aka osc ESC ] <- note the right brace, not left brace for osc
|
//Operating system command aka osc ESC ] <- note the right brace, not left brace for osc
|
||||||
// OCS's need to end with a bell '\x07' char
|
// OCS's need to end with a bell '\x07' char
|
||||||
let output = format!("\x1b]{};", o.item);
|
let output = format!("\x1b]{};", o.item);
|
||||||
@ -157,25 +154,24 @@ Format: #
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let color_string = color.as_string()?;
|
let code_string = code.as_string()?;
|
||||||
let ansi_code = str_to_ansi_color(color_string);
|
let ansi_code = str_to_ansi(code_string);
|
||||||
|
|
||||||
if let Some(output) = ansi_code {
|
if let Some(output) = ansi_code {
|
||||||
Ok(OutputStream::one(ReturnSuccess::value(
|
Ok(OutputStream::one(ReturnSuccess::value(
|
||||||
UntaggedValue::string(output).into_value(color.tag()),
|
UntaggedValue::string(output).into_value(code.tag()),
|
||||||
)))
|
)))
|
||||||
} else {
|
} else {
|
||||||
Err(ShellError::labeled_error(
|
Err(ShellError::labeled_error(
|
||||||
"Unknown color",
|
"Unknown ansi code",
|
||||||
"unknown color",
|
"unknown ansi code",
|
||||||
color.tag(),
|
code.tag(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn str_to_ansi_color(s: String) -> Option<String> {
|
pub fn str_to_ansi(s: String) -> Option<String> {
|
||||||
match s.as_str() {
|
match s.as_str() {
|
||||||
"g" | "green" => Some(Color::Green.prefix().to_string()),
|
"g" | "green" => Some(Color::Green.prefix().to_string()),
|
||||||
"gb" | "green_bold" => Some(Color::Green.bold().prefix().to_string()),
|
"gb" | "green_bold" => Some(Color::Green.bold().prefix().to_string()),
|
||||||
@ -226,6 +222,57 @@ pub fn str_to_ansi_color(s: String) -> Option<String> {
|
|||||||
"wd" | "white_dimmed" => Some(Color::White.dimmed().prefix().to_string()),
|
"wd" | "white_dimmed" => Some(Color::White.dimmed().prefix().to_string()),
|
||||||
"wr" | "white_reverse" => Some(Color::White.reverse().prefix().to_string()),
|
"wr" | "white_reverse" => Some(Color::White.reverse().prefix().to_string()),
|
||||||
"reset" => Some("\x1b[0m".to_owned()),
|
"reset" => Some("\x1b[0m".to_owned()),
|
||||||
|
|
||||||
|
// Reference for ansi codes https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
|
||||||
|
// Another good reference http://ascii-table.com/ansi-escape-sequences.php
|
||||||
|
|
||||||
|
// For setting title like `echo [$(char title) $(pwd) $(char bel)] | str collect`
|
||||||
|
"title" => Some("\x1b]2;".to_string()), // ESC]2; xterm sets window title using OSC syntax escapes
|
||||||
|
"bel" => Some('\x07'.to_string()), // Terminal Bell
|
||||||
|
"backspace" => Some('\x08'.to_string()), // Backspace
|
||||||
|
|
||||||
|
// Ansi Erase Sequences
|
||||||
|
"clear_screen" => Some("\x1b[J".to_string()), // clears the screen
|
||||||
|
"clear_screen_from_cursor_to_end" => Some("\x1b[0J".to_string()), // clears from cursor until end of screen
|
||||||
|
"clear_screen_from_cursor_to_beginning" => Some("\x1b[1J".to_string()), // clears from cursor to beginning of screen
|
||||||
|
"cls" | "clear_entire_screen" => Some("\x1b[2J".to_string()), // clears the entire screen
|
||||||
|
"erase_line" => Some("\x1b[K".to_string()), // clears the current line
|
||||||
|
"erase_line_from_cursor_to_end" => Some("\x1b[0K".to_string()), // clears from cursor to end of line
|
||||||
|
"erase_line_from_cursor_to_beginning" => Some("\x1b[1K".to_string()), // clears from cursor to start of line
|
||||||
|
"erase_entire_line" => Some("\x1b[2K".to_string()), // clears entire line
|
||||||
|
|
||||||
|
// Turn on/off cursor
|
||||||
|
"cursor_off" => Some("\x1b[?25l".to_string()),
|
||||||
|
"cursor_on" => Some("\x1b[?25h".to_string()),
|
||||||
|
|
||||||
|
// Turn on/off blinking
|
||||||
|
"cursor_blink_off" => Some("\x1b[?12l".to_string()),
|
||||||
|
"cursor_blink_on" => Some("\x1b[?12h".to_string()),
|
||||||
|
|
||||||
|
// Cursor position in ESC [ <r>;<c>R where r = row and c = column
|
||||||
|
"cursor_position" => Some("\x1b[6n".to_string()),
|
||||||
|
|
||||||
|
// Report Terminal Identity
|
||||||
|
"identity" => Some("\x1b[0c".to_string()),
|
||||||
|
|
||||||
|
// Ansi escape only - CSI command
|
||||||
|
"csi" | "escape" | "escape_left" => Some("\x1b[".to_string()),
|
||||||
|
// OSC escape (Operating system command)
|
||||||
|
"osc" | "escape_right" => Some("\x1b]".to_string()),
|
||||||
|
|
||||||
|
// Ansi RGB - Needs to be 32;2;r;g;b or 48;2;r;g;b
|
||||||
|
// assuming the rgb will be passed via command and no here
|
||||||
|
"rgb_fg" => Some("\x1b[32;2;".to_string()),
|
||||||
|
"rgb_bg" => Some("\x1b[48;2;".to_string()),
|
||||||
|
|
||||||
|
// Ansi color index - Needs 38;5;idx or 48;5;idx where idx = 0 to 255
|
||||||
|
"idx_fg" | "color_idx_fg" => Some("\x1b[38;5;".to_string()),
|
||||||
|
"idx_bg" | "color_idx_bg" => Some("\x1b[48;5;".to_string()),
|
||||||
|
|
||||||
|
// Returns terminal size like "[<r>;<c>R" where r is rows and c is columns
|
||||||
|
// This should work assuming your terminal is not greater than 999x999
|
||||||
|
"size" => Some("\x1b[s\x1b[999;999H\x1b[6n\x1b[u".to_string()),
|
||||||
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,5 @@
|
|||||||
use crate::command_registry::CommandRegistry;
|
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||||
|
|
||||||
@ -29,12 +28,8 @@ impl WholeStreamCommand for Command {
|
|||||||
"Append a row to the table"
|
"Append a row to the table"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
let (Arguments { mut value }, input) = args.process().await?;
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let (Arguments { mut value }, input) = args.process(registry).await?;
|
|
||||||
|
|
||||||
let input: Vec<Value> = input.collect().await;
|
let input: Vec<Value> = input.collect().await;
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@ -61,15 +61,9 @@ The file can contain several optional sections:
|
|||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("autoenv")
|
Signature::build("autoenv")
|
||||||
}
|
}
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
|
||||||
_args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let registry = registry.clone();
|
|
||||||
Ok(OutputStream::one(ReturnSuccess::value(
|
Ok(OutputStream::one(ReturnSuccess::value(
|
||||||
UntaggedValue::string(crate::commands::help::get_help(&Autoenv, ®istry))
|
UntaggedValue::string(get_help(&Autoenv, &args.scope)).into_value(Tag::unknown()),
|
||||||
.into_value(Tag::unknown()),
|
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
use super::autoenv::read_trusted;
|
use super::autoenv::read_trusted;
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::SyntaxShape;
|
use nu_protocol::SyntaxShape;
|
||||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
|
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
|
||||||
@ -22,14 +22,11 @@ impl WholeStreamCommand for AutoenvTrust {
|
|||||||
"Trust a .nu-env file in the current or given directory"
|
"Trust a .nu-env file in the current or given directory"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let tag = args.call_info.name_tag.clone();
|
let tag = args.call_info.name_tag.clone();
|
||||||
|
let ctx = EvaluationContext::from_args(&args);
|
||||||
|
|
||||||
let file_to_trust = match args.call_info.evaluate(registry).await?.args.nth(0) {
|
let file_to_trust = match args.call_info.evaluate(&ctx).await?.args.nth(0) {
|
||||||
Some(Value {
|
Some(Value {
|
||||||
value: UntaggedValue::Primitive(Primitive::String(ref path)),
|
value: UntaggedValue::Primitive(Primitive::String(ref path)),
|
||||||
tag: _,
|
tag: _,
|
@ -1,6 +1,6 @@
|
|||||||
use super::autoenv::Trusted;
|
use super::autoenv::Trusted;
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::SyntaxShape;
|
use nu_protocol::SyntaxShape;
|
||||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
|
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
|
||||||
@ -26,13 +26,10 @@ impl WholeStreamCommand for AutoenvUnTrust {
|
|||||||
"Untrust a .nu-env file in the current or given directory"
|
"Untrust a .nu-env file in the current or given directory"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let tag = args.call_info.name_tag.clone();
|
let tag = args.call_info.name_tag.clone();
|
||||||
let file_to_untrust = match args.call_info.evaluate(registry).await?.args.nth(0) {
|
let ctx = EvaluationContext::from_args(&args);
|
||||||
|
let file_to_untrust = match args.call_info.evaluate(&ctx).await?.args.nth(0) {
|
||||||
Some(Value {
|
Some(Value {
|
||||||
value: UntaggedValue::Primitive(Primitive::String(ref path)),
|
value: UntaggedValue::Primitive(Primitive::String(ref path)),
|
||||||
tag: _,
|
tag: _,
|
@ -1,11 +1,11 @@
|
|||||||
use crate::commands::autoview::options::{ConfigExtensions, NuConfig as AutoViewConfiguration};
|
use crate::commands::autoview::options::{ConfigExtensions, NuConfig as AutoViewConfiguration};
|
||||||
use crate::commands::{UnevaluatedCallInfo, WholeStreamCommand};
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::primitive::get_color_config;
|
use crate::primitive::get_color_config;
|
||||||
use nu_data::value::format_leaf;
|
use nu_data::value::format_leaf;
|
||||||
|
use nu_engine::{UnevaluatedCallInfo, WholeStreamCommand};
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::hir::{self, Expression, ExternalRedirection, Literal, SpannedExpression};
|
use nu_protocol::hir::{self, Expression, ExternalRedirection, Literal, SpannedExpression};
|
||||||
use nu_protocol::{Primitive, Scope, Signature, UntaggedValue, Value};
|
use nu_protocol::{Primitive, Signature, UntaggedValue, Value};
|
||||||
use nu_table::TextStyle;
|
use nu_table::TextStyle;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
@ -26,20 +26,15 @@ impl WholeStreamCommand for Command {
|
|||||||
"View the contents of the pipeline as a table or list."
|
"View the contents of the pipeline as a table or list."
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
autoview(RunnableContext {
|
autoview(RunnableContext {
|
||||||
input: args.input,
|
input: args.input,
|
||||||
registry: registry.clone(),
|
scope: args.scope.clone(),
|
||||||
shell_manager: args.shell_manager,
|
shell_manager: args.shell_manager,
|
||||||
host: args.host,
|
host: args.host,
|
||||||
ctrl_c: args.ctrl_c,
|
ctrl_c: args.ctrl_c,
|
||||||
current_errors: args.current_errors,
|
current_errors: args.current_errors,
|
||||||
name: args.call_info.name_tag,
|
name: args.call_info.name_tag,
|
||||||
raw_input: args.raw_input,
|
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
@ -65,7 +60,7 @@ pub struct RunnableContextWithoutInput {
|
|||||||
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
|
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
|
||||||
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
|
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
|
||||||
pub ctrl_c: Arc<AtomicBool>,
|
pub ctrl_c: Arc<AtomicBool>,
|
||||||
pub registry: CommandRegistry,
|
pub scope: Scope,
|
||||||
pub name: Tag,
|
pub name: Tag,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +71,7 @@ impl RunnableContextWithoutInput {
|
|||||||
host: context.host,
|
host: context.host,
|
||||||
ctrl_c: context.ctrl_c,
|
ctrl_c: context.ctrl_c,
|
||||||
current_errors: context.current_errors,
|
current_errors: context.current_errors,
|
||||||
registry: context.registry,
|
scope: context.scope,
|
||||||
name: context.name,
|
name: context.name,
|
||||||
};
|
};
|
||||||
(context.input, new_context)
|
(context.input, new_context)
|
||||||
@ -109,7 +104,7 @@ pub async fn autoview(context: RunnableContext) -> Result<OutputStream, ShellErr
|
|||||||
|
|
||||||
if let Some(table) = table {
|
if let Some(table) = table {
|
||||||
let command_args = create_default_command_args(&context).with_input(stream);
|
let command_args = create_default_command_args(&context).with_input(stream);
|
||||||
let result = table.run(command_args, &context.registry).await?;
|
let result = table.run(command_args).await?;
|
||||||
result.collect::<Vec<_>>().await;
|
result.collect::<Vec<_>>().await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,7 +121,7 @@ pub async fn autoview(context: RunnableContext) -> Result<OutputStream, ShellErr
|
|||||||
);
|
);
|
||||||
let command_args =
|
let command_args =
|
||||||
create_default_command_args(&context).with_input(stream);
|
create_default_command_args(&context).with_input(stream);
|
||||||
let result = text.run(command_args, &context.registry).await?;
|
let result = text.run(command_args).await?;
|
||||||
result.collect::<Vec<_>>().await;
|
result.collect::<Vec<_>>().await;
|
||||||
} else {
|
} else {
|
||||||
out!("{}", s);
|
out!("{}", s);
|
||||||
@ -139,30 +134,7 @@ pub async fn autoview(context: RunnableContext) -> Result<OutputStream, ShellErr
|
|||||||
out!("{}", s);
|
out!("{}", s);
|
||||||
}
|
}
|
||||||
Value {
|
Value {
|
||||||
value: UntaggedValue::Primitive(Primitive::Line(ref s)),
|
value: UntaggedValue::Primitive(Primitive::FilePath(s)),
|
||||||
tag: Tag { anchor, span },
|
|
||||||
} if anchor.is_some() => {
|
|
||||||
if let Some(text) = text {
|
|
||||||
let mut stream = VecDeque::new();
|
|
||||||
stream.push_back(
|
|
||||||
UntaggedValue::string(s).into_value(Tag { anchor, span }),
|
|
||||||
);
|
|
||||||
let command_args =
|
|
||||||
create_default_command_args(&context).with_input(stream);
|
|
||||||
let result = text.run(command_args, &context.registry).await?;
|
|
||||||
result.collect::<Vec<_>>().await;
|
|
||||||
} else {
|
|
||||||
out!("{}\n", s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Value {
|
|
||||||
value: UntaggedValue::Primitive(Primitive::Line(s)),
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
out!("{}\n", s);
|
|
||||||
}
|
|
||||||
Value {
|
|
||||||
value: UntaggedValue::Primitive(Primitive::Path(s)),
|
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
out!("{}", s.display());
|
out!("{}", s.display());
|
||||||
@ -224,7 +196,7 @@ pub async fn autoview(context: RunnableContext) -> Result<OutputStream, ShellErr
|
|||||||
stream.push_back(x);
|
stream.push_back(x);
|
||||||
let command_args =
|
let command_args =
|
||||||
create_default_command_args(&context).with_input(stream);
|
create_default_command_args(&context).with_input(stream);
|
||||||
let result = binary.run(command_args, &context.registry).await?;
|
let result = binary.run(command_args).await?;
|
||||||
result.collect::<Vec<_>>().await;
|
result.collect::<Vec<_>>().await;
|
||||||
} else {
|
} else {
|
||||||
use pretty_hex::*;
|
use pretty_hex::*;
|
||||||
@ -276,7 +248,12 @@ pub async fn autoview(context: RunnableContext) -> Result<OutputStream, ShellErr
|
|||||||
|
|
||||||
nu_table::draw_table(&table, term_width, &color_hm);
|
nu_table::draw_table(&table, term_width, &color_hm);
|
||||||
}
|
}
|
||||||
|
Value {
|
||||||
|
value: UntaggedValue::Primitive(Primitive::Nothing),
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
Value {
|
Value {
|
||||||
value: ref item, ..
|
value: ref item, ..
|
||||||
} => {
|
} => {
|
||||||
@ -285,7 +262,7 @@ pub async fn autoview(context: RunnableContext) -> Result<OutputStream, ShellErr
|
|||||||
stream.push_back(x);
|
stream.push_back(x);
|
||||||
let command_args =
|
let command_args =
|
||||||
create_default_command_args(&context).with_input(stream);
|
create_default_command_args(&context).with_input(stream);
|
||||||
let result = table.run(command_args, &context.registry).await?;
|
let result = table.run(command_args).await?;
|
||||||
result.collect::<Vec<_>>().await;
|
result.collect::<Vec<_>>().await;
|
||||||
} else {
|
} else {
|
||||||
out!("{:?}", item);
|
out!("{:?}", item);
|
||||||
@ -318,8 +295,8 @@ 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::create(),
|
|
||||||
},
|
},
|
||||||
|
scope: Scope::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,12 +1,12 @@
|
|||||||
use crate::commands::classified::block::run_block;
|
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
#[cfg(feature = "rich-benchmark")]
|
// #[cfg(feature = "rich-benchmark")]
|
||||||
use heim::cpu::time;
|
// use heim::cpu::time;
|
||||||
|
use nu_engine::run_block;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
hir::{Block, ClassifiedCommand, Commands, InternalCommand},
|
hir::{Block, CapturedBlock, ClassifiedCommand, Group, InternalCommand, Pipeline},
|
||||||
Dictionary, Scope, Signature, SyntaxShape, UntaggedValue, Value,
|
Dictionary, Signature, SyntaxShape, UntaggedValue, Value,
|
||||||
};
|
};
|
||||||
use rand::{
|
use rand::{
|
||||||
distributions::Alphanumeric,
|
distributions::Alphanumeric,
|
||||||
@ -19,8 +19,8 @@ pub struct Benchmark;
|
|||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
struct BenchmarkArgs {
|
struct BenchmarkArgs {
|
||||||
block: Block,
|
block: CapturedBlock,
|
||||||
passthrough: Option<Block>,
|
passthrough: Option<CapturedBlock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@ -48,12 +48,8 @@ impl WholeStreamCommand for Benchmark {
|
|||||||
"Runs a block and returns the time it took to execute it"
|
"Runs a block and returns the time it took to execute it"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
benchmark(args).await
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
benchmark(args, registry).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -72,78 +68,73 @@ impl WholeStreamCommand for Benchmark {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn benchmark(
|
async fn benchmark(raw_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
raw_args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let registry = registry.clone();
|
|
||||||
|
|
||||||
let tag = raw_args.call_info.args.span;
|
let tag = raw_args.call_info.args.span;
|
||||||
let mut context = EvaluationContext::from_raw(&raw_args, ®istry);
|
let mut context = EvaluationContext::from_raw(&raw_args);
|
||||||
let scope = raw_args.call_info.scope.clone();
|
let scope = raw_args.scope.clone();
|
||||||
let (BenchmarkArgs { block, passthrough }, input) = raw_args.process(®istry).await?;
|
let (BenchmarkArgs { block, passthrough }, input) = raw_args.process().await?;
|
||||||
|
|
||||||
let env = scope.env();
|
let env = scope.get_env_vars();
|
||||||
let name = generate_free_name(&env);
|
let name = generate_free_name(&env);
|
||||||
let mut env = IndexMap::new();
|
|
||||||
env.insert(name, generate_random_env_value());
|
scope.add_env_var(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(&block, &mut context, input, scope.clone()).await;
|
context.scope.enter_scope();
|
||||||
|
let result = run_block(&block.block, &context, input).await;
|
||||||
|
context.scope.exit_scope();
|
||||||
let output = result?.into_vec().await;
|
let output = result?.into_vec().await;
|
||||||
|
|
||||||
#[cfg(feature = "rich-benchmark")]
|
// #[cfg(feature = "rich-benchmark")]
|
||||||
let end = time().await;
|
// let end = time().await;
|
||||||
|
|
||||||
let end_time = Instant::now();
|
let end_time = Instant::now();
|
||||||
context.clear_errors();
|
context.clear_errors();
|
||||||
|
|
||||||
// return basic runtime
|
// return basic runtime
|
||||||
#[cfg(not(feature = "rich-benchmark"))]
|
//#[cfg(not(feature = "rich-benchmark"))]
|
||||||
{
|
{
|
||||||
let mut indexmap = IndexMap::with_capacity(1);
|
let mut indexmap = IndexMap::with_capacity(1);
|
||||||
|
|
||||||
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).await
|
||||||
}
|
}
|
||||||
// return advanced stats
|
// return advanced stats
|
||||||
#[cfg(feature = "rich-benchmark")]
|
// #[cfg(feature = "rich-benchmark")]
|
||||||
if let (Ok(start), Ok(end)) = (start, end) {
|
// if let (Ok(start), Ok(end)) = (start, end) {
|
||||||
let mut indexmap = IndexMap::with_capacity(4);
|
// let mut indexmap = IndexMap::with_capacity(4);
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
let user_time = into_big_int(end.user() - start.user());
|
// let user_time = into_big_int(end.user() - start.user());
|
||||||
indexmap.insert("user time".to_string(), user_time);
|
// indexmap.insert("user time".to_string(), user_time);
|
||||||
|
|
||||||
let system_time = into_big_int(end.system() - start.system());
|
// let system_time = into_big_int(end.system() - start.system());
|
||||||
indexmap.insert("system time".to_string(), system_time);
|
// indexmap.insert("system time".to_string(), system_time);
|
||||||
|
|
||||||
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).await
|
||||||
} else {
|
// } else {
|
||||||
Err(ShellError::untagged_runtime_error(
|
// Err(ShellError::untagged_runtime_error(
|
||||||
"Could not retreive CPU time",
|
// "Could not retrieve CPU time",
|
||||||
))
|
// ))
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn benchmark_output<T, Output>(
|
async fn benchmark_output<T, Output>(
|
||||||
indexmap: IndexMap<String, BigInt>,
|
indexmap: IndexMap<String, BigInt>,
|
||||||
block_output: Output,
|
block_output: Output,
|
||||||
passthrough: Option<Block>,
|
passthrough: Option<CapturedBlock>,
|
||||||
tag: T,
|
tag: T,
|
||||||
context: &mut EvaluationContext,
|
context: &mut EvaluationContext,
|
||||||
scope: Arc<Scope>,
|
|
||||||
) -> Result<OutputStream, ShellError>
|
) -> Result<OutputStream, ShellError>
|
||||||
where
|
where
|
||||||
T: Into<Tag> + Copy,
|
T: Into<Tag> + Copy,
|
||||||
@ -161,9 +152,12 @@ where
|
|||||||
let benchmark_output = InputStream::one(value);
|
let benchmark_output = InputStream::one(value);
|
||||||
|
|
||||||
// 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.block);
|
||||||
|
|
||||||
let _ = run_block(&time_block, context, benchmark_output, scope).await?;
|
context.scope.enter_scope();
|
||||||
|
let result = run_block(&time_block, context, benchmark_output).await;
|
||||||
|
context.scope.exit_scope();
|
||||||
|
result?;
|
||||||
context.clear_errors();
|
context.clear_errors();
|
||||||
|
|
||||||
Ok(block_output.into())
|
Ok(block_output.into())
|
||||||
@ -175,15 +169,19 @@ where
|
|||||||
|
|
||||||
fn add_implicit_autoview(mut block: Block) -> Block {
|
fn add_implicit_autoview(mut block: Block) -> Block {
|
||||||
if block.block.is_empty() {
|
if block.block.is_empty() {
|
||||||
block.push({
|
let group = Group::new(
|
||||||
let mut commands = Commands::new(block.span);
|
vec![{
|
||||||
|
let mut commands = Pipeline::new(block.span);
|
||||||
commands.push(ClassifiedCommand::Internal(InternalCommand::new(
|
commands.push(ClassifiedCommand::Internal(InternalCommand::new(
|
||||||
"autoview".to_string(),
|
"autoview".to_string(),
|
||||||
block.span,
|
block.span,
|
||||||
block.span,
|
block.span,
|
||||||
)));
|
)));
|
||||||
commands
|
commands
|
||||||
});
|
}],
|
||||||
|
block.span,
|
||||||
|
);
|
||||||
|
block.push(group);
|
||||||
}
|
}
|
||||||
block
|
block
|
||||||
}
|
}
|
@ -1,8 +1,8 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
|
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use nu_data::value::format_leaf;
|
use nu_data::value::format_leaf;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
@ -27,13 +27,9 @@ impl WholeStreamCommand for BuildString {
|
|||||||
"Builds a string from the arguments"
|
"Builds a string from the arguments"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let tag = args.call_info.name_tag.clone();
|
let tag = args.call_info.name_tag.clone();
|
||||||
let (BuildStringArgs { rest }, _) = args.process(®istry).await?;
|
let (BuildStringArgs { rest }, _) = args.process().await?;
|
||||||
|
|
||||||
let mut output_string = String::new();
|
let mut output_string = String::new();
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
use crate::commands::{command::EvaluatedWholeStreamCommandArgs, WholeStreamCommand};
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use chrono::{Datelike, Local, NaiveDate};
|
use chrono::{Datelike, Local, NaiveDate};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
use nu_engine::{EvaluatedWholeStreamCommandArgs, WholeStreamCommand};
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{Dictionary, Signature, SyntaxShape, UntaggedValue, Value};
|
use nu_protocol::{Dictionary, Signature, SyntaxShape, UntaggedValue, Value};
|
||||||
|
|
||||||
@ -41,12 +41,8 @@ impl WholeStreamCommand for Cal {
|
|||||||
"Display a calendar."
|
"Display a calendar."
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
cal(args).await
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
cal(args, registry).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -70,12 +66,8 @@ impl WholeStreamCommand for Cal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn cal(
|
pub async fn cal(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
args: CommandArgs,
|
let args = args.evaluate_once().await?;
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let registry = registry.clone();
|
|
||||||
let args = args.evaluate_once(®istry).await?;
|
|
||||||
let mut calendar_vec_deque = VecDeque::new();
|
let mut calendar_vec_deque = VecDeque::new();
|
||||||
let tag = args.call_info.name_tag.clone();
|
let tag = args.call_info.name_tag.clone();
|
||||||
|
|
@ -1,16 +1,9 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use nu_engine::shell::CdArgs;
|
||||||
|
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{Signature, SyntaxShape};
|
use nu_protocol::{Signature, SyntaxShape};
|
||||||
use nu_source::Tagged;
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
pub struct CdArgs {
|
|
||||||
pub(crate) path: Option<Tagged<PathBuf>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Cd;
|
pub struct Cd;
|
||||||
|
|
||||||
@ -23,7 +16,7 @@ impl WholeStreamCommand for Cd {
|
|||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("cd").optional(
|
Signature::build("cd").optional(
|
||||||
"directory",
|
"directory",
|
||||||
SyntaxShape::Path,
|
SyntaxShape::FilePath,
|
||||||
"the directory to change to",
|
"the directory to change to",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -32,14 +25,10 @@ impl WholeStreamCommand for Cd {
|
|||||||
"Change to a new path."
|
"Change to a new path."
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let name = args.call_info.name_tag.clone();
|
let name = args.call_info.name_tag.clone();
|
||||||
let shell_manager = args.shell_manager.clone();
|
let shell_manager = args.shell_manager.clone();
|
||||||
let (args, _): (CdArgs, _) = args.process(®istry).await?;
|
let (args, _): (CdArgs, _) = args.process().await?;
|
||||||
shell_manager.cd(args, name)
|
shell_manager.cd(args, name)
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
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;
|
||||||
@ -19,7 +19,7 @@ impl WholeStreamCommand for Char {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("ansi")
|
Signature::build("char")
|
||||||
.required(
|
.required(
|
||||||
"character",
|
"character",
|
||||||
SyntaxShape::Any,
|
SyntaxShape::Any,
|
||||||
@ -56,12 +56,8 @@ impl WholeStreamCommand for Char {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
let (CharArgs { name, unicode }, _) = args.process().await?;
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let (CharArgs { name, unicode }, _) = args.process(®istry).await?;
|
|
||||||
|
|
||||||
if unicode {
|
if unicode {
|
||||||
let decoded_char = string_to_unicode_char(&name.item);
|
let decoded_char = string_to_unicode_char(&name.item);
|
||||||
@ -134,24 +130,6 @@ fn str_to_character(s: &str) -> Option<String> {
|
|||||||
"snowy" | "snow" => Some("❄️".to_string()),
|
"snowy" | "snow" => Some("❄️".to_string()),
|
||||||
"thunderstorm" | "thunder" => Some("🌩️".to_string()),
|
"thunderstorm" | "thunder" => Some("🌩️".to_string()),
|
||||||
|
|
||||||
// Reference for ansi codes https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
|
|
||||||
// Another good reference http://ascii-table.com/ansi-escape-sequences.php
|
|
||||||
|
|
||||||
// For setting title like `echo [$(char title) $(pwd) $(char bel)] | str collect`
|
|
||||||
"title" => Some("\x1b]2;".to_string()), // ESC]2; xterm sets window title
|
|
||||||
"bel" => Some('\x07'.to_string()), // Terminal Bell
|
|
||||||
"backspace" => Some('\x08'.to_string()), // Backspace
|
|
||||||
|
|
||||||
// Ansi Erase Sequences
|
|
||||||
"clear_screen" => Some("\x1b[J".to_string()), // clears the screen
|
|
||||||
"clear_screen_from_cursor_to_end" => Some("\x1b[0J".to_string()), // clears from cursor until end of screen
|
|
||||||
"clear_screen_from_cursor_to_beginning" => Some("\x1b[1J".to_string()), // clears from cursor to beginning of screen
|
|
||||||
"cls" | "clear_entire_screen" => Some("\x1b[2J".to_string()), // clears the entire screen
|
|
||||||
"erase_line" => Some("\x1b[K".to_string()), // clears the current line
|
|
||||||
"erase_line_from_cursor_to_end" => Some("\x1b[0K".to_string()), // clears from cursor to end of line
|
|
||||||
"erase_line_from_cursor_to_beginning" => Some("\x1b[1K".to_string()), // clears from cursor to start of line
|
|
||||||
"erase_entire_line" => Some("\x1b[2K".to_string()), // clears entire line
|
|
||||||
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||||
|
|
||||||
@ -20,21 +20,15 @@ impl WholeStreamCommand for Chart {
|
|||||||
"Displays charts."
|
"Displays charts."
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
if args.scope.get_command("chart bar").is_none() {
|
||||||
_args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
if registry.get_command("chart bar").is_none() {
|
|
||||||
return Err(ShellError::untagged_runtime_error(
|
return Err(ShellError::untagged_runtime_error(
|
||||||
"nu_plugin_chart not installed.",
|
"nu_plugin_chart not installed.",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let registry = registry.clone();
|
|
||||||
Ok(OutputStream::one(Ok(ReturnSuccess::Value(
|
Ok(OutputStream::one(Ok(ReturnSuccess::Value(
|
||||||
UntaggedValue::string(crate::commands::help::get_help(&Chart, ®istry))
|
UntaggedValue::string(get_help(&Chart, &args.scope)).into_value(Tag::unknown()),
|
||||||
.into_value(Tag::unknown()),
|
|
||||||
))))
|
))))
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
use crate::commands::classified::maybe_text_codec::{MaybeTextCodec, StringOrBinary};
|
|
||||||
use crate::evaluate::evaluate_baseline_expr;
|
|
||||||
use crate::futures::ThreadedReceiver;
|
use crate::futures::ThreadedReceiver;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::evaluate_baseline_expr;
|
||||||
|
use nu_engine::{MaybeTextCodec, StringOrBinary};
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
@ -16,14 +16,14 @@ use log::trace;
|
|||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::hir::Expression;
|
use nu_protocol::hir::Expression;
|
||||||
use nu_protocol::hir::{ExternalCommand, ExternalRedirection};
|
use nu_protocol::hir::{ExternalCommand, ExternalRedirection};
|
||||||
use nu_protocol::{Primitive, Scope, ShellTypeName, UntaggedValue, Value};
|
use nu_protocol::{Primitive, ShellTypeName, UntaggedValue, Value};
|
||||||
use nu_source::Tag;
|
use nu_source::Tag;
|
||||||
|
use nu_stream::trace_stream;
|
||||||
|
|
||||||
pub(crate) async fn run_external_command(
|
pub(crate) async fn run_external_command(
|
||||||
command: ExternalCommand,
|
command: ExternalCommand,
|
||||||
context: &mut EvaluationContext,
|
context: &mut EvaluationContext,
|
||||||
input: InputStream,
|
input: InputStream,
|
||||||
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);
|
||||||
@ -36,14 +36,13 @@ pub(crate) async fn run_external_command(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
run_with_stdin(command, context, input, scope, external_redirection).await
|
run_with_stdin(command, context, input, external_redirection).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run_with_stdin(
|
async fn run_with_stdin(
|
||||||
command: ExternalCommand,
|
command: ExternalCommand,
|
||||||
context: &mut EvaluationContext,
|
context: &mut EvaluationContext,
|
||||||
input: InputStream,
|
input: InputStream,
|
||||||
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();
|
||||||
@ -53,7 +52,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 is_literal = matches!(arg.expr, Expression::Literal(_));
|
let is_literal = matches!(arg.expr, Expression::Literal(_));
|
||||||
let value = evaluate_baseline_expr(arg, &context.registry, scope.clone()).await?;
|
let value = evaluate_baseline_expr(arg, context).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
|
||||||
@ -97,7 +96,7 @@ async fn run_with_stdin(
|
|||||||
|
|
||||||
#[cfg(feature = "dirs")]
|
#[cfg(feature = "dirs")]
|
||||||
{
|
{
|
||||||
home_dir = dirs::home_dir;
|
home_dir = dirs_next::home_dir;
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "dirs"))]
|
#[cfg(not(feature = "dirs"))]
|
||||||
{
|
{
|
||||||
@ -132,7 +131,7 @@ async fn run_with_stdin(
|
|||||||
&process_args[..],
|
&process_args[..],
|
||||||
input,
|
input,
|
||||||
external_redirection,
|
external_redirection,
|
||||||
scope,
|
&context.scope,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +141,7 @@ fn spawn(
|
|||||||
args: &[String],
|
args: &[String],
|
||||||
input: InputStream,
|
input: InputStream,
|
||||||
external_redirection: ExternalRedirection,
|
external_redirection: ExternalRedirection,
|
||||||
scope: Arc<Scope>,
|
scope: &Scope,
|
||||||
) -> Result<InputStream, ShellError> {
|
) -> Result<InputStream, ShellError> {
|
||||||
let command = command.clone();
|
let command = command.clone();
|
||||||
|
|
||||||
@ -173,7 +172,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());
|
process.envs(scope.get_env_vars());
|
||||||
|
|
||||||
// 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)
|
||||||
@ -223,8 +222,7 @@ fn spawn(
|
|||||||
for value in block_on_stream(input) {
|
for value in block_on_stream(input) {
|
||||||
match &value.value {
|
match &value.value {
|
||||||
UntaggedValue::Primitive(Primitive::Nothing) => continue,
|
UntaggedValue::Primitive(Primitive::Nothing) => continue,
|
||||||
UntaggedValue::Primitive(Primitive::String(s))
|
UntaggedValue::Primitive(Primitive::String(s)) => {
|
||||||
| UntaggedValue::Primitive(Primitive::Line(s)) => {
|
|
||||||
if stdin_write.write(s.as_bytes()).is_err() {
|
if stdin_write.write(s.as_bytes()).is_err() {
|
||||||
// Other side has closed, so exit
|
// Other side has closed, so exit
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -466,7 +464,7 @@ pub fn did_find_command(#[allow(unused)] name: &str) -> bool {
|
|||||||
let cmd_builtins = [
|
let cmd_builtins = [
|
||||||
"assoc", "break", "color", "copy", "date", "del", "dir", "dpath", "echo", "erase",
|
"assoc", "break", "color", "copy", "date", "del", "dir", "dpath", "echo", "erase",
|
||||||
"for", "ftype", "md", "mkdir", "mklink", "move", "path", "ren", "rename", "rd",
|
"for", "ftype", "md", "mkdir", "mklink", "move", "path", "ren", "rename", "rd",
|
||||||
"rmdir", "set", "start", "time", "title", "type", "ver", "verify", "vol",
|
"rmdir", "start", "time", "title", "type", "ver", "verify", "vol",
|
||||||
];
|
];
|
||||||
|
|
||||||
cmd_builtins.contains(&name)
|
cmd_builtins.contains(&name)
|
||||||
@ -535,17 +533,16 @@ mod tests {
|
|||||||
add_double_quotes, argument_is_quoted, escape_double_quotes, expand_tilde, remove_quotes,
|
add_double_quotes, argument_is_quoted, escape_double_quotes, expand_tilde, remove_quotes,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "which")]
|
#[cfg(feature = "which")]
|
||||||
use super::{run_external_command, EvaluationContext, InputStream};
|
use super::{run_external_command, InputStream};
|
||||||
|
|
||||||
#[cfg(feature = "which")]
|
#[cfg(feature = "which")]
|
||||||
use futures::executor::block_on;
|
use futures::executor::block_on;
|
||||||
#[cfg(feature = "which")]
|
#[cfg(feature = "which")]
|
||||||
|
use nu_engine::basic_evaluation_context;
|
||||||
|
#[cfg(feature = "which")]
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
#[cfg(feature = "which")]
|
#[cfg(feature = "which")]
|
||||||
use nu_protocol::Scope;
|
|
||||||
#[cfg(feature = "which")]
|
|
||||||
use nu_test_support::commands::ExternalBuilder;
|
use nu_test_support::commands::ExternalBuilder;
|
||||||
|
|
||||||
// async fn read(mut stream: OutputStream) -> Option<Value> {
|
// async fn read(mut stream: OutputStream) -> Option<Value> {
|
||||||
// match stream.try_next().await {
|
// match stream.try_next().await {
|
||||||
// Ok(val) => {
|
// Ok(val) => {
|
||||||
@ -566,17 +563,13 @@ mod tests {
|
|||||||
|
|
||||||
let input = InputStream::empty();
|
let input = InputStream::empty();
|
||||||
let mut ctx =
|
let mut ctx =
|
||||||
EvaluationContext::basic().expect("There was a problem creating a basic context.");
|
basic_evaluation_context().expect("There was a problem creating a basic context.");
|
||||||
|
|
||||||
assert!(run_external_command(
|
assert!(
|
||||||
cmd,
|
run_external_command(cmd, &mut ctx, input, ExternalRedirection::Stdout)
|
||||||
&mut ctx,
|
|
||||||
input,
|
|
||||||
Scope::create(),
|
|
||||||
ExternalRedirection::Stdout
|
|
||||||
)
|
|
||||||
.await
|
.await
|
||||||
.is_err());
|
.is_err()
|
||||||
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -584,7 +577,7 @@ mod tests {
|
|||||||
// async fn failure_run() -> Result<(), ShellError> {
|
// async fn failure_run() -> Result<(), ShellError> {
|
||||||
// let cmd = ExternalBuilder::for_name("fail").build();
|
// let cmd = ExternalBuilder::for_name("fail").build();
|
||||||
|
|
||||||
// let mut ctx = EvaluationContext::basic().expect("There was a problem creating a basic context.");
|
// let mut ctx = crate::cli::basic_evaluation_context().expect("There was a problem creating a basic context.");
|
||||||
// let stream = run_external_command(cmd, &mut ctx, None, false)
|
// let stream = run_external_command(cmd, &mut ctx, None, false)
|
||||||
// .await?
|
// .await?
|
||||||
// .expect("There was a problem running the external command.");
|
// .expect("There was a problem running the external command.");
|
5
crates/nu-command/src/commands/classified/mod.rs
Normal file
5
crates/nu-command/src/commands/classified/mod.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
mod dynamic;
|
||||||
|
pub(crate) mod external;
|
||||||
|
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
pub(crate) use dynamic::Command as DynamicCommand;
|
@ -1,5 +1,5 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::Signature;
|
use nu_protocol::Signature;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
@ -20,7 +20,7 @@ impl WholeStreamCommand for Clear {
|
|||||||
"Clears the terminal"
|
"Clears the terminal"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(&self, _: CommandArgs, _: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
async fn run(&self, _: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
if cfg!(windows) {
|
if cfg!(windows) {
|
||||||
Command::new("cmd")
|
Command::new("cmd")
|
||||||
.args(&["/C", "cls"])
|
.args(&["/C", "cls"])
|
@ -1,11 +1,10 @@
|
|||||||
use crate::command_registry::CommandRegistry;
|
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use futures::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{Signature, Value};
|
use nu_protocol::{Signature, Value};
|
||||||
|
|
||||||
use clipboard::{ClipboardContext, ClipboardProvider};
|
use arboard::Clipboard;
|
||||||
|
|
||||||
pub struct Clip;
|
pub struct Clip;
|
||||||
|
|
||||||
@ -23,12 +22,8 @@ impl WholeStreamCommand for Clip {
|
|||||||
"Copy the contents of the pipeline to the copy/paste buffer"
|
"Copy the contents of the pipeline to the copy/paste buffer"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
clip(args).await
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
clip(args, registry).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -47,16 +42,12 @@ impl WholeStreamCommand for Clip {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn clip(
|
pub async fn clip(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
args: CommandArgs,
|
|
||||||
_registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let input = args.input;
|
let input = args.input;
|
||||||
let name = args.call_info.name_tag.clone();
|
let name = args.call_info.name_tag.clone();
|
||||||
let values: Vec<Value> = input.collect().await;
|
let values: Vec<Value> = input.collect().await;
|
||||||
|
|
||||||
if let Ok(clip_context) = ClipboardProvider::new() {
|
if let Ok(mut clip_context) = Clipboard::new() {
|
||||||
let mut clip_context: ClipboardContext = clip_context;
|
|
||||||
let mut new_copy_data = String::new();
|
let mut new_copy_data = String::new();
|
||||||
|
|
||||||
if !values.is_empty() {
|
if !values.is_empty() {
|
||||||
@ -81,7 +72,7 @@ pub async fn clip(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match clip_context.set_contents(new_copy_data) {
|
match clip_context.set_text(new_copy_data) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
21
crates/nu-command/src/commands/command.rs
Normal file
21
crates/nu-command/src/commands/command.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
use nu_engine::Command;
|
||||||
|
use nu_errors::ShellError;
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
use std::sync::atomic::AtomicBool;
|
||||||
|
|
||||||
|
pub struct RunnableContext {
|
||||||
|
pub input: InputStream,
|
||||||
|
pub shell_manager: ShellManager,
|
||||||
|
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
|
||||||
|
pub ctrl_c: Arc<AtomicBool>,
|
||||||
|
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
|
||||||
|
pub scope: Scope,
|
||||||
|
pub name: Tag,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RunnableContext {
|
||||||
|
pub fn get_command(&self, name: &str) -> Option<Command> {
|
||||||
|
self.scope.get_command(name)
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,7 @@
|
|||||||
use crate::command_registry::CommandRegistry;
|
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use futures::future;
|
use futures::future;
|
||||||
use futures::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
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;
|
||||||
@ -28,12 +27,8 @@ impl WholeStreamCommand for Compact {
|
|||||||
"Creates a table with non-empty rows"
|
"Creates a table with non-empty rows"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
compact(args).await
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
compact(args, registry).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -45,12 +40,8 @@ impl WholeStreamCommand for Compact {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn compact(
|
pub async fn compact(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
args: CommandArgs,
|
let (CompactArgs { rest: columns }, input) = args.process().await?;
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let registry = registry.clone();
|
|
||||||
let (CompactArgs { rest: columns }, input) = args.process(®istry).await?;
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.filter_map(move |item| {
|
.filter_map(move |item| {
|
||||||
future::ready(if columns.is_empty() {
|
future::ready(if columns.is_empty() {
|
@ -1,6 +1,5 @@
|
|||||||
use crate::command_registry::CommandRegistry;
|
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||||
|
|
||||||
@ -20,12 +19,8 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
"clear the config"
|
"clear the config"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
clear(args).await
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
clear(args, registry).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -37,10 +32,7 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn clear(
|
pub async fn clear(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
args: CommandArgs,
|
|
||||||
_registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let name_span = args.call_info.name_tag.clone();
|
let name_span = args.call_info.name_tag.clone();
|
||||||
|
|
||||||
// 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
|
@ -1,8 +1,9 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::{CommandArgs, CommandRegistry, OutputStream};
|
use nu_engine::CommandArgs;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||||
|
use nu_stream::OutputStream;
|
||||||
|
|
||||||
pub struct Command;
|
pub struct Command;
|
||||||
|
|
||||||
@ -20,11 +21,7 @@ impl WholeStreamCommand for Command {
|
|||||||
"Configuration management."
|
"Configuration management."
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
|
||||||
args: CommandArgs,
|
|
||||||
_registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let name_span = args.call_info.name_tag.clone();
|
let name_span = args.call_info.name_tag.clone();
|
||||||
let name = args.call_info.name_tag;
|
let name = args.call_info.name_tag;
|
||||||
let result = nu_data::config::read(name_span, &None)?;
|
let result = nu_data::config::read(name_span, &None)?;
|
@ -1,6 +1,5 @@
|
|||||||
use crate::command_registry::CommandRegistry;
|
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||||
|
|
||||||
@ -29,12 +28,8 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
"Gets a value from the config"
|
"Gets a value from the config"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
get(args).await
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
get(args, registry).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -46,12 +41,9 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get(
|
pub async fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let name_tag = args.call_info.name_tag.clone();
|
let name_tag = args.call_info.name_tag.clone();
|
||||||
let (GetArgs { path }, _) = args.process(®istry).await?;
|
let (GetArgs { path }, _) = args.process().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
|
@ -1,6 +1,5 @@
|
|||||||
use crate::command_registry::CommandRegistry;
|
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
|
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
|
||||||
use nu_source::Tagged;
|
use nu_source::Tagged;
|
||||||
@ -22,7 +21,7 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("config load").required(
|
Signature::build("config load").required(
|
||||||
"load",
|
"load",
|
||||||
SyntaxShape::Path,
|
SyntaxShape::FilePath,
|
||||||
"Path to load the config from",
|
"Path to load the config from",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -31,22 +30,15 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
"Loads the config from the path given"
|
"Loads the config from the path given"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
set(args).await
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
set(args, registry).await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set(
|
pub async fn set(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let name = args.call_info.name_tag.clone();
|
let name = args.call_info.name_tag.clone();
|
||||||
let name_span = args.call_info.name_tag.clone();
|
let name_span = args.call_info.name_tag.clone();
|
||||||
let (LoadArgs { load }, _) = args.process(®istry).await?;
|
let (LoadArgs { load }, _) = args.process().await?;
|
||||||
|
|
||||||
let configuration = load.item().clone();
|
let configuration = load.item().clone();
|
||||||
|
|
@ -1,6 +1,5 @@
|
|||||||
use crate::command_registry::CommandRegistry;
|
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue};
|
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue};
|
||||||
|
|
||||||
@ -20,12 +19,8 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
"return the path to the config file"
|
"return the path to the config file"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
path(args).await
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
path(args, registry).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -37,13 +32,10 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn path(
|
pub async fn path(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
args: CommandArgs,
|
|
||||||
_registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let path = config::default_path()?;
|
let path = config::default_path()?;
|
||||||
|
|
||||||
Ok(OutputStream::one(ReturnSuccess::value(
|
Ok(OutputStream::one(ReturnSuccess::value(
|
||||||
UntaggedValue::Primitive(Primitive::Path(path)).into_value(args.call_info.name_tag),
|
UntaggedValue::Primitive(Primitive::FilePath(path)).into_value(args.call_info.name_tag),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
@ -1,6 +1,5 @@
|
|||||||
use crate::command_registry::CommandRegistry;
|
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
|
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
|
||||||
use nu_source::Tagged;
|
use nu_source::Tagged;
|
||||||
@ -30,12 +29,8 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
"Removes a value from the config"
|
"Removes a value from the config"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
remove(args).await
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
remove(args, registry).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -47,12 +42,9 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn remove(
|
pub async fn remove(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let name_span = args.call_info.name_tag.clone();
|
let name_span = args.call_info.name_tag.clone();
|
||||||
let (RemoveArgs { remove }, _) = args.process(®istry).await?;
|
let (RemoveArgs { remove }, _) = args.process().await?;
|
||||||
|
|
||||||
let mut result = nu_data::config::read(name_span, &None)?;
|
let mut result = nu_data::config::read(name_span, &None)?;
|
||||||
|
|
@ -1,6 +1,5 @@
|
|||||||
use crate::command_registry::CommandRegistry;
|
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||||
|
|
||||||
@ -28,12 +27,8 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
"Sets a value in the config"
|
"Sets a value in the config"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
set(args).await
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
set(args, registry).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -62,12 +57,9 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set(
|
pub async fn set(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let name_tag = args.call_info.name_tag.clone();
|
let name_tag = args.call_info.name_tag.clone();
|
||||||
let (SetArgs { path, mut value }, _) = args.process(®istry).await?;
|
let (SetArgs { path, mut value }, _) = args.process().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
|
@ -1,6 +1,5 @@
|
|||||||
use crate::command_registry::CommandRegistry;
|
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
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;
|
||||||
@ -30,12 +29,8 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
"Sets a value in the config"
|
"Sets a value in the config"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
set_into(args).await
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
set_into(args, registry).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -47,14 +42,11 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set_into(
|
pub async fn set_into(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let name_span = args.call_info.name_tag.clone();
|
let name_span = args.call_info.name_tag.clone();
|
||||||
let name = args.call_info.name_tag.clone();
|
let name = args.call_info.name_tag.clone();
|
||||||
|
|
||||||
let (SetIntoArgs { set_into: v }, input) = args.process(®istry).await?;
|
let (SetIntoArgs { set_into: v }, input) = args.process().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
|
@ -1,7 +1,6 @@
|
|||||||
use crate::command_registry::CommandRegistry;
|
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use futures::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{Signature, UntaggedValue, Value};
|
use nu_protocol::{Signature, UntaggedValue, Value};
|
||||||
|
|
||||||
@ -30,13 +29,9 @@ impl WholeStreamCommand for Count {
|
|||||||
"Show the total number of rows or items."
|
"Show the total number of rows or items."
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let tag = args.call_info.name_tag.clone();
|
let tag = args.call_info.name_tag.clone();
|
||||||
let (CountArgs { column }, input) = args.process(®istry).await?;
|
let (CountArgs { column }, input) = args.process().await?;
|
||||||
let rows: Vec<Value> = input.collect().await;
|
let rows: Vec<Value> = input.collect().await;
|
||||||
|
|
||||||
let count = if column {
|
let count = if column {
|
@ -1,20 +1,10 @@
|
|||||||
use crate::command_registry::CommandRegistry;
|
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{Signature, SyntaxShape};
|
use nu_protocol::{Signature, SyntaxShape};
|
||||||
use nu_source::Tagged;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
pub struct Cpy;
|
pub struct Cpy;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
pub struct CopyArgs {
|
|
||||||
pub src: Tagged<PathBuf>,
|
|
||||||
pub dst: Tagged<PathBuf>,
|
|
||||||
pub recursive: Tagged<bool>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl WholeStreamCommand for Cpy {
|
impl WholeStreamCommand for Cpy {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
@ -23,8 +13,8 @@ impl WholeStreamCommand for Cpy {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("cp")
|
Signature::build("cp")
|
||||||
.required("src", SyntaxShape::Pattern, "the place to copy from")
|
.required("src", SyntaxShape::GlobPattern, "the place to copy from")
|
||||||
.required("dst", SyntaxShape::Path, "the place to copy to")
|
.required("dst", SyntaxShape::FilePath, "the place to copy to")
|
||||||
.switch(
|
.switch(
|
||||||
"recursive",
|
"recursive",
|
||||||
"copy recursively through subdirectories",
|
"copy recursively through subdirectories",
|
||||||
@ -36,14 +26,10 @@ impl WholeStreamCommand for Cpy {
|
|||||||
"Copy files."
|
"Copy files."
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let shell_manager = args.shell_manager.clone();
|
let shell_manager = args.shell_manager.clone();
|
||||||
let name = args.call_info.name_tag.clone();
|
let name = args.call_info.name_tag.clone();
|
||||||
let (args, _) = args.process(®istry).await?;
|
let (args, _) = args.process().await?;
|
||||||
shell_manager.cp(args, name)
|
shell_manager.cp(args, name)
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||||
|
|
||||||
@ -19,16 +19,9 @@ impl WholeStreamCommand for Command {
|
|||||||
"Apply date function"
|
"Apply date function"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
|
||||||
_args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let registry = registry.clone();
|
|
||||||
|
|
||||||
Ok(OutputStream::one(ReturnSuccess::value(
|
Ok(OutputStream::one(ReturnSuccess::value(
|
||||||
UntaggedValue::string(crate::commands::help::get_help(&Command, ®istry))
|
UntaggedValue::string(get_help(&Command, &args.scope)).into_value(Tag::unknown()),
|
||||||
.into_value(Tag::unknown()),
|
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
Dictionary, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
Dictionary, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||||
@ -31,12 +31,8 @@ impl WholeStreamCommand for Date {
|
|||||||
"Format a given date using the given format string."
|
"Format a given date using the given format string."
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
format(args).await
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
format(args, registry).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -55,13 +51,9 @@ impl WholeStreamCommand for Date {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn format(
|
pub async fn format(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let registry = registry.clone();
|
|
||||||
let tag = args.call_info.name_tag.clone();
|
let tag = args.call_info.name_tag.clone();
|
||||||
let (FormatArgs { format, table }, input) = args.process(®istry).await?;
|
let (FormatArgs { format, table }, input) = args.process().await?;
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |value| match value {
|
.map(move |value| match value {
|
@ -1,7 +1,7 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use chrono_tz::TZ_VARIANTS;
|
use chrono_tz::TZ_VARIANTS;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{Dictionary, ReturnSuccess, Signature, UntaggedValue};
|
use nu_protocol::{Dictionary, ReturnSuccess, Signature, UntaggedValue};
|
||||||
|
|
||||||
@ -21,12 +21,8 @@ impl WholeStreamCommand for Date {
|
|||||||
"List supported time zones."
|
"List supported time zones."
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
list_timezone(args).await
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
list_timezone(args, registry).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -45,11 +41,8 @@ impl WholeStreamCommand for Date {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn list_timezone(
|
async fn list_timezone(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
args: CommandArgs,
|
let args = args.evaluate_once().await?;
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let args = args.evaluate_once(®istry).await?;
|
|
||||||
let tag = args.call_info.name_tag.clone();
|
let tag = args.call_info.name_tag.clone();
|
||||||
|
|
||||||
let list = TZ_VARIANTS.iter().map(move |tz| {
|
let list = TZ_VARIANTS.iter().map(move |tz| {
|
@ -1,6 +1,6 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use chrono::{DateTime, Local};
|
use chrono::{DateTime, Local};
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{Signature, UntaggedValue};
|
use nu_protocol::{Signature, UntaggedValue};
|
||||||
|
|
||||||
@ -20,20 +20,13 @@ impl WholeStreamCommand for Date {
|
|||||||
"Get the current date."
|
"Get the current date."
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
now(args).await
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
now(args, registry).await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn now(
|
pub async fn now(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
args: CommandArgs,
|
let args = args.evaluate_once().await?;
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let args = args.evaluate_once(®istry).await?;
|
|
||||||
let tag = args.call_info.name_tag.clone();
|
let tag = args.call_info.name_tag.clone();
|
||||||
|
|
||||||
let now: DateTime<Local> = Local::now();
|
let now: DateTime<Local> = Local::now();
|
@ -1,7 +1,7 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use chrono::{Datelike, Timelike};
|
use chrono::{Datelike, Timelike};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{Dictionary, Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
|
use nu_protocol::{Dictionary, Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
|
||||||
|
|
||||||
@ -21,12 +21,8 @@ impl WholeStreamCommand for Date {
|
|||||||
"Print the date in a structured table."
|
"Print the date in a structured table."
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
to_table(args).await
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
to_table(args, registry).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -38,12 +34,8 @@ impl WholeStreamCommand for Date {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn to_table(
|
async fn to_table(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
args: CommandArgs,
|
let args = args.evaluate_once().await?;
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let registry = registry.clone();
|
|
||||||
let args = args.evaluate_once(®istry).await?;
|
|
||||||
let tag = args.call_info.name_tag.clone();
|
let tag = args.call_info.name_tag.clone();
|
||||||
let input = args.input;
|
let input = args.input;
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
use crate::commands::date::parser::{datetime_in_timezone, ParseErrorKind};
|
use crate::commands::date::parser::{datetime_in_timezone, ParseErrorKind};
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||||
use nu_source::Tagged;
|
use nu_source::Tagged;
|
||||||
@ -33,12 +33,8 @@ Use `date list-timezone` to list all supported time zones.
|
|||||||
"
|
"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
to_timezone(args).await
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
to_timezone(args, registry).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -62,13 +58,9 @@ Use `date list-timezone` to list all supported time zones.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn to_timezone(
|
async fn to_timezone(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let registry = registry.clone();
|
|
||||||
let tag = args.call_info.name_tag.clone();
|
let tag = args.call_info.name_tag.clone();
|
||||||
let (DateToTimeZoneArgs { timezone }, input) = args.process(®istry).await?;
|
let (DateToTimeZoneArgs { timezone }, input) = args.process().await?;
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |value| match value {
|
.map(move |value| match value {
|
55
crates/nu-command/src/commands/date/utc.rs
Normal file
55
crates/nu-command/src/commands/date/utc.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use nu_errors::ShellError;
|
||||||
|
|
||||||
|
use crate::commands::date::utils::date_to_value;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
|
use nu_protocol::Signature;
|
||||||
|
|
||||||
|
pub struct Date;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl WholeStreamCommand for Date {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"date utc"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("date utc")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"return the current date in utc."
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
|
utc(args).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn utc(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
|
let args = args.evaluate_once().await?;
|
||||||
|
let tag = args.call_info.name_tag.clone();
|
||||||
|
|
||||||
|
let no_fmt = "".to_string();
|
||||||
|
|
||||||
|
let value = {
|
||||||
|
let local: DateTime<Utc> = Utc::now();
|
||||||
|
date_to_value(local, tag, no_fmt)
|
||||||
|
};
|
||||||
|
|
||||||
|
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 {})?)
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||||
|
|
||||||
@ -24,21 +24,13 @@ impl WholeStreamCommand for Debug {
|
|||||||
"Print the Rust debug representation of the values"
|
"Print the Rust debug representation of the values"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
debug_value(args).await
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
debug_value(args, registry).await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn debug_value(
|
async fn debug_value(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
args: CommandArgs,
|
let (DebugArgs { raw }, input) = args.process().await?;
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let registry = registry.clone();
|
|
||||||
let (DebugArgs { raw }, input) = args.process(®istry).await?;
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |v| {
|
.map(move |v| {
|
||||||
if raw {
|
if raw {
|
48
crates/nu-command/src/commands/def.rs
Normal file
48
crates/nu-command/src/commands/def.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
|
|
||||||
|
use nu_errors::ShellError;
|
||||||
|
use nu_protocol::{hir::CapturedBlock, Signature, SyntaxShape, Value};
|
||||||
|
use nu_source::Tagged;
|
||||||
|
|
||||||
|
pub struct Def;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct DefArgs {
|
||||||
|
pub name: Tagged<String>,
|
||||||
|
pub args: Tagged<Vec<Value>>,
|
||||||
|
pub block: CapturedBlock,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl WholeStreamCommand for Def {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"def"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("def")
|
||||||
|
.required("name", SyntaxShape::String, "the name of the command")
|
||||||
|
.required(
|
||||||
|
"params",
|
||||||
|
SyntaxShape::Table,
|
||||||
|
"the parameters of the command",
|
||||||
|
)
|
||||||
|
.required("block", SyntaxShape::Block, "the body of the command")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Create a command and set it to a definition."
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run(&self, _args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
|
// Currently, we don't do anything here because we should have already
|
||||||
|
// installed the definition as we entered the scope
|
||||||
|
// We just create a command so that we can get proper coloring
|
||||||
|
Ok(OutputStream::empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
use crate::command_registry::CommandRegistry;
|
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
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;
|
||||||
@ -34,12 +33,8 @@ impl WholeStreamCommand for Default {
|
|||||||
"Sets a default row's column if missing."
|
"Sets a default row's column if missing."
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
default(args).await
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
default(args, registry).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -51,12 +46,8 @@ impl WholeStreamCommand for Default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn default(
|
async fn default(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
args: CommandArgs,
|
let (DefaultArgs { column, value }, input) = args.process().await?;
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let registry = registry.clone();
|
|
||||||
let (DefaultArgs { column, value }, input) = args.process(®istry).await?;
|
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |item| {
|
.map(move |item| {
|
249
crates/nu-command/src/commands/default_context.rs
Normal file
249
crates/nu-command/src/commands/default_context.rs
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
use nu_engine::basic_evaluation_context;
|
||||||
|
use nu_engine::whole_stream_command;
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Box<dyn Error>> {
|
||||||
|
let context = basic_evaluation_context()?;
|
||||||
|
|
||||||
|
{
|
||||||
|
use crate::commands::*;
|
||||||
|
|
||||||
|
context.add_commands(vec![
|
||||||
|
// Fundamentals
|
||||||
|
whole_stream_command(NuPlugin),
|
||||||
|
whole_stream_command(Let),
|
||||||
|
whole_stream_command(LetEnv),
|
||||||
|
whole_stream_command(Def),
|
||||||
|
whole_stream_command(Source),
|
||||||
|
// System/file operations
|
||||||
|
whole_stream_command(Exec),
|
||||||
|
whole_stream_command(Pwd),
|
||||||
|
whole_stream_command(Ls),
|
||||||
|
whole_stream_command(Du),
|
||||||
|
whole_stream_command(Cd),
|
||||||
|
whole_stream_command(Remove),
|
||||||
|
whole_stream_command(Open),
|
||||||
|
whole_stream_command(Config),
|
||||||
|
whole_stream_command(ConfigGet),
|
||||||
|
whole_stream_command(ConfigSet),
|
||||||
|
whole_stream_command(ConfigSetInto),
|
||||||
|
whole_stream_command(ConfigClear),
|
||||||
|
whole_stream_command(ConfigLoad),
|
||||||
|
whole_stream_command(ConfigRemove),
|
||||||
|
whole_stream_command(ConfigPath),
|
||||||
|
whole_stream_command(Help),
|
||||||
|
whole_stream_command(History),
|
||||||
|
whole_stream_command(Save),
|
||||||
|
whole_stream_command(Touch),
|
||||||
|
whole_stream_command(Cpy),
|
||||||
|
whole_stream_command(Date),
|
||||||
|
whole_stream_command(DateListTimeZone),
|
||||||
|
whole_stream_command(DateNow),
|
||||||
|
whole_stream_command(DateToTable),
|
||||||
|
whole_stream_command(DateToTimeZone),
|
||||||
|
whole_stream_command(DateFormat),
|
||||||
|
whole_stream_command(Cal),
|
||||||
|
whole_stream_command(Mkdir),
|
||||||
|
whole_stream_command(Mv),
|
||||||
|
whole_stream_command(Kill),
|
||||||
|
whole_stream_command(Version),
|
||||||
|
whole_stream_command(Clear),
|
||||||
|
whole_stream_command(Describe),
|
||||||
|
whole_stream_command(Which),
|
||||||
|
whole_stream_command(Debug),
|
||||||
|
whole_stream_command(WithEnv),
|
||||||
|
whole_stream_command(Do),
|
||||||
|
whole_stream_command(Sleep),
|
||||||
|
// Statistics
|
||||||
|
whole_stream_command(Size),
|
||||||
|
whole_stream_command(Count),
|
||||||
|
whole_stream_command(Benchmark),
|
||||||
|
// Metadata
|
||||||
|
whole_stream_command(Tags),
|
||||||
|
// Shells
|
||||||
|
whole_stream_command(Next),
|
||||||
|
whole_stream_command(Previous),
|
||||||
|
whole_stream_command(Shells),
|
||||||
|
whole_stream_command(Enter),
|
||||||
|
whole_stream_command(Exit),
|
||||||
|
// Viz
|
||||||
|
whole_stream_command(Chart),
|
||||||
|
// Viewers
|
||||||
|
whole_stream_command(Autoview),
|
||||||
|
whole_stream_command(Table),
|
||||||
|
// Text manipulation
|
||||||
|
whole_stream_command(Hash),
|
||||||
|
whole_stream_command(HashBase64),
|
||||||
|
whole_stream_command(Split),
|
||||||
|
whole_stream_command(SplitColumn),
|
||||||
|
whole_stream_command(SplitRow),
|
||||||
|
whole_stream_command(SplitChars),
|
||||||
|
whole_stream_command(Lines),
|
||||||
|
whole_stream_command(Echo),
|
||||||
|
whole_stream_command(Parse),
|
||||||
|
whole_stream_command(Str),
|
||||||
|
whole_stream_command(StrToDecimal),
|
||||||
|
whole_stream_command(StrToInteger),
|
||||||
|
whole_stream_command(StrDowncase),
|
||||||
|
whole_stream_command(StrUpcase),
|
||||||
|
whole_stream_command(StrCapitalize),
|
||||||
|
whole_stream_command(StrFindReplace),
|
||||||
|
whole_stream_command(StrFrom),
|
||||||
|
whole_stream_command(StrSubstring),
|
||||||
|
whole_stream_command(StrToDatetime),
|
||||||
|
whole_stream_command(StrContains),
|
||||||
|
whole_stream_command(StrIndexOf),
|
||||||
|
whole_stream_command(StrTrim),
|
||||||
|
whole_stream_command(StrTrimLeft),
|
||||||
|
whole_stream_command(StrTrimRight),
|
||||||
|
whole_stream_command(StrStartsWith),
|
||||||
|
whole_stream_command(StrEndsWith),
|
||||||
|
whole_stream_command(StrCollect),
|
||||||
|
whole_stream_command(StrLength),
|
||||||
|
whole_stream_command(StrLPad),
|
||||||
|
whole_stream_command(StrReverse),
|
||||||
|
whole_stream_command(StrRPad),
|
||||||
|
whole_stream_command(StrCamelCase),
|
||||||
|
whole_stream_command(StrPascalCase),
|
||||||
|
whole_stream_command(StrKebabCase),
|
||||||
|
whole_stream_command(StrSnakeCase),
|
||||||
|
whole_stream_command(StrScreamingSnakeCase),
|
||||||
|
whole_stream_command(BuildString),
|
||||||
|
whole_stream_command(Ansi),
|
||||||
|
whole_stream_command(Char),
|
||||||
|
// Column manipulation
|
||||||
|
whole_stream_command(Move),
|
||||||
|
whole_stream_command(Reject),
|
||||||
|
whole_stream_command(Select),
|
||||||
|
whole_stream_command(Get),
|
||||||
|
whole_stream_command(Update),
|
||||||
|
whole_stream_command(Insert),
|
||||||
|
whole_stream_command(IntoInt),
|
||||||
|
whole_stream_command(SplitBy),
|
||||||
|
// Row manipulation
|
||||||
|
whole_stream_command(Reverse),
|
||||||
|
whole_stream_command(Append),
|
||||||
|
whole_stream_command(Prepend),
|
||||||
|
whole_stream_command(SortBy),
|
||||||
|
whole_stream_command(GroupBy),
|
||||||
|
whole_stream_command(GroupByDate),
|
||||||
|
whole_stream_command(First),
|
||||||
|
whole_stream_command(Last),
|
||||||
|
whole_stream_command(Every),
|
||||||
|
whole_stream_command(Nth),
|
||||||
|
whole_stream_command(Drop),
|
||||||
|
whole_stream_command(Format),
|
||||||
|
whole_stream_command(FileSize),
|
||||||
|
whole_stream_command(Where),
|
||||||
|
whole_stream_command(If),
|
||||||
|
whole_stream_command(Compact),
|
||||||
|
whole_stream_command(Default),
|
||||||
|
whole_stream_command(Skip),
|
||||||
|
whole_stream_command(SkipUntil),
|
||||||
|
whole_stream_command(SkipWhile),
|
||||||
|
whole_stream_command(Keep),
|
||||||
|
whole_stream_command(KeepUntil),
|
||||||
|
whole_stream_command(KeepWhile),
|
||||||
|
whole_stream_command(Range),
|
||||||
|
whole_stream_command(Rename),
|
||||||
|
whole_stream_command(Uniq),
|
||||||
|
whole_stream_command(Each),
|
||||||
|
whole_stream_command(EachGroup),
|
||||||
|
whole_stream_command(EachWindow),
|
||||||
|
whole_stream_command(Empty),
|
||||||
|
// Table manipulation
|
||||||
|
whole_stream_command(Flatten),
|
||||||
|
whole_stream_command(Move),
|
||||||
|
whole_stream_command(Merge),
|
||||||
|
whole_stream_command(Shuffle),
|
||||||
|
whole_stream_command(Wrap),
|
||||||
|
whole_stream_command(Pivot),
|
||||||
|
whole_stream_command(Headers),
|
||||||
|
whole_stream_command(Reduce),
|
||||||
|
// Data processing
|
||||||
|
whole_stream_command(Histogram),
|
||||||
|
whole_stream_command(Autoenv),
|
||||||
|
whole_stream_command(AutoenvTrust),
|
||||||
|
whole_stream_command(AutoenvUnTrust),
|
||||||
|
whole_stream_command(Math),
|
||||||
|
whole_stream_command(MathAbs),
|
||||||
|
whole_stream_command(MathAverage),
|
||||||
|
whole_stream_command(MathEval),
|
||||||
|
whole_stream_command(MathMedian),
|
||||||
|
whole_stream_command(MathMinimum),
|
||||||
|
whole_stream_command(MathMode),
|
||||||
|
whole_stream_command(MathMaximum),
|
||||||
|
whole_stream_command(MathStddev),
|
||||||
|
whole_stream_command(MathSummation),
|
||||||
|
whole_stream_command(MathVariance),
|
||||||
|
whole_stream_command(MathProduct),
|
||||||
|
whole_stream_command(MathRound),
|
||||||
|
whole_stream_command(MathFloor),
|
||||||
|
whole_stream_command(MathCeil),
|
||||||
|
// File format output
|
||||||
|
whole_stream_command(To),
|
||||||
|
whole_stream_command(ToCSV),
|
||||||
|
whole_stream_command(ToHTML),
|
||||||
|
whole_stream_command(ToJSON),
|
||||||
|
whole_stream_command(ToMarkdown),
|
||||||
|
whole_stream_command(ToTOML),
|
||||||
|
whole_stream_command(ToTSV),
|
||||||
|
whole_stream_command(ToURL),
|
||||||
|
whole_stream_command(ToYAML),
|
||||||
|
whole_stream_command(ToXML),
|
||||||
|
// File format input
|
||||||
|
whole_stream_command(From),
|
||||||
|
whole_stream_command(FromCSV),
|
||||||
|
whole_stream_command(FromEML),
|
||||||
|
whole_stream_command(FromTSV),
|
||||||
|
whole_stream_command(FromSSV),
|
||||||
|
whole_stream_command(FromINI),
|
||||||
|
whole_stream_command(FromJSON),
|
||||||
|
whole_stream_command(FromODS),
|
||||||
|
whole_stream_command(FromTOML),
|
||||||
|
whole_stream_command(FromURL),
|
||||||
|
whole_stream_command(FromXLSX),
|
||||||
|
whole_stream_command(FromXML),
|
||||||
|
whole_stream_command(FromYAML),
|
||||||
|
whole_stream_command(FromYML),
|
||||||
|
whole_stream_command(FromIcs),
|
||||||
|
whole_stream_command(FromVcf),
|
||||||
|
// "Private" commands (not intended to be accessed directly)
|
||||||
|
whole_stream_command(RunExternalCommand { interactive }),
|
||||||
|
// Random value generation
|
||||||
|
whole_stream_command(Random),
|
||||||
|
whole_stream_command(RandomBool),
|
||||||
|
whole_stream_command(RandomDice),
|
||||||
|
#[cfg(feature = "uuid_crate")]
|
||||||
|
whole_stream_command(RandomUUID),
|
||||||
|
whole_stream_command(RandomInteger),
|
||||||
|
whole_stream_command(RandomDecimal),
|
||||||
|
whole_stream_command(RandomChars),
|
||||||
|
// Path
|
||||||
|
whole_stream_command(PathBasename),
|
||||||
|
whole_stream_command(PathCommand),
|
||||||
|
whole_stream_command(PathDirname),
|
||||||
|
whole_stream_command(PathExists),
|
||||||
|
whole_stream_command(PathExpand),
|
||||||
|
whole_stream_command(PathExtension),
|
||||||
|
whole_stream_command(PathFilestem),
|
||||||
|
whole_stream_command(PathType),
|
||||||
|
// Url
|
||||||
|
whole_stream_command(UrlCommand),
|
||||||
|
whole_stream_command(UrlScheme),
|
||||||
|
whole_stream_command(UrlPath),
|
||||||
|
whole_stream_command(UrlHost),
|
||||||
|
whole_stream_command(UrlQuery),
|
||||||
|
whole_stream_command(Seq),
|
||||||
|
whole_stream_command(SeqDates),
|
||||||
|
]);
|
||||||
|
|
||||||
|
#[cfg(feature = "clipboard-cli")]
|
||||||
|
{
|
||||||
|
context.add_commands(vec![whole_stream_command(crate::commands::clip::Clip)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(context)
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
|
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||||
@ -23,19 +23,12 @@ impl WholeStreamCommand for Describe {
|
|||||||
"Describes the objects in the stream."
|
"Describes the objects in the stream."
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
describe(args).await
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
describe(args, registry).await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn describe(
|
pub async fn describe(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
args: CommandArgs,
|
|
||||||
_registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
Ok(args
|
Ok(args
|
||||||
.input
|
.input
|
||||||
.map(|row| {
|
.map(|row| {
|
@ -1,16 +1,14 @@
|
|||||||
use crate::commands::classified::block::run_block;
|
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::run_block;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{
|
use nu_protocol::{hir::CapturedBlock, hir::ExternalRedirection, Signature, SyntaxShape, Value};
|
||||||
hir::Block, hir::ExternalRedirection, ReturnSuccess, Signature, SyntaxShape, Value,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct Do;
|
pub struct Do;
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
struct DoArgs {
|
struct DoArgs {
|
||||||
block: Block,
|
block: CapturedBlock,
|
||||||
ignore_errors: bool,
|
ignore_errors: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,12 +32,8 @@ impl WholeStreamCommand for Do {
|
|||||||
"Runs a block, optionally ignoring errors"
|
"Runs a block, optionally ignoring errors"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
do_(args).await
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
do_(args, registry).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -52,28 +46,23 @@ impl WholeStreamCommand for Do {
|
|||||||
Example {
|
Example {
|
||||||
description: "Run the block and ignore errors",
|
description: "Run the block and ignore errors",
|
||||||
example: r#"do -i { thisisnotarealcommand }"#,
|
example: r#"do -i { thisisnotarealcommand }"#,
|
||||||
result: Some(vec![Value::nothing()]),
|
result: Some(vec![]),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn do_(
|
async fn do_(raw_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
raw_args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let registry = registry.clone();
|
|
||||||
let external_redirection = raw_args.call_info.args.external_redirection;
|
let external_redirection = raw_args.call_info.args.external_redirection;
|
||||||
|
|
||||||
let mut context = EvaluationContext::from_raw(&raw_args, ®istry);
|
let context = EvaluationContext::from_raw(&raw_args);
|
||||||
let scope = raw_args.call_info.scope.clone();
|
|
||||||
let (
|
let (
|
||||||
DoArgs {
|
DoArgs {
|
||||||
ignore_errors,
|
ignore_errors,
|
||||||
mut block,
|
mut block,
|
||||||
},
|
},
|
||||||
input,
|
input,
|
||||||
) = raw_args.process(®istry).await?;
|
) = raw_args.process().await?;
|
||||||
|
|
||||||
let block_redirection = match external_redirection {
|
let block_redirection = match external_redirection {
|
||||||
ExternalRedirection::None => {
|
ExternalRedirection::None => {
|
||||||
@ -93,9 +82,10 @@ async fn do_(
|
|||||||
x => x,
|
x => x,
|
||||||
};
|
};
|
||||||
|
|
||||||
block.set_redirect(block_redirection);
|
block.block.set_redirect(block_redirection);
|
||||||
|
context.scope.enter_scope();
|
||||||
let result = run_block(&block, &mut context, input, scope).await;
|
let result = run_block(&block.block, &context, input).await;
|
||||||
|
context.scope.exit_scope();
|
||||||
|
|
||||||
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
|
||||||
@ -107,7 +97,7 @@ async fn do_(
|
|||||||
context.clear_errors();
|
context.clear_errors();
|
||||||
Ok(futures::stream::iter(output).to_output_stream())
|
Ok(futures::stream::iter(output).to_output_stream())
|
||||||
}
|
}
|
||||||
Err(_) => Ok(OutputStream::one(ReturnSuccess::value(Value::nothing()))),
|
Err(_) => Ok(OutputStream::empty()),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result.map(|x| x.to_output_stream())
|
result.map(|x| x.to_output_stream())
|
@ -1,6 +1,5 @@
|
|||||||
use crate::command_registry::CommandRegistry;
|
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{Signature, SyntaxShape, UntaggedValue};
|
use nu_protocol::{Signature, SyntaxShape, UntaggedValue};
|
||||||
use nu_source::Tagged;
|
use nu_source::Tagged;
|
||||||
@ -30,12 +29,8 @@ impl WholeStreamCommand for Drop {
|
|||||||
"Remove the last number of rows. If you want to remove columns, try 'reject'."
|
"Remove the last number of rows. If you want to remove columns, try 'reject'."
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
drop(args).await
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
drop(args, registry).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -57,8 +52,8 @@ impl WholeStreamCommand for Drop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn drop(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
async fn drop(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let (DropArgs { rows }, input) = args.process(®istry).await?;
|
let (DropArgs { rows }, input) = args.process().await?;
|
||||||
let v: Vec<_> = input.into_vec().await;
|
let v: Vec<_> = input.into_vec().await;
|
||||||
|
|
||||||
let rows_to_drop = if let Some(quantity) = rows {
|
let rows_to_drop = if let Some(quantity) = rows {
|
173
crates/nu-command/src/commands/du.rs
Normal file
173
crates/nu-command/src/commands/du.rs
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
use glob::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
|
use nu_engine::{DirBuilder, DirInfo, FileInfo};
|
||||||
|
use nu_errors::ShellError;
|
||||||
|
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape};
|
||||||
|
use nu_source::Tagged;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
const NAME: &str = "du";
|
||||||
|
const GLOB_PARAMS: MatchOptions = MatchOptions {
|
||||||
|
case_sensitive: true,
|
||||||
|
require_literal_separator: true,
|
||||||
|
require_literal_leading_dot: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Du;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone)]
|
||||||
|
pub struct DuArgs {
|
||||||
|
path: Option<Tagged<PathBuf>>,
|
||||||
|
all: bool,
|
||||||
|
deref: bool,
|
||||||
|
exclude: Option<Tagged<String>>,
|
||||||
|
#[serde(rename = "max-depth")]
|
||||||
|
max_depth: Option<Tagged<u64>>,
|
||||||
|
#[serde(rename = "min-size")]
|
||||||
|
min_size: Option<Tagged<u64>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl WholeStreamCommand for Du {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
NAME
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(NAME)
|
||||||
|
.optional("path", SyntaxShape::GlobPattern, "starting directory")
|
||||||
|
.switch(
|
||||||
|
"all",
|
||||||
|
"Output file sizes as well as directory sizes",
|
||||||
|
Some('a'),
|
||||||
|
)
|
||||||
|
.switch(
|
||||||
|
"deref",
|
||||||
|
"Dereference symlinks to their targets for size",
|
||||||
|
Some('r'),
|
||||||
|
)
|
||||||
|
.named(
|
||||||
|
"exclude",
|
||||||
|
SyntaxShape::GlobPattern,
|
||||||
|
"Exclude these file names",
|
||||||
|
Some('x'),
|
||||||
|
)
|
||||||
|
.named(
|
||||||
|
"max-depth",
|
||||||
|
SyntaxShape::Int,
|
||||||
|
"Directory recursion limit",
|
||||||
|
Some('d'),
|
||||||
|
)
|
||||||
|
.named(
|
||||||
|
"min-size",
|
||||||
|
SyntaxShape::Int,
|
||||||
|
"Exclude files below this size",
|
||||||
|
Some('m'),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Find disk usage sizes of specified items"
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
|
du(args).await
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
description: "Disk usage of the current directory",
|
||||||
|
example: "du",
|
||||||
|
result: None,
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn du(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
|
let tag = args.call_info.name_tag.clone();
|
||||||
|
let ctrl_c = args.ctrl_c.clone();
|
||||||
|
let ctrl_c_copy = ctrl_c.clone();
|
||||||
|
|
||||||
|
let (args, _): (DuArgs, _) = args.process().await?;
|
||||||
|
let exclude = args.exclude.map_or(Ok(None), move |x| {
|
||||||
|
Pattern::new(&x.item)
|
||||||
|
.map(Option::Some)
|
||||||
|
.map_err(|e| ShellError::labeled_error(e.msg, "glob error", x.tag.clone()))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let include_files = args.all;
|
||||||
|
let paths = match args.path {
|
||||||
|
Some(p) => {
|
||||||
|
let p = p.item.to_str().expect("Why isn't this encoded properly?");
|
||||||
|
glob::glob_with(p, GLOB_PARAMS)
|
||||||
|
}
|
||||||
|
None => glob::glob_with("*", GLOB_PARAMS),
|
||||||
|
}
|
||||||
|
.map_err(|e| ShellError::labeled_error(e.msg, "glob error", tag.clone()))?
|
||||||
|
.filter(move |p| {
|
||||||
|
if include_files {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
match p {
|
||||||
|
Ok(f) if f.is_dir() => true,
|
||||||
|
Err(e) if e.path().is_dir() => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|v| v.map_err(glob_err_into));
|
||||||
|
|
||||||
|
let all = args.all;
|
||||||
|
let deref = args.deref;
|
||||||
|
let max_depth = args.max_depth.map(|f| f.item);
|
||||||
|
let min_size = args.min_size.map(|f| f.item);
|
||||||
|
|
||||||
|
let params = DirBuilder {
|
||||||
|
tag: tag.clone(),
|
||||||
|
min: min_size,
|
||||||
|
deref,
|
||||||
|
exclude,
|
||||||
|
all,
|
||||||
|
};
|
||||||
|
|
||||||
|
let inp = futures::stream::iter(paths);
|
||||||
|
|
||||||
|
Ok(inp
|
||||||
|
.flat_map(move |path| match path {
|
||||||
|
Ok(p) => {
|
||||||
|
let mut output = vec![];
|
||||||
|
if p.is_dir() {
|
||||||
|
output.push(Ok(ReturnSuccess::Value(
|
||||||
|
DirInfo::new(p, ¶ms, max_depth, ctrl_c.clone()).into(),
|
||||||
|
)));
|
||||||
|
} else {
|
||||||
|
for v in FileInfo::new(p, deref, tag.clone()).into_iter() {
|
||||||
|
output.push(Ok(ReturnSuccess::Value(v.into())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
futures::stream::iter(output)
|
||||||
|
}
|
||||||
|
Err(e) => futures::stream::iter(vec![Err(e)]),
|
||||||
|
})
|
||||||
|
.interruptible(ctrl_c_copy)
|
||||||
|
.to_output_stream())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn glob_err_into(e: GlobError) -> ShellError {
|
||||||
|
let e = e.into_error();
|
||||||
|
ShellError::from(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::Du;
|
||||||
|
use super::ShellError;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||||
|
use crate::examples::test as test_examples;
|
||||||
|
|
||||||
|
Ok(test_examples(Du {})?)
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,11 @@
|
|||||||
use crate::command_registry::CommandRegistry;
|
|
||||||
use crate::commands::classified::block::run_block;
|
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::run_block;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
|
|
||||||
use futures::stream::once;
|
use futures::stream::once;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
hir::Block, Scope, Signature, SyntaxShape, TaggedDictBuilder, UntaggedValue, Value,
|
hir::CapturedBlock, Signature, SyntaxShape, TaggedDictBuilder, UntaggedValue, Value,
|
||||||
};
|
};
|
||||||
use nu_source::Tagged;
|
use nu_source::Tagged;
|
||||||
|
|
||||||
@ -14,7 +13,7 @@ pub struct Each;
|
|||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct EachArgs {
|
pub struct EachArgs {
|
||||||
block: Block,
|
block: CapturedBlock,
|
||||||
numbered: Tagged<bool>,
|
numbered: Tagged<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,12 +37,8 @@ impl WholeStreamCommand for Each {
|
|||||||
"Run a block on each row of the table."
|
"Run a block on each row of the table."
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
each(args).await
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
each(args, registry).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -73,9 +68,8 @@ impl WholeStreamCommand for Each {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn process_row(
|
pub async fn process_row(
|
||||||
block: Arc<Block>,
|
captured_block: Arc<Box<CapturedBlock>>,
|
||||||
scope: Arc<Scope>,
|
context: Arc<EvaluationContext>,
|
||||||
mut context: Arc<EvaluationContext>,
|
|
||||||
input: Value,
|
input: Value,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let input_clone = input.clone();
|
let input_clone = input.clone();
|
||||||
@ -83,24 +77,29 @@ pub async fn process_row(
|
|||||||
// a parameter to the block (so it gets assigned to a variable that can be used inside the block) or
|
// a parameter to the block (so it gets assigned to a variable that can be used inside the block) or
|
||||||
// if it wants the contents as as an input stream
|
// if it wants the contents as as an input stream
|
||||||
|
|
||||||
let input_stream = if !block.params.is_empty() {
|
let input_stream = if !captured_block.block.params.positional.is_empty() {
|
||||||
InputStream::empty()
|
InputStream::empty()
|
||||||
} else {
|
} else {
|
||||||
once(async { Ok(input_clone) }).to_input_stream()
|
once(async { Ok(input_clone) }).to_input_stream()
|
||||||
};
|
};
|
||||||
|
|
||||||
let scope = if !block.params.is_empty() {
|
context.scope.enter_scope();
|
||||||
// FIXME: add check for more than parameter, once that's supported
|
context.scope.add_vars(&captured_block.captured.entries);
|
||||||
Scope::append_var(scope, block.params[0].clone(), input)
|
|
||||||
} else {
|
|
||||||
scope
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(
|
if !captured_block.block.params.positional.is_empty() {
|
||||||
run_block(&block, Arc::make_mut(&mut context), input_stream, scope)
|
// FIXME: add check for more than parameter, once that's supported
|
||||||
.await?
|
context
|
||||||
.to_output_stream(),
|
.scope
|
||||||
)
|
.add_var(captured_block.block.params.positional[0].0.name(), input);
|
||||||
|
} else {
|
||||||
|
context.scope.add_var("$it", input);
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = run_block(&captured_block.block, &*context, input_stream).await;
|
||||||
|
|
||||||
|
context.scope.exit_scope();
|
||||||
|
|
||||||
|
Ok(result?.to_output_stream())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn make_indexed_item(index: usize, item: Value) -> Value {
|
pub(crate) fn make_indexed_item(index: usize, item: Value) -> Value {
|
||||||
@ -111,27 +110,22 @@ pub(crate) fn make_indexed_item(index: usize, item: Value) -> Value {
|
|||||||
dict.into_value()
|
dict.into_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn each(
|
async fn each(raw_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
raw_args: CommandArgs,
|
let context = Arc::new(EvaluationContext::from_raw(&raw_args));
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
let (each_args, input): (EachArgs, _) = raw_args.process().await?;
|
||||||
let registry = registry.clone();
|
let block = Arc::new(Box::new(each_args.block));
|
||||||
let scope = raw_args.call_info.scope.clone();
|
|
||||||
let context = Arc::new(EvaluationContext::from_raw(&raw_args, ®istry));
|
|
||||||
let (each_args, input): (EachArgs, _) = raw_args.process(®istry).await?;
|
|
||||||
let block = Arc::new(each_args.block);
|
|
||||||
|
|
||||||
if each_args.numbered.item {
|
if each_args.numbered.item {
|
||||||
Ok(input
|
Ok(input
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.then(move |input| {
|
.then(move |input| {
|
||||||
let block = block.clone();
|
let block = block.clone();
|
||||||
let scope = scope.clone();
|
|
||||||
let context = context.clone();
|
let context = context.clone();
|
||||||
let row = make_indexed_item(input.0, input.1);
|
let row = make_indexed_item(input.0, input.1);
|
||||||
|
|
||||||
async {
|
async {
|
||||||
match process_row(block, scope, context, row).await {
|
match process_row(block, context, row).await {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(e) => OutputStream::one(Err(e)),
|
Err(e) => OutputStream::one(Err(e)),
|
||||||
}
|
}
|
||||||
@ -143,11 +137,10 @@ async fn each(
|
|||||||
Ok(input
|
Ok(input
|
||||||
.then(move |input| {
|
.then(move |input| {
|
||||||
let block = block.clone();
|
let block = block.clone();
|
||||||
let scope = scope.clone();
|
|
||||||
let context = context.clone();
|
let context = context.clone();
|
||||||
|
|
||||||
async {
|
async {
|
||||||
match process_row(block, scope, context, input).await {
|
match process_row(block, context, input).await {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(e) => OutputStream::one(Err(e)),
|
Err(e) => OutputStream::one(Err(e)),
|
||||||
}
|
}
|
@ -1,8 +1,10 @@
|
|||||||
use crate::commands::each::process_row;
|
use crate::commands::each::process_row;
|
||||||
use crate::commands::WholeStreamCommand;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{hir::Block, ReturnSuccess, Scope, Signature, SyntaxShape, UntaggedValue, Value};
|
use nu_protocol::{
|
||||||
|
hir::CapturedBlock, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||||
|
};
|
||||||
use nu_source::Tagged;
|
use nu_source::Tagged;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
@ -11,7 +13,7 @@ pub struct EachGroup;
|
|||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct EachGroupArgs {
|
pub struct EachGroupArgs {
|
||||||
group_size: Tagged<usize>,
|
group_size: Tagged<usize>,
|
||||||
block: Block,
|
block: CapturedBlock,
|
||||||
//numbered: Tagged<bool>,
|
//numbered: Tagged<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,22 +45,14 @@ impl WholeStreamCommand for EachGroup {
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run(
|
async fn run(&self, raw_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
&self,
|
let context = Arc::new(EvaluationContext::from_raw(&raw_args));
|
||||||
raw_args: CommandArgs,
|
let (each_args, input): (EachGroupArgs, _) = raw_args.process().await?;
|
||||||
registry: &CommandRegistry,
|
let block = Arc::new(Box::new(each_args.block));
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
let registry = registry.clone();
|
|
||||||
let scope = raw_args.call_info.scope.clone();
|
|
||||||
let context = Arc::new(EvaluationContext::from_raw(&raw_args, ®istry));
|
|
||||||
let (each_args, input): (EachGroupArgs, _) = raw_args.process(®istry).await?;
|
|
||||||
let block = Arc::new(each_args.block);
|
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.chunks(each_args.group_size.item)
|
.chunks(each_args.group_size.item)
|
||||||
.then(move |input| {
|
.then(move |input| run_block_on_vec(input, block.clone(), context.clone()))
|
||||||
run_block_on_vec(input, block.clone(), scope.clone(), context.clone())
|
|
||||||
})
|
|
||||||
.flatten()
|
.flatten()
|
||||||
.to_output_stream())
|
.to_output_stream())
|
||||||
}
|
}
|
||||||
@ -66,8 +60,7 @@ impl WholeStreamCommand for EachGroup {
|
|||||||
|
|
||||||
pub(crate) fn run_block_on_vec(
|
pub(crate) fn run_block_on_vec(
|
||||||
input: Vec<Value>,
|
input: Vec<Value>,
|
||||||
block: Arc<Block>,
|
block: Arc<Box<CapturedBlock>>,
|
||||||
scope: Arc<Scope>,
|
|
||||||
context: Arc<EvaluationContext>,
|
context: Arc<EvaluationContext>,
|
||||||
) -> impl Future<Output = OutputStream> {
|
) -> impl Future<Output = OutputStream> {
|
||||||
let value = Value {
|
let value = Value {
|
||||||
@ -76,7 +69,7 @@ pub(crate) fn run_block_on_vec(
|
|||||||
};
|
};
|
||||||
|
|
||||||
async {
|
async {
|
||||||
match process_row(block, scope, context, value).await {
|
match process_row(block, context, value).await {
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
// We need to handle this differently depending on whether process_row
|
// We need to handle this differently depending on whether process_row
|
||||||
// returned just 1 value or if it returned multiple as a stream.
|
// returned just 1 value or if it returned multiple as a stream.
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user