mirror of
https://github.com/nushell/nushell.git
synced 2025-07-01 15:11:52 +02:00
Compare commits
115 Commits
Author | SHA1 | Date | |
---|---|---|---|
7dc1d6a350 | |||
deff1aa63b | |||
08e7d0dfb6 | |||
892aae267d | |||
11a9144e84 | |||
039f223b53 | |||
e1cb026184 | |||
2a96152a43 | |||
0795d56c1c | |||
48a90fea70 | |||
b202951c1d | |||
c3d2c61729 | |||
d7b707939f | |||
991ac6eb77 | |||
011b7c4a07 | |||
617341f8d5 | |||
abd2632977 | |||
5481db4079 | |||
041086d22a | |||
aa564f5072 | |||
8367f2001c | |||
1cfb228924 | |||
b403fb1275 | |||
3443ca40c5 | |||
96f95653a6 | |||
7f7e8465da | |||
e3a273cf73 | |||
233161d56e | |||
d883ab250a | |||
ef4e3f907c | |||
debeadbf3f | |||
d66baaceb9 | |||
85329f9a81 | |||
a5fefaf78b | |||
6f17662a4e | |||
c83aea3c89 | |||
67aaf4cb2d | |||
3083346884 | |||
d07789677f | |||
fb1846120d | |||
da1e1295ea | |||
ecaea57263 | |||
fa928bd25d | |||
c1981dfc26 | |||
fd41fa31d5 | |||
2c52144f41 | |||
87c7898b65 | |||
44e088c6fe | |||
7b4cbd7ce9 | |||
b052d524da | |||
47c4b8e88a | |||
d0a2a02eea | |||
b1e1dab4cb | |||
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 |
@ -4,7 +4,7 @@ tasks:
|
||||
- name: Clippy
|
||||
init: cargo clippy --all --features=stable -- -D clippy::result_unwrap_used -D clippy::option_unwrap_used
|
||||
- name: Testing
|
||||
init: cargo test --all --features=stable,test-bins
|
||||
init: cargo test --all --features=stable
|
||||
- name: Build
|
||||
init: cargo build --features=stable
|
||||
- name: Nu
|
||||
|
2150
Cargo.lock
generated
2150
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
157
Cargo.toml
157
Cargo.toml
@ -10,7 +10,7 @@ license = "MIT"
|
||||
name = "nu"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/nushell/nushell"
|
||||
version = "0.25.1"
|
||||
version = "0.27.1"
|
||||
|
||||
[workspace]
|
||||
members = ["crates/*/"]
|
||||
@ -18,83 +18,110 @@ members = ["crates/*/"]
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nu-cli = {version = "0.25.1", path = "./crates/nu-cli"}
|
||||
nu-data = {version = "0.25.1", path = "./crates/nu-data"}
|
||||
nu-errors = {version = "0.25.1", path = "./crates/nu-errors"}
|
||||
nu-parser = {version = "0.25.1", path = "./crates/nu-parser"}
|
||||
nu-plugin = {version = "0.25.1", path = "./crates/nu-plugin"}
|
||||
nu-protocol = {version = "0.25.1", path = "./crates/nu-protocol"}
|
||||
nu-source = {version = "0.25.1", path = "./crates/nu-source"}
|
||||
nu-value-ext = {version = "0.25.1", path = "./crates/nu-value-ext"}
|
||||
nu-cli = { version = "0.27.1", path = "./crates/nu-cli", default-features = false }
|
||||
nu-command = { version = "0.27.1", path = "./crates/nu-command" }
|
||||
nu-data = { version = "0.27.1", path = "./crates/nu-data" }
|
||||
nu-engine = { version = "0.27.1", path = "./crates/nu-engine" }
|
||||
nu-errors = { version = "0.27.1", path = "./crates/nu-errors" }
|
||||
nu-parser = { version = "0.27.1", path = "./crates/nu-parser" }
|
||||
nu-plugin = { version = "0.27.1", path = "./crates/nu-plugin" }
|
||||
nu-protocol = { version = "0.27.1", path = "./crates/nu-protocol" }
|
||||
nu-source = { version = "0.27.1", path = "./crates/nu-source" }
|
||||
nu-value-ext = { version = "0.27.1", path = "./crates/nu-value-ext" }
|
||||
|
||||
nu_plugin_binaryview = {version = "0.25.1", path = "./crates/nu_plugin_binaryview", optional = true}
|
||||
nu_plugin_chart = {version = "0.25.1", path = "./crates/nu_plugin_chart", optional = true}
|
||||
nu_plugin_fetch = {version = "0.25.1", path = "./crates/nu_plugin_fetch", optional = true}
|
||||
nu_plugin_from_bson = {version = "0.25.1", path = "./crates/nu_plugin_from_bson", optional = true}
|
||||
nu_plugin_from_sqlite = {version = "0.25.1", path = "./crates/nu_plugin_from_sqlite", optional = true}
|
||||
nu_plugin_inc = {version = "0.25.1", path = "./crates/nu_plugin_inc", optional = true}
|
||||
nu_plugin_match = {version = "0.25.1", path = "./crates/nu_plugin_match", optional = true}
|
||||
nu_plugin_post = {version = "0.25.1", path = "./crates/nu_plugin_post", optional = true}
|
||||
nu_plugin_ps = {version = "0.25.1", path = "./crates/nu_plugin_ps", optional = true}
|
||||
nu_plugin_s3 = {version = "0.25.1", path = "./crates/nu_plugin_s3", optional = true}
|
||||
nu_plugin_selector = {version = "0.25.1", path = "./crates/nu_plugin_selector", optional = true}
|
||||
nu_plugin_start = {version = "0.25.1", path = "./crates/nu_plugin_start", optional = true}
|
||||
nu_plugin_sys = {version = "0.25.1", path = "./crates/nu_plugin_sys", optional = true}
|
||||
nu_plugin_textview = {version = "0.25.1", path = "./crates/nu_plugin_textview", optional = true}
|
||||
nu_plugin_to_bson = {version = "0.25.1", path = "./crates/nu_plugin_to_bson", optional = true}
|
||||
nu_plugin_to_sqlite = {version = "0.25.1", path = "./crates/nu_plugin_to_sqlite", optional = true}
|
||||
nu_plugin_tree = {version = "0.25.1", path = "./crates/nu_plugin_tree", optional = true}
|
||||
nu_plugin_xpath = {version = "0.25.1", path = "./crates/nu_plugin_xpath", optional = true}
|
||||
nu_plugin_binaryview = { version = "0.27.1", path = "./crates/nu_plugin_binaryview", optional = true }
|
||||
nu_plugin_chart = { version = "0.27.1", path = "./crates/nu_plugin_chart", optional = true }
|
||||
nu_plugin_fetch = { version = "0.27.1", path = "./crates/nu_plugin_fetch", optional = true }
|
||||
nu_plugin_from_bson = { version = "0.27.1", path = "./crates/nu_plugin_from_bson", optional = true }
|
||||
nu_plugin_from_sqlite = { version = "0.27.1", path = "./crates/nu_plugin_from_sqlite", optional = true }
|
||||
nu_plugin_inc = { version = "0.27.1", path = "./crates/nu_plugin_inc", optional = true }
|
||||
nu_plugin_match = { version = "0.27.1", path = "./crates/nu_plugin_match", optional = true }
|
||||
nu_plugin_post = { version = "0.27.1", path = "./crates/nu_plugin_post", optional = true }
|
||||
nu_plugin_ps = { version = "0.27.1", path = "./crates/nu_plugin_ps", optional = true }
|
||||
nu_plugin_s3 = { version = "0.27.1", path = "./crates/nu_plugin_s3", optional = true }
|
||||
nu_plugin_selector = { version = "0.27.1", path = "./crates/nu_plugin_selector", optional = true }
|
||||
nu_plugin_start = { version = "0.27.1", path = "./crates/nu_plugin_start", optional = true }
|
||||
nu_plugin_sys = { version = "0.27.1", path = "./crates/nu_plugin_sys", optional = true }
|
||||
nu_plugin_textview = { version = "0.27.1", path = "./crates/nu_plugin_textview", optional = true }
|
||||
nu_plugin_to_bson = { version = "0.27.1", path = "./crates/nu_plugin_to_bson", optional = true }
|
||||
nu_plugin_to_sqlite = { version = "0.27.1", path = "./crates/nu_plugin_to_sqlite", optional = true }
|
||||
nu_plugin_tree = { version = "0.27.1", path = "./crates/nu_plugin_tree", optional = true }
|
||||
nu_plugin_xpath = { version = "0.27.1", path = "./crates/nu_plugin_xpath", optional = true }
|
||||
|
||||
# Required to bootstrap the main binary
|
||||
clap = "2.33.3"
|
||||
ctrlc = {version = "3.1.6", optional = true}
|
||||
futures = {version = "0.3.5", features = ["compat", "io-compat"]}
|
||||
itertools = "0.9.0"
|
||||
log = "0.4.11"
|
||||
ctrlc = { version = "3.1.7", optional = true }
|
||||
futures = { version = "0.3.12", features = ["compat", "io-compat"] }
|
||||
itertools = "0.10.0"
|
||||
log = "0.4.14"
|
||||
pretty_env_logger = "0.4.0"
|
||||
syn = "=1.0.57"
|
||||
|
||||
[dev-dependencies]
|
||||
nu-test-support = { version = "0.27.1", path = "./crates/nu-test-support" }
|
||||
dunce = "1.0.1"
|
||||
nu-test-support = {version = "0.25.1", path = "./crates/nu-test-support"}
|
||||
serial_test = "0.5.1"
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
|
||||
[features]
|
||||
ctrlc-support = ["nu-cli/ctrlc"]
|
||||
directories-support = ["nu-cli/directories", "nu-cli/dirs", "nu-data/directories", "nu-data/dirs"]
|
||||
git-support = ["nu-cli/git2"]
|
||||
ptree-support = ["nu-cli/ptree"]
|
||||
rich-benchmark = ["nu-cli/rich-benchmark"]
|
||||
rustyline-support = ["nu-cli/rustyline-support"]
|
||||
term-support = ["nu-cli/term"]
|
||||
uuid-support = ["nu-cli/uuid_crate"]
|
||||
which-support = ["nu-cli/ichwh", "nu-cli/which"]
|
||||
ctrlc-support = ["nu-cli/ctrlc", "nu-command/ctrlc"]
|
||||
directories-support = [
|
||||
"nu-cli/directories",
|
||||
"nu-cli/dirs",
|
||||
"nu-command/directories",
|
||||
"nu-command/dirs",
|
||||
"nu-data/directories",
|
||||
"nu-data/dirs",
|
||||
"nu-engine/dirs",
|
||||
]
|
||||
ptree-support = ["nu-cli/ptree", "nu-command/ptree"]
|
||||
rustyline-support = ["nu-cli/rustyline-support", "nu-command/rustyline-support"]
|
||||
term-support = ["nu-cli/term", "nu-command/term"]
|
||||
uuid-support = ["nu-cli/uuid_crate", "nu-command/uuid_crate"]
|
||||
which-support = [
|
||||
"nu-cli/ichwh",
|
||||
"nu-cli/which",
|
||||
"nu-command/ichwh",
|
||||
"nu-command/which",
|
||||
]
|
||||
|
||||
default = [
|
||||
"sys",
|
||||
"ps",
|
||||
"textview",
|
||||
"inc",
|
||||
"git-support",
|
||||
"directories-support",
|
||||
"ctrlc-support",
|
||||
"which-support",
|
||||
"ptree-support",
|
||||
"term-support",
|
||||
"uuid-support",
|
||||
"rustyline-support",
|
||||
"match",
|
||||
"post",
|
||||
"fetch",
|
||||
"rich-benchmark",
|
||||
"zip-support",
|
||||
"nu-cli/shadow-rs",
|
||||
"sys",
|
||||
"ps",
|
||||
"textview",
|
||||
"inc",
|
||||
"directories-support",
|
||||
"ctrlc-support",
|
||||
"which-support",
|
||||
"ptree-support",
|
||||
"term-support",
|
||||
"uuid-support",
|
||||
"rustyline-support",
|
||||
"match",
|
||||
"post",
|
||||
"fetch",
|
||||
"zip-support",
|
||||
]
|
||||
extra = ["default", "binaryview", "tree", "clipboard-cli", "trash-support", "start", "bson", "sqlite", "s3", "chart", "xpath", "selector"]
|
||||
stable = ["default"]
|
||||
|
||||
wasi = ["inc", "match", "directories-support", "ptree-support", "match", "tree", "rustyline-support"]
|
||||
stable = ["default"]
|
||||
extra = [
|
||||
"default",
|
||||
"binaryview",
|
||||
"tree",
|
||||
"clipboard-cli",
|
||||
"trash-support",
|
||||
"start",
|
||||
"bson",
|
||||
"sqlite",
|
||||
"s3",
|
||||
"chart",
|
||||
"xpath",
|
||||
"selector",
|
||||
]
|
||||
|
||||
wasi = ["inc", "match", "ptree-support", "match", "tree", "rustyline-support"]
|
||||
|
||||
trace = ["nu-parser/trace"]
|
||||
|
||||
@ -106,18 +133,18 @@ post = ["nu_plugin_post"]
|
||||
ps = ["nu_plugin_ps"]
|
||||
sys = ["nu_plugin_sys"]
|
||||
textview = ["nu_plugin_textview"]
|
||||
zip-support = ["nu-cli/zip"]
|
||||
zip-support = ["nu-cli/zip", "nu-command/zip"]
|
||||
|
||||
# Extra
|
||||
binaryview = ["nu_plugin_binaryview"]
|
||||
bson = ["nu_plugin_from_bson", "nu_plugin_to_bson"]
|
||||
chart = ["nu_plugin_chart"]
|
||||
clipboard-cli = ["nu-cli/clipboard-cli"]
|
||||
clipboard-cli = ["nu-cli/clipboard-cli", "nu-command/clipboard-cli"]
|
||||
s3 = ["nu_plugin_s3"]
|
||||
selector = ["nu_plugin_selector"]
|
||||
sqlite = ["nu_plugin_from_sqlite", "nu_plugin_to_sqlite"]
|
||||
start = ["nu_plugin_start"]
|
||||
trash-support = ["nu-cli/trash-support"]
|
||||
trash-support = ["nu-cli/trash-support", "nu-command/trash-support"]
|
||||
tree = ["nu_plugin_tree"]
|
||||
xpath = ["nu_plugin_xpath"]
|
||||
|
||||
|
70
README.md
70
README.md
@ -11,7 +11,7 @@
|
||||
|
||||
A new type of shell.
|
||||
|
||||

|
||||

|
||||
|
||||
## Status
|
||||
|
||||
@ -44,19 +44,19 @@ Try it in Gitpod.
|
||||
|
||||
### Local
|
||||
|
||||
Up-to-date installation instructions can be found in the [installation chapter of the book](https://www.nushell.sh/book/installation.html). **Windows users**: please note that Nu works on Windows 10 and does not currently have Windows 7/8.1 support.
|
||||
Up-to-date installation instructions can be found in the [installation chapter of the book](https://www.nushell.sh/book/installation.html). **Windows users**: please note that Nu works on Windows 10 and does not currently have Windows 7/8.1 support.
|
||||
|
||||
To build Nu, you will need to use the **latest stable (1.47 or later)** version of the compiler.
|
||||
|
||||
Required dependencies:
|
||||
|
||||
* pkg-config and libssl (only needed on Linux)
|
||||
* On Debian/Ubuntu: `apt install pkg-config libssl-dev`
|
||||
- pkg-config and libssl (only needed on Linux)
|
||||
- On Debian/Ubuntu: `apt install pkg-config libssl-dev`
|
||||
|
||||
Optional dependencies:
|
||||
|
||||
* To use Nu with all possible optional features enabled, you'll also need the following:
|
||||
* On Linux (on Debian/Ubuntu): `apt install libxcb-composite0-dev libx11-dev`
|
||||
- To use Nu with all possible optional features enabled, you'll also need the following:
|
||||
- On Linux (on Debian/Ubuntu): `apt install libxcb-composite0-dev libx11-dev`
|
||||
|
||||
To install Nu via cargo (make sure you have installed [rustup](https://rustup.rs/) and the latest stable compiler via `rustup install stable`):
|
||||
|
||||
@ -139,9 +139,9 @@ Just as the Unix philosophy, Nu allows commands to output from stdout and read f
|
||||
Additionally, commands can output structured data (you can think of this as a third kind of stream).
|
||||
Commands that work in the pipeline fit into one of three categories:
|
||||
|
||||
* Commands that produce a stream (eg, `ls`)
|
||||
* Commands that filter a stream (eg, `where type == "Dir"`)
|
||||
* Commands that consume the output of the pipeline (eg, `autoview`)
|
||||
- Commands that produce a stream (eg, `ls`)
|
||||
- Commands that filter a stream (eg, `where type == "Dir"`)
|
||||
- Commands that consume the output of the pipeline (eg, `autoview`)
|
||||
|
||||
Commands are separated by the pipe symbol (`|`) to denote a pipeline flowing left to right.
|
||||
|
||||
@ -270,40 +270,40 @@ If the plugin is a sink, it is given the full vector of final data and is given
|
||||
|
||||
Nu adheres closely to a set of goals that make up its design philosophy. As features are added, they are checked against these goals.
|
||||
|
||||
* First and foremost, Nu is cross-platform. Commands and techniques should carry between platforms and offer first-class consistent support for Windows, macOS, and Linux.
|
||||
- First and foremost, Nu is cross-platform. Commands and techniques should carry between platforms and offer first-class consistent support for Windows, macOS, and Linux.
|
||||
|
||||
* Nu ensures direct compatibility with existing platform-specific executables that make up people's workflows.
|
||||
- Nu ensures direct compatibility with existing platform-specific executables that make up people's workflows.
|
||||
|
||||
* Nu's workflow and tools should have the usability in day-to-day experience of using a shell in 2019 (and beyond).
|
||||
- Nu's workflow and tools should have the usability in day-to-day experience of using a shell in 2019 (and beyond).
|
||||
|
||||
* Nu views data as both structured and unstructured. It is a structured shell like PowerShell.
|
||||
- Nu views data as both structured and unstructured. It is a structured shell like PowerShell.
|
||||
|
||||
* Finally, Nu views data functionally. Rather than using mutation, pipelines act as a means to load, change, and save data without mutable state.
|
||||
- Finally, Nu views data functionally. Rather than using mutation, pipelines act as a means to load, change, and save data without mutable state.
|
||||
|
||||
## Commands
|
||||
|
||||
You can find a list of Nu commands, complete with documentation, in [quick command references](https://www.nushell.sh/documentation.html#quick-command-references).
|
||||
You can find a list of Nu commands, complete with documentation, in [quick command references](https://www.nushell.sh/book/command_reference.html).
|
||||
|
||||
## Progress
|
||||
|
||||
Nu is in heavy development, and will naturally change as it matures and people use it. The chart below isn't meant to be exhaustive, but rather helps give an idea for some of the areas of development and their relative completion:
|
||||
Nu is in heavy development, and will naturally change as it matures and people use it. The chart below isn't meant to be exhaustive, but rather helps give an idea for some of the areas of development and their relative completion:
|
||||
|
||||
| Features | Not started | Prototype | MVP | Preview | Mature | Notes
|
||||
| -------- |:-----------:|:---------:|:---:|:-------:|:------:| -----
|
||||
| Aliases | | X | | | | Initial implementation but lacks necessary features
|
||||
| Notebook | | X | | | | Initial jupyter support, but it loses state and lacks features
|
||||
| File ops | | | X | | | cp, mv, rm, mkdir have some support, but lacking others
|
||||
| Environment | | X | | | | Temporary environment, but no session-wide env variables
|
||||
| Shells | | X | | | | Basic value and file shells, but no opt-in/opt-out for commands
|
||||
| Protocol | | | X | | | Streaming protocol is serviceable
|
||||
| Plugins | | X | | | | Plugins work on one row at a time, lack batching and expression eval
|
||||
| Errors | | | X | | | Error reporting works, but could use usability polish
|
||||
| Documentation | | X | | | | Book and related are barebones and lack task-based lessons
|
||||
| Paging | | X | | | | Textview has paging, but we'd like paging for tables
|
||||
| Functions| X | | | | | No functions, yet, only aliases
|
||||
| Variables| X | | | | | Nu doesn't yet support variables
|
||||
| Completions | | X | | | | Completions are currently barebones, at best
|
||||
| Type-checking | | X | | | | Commands check basic types, but input/output isn't checked
|
||||
| Features | Not started | Prototype | MVP | Preview | Mature | Notes |
|
||||
| ------------- | :---------: | :-------: | :-: | :-----: | :----: | -------------------------------------------------------------------- |
|
||||
| Aliases | | X | | | | Initial implementation but lacks necessary features |
|
||||
| Notebook | | X | | | | Initial jupyter support, but it loses state and lacks features |
|
||||
| File ops | | | X | | | cp, mv, rm, mkdir have some support, but lacking others |
|
||||
| Environment | | X | | | | Temporary environment, but no session-wide env variables |
|
||||
| Shells | | X | | | | Basic value and file shells, but no opt-in/opt-out for commands |
|
||||
| Protocol | | | X | | | Streaming protocol is serviceable |
|
||||
| Plugins | | X | | | | Plugins work on one row at a time, lack batching and expression eval |
|
||||
| Errors | | | X | | | Error reporting works, but could use usability polish |
|
||||
| Documentation | | X | | | | Book and related are barebones and lack task-based lessons |
|
||||
| Paging | | X | | | | Textview has paging, but we'd like paging for tables |
|
||||
| Functions | | X | | | | No functions, yet, only aliases |
|
||||
| Variables | | X | | | | Nu doesn't yet support variables |
|
||||
| Completions | | X | | | | Completions are currently barebones, at best |
|
||||
| Type-checking | | X | | | | Commands check basic types, but input/output isn't checked |
|
||||
|
||||
## Current Roadmap
|
||||
|
||||
@ -313,6 +313,12 @@ We've added a `Roadmap Board` to help collaboratively capture the direction we'r
|
||||
|
||||
See [Contributing](CONTRIBUTING.md) for details.
|
||||
|
||||
Thanks to all the people who already contributed!
|
||||
|
||||
<a href="https://github.com/nushell/nushell/graphs/contributors">
|
||||
<img src="https://contributors-img.web.app/image?repo=nushell/nushell" />
|
||||
</a>
|
||||
|
||||
## License
|
||||
|
||||
The project is made available under the MIT license. See the `LICENSE` file for more information.
|
||||
|
@ -5,107 +5,107 @@ description = "CLI for nushell"
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
name = "nu-cli"
|
||||
version = "0.25.1"
|
||||
version = "0.27.1"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
nu-data = {version = "0.25.1", path = "../nu-data"}
|
||||
nu-errors = {version = "0.25.1", path = "../nu-errors"}
|
||||
nu-json = {version = "0.25.1", path = "../nu-json"}
|
||||
nu-parser = {version = "0.25.1", path = "../nu-parser"}
|
||||
nu-plugin = {version = "0.25.1", path = "../nu-plugin"}
|
||||
nu-protocol = {version = "0.25.1", path = "../nu-protocol"}
|
||||
nu-source = {version = "0.25.1", path = "../nu-source"}
|
||||
nu-stream = {version = "0.25.1", path = "../nu-stream"}
|
||||
nu-table = {version = "0.25.1", path = "../nu-table"}
|
||||
nu-test-support = {version = "0.25.1", path = "../nu-test-support"}
|
||||
nu-value-ext = {version = "0.25.1", path = "../nu-value-ext"}
|
||||
nu-command = { version = "0.27.1", path = "../nu-command" }
|
||||
nu-data = { version = "0.27.1", path = "../nu-data" }
|
||||
nu-engine = { version = "0.27.1", path = "../nu-engine" }
|
||||
nu-errors = { version = "0.27.1", path = "../nu-errors" }
|
||||
nu-json = { version = "0.27.1", path = "../nu-json" }
|
||||
nu-parser = { version = "0.27.1", path = "../nu-parser" }
|
||||
nu-plugin = { version = "0.27.1", path = "../nu-plugin" }
|
||||
nu-protocol = { version = "0.27.1", path = "../nu-protocol" }
|
||||
nu-source = { version = "0.27.1", path = "../nu-source" }
|
||||
nu-stream = { version = "0.27.1", path = "../nu-stream" }
|
||||
nu-table = { version = "0.27.1", path = "../nu-table" }
|
||||
nu-test-support = { version = "0.27.1", path = "../nu-test-support" }
|
||||
nu-value-ext = { version = "0.27.1", 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"
|
||||
arboard = { version = "1.1.0", optional = true }
|
||||
async-recursion = "0.3.2"
|
||||
async-trait = "0.1.42"
|
||||
base64 = "0.13.0"
|
||||
bigdecimal = {version = "0.2.0", features = ["serde"]}
|
||||
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"]}
|
||||
bytes = "1.0.1"
|
||||
calamine = "0.17.0"
|
||||
chrono = { version = "0.4.19", features = ["serde"] }
|
||||
chrono-tz = "0.5.3"
|
||||
clap = "2.33.3"
|
||||
codespan-reporting = "0.9.5"
|
||||
csv = "1.1.3"
|
||||
ctrlc = {version = "3.1.6", optional = true}
|
||||
codespan-reporting = "0.11.0"
|
||||
csv = "1.1.5"
|
||||
ctrlc = { version = "3.1.7", optional = true }
|
||||
derive-new = "0.5.8"
|
||||
directories = {version = "3.0.1", optional = true}
|
||||
dirs = {version = "3.0.1", optional = true}
|
||||
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"
|
||||
encoding_rs = "0.8.28"
|
||||
filesize = "0.2.0"
|
||||
fs_extra = "1.2.0"
|
||||
futures = {version = "0.3.5", features = ["compat", "io-compat"]}
|
||||
futures-util = "0.3.5"
|
||||
futures = { version = "0.3.12", features = ["compat", "io-compat"] }
|
||||
futures-util = "0.3.12"
|
||||
futures_codec = "0.4.1"
|
||||
getset = "0.1.1"
|
||||
git2 = {version = "0.13.11", default_features = false, optional = true}
|
||||
glob = "0.3.0"
|
||||
heim = {version = "0.1.0-rc.1", optional = true}
|
||||
htmlescape = "0.3.1"
|
||||
ical = "0.6.0"
|
||||
ichwh = {version = "0.3.4", optional = true}
|
||||
indexmap = {version = "1.6.0", features = ["serde-1"]}
|
||||
itertools = "0.9.0"
|
||||
ical = "0.7.0"
|
||||
ichwh = { version = "0.3.4", optional = true }
|
||||
indexmap = { version = "1.6.1", features = ["serde-1"] }
|
||||
itertools = "0.10.0"
|
||||
lazy_static = "1.*"
|
||||
log = "0.4.11"
|
||||
log = "0.4.14"
|
||||
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"
|
||||
num-bigint = { version = "0.3.1", features = ["serde"] }
|
||||
num-format = { version = "0.4.0", features = ["with-num-bigint"] }
|
||||
num-traits = "0.2.14"
|
||||
parking_lot = "0.11.1"
|
||||
pin-utils = "0.1.0"
|
||||
pretty-hex = "0.2.0"
|
||||
ptree = {version = "0.3.0", optional = true}
|
||||
pretty-hex = "0.2.1"
|
||||
ptree = { version = "0.3.1", optional = true }
|
||||
query_interface = "0.3.5"
|
||||
quick-xml = "0.18.1"
|
||||
rand = "0.7.3"
|
||||
rayon = "1.4.0"
|
||||
regex = "1.3.9"
|
||||
roxmltree = "0.13.0"
|
||||
rust-embed = "5.6.0"
|
||||
rustyline = {version = "6.3.0", optional = true}
|
||||
serde = {version = "1.0.115", features = ["derive"]}
|
||||
quick-xml = "0.21.0"
|
||||
rand = "0.8.3"
|
||||
rayon = "1.5.0"
|
||||
regex = "1.4.3"
|
||||
roxmltree = "0.14.0"
|
||||
rust-embed = "5.9.0"
|
||||
rustyline = { version = "6.3.0", optional = true }
|
||||
serde = { version = "1.0.123", features = ["derive"] }
|
||||
serde_bytes = "0.11.5"
|
||||
serde_ini = "0.2.0"
|
||||
serde_json = "1.0.57"
|
||||
serde_json = "1.0.61"
|
||||
serde_urlencoded = "0.7.0"
|
||||
serde_yaml = "0.8.13"
|
||||
sha2 = "0.9.1"
|
||||
shellexpand = "2.0.0"
|
||||
serde_yaml = "0.8.16"
|
||||
sha2 = "0.9.3"
|
||||
shellexpand = "2.1.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}
|
||||
tempfile = "3.2.0"
|
||||
term = { version = "0.7.0", 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"
|
||||
uom = {version = "0.30.0", features = ["f64", "try-from"]}
|
||||
termcolor = "1.1.2"
|
||||
titlecase = "1.1.0"
|
||||
toml = "0.5.8"
|
||||
trash = { version = "1.3.0", optional = true }
|
||||
unicode-segmentation = "1.7.1"
|
||||
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}
|
||||
uuid_crate = { package = "uuid", version = "0.8.2", features = ["v4"], optional = true }
|
||||
which = { version = "4.0.2", optional = true }
|
||||
zip = { version = "0.5.9", optional = true }
|
||||
shadow-rs = { version = "0.5", default-features = false, optional = true }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
umask = "1.0.0"
|
||||
users = "0.10.0"
|
||||
users = "0.11.0"
|
||||
|
||||
# TODO this will be possible with new dependency resolver
|
||||
# (currently on nightly behind -Zfeatures=itarget):
|
||||
@ -122,12 +122,14 @@ version = "0.24.2"
|
||||
shadow-rs = "0.5"
|
||||
|
||||
[dev-dependencies]
|
||||
quickcheck = "0.9.2"
|
||||
quickcheck_macros = "0.9.1"
|
||||
quickcheck = "1.0.3"
|
||||
quickcheck_macros = "1.0.0"
|
||||
|
||||
[features]
|
||||
default = ["shadow-rs"]
|
||||
clipboard-cli = ["arboard"]
|
||||
rich-benchmark = ["heim"]
|
||||
rustyline-support = ["rustyline"]
|
||||
rustyline-support = ["rustyline", "nu-engine/rustyline-support"]
|
||||
stable = []
|
||||
trash-support = ["trash"]
|
||||
dirs = ["dirs-next"]
|
||||
directories = ["directories-next"]
|
||||
|
@ -1,27 +1,36 @@
|
||||
use crate::commands::classified::block::run_block;
|
||||
use crate::commands::default_context::create_default_context;
|
||||
use crate::evaluation_context::EvaluationContext;
|
||||
use crate::prelude::*;
|
||||
use crate::script::{print_err, run_script_standalone};
|
||||
use crate::line_editor::configure_ctrl_c;
|
||||
use nu_command::commands::default_context::create_default_context;
|
||||
#[allow(unused_imports)]
|
||||
use nu_command::maybe_print_errors;
|
||||
use nu_engine::run_block;
|
||||
use nu_engine::EvaluationContext;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) use crate::script::{process_script, LineResult};
|
||||
pub(crate) use nu_command::script::{process_script, LineResult};
|
||||
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
use crate::shell::Helper;
|
||||
use crate::line_editor::{
|
||||
configure_rustyline_editor, convert_rustyline_result_to_string,
|
||||
default_rustyline_editor_configuration, nu_line_editor_helper,
|
||||
};
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use nu_data::config;
|
||||
use nu_source::{Tag, Text};
|
||||
use nu_stream::InputStream;
|
||||
#[allow(unused_imports)]
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use nu_command::script::{print_err, run_script_standalone};
|
||||
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
use rustyline::{self, error::ReadlineError};
|
||||
|
||||
use crate::EnvironmentSyncer;
|
||||
use nu_errors::ShellError;
|
||||
use nu_parser::ParserScope;
|
||||
use nu_protocol::{UntaggedValue, Value};
|
||||
use nu_protocol::{hir::ExternalRedirection, UntaggedValue, Value};
|
||||
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
use rustyline::{
|
||||
self,
|
||||
config::Configurer,
|
||||
config::{ColorMode, CompletionType, Config},
|
||||
error::ReadlineError,
|
||||
At, Cmd, Editor, KeyPress, Movement, Word,
|
||||
};
|
||||
use std::error::Error;
|
||||
use std::iter::Iterator;
|
||||
use std::path::PathBuf;
|
||||
@ -39,16 +48,14 @@ pub fn search_paths() -> Vec<std::path::PathBuf> {
|
||||
}
|
||||
|
||||
if let Ok(config) = nu_data::config::config(Tag::unknown()) {
|
||||
if let Some(plugin_dirs) = config.get("plugin_dirs") {
|
||||
if let Value {
|
||||
value: UntaggedValue::Table(pipelines),
|
||||
..
|
||||
} = plugin_dirs
|
||||
{
|
||||
for pipeline in pipelines {
|
||||
if let Ok(plugin_dir) = pipeline.as_string() {
|
||||
search_paths.push(PathBuf::from(plugin_dir));
|
||||
}
|
||||
if let Some(Value {
|
||||
value: UntaggedValue::Table(pipelines),
|
||||
..
|
||||
}) = config.get("plugin_dirs")
|
||||
{
|
||||
for pipeline in pipelines {
|
||||
if let Ok(plugin_dir) = pipeline.as_string() {
|
||||
search_paths.push(PathBuf::from(plugin_dir));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -85,20 +92,6 @@ pub async fn run_script_file(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The entry point for the CLI. Will register all known internal commands, load experimental commands, load plugins, then prepare the prompt and line reader for input.
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
|
||||
@ -128,7 +121,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
|
||||
// Give ourselves a scope to work in
|
||||
context.scope.enter_scope();
|
||||
|
||||
let history_path = crate::commands::history::history_path(&configuration);
|
||||
let history_path = nu_engine::history_path(&configuration);
|
||||
let _ = rl.load_history(&history_path);
|
||||
|
||||
let mut session_text = String::new();
|
||||
@ -165,20 +158,14 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
|
||||
let prompt_line = prompt.as_string()?;
|
||||
|
||||
context.scope.enter_scope();
|
||||
let (prompt_block, err) = nu_parser::parse(&prompt_line, 0, &context.scope);
|
||||
let (mut prompt_block, err) = nu_parser::parse(&prompt_line, 0, &context.scope);
|
||||
|
||||
prompt_block.set_redirect(ExternalRedirection::Stdout);
|
||||
|
||||
if err.is_some() {
|
||||
use crate::git::current_branch;
|
||||
context.scope.exit_scope();
|
||||
|
||||
format!(
|
||||
"\x1b[32m{}{}\x1b[m> ",
|
||||
cwd,
|
||||
match current_branch() {
|
||||
Some(s) => format!("({})", s),
|
||||
None => "".to_string(),
|
||||
}
|
||||
)
|
||||
format!("\x1b[32m{}{}\x1b[m> ", cwd, current_branch())
|
||||
} else {
|
||||
// let env = context.get_env();
|
||||
|
||||
@ -189,7 +176,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
|
||||
Ok(result) => match result.collect_string(Tag::unknown()).await {
|
||||
Ok(string_result) => {
|
||||
let errors = context.get_errors();
|
||||
context.maybe_print_errors(Text::from(prompt_line));
|
||||
maybe_print_errors(&context, Text::from(prompt_line));
|
||||
context.clear_errors();
|
||||
|
||||
if !errors.is_empty() {
|
||||
@ -214,15 +201,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
use crate::git::current_branch;
|
||||
format!(
|
||||
"\x1b[32m{}{}\x1b[m> ",
|
||||
cwd,
|
||||
match current_branch() {
|
||||
Some(s) => format!("({})", s),
|
||||
None => "".to_string(),
|
||||
}
|
||||
)
|
||||
format!("\x1b[32m{}{}\x1b[m> ", cwd, current_branch())
|
||||
}
|
||||
};
|
||||
|
||||
@ -284,7 +263,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
|
||||
LineResult::Success(line) => {
|
||||
rl.add_history_entry(&line);
|
||||
let _ = rl.save_history(&history_path);
|
||||
context.maybe_print_errors(Text::from(session_text.clone()));
|
||||
maybe_print_errors(&context, Text::from(session_text.clone()));
|
||||
}
|
||||
|
||||
LineResult::ClearHistory => {
|
||||
@ -300,7 +279,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
|
||||
print_err(err, &Text::from(session_text.clone()));
|
||||
});
|
||||
|
||||
context.maybe_print_errors(Text::from(session_text.clone()));
|
||||
maybe_print_errors(&context, Text::from(session_text.clone()));
|
||||
}
|
||||
|
||||
LineResult::CtrlC => {
|
||||
@ -344,7 +323,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
|
||||
}
|
||||
|
||||
pub fn register_plugins(context: &mut EvaluationContext) -> Result<(), ShellError> {
|
||||
if let Ok(plugins) = crate::plugin::scan(search_paths()) {
|
||||
if let Ok(plugins) = nu_engine::plugin::build_plugin::scan(search_paths()) {
|
||||
context.add_commands(
|
||||
plugins
|
||||
.into_iter()
|
||||
@ -356,23 +335,6 @@ pub fn register_plugins(context: &mut EvaluationContext) -> Result<(), ShellErro
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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(())
|
||||
}
|
||||
|
||||
async fn run_startup_commands(
|
||||
context: &mut EvaluationContext,
|
||||
config: &dyn nu_data::config::Conf,
|
||||
@ -383,16 +345,17 @@ async fn run_startup_commands(
|
||||
value: UntaggedValue::Table(pipelines),
|
||||
..
|
||||
} => {
|
||||
let mut script_file = String::new();
|
||||
for pipeline in pipelines {
|
||||
if let Ok(pipeline_string) = pipeline.as_string() {
|
||||
let _ = run_script_standalone(pipeline_string, false, context, false).await;
|
||||
}
|
||||
script_file.push_str(&pipeline.as_string()?);
|
||||
script_file.push('\n');
|
||||
}
|
||||
let _ = run_script_standalone(script_file, false, context, false).await;
|
||||
}
|
||||
_ => {
|
||||
return Err(ShellError::untagged_runtime_error(
|
||||
"expected a table of pipeline strings as startup commands",
|
||||
))
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -400,187 +363,6 @@ async fn run_startup_commands(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
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")]
|
||||
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")]
|
||||
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")]
|
||||
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 async fn parse_and_eval(line: &str, ctx: &EvaluationContext) -> Result<String, ShellError> {
|
||||
// FIXME: do we still need this?
|
||||
let line = if let Some(s) = line.strip_suffix('\n') {
|
||||
@ -607,15 +389,32 @@ pub async fn parse_and_eval(line: &str, ctx: &EvaluationContext) -> Result<Strin
|
||||
result?.collect_string(Tag::unknown()).await.map(|x| x.item)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn current_branch() -> String {
|
||||
#[cfg(feature = "shadow-rs")]
|
||||
{
|
||||
Some(shadow_rs::branch())
|
||||
.map(|x| x.trim().to_string())
|
||||
.filter(|x| !x.is_empty())
|
||||
.map(|x| format!("({})", x))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
#[cfg(not(feature = "shadow-rs"))]
|
||||
{
|
||||
"".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use nu_engine::basic_evaluation_context;
|
||||
|
||||
#[quickcheck]
|
||||
fn quickcheck_parse(data: String) -> bool {
|
||||
let (tokens, err) = nu_parser::lex(&data, 0);
|
||||
let (lite_block, err2) = nu_parser::group(tokens);
|
||||
let (lite_block, err2) = nu_parser::parse_block(tokens);
|
||||
if err.is_none() && err2.is_none() {
|
||||
let context = crate::evaluation_context::EvaluationContext::basic().unwrap();
|
||||
let context = basic_evaluation_context().unwrap();
|
||||
let _ = nu_parser::classify_block(&lite_block, &context.scope);
|
||||
}
|
||||
true
|
||||
|
@ -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,395 +0,0 @@
|
||||
use crate::deserializer::ConfigDeserializer;
|
||||
use crate::evaluate::evaluate_args::evaluate_args;
|
||||
use crate::prelude::*;
|
||||
use crate::{commands::help::get_help, run_block};
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::hir::{self, Block};
|
||||
use nu_protocol::{CallInfo, EvaluatedArgs, ReturnSuccess, Signature, UntaggedValue, Value};
|
||||
use parking_lot::Mutex;
|
||||
use serde::Deserialize;
|
||||
use std::ops::Deref;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UnevaluatedCallInfo {
|
||||
pub args: hir::Call,
|
||||
pub name_tag: Tag,
|
||||
}
|
||||
|
||||
impl UnevaluatedCallInfo {
|
||||
pub async fn evaluate(self, ctx: &EvaluationContext) -> Result<CallInfo, ShellError> {
|
||||
let args = evaluate_args(&self.args, ctx).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 scope: Scope,
|
||||
pub input: InputStream,
|
||||
}
|
||||
|
||||
#[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 scope: Scope,
|
||||
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,
|
||||
scope: self.scope,
|
||||
input: input.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) -> Result<EvaluatedWholeStreamCommandArgs, ShellError> {
|
||||
let ctx = EvaluationContext::from_args(&self);
|
||||
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(&ctx).await?;
|
||||
let scope = self.scope.clone();
|
||||
|
||||
Ok(EvaluatedWholeStreamCommandArgs::new(
|
||||
host,
|
||||
ctrl_c,
|
||||
shell_manager,
|
||||
call_info,
|
||||
input,
|
||||
scope,
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn process<'de, T: Deserialize<'de>>(self) -> Result<(T, InputStream), ShellError> {
|
||||
let args = self.evaluate_once().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 scope: Scope,
|
||||
pub name: Tag,
|
||||
}
|
||||
|
||||
impl RunnableContext {
|
||||
pub fn get_command(&self, name: &str) -> Option<Command> {
|
||||
self.scope.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>,
|
||||
scope: Scope,
|
||||
) -> EvaluatedWholeStreamCommandArgs {
|
||||
EvaluatedWholeStreamCommandArgs {
|
||||
args: EvaluatedCommandArgs {
|
||||
host,
|
||||
ctrl_c,
|
||||
shell_manager,
|
||||
call_info,
|
||||
scope,
|
||||
},
|
||||
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,
|
||||
pub scope: Scope,
|
||||
}
|
||||
|
||||
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) -> 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()
|
||||
}
|
||||
}
|
||||
|
||||
// Custom commands are blocks, so we can use the information in the block to also
|
||||
// implement a WholeStreamCommand
|
||||
#[allow(clippy::suspicious_else_formatting)]
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Block {
|
||||
fn name(&self) -> &str {
|
||||
&self.params.name
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
self.params.clone()
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
""
|
||||
}
|
||||
|
||||
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let call_info = args.call_info.clone();
|
||||
|
||||
let mut block = self.clone();
|
||||
block.set_redirect(call_info.args.external_redirection);
|
||||
|
||||
let ctx = EvaluationContext::from_args(&args);
|
||||
let evaluated = call_info.evaluate(&ctx).await?;
|
||||
|
||||
let input = args.input;
|
||||
ctx.scope.enter_scope();
|
||||
if let Some(args) = evaluated.args.positional {
|
||||
// FIXME: do not do this
|
||||
for arg in args.into_iter().zip(self.params.positional.iter()) {
|
||||
let name = arg.1 .0.name();
|
||||
|
||||
if name.starts_with('$') {
|
||||
ctx.scope.add_var(name, arg.0);
|
||||
} else {
|
||||
ctx.scope.add_var(format!("${}", name), arg.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(args) = evaluated.args.named {
|
||||
for named in &block.params.named {
|
||||
let name = named.0;
|
||||
if let Some(value) = args.get(name) {
|
||||
if name.starts_with('$') {
|
||||
ctx.scope.add_var(name, value.clone());
|
||||
} else {
|
||||
ctx.scope.add_var(format!("${}", name), value.clone());
|
||||
}
|
||||
} else if name.starts_with('$') {
|
||||
ctx.scope
|
||||
.add_var(name, UntaggedValue::nothing().into_untagged_value());
|
||||
} else {
|
||||
ctx.scope.add_var(
|
||||
format!("${}", name),
|
||||
UntaggedValue::nothing().into_untagged_value(),
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for named in &block.params.named {
|
||||
let name = named.0;
|
||||
if name.starts_with('$') {
|
||||
ctx.scope
|
||||
.add_var(name, UntaggedValue::nothing().into_untagged_value());
|
||||
} else {
|
||||
ctx.scope.add_var(
|
||||
format!("${}", name),
|
||||
UntaggedValue::nothing().into_untagged_value(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
let result = run_block(&block, &ctx, input).await;
|
||||
ctx.scope.exit_scope();
|
||||
result.map(|x| x.to_output_stream())
|
||||
}
|
||||
|
||||
fn is_binary(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn is_internal(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
#[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) -> Result<OutputStream, ShellError> {
|
||||
if args.call_info.switch_present("help") {
|
||||
let cl = self.0.clone();
|
||||
Ok(OutputStream::one(Ok(ReturnSuccess::Value(
|
||||
UntaggedValue::string(get_help(&*cl, &args.scope)).into_value(Tag::unknown()),
|
||||
))))
|
||||
} else {
|
||||
self.0.run(args).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,186 +0,0 @@
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use nu_protocol::{
|
||||
ColumnPath, Primitive::Filesize, ReturnSuccess, Signature, SyntaxShape, UntaggedValue,
|
||||
UntaggedValue::Primitive, Value,
|
||||
};
|
||||
use nu_source::Tagged;
|
||||
use nu_value_ext::get_data_by_column_path;
|
||||
|
||||
use num_format::{Locale, ToFormattedString};
|
||||
|
||||
pub struct FileSize;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Arguments {
|
||||
field: ColumnPath,
|
||||
format: Tagged<String>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for FileSize {
|
||||
fn name(&self) -> &str {
|
||||
"format filesize"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("format filesize")
|
||||
.required(
|
||||
"field",
|
||||
SyntaxShape::ColumnPath,
|
||||
"the name of the column to update",
|
||||
)
|
||||
.required(
|
||||
"format value",
|
||||
SyntaxShape::String,
|
||||
"the format into which convert the filesizes",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Converts a column of filesizes to some specified format"
|
||||
}
|
||||
|
||||
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
filesize(args).await
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Convert the size row to KB",
|
||||
example: "ls | format filesize size KB",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Convert the apparent row to B",
|
||||
example: "du | format filesize apparent B",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
async fn process_row(
|
||||
input: Value,
|
||||
format: Tagged<String>,
|
||||
field: Arc<ColumnPath>,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
Ok({
|
||||
let replace_for = get_data_by_column_path(&input, &field, move |_, _, error| error);
|
||||
match replace_for {
|
||||
Ok(s) => match convert_bytes_to_string_using_format(s, format) {
|
||||
Ok(b) => OutputStream::one(ReturnSuccess::value(
|
||||
input.replace_data_at_column_path(&field, b).expect("Given that the existence check was already done, this shouldn't trigger never"),
|
||||
)),
|
||||
Err(e) => OutputStream::one(Err(e)),
|
||||
},
|
||||
Err(e) => OutputStream::one(Err(e)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async fn filesize(raw_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let (Arguments { field, format }, input) = raw_args.process().await?;
|
||||
let field = Arc::new(field);
|
||||
|
||||
Ok(input
|
||||
.then(move |input| {
|
||||
let format = format.clone();
|
||||
let field = field.clone();
|
||||
|
||||
async {
|
||||
match process_row(input, format, field).await {
|
||||
Ok(s) => s,
|
||||
Err(e) => OutputStream::one(Err(e)),
|
||||
}
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.to_output_stream())
|
||||
}
|
||||
|
||||
fn convert_bytes_to_string_using_format(
|
||||
bytes: Value,
|
||||
format: Tagged<String>,
|
||||
) -> Result<Value, ShellError> {
|
||||
match bytes.value {
|
||||
Primitive(Filesize(b)) => {
|
||||
let byte = byte_unit::Byte::from_bytes(b as u128);
|
||||
let value = match format.item().to_lowercase().as_str() {
|
||||
"b" => Ok(UntaggedValue::string(b.to_formatted_string(&Locale::en))),
|
||||
"kb" => Ok(UntaggedValue::string(
|
||||
byte.get_adjusted_unit(byte_unit::ByteUnit::KB).to_string(),
|
||||
)),
|
||||
"kib" => Ok(UntaggedValue::string(
|
||||
byte.get_adjusted_unit(byte_unit::ByteUnit::KiB).to_string(),
|
||||
)),
|
||||
"mb" => Ok(UntaggedValue::string(
|
||||
byte.get_adjusted_unit(byte_unit::ByteUnit::MB).to_string(),
|
||||
)),
|
||||
"mib" => Ok(UntaggedValue::string(
|
||||
byte.get_adjusted_unit(byte_unit::ByteUnit::MiB).to_string(),
|
||||
)),
|
||||
"gb" => Ok(UntaggedValue::string(
|
||||
byte.get_adjusted_unit(byte_unit::ByteUnit::GB).to_string(),
|
||||
)),
|
||||
"gib" => Ok(UntaggedValue::string(
|
||||
byte.get_adjusted_unit(byte_unit::ByteUnit::GiB).to_string(),
|
||||
)),
|
||||
"tb" => Ok(UntaggedValue::string(
|
||||
byte.get_adjusted_unit(byte_unit::ByteUnit::TB).to_string(),
|
||||
)),
|
||||
"tib" => Ok(UntaggedValue::string(
|
||||
byte.get_adjusted_unit(byte_unit::ByteUnit::TiB).to_string(),
|
||||
)),
|
||||
"pb" => Ok(UntaggedValue::string(
|
||||
byte.get_adjusted_unit(byte_unit::ByteUnit::PB).to_string(),
|
||||
)),
|
||||
"pib" => Ok(UntaggedValue::string(
|
||||
byte.get_adjusted_unit(byte_unit::ByteUnit::PiB).to_string(),
|
||||
)),
|
||||
"eb" => Ok(UntaggedValue::string(
|
||||
byte.get_adjusted_unit(byte_unit::ByteUnit::EB).to_string(),
|
||||
)),
|
||||
"eib" => Ok(UntaggedValue::string(
|
||||
byte.get_adjusted_unit(byte_unit::ByteUnit::EiB).to_string(),
|
||||
)),
|
||||
"zb" => Ok(UntaggedValue::string(
|
||||
byte.get_adjusted_unit(byte_unit::ByteUnit::ZB).to_string(),
|
||||
)),
|
||||
"zib" => Ok(UntaggedValue::string(
|
||||
byte.get_adjusted_unit(byte_unit::ByteUnit::ZiB).to_string(),
|
||||
)),
|
||||
_ => Err(ShellError::labeled_error(
|
||||
format!("Invalid format code: {:}", format.item()),
|
||||
"invalid format",
|
||||
format.tag(),
|
||||
)),
|
||||
};
|
||||
match value {
|
||||
Ok(b) => Ok(Value { value: b, ..bytes }),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
_ => Err(ShellError::labeled_error(
|
||||
"the data in this row is not of the type filesize",
|
||||
"invalid row type",
|
||||
bytes.tag(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::FileSize;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(FileSize {})?)
|
||||
}
|
||||
}
|
@ -1,62 +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) -> 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,55 +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) -> 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,115 +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) -> Result<OutputStream, ShellError> {
|
||||
operate(args).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) -> Result<OutputStream, ShellError> {
|
||||
let (Arguments { replace, rest }, input) = args.process().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,215 +0,0 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use futures::StreamExt;
|
||||
use nu_data::value::format_leaf;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue, Value};
|
||||
|
||||
pub struct ToMarkdown;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ToMarkdownArgs {
|
||||
pretty: bool,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for ToMarkdown {
|
||||
fn name(&self) -> &str {
|
||||
"to md"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("to md").switch(
|
||||
"pretty",
|
||||
"Formats the Markdown table to vertically align items",
|
||||
Some('p'),
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Convert table into simple Markdown"
|
||||
}
|
||||
|
||||
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
to_md(args).await
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Outputs an unformatted md string representing the contents of ls",
|
||||
example: "ls | to md",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Outputs a formatted md string representing the contents of ls",
|
||||
example: "ls | to md -p",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
async fn to_md(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name_tag = args.call_info.name_tag.clone();
|
||||
let (ToMarkdownArgs { pretty }, input) = args.process().await?;
|
||||
let input: Vec<Value> = input.collect().await;
|
||||
let headers = nu_protocol::merge_descriptors(&input);
|
||||
|
||||
let mut escaped_headers: Vec<String> = Vec::new();
|
||||
let mut column_widths: Vec<usize> = Vec::new();
|
||||
|
||||
if !headers.is_empty() && (headers.len() > 1 || !headers[0].is_empty()) {
|
||||
for header in &headers {
|
||||
let escaped_header_string = htmlescape::encode_minimal(&header);
|
||||
column_widths.push(escaped_header_string.len());
|
||||
escaped_headers.push(escaped_header_string);
|
||||
}
|
||||
} else {
|
||||
column_widths = vec![0; headers.len()]
|
||||
}
|
||||
|
||||
let mut escaped_rows: Vec<Vec<String>> = Vec::new();
|
||||
|
||||
for row in &input {
|
||||
let mut escaped_row: Vec<String> = Vec::new();
|
||||
|
||||
match row.value.clone() {
|
||||
UntaggedValue::Row(row) => {
|
||||
for i in 0..headers.len() {
|
||||
let data = row.get_data(&headers[i]);
|
||||
let value_string = format_leaf(data.borrow()).plain_string(100_000);
|
||||
let new_column_width = value_string.len();
|
||||
|
||||
escaped_row.push(value_string);
|
||||
|
||||
if column_widths[i] < new_column_width {
|
||||
column_widths[i] = new_column_width;
|
||||
}
|
||||
}
|
||||
}
|
||||
p => {
|
||||
let value_string =
|
||||
htmlescape::encode_minimal(&format_leaf(&p).plain_string(100_000));
|
||||
escaped_row.push(value_string);
|
||||
}
|
||||
}
|
||||
|
||||
escaped_rows.push(escaped_row);
|
||||
}
|
||||
|
||||
let output_string = if (column_widths.is_empty() || column_widths.iter().all(|x| *x == 0))
|
||||
&& escaped_rows.is_empty()
|
||||
{
|
||||
String::from("")
|
||||
} else {
|
||||
get_output_string(&escaped_headers, &escaped_rows, &column_widths, pretty)
|
||||
.trim()
|
||||
.to_string()
|
||||
};
|
||||
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::string(output_string).into_value(name_tag),
|
||||
)))
|
||||
}
|
||||
|
||||
fn get_output_string(
|
||||
headers: &[String],
|
||||
rows: &[Vec<String>],
|
||||
column_widths: &[usize],
|
||||
pretty: bool,
|
||||
) -> String {
|
||||
let mut output_string = String::new();
|
||||
|
||||
if !headers.is_empty() {
|
||||
output_string.push('|');
|
||||
|
||||
for i in 0..headers.len() {
|
||||
if pretty {
|
||||
output_string.push(' ');
|
||||
output_string.push_str(&get_padded_string(
|
||||
headers[i].clone(),
|
||||
column_widths[i],
|
||||
' ',
|
||||
));
|
||||
output_string.push(' ');
|
||||
} else {
|
||||
output_string.push_str(headers[i].as_str());
|
||||
}
|
||||
|
||||
output_string.push('|');
|
||||
}
|
||||
|
||||
output_string.push_str("\n|");
|
||||
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
for i in 0..headers.len() {
|
||||
if pretty {
|
||||
output_string.push(' ');
|
||||
output_string.push_str(&get_padded_string(
|
||||
String::from("-"),
|
||||
column_widths[i],
|
||||
'-',
|
||||
));
|
||||
output_string.push(' ');
|
||||
} else {
|
||||
output_string.push('-');
|
||||
}
|
||||
|
||||
output_string.push('|');
|
||||
}
|
||||
|
||||
output_string.push('\n');
|
||||
}
|
||||
|
||||
for row in rows {
|
||||
if !headers.is_empty() {
|
||||
output_string.push('|');
|
||||
}
|
||||
|
||||
for i in 0..row.len() {
|
||||
if pretty {
|
||||
output_string.push(' ');
|
||||
output_string.push_str(&get_padded_string(row[i].clone(), column_widths[i], ' '));
|
||||
output_string.push(' ');
|
||||
} else {
|
||||
output_string.push_str(row[i].as_str());
|
||||
}
|
||||
|
||||
if !headers.is_empty() {
|
||||
output_string.push('|');
|
||||
}
|
||||
}
|
||||
|
||||
output_string.push('\n');
|
||||
}
|
||||
|
||||
output_string
|
||||
}
|
||||
|
||||
fn get_padded_string(text: String, desired_length: usize, padding_character: char) -> String {
|
||||
let repeat_length = if text.len() > desired_length {
|
||||
0
|
||||
} else {
|
||||
desired_length - text.len()
|
||||
};
|
||||
|
||||
format!(
|
||||
"{}{}",
|
||||
text,
|
||||
padding_character.to_string().repeat(repeat_length)
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ShellError;
|
||||
use super::ToMarkdown;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(ToMarkdown {})?)
|
||||
}
|
||||
}
|
@ -1,136 +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, alias or custom command."
|
||||
}
|
||||
|
||||
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
which(args).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! create_entry {
|
||||
($arg:expr, $path:expr, $tag:expr, $is_builtin:expr) => {
|
||||
entry(
|
||||
$arg.clone(),
|
||||
UntaggedValue::Primitive(Primitive::String($path.to_string())).into_value($tag.clone()),
|
||||
$is_builtin,
|
||||
$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) -> Result<OutputStream, ShellError> {
|
||||
let mut output = vec![];
|
||||
let scope = args.scope.clone();
|
||||
|
||||
let (WhichArgs { application, all }, _) = args.process().await?;
|
||||
let external = application.starts_with('^');
|
||||
let item = if external {
|
||||
application.item[1..].to_string()
|
||||
} else {
|
||||
application.item.clone()
|
||||
};
|
||||
if !external {
|
||||
if let Some(entry) = entry_for(&scope, &item, application.tag.clone()) {
|
||||
output.push(ReturnSuccess::value(entry));
|
||||
}
|
||||
}
|
||||
|
||||
#[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())
|
||||
}
|
||||
}
|
||||
|
||||
fn entry_for(scope: &Scope, name: &str, tag: Tag) -> Option<Value> {
|
||||
if scope.has_custom_command(name) {
|
||||
Some(create_entry!(name, "Nushell custom command", tag, false))
|
||||
} else if scope.has_command(name) {
|
||||
Some(create_entry!(name, "Nushell built-in command", tag, true))
|
||||
} else if scope.has_alias(name) {
|
||||
Some(create_entry!(name, "Nushell alias", tag, false))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[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 crate::completion::{Completer, CompletionContext, Suggestion};
|
||||
use crate::evaluation_context::EvaluationContext;
|
||||
use nu_engine::EvaluationContext;
|
||||
|
||||
pub struct CommandCompleter;
|
||||
|
||||
|
@ -256,7 +256,7 @@ pub fn completion_location(line: &str, block: &Block, pos: usize) -> Vec<Complet
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use nu_parser::{classify_block, group, lex, ParserScope};
|
||||
use nu_parser::{classify_block, lex, parse_block, ParserScope};
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -307,7 +307,7 @@ mod tests {
|
||||
pos: usize,
|
||||
) -> Vec<LocationType> {
|
||||
let (tokens, _) = lex(line, 0);
|
||||
let (lite_block, _) = group(tokens);
|
||||
let (lite_block, _) = parse_block(tokens);
|
||||
|
||||
scope.enter_scope();
|
||||
let (block, _) = classify_block(&lite_block, scope);
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::matchers::Matcher;
|
||||
use crate::completion::{Completer, CompletionContext, Suggestion};
|
||||
use crate::evaluation_context::EvaluationContext;
|
||||
use nu_engine::EvaluationContext;
|
||||
|
||||
pub struct FlagCompleter {
|
||||
pub(crate) cmd: String,
|
||||
|
@ -4,8 +4,8 @@ pub(crate) mod flag;
|
||||
pub(crate) mod matchers;
|
||||
pub(crate) mod path;
|
||||
|
||||
use crate::evaluation_context::EvaluationContext;
|
||||
use matchers::Matcher;
|
||||
use nu_engine::EvaluationContext;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct Suggestion {
|
||||
|
@ -29,7 +29,7 @@ impl PathCompleter {
|
||||
{
|
||||
let home_prefix = format!("~{}", SEP);
|
||||
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
|
||||
} else {
|
||||
|
@ -1,6 +1,3 @@
|
||||
pub(crate) mod directory_specific_environment;
|
||||
pub(crate) mod environment;
|
||||
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 nu_command::commands::autoenv;
|
||||
use nu_errors::ShellError;
|
||||
use serde::Deserialize;
|
||||
use std::env::*;
|
||||
@ -52,7 +51,7 @@ impl DirectorySpecificEnvironment {
|
||||
}
|
||||
}
|
||||
|
||||
fn toml_if_trusted(&mut self, nu_env_file: &PathBuf) -> Result<NuEnvDoc, ShellError> {
|
||||
fn toml_if_trusted(&mut self, nu_env_file: &Path) -> Result<NuEnvDoc, ShellError> {
|
||||
let content = std::fs::read(&nu_env_file)?;
|
||||
|
||||
if autoenv::file_is_trusted(&nu_env_file, &content)? {
|
||||
@ -162,7 +161,7 @@ impl DirectorySpecificEnvironment {
|
||||
pub fn maybe_add_key(
|
||||
&mut self,
|
||||
seen_vars: &mut IndexSet<EnvKey>,
|
||||
dir: &PathBuf,
|
||||
dir: &Path,
|
||||
key: &str,
|
||||
val: &str,
|
||||
) {
|
||||
@ -170,7 +169,7 @@ impl DirectorySpecificEnvironment {
|
||||
if !seen_vars.contains(key) {
|
||||
seen_vars.insert(key.to_string());
|
||||
self.added_vars
|
||||
.entry(dir.clone())
|
||||
.entry(PathBuf::from(dir))
|
||||
.or_insert(IndexMap::new())
|
||||
.insert(key.to_string(), var_os(key));
|
||||
|
||||
|
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 indexmap::{indexmap, IndexSet};
|
||||
use nu_data::config::Conf;
|
||||
use nu_engine::Env;
|
||||
use nu_errors::ShellError;
|
||||
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)]
|
||||
pub struct Environment {
|
||||
@ -128,7 +99,7 @@ impl Env for Environment {
|
||||
{
|
||||
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())
|
||||
});
|
||||
|
||||
|
43
crates/nu-cli/src/env/environment_syncer.rs
vendored
43
crates/nu-cli/src/env/environment_syncer.rs
vendored
@ -1,6 +1,7 @@
|
||||
use crate::env::environment::{Env, Environment};
|
||||
use crate::evaluation_context::EvaluationContext;
|
||||
use crate::env::environment::Environment;
|
||||
use nu_data::config::{Conf, NuConfig};
|
||||
use nu_engine::Env;
|
||||
use nu_engine::EvaluationContext;
|
||||
use nu_errors::ShellError;
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::{atomic::Ordering, Arc};
|
||||
@ -94,9 +95,11 @@ impl EnvironmentSyncer {
|
||||
ctx.with_host(|host| {
|
||||
host.env_set(
|
||||
std::ffi::OsString::from(var.0),
|
||||
std::ffi::OsString::from(string),
|
||||
std::ffi::OsString::from(&string),
|
||||
)
|
||||
});
|
||||
|
||||
ctx.scope.add_env_var_to_base(var.0, string);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -127,8 +130,14 @@ impl EnvironmentSyncer {
|
||||
|
||||
if let Ok(paths_ready) = prepared {
|
||||
ctx.with_host(|host| {
|
||||
host.env_set(std::ffi::OsString::from("PATH"), paths_ready);
|
||||
host.env_set(
|
||||
std::ffi::OsString::from("PATH"),
|
||||
std::ffi::OsString::from(&paths_ready),
|
||||
);
|
||||
});
|
||||
|
||||
ctx.scope
|
||||
.add_env_var_to_base("PATH", paths_ready.to_string_lossy().to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -152,10 +161,10 @@ impl EnvironmentSyncer {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::EnvironmentSyncer;
|
||||
use crate::env::environment::Env;
|
||||
use crate::evaluation_context::EvaluationContext;
|
||||
use indexmap::IndexMap;
|
||||
use nu_data::config::tests::FakeConfig;
|
||||
use nu_engine::basic_evaluation_context;
|
||||
use nu_engine::Env;
|
||||
use nu_errors::ShellError;
|
||||
use nu_test_support::fs::Stub::FileWithContent;
|
||||
use nu_test_support::playground::Playground;
|
||||
@ -170,8 +179,8 @@ mod tests {
|
||||
#[test]
|
||||
fn syncs_env_if_new_env_entry_is_added_to_an_existing_configuration() -> Result<(), ShellError>
|
||||
{
|
||||
let mut ctx = EvaluationContext::basic()?;
|
||||
ctx.host = Arc::new(Mutex::new(Box::new(crate::env::host::FakeHost::new())));
|
||||
let mut ctx = basic_evaluation_context()?;
|
||||
ctx.host = Arc::new(Mutex::new(Box::new(nu_engine::FakeHost::new())));
|
||||
|
||||
let mut expected = IndexMap::new();
|
||||
expected.insert(
|
||||
@ -202,7 +211,7 @@ mod tests {
|
||||
let new_file = dirs.test().join("updated_configuration.toml");
|
||||
|
||||
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
|
||||
// are cleared since we will load and set them from the
|
||||
@ -273,8 +282,8 @@ mod tests {
|
||||
#[test]
|
||||
fn syncs_env_if_new_env_entry_in_session_is_not_in_configuration_file() -> Result<(), ShellError>
|
||||
{
|
||||
let mut ctx = EvaluationContext::basic()?;
|
||||
ctx.host = Arc::new(Mutex::new(Box::new(crate::env::host::FakeHost::new())));
|
||||
let mut ctx = basic_evaluation_context()?;
|
||||
ctx.host = Arc::new(Mutex::new(Box::new(nu_engine::FakeHost::new())));
|
||||
|
||||
let mut expected = IndexMap::new();
|
||||
expected.insert(
|
||||
@ -372,8 +381,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn nu_envs_have_higher_priority_and_does_not_get_overwritten() -> Result<(), ShellError> {
|
||||
let mut ctx = EvaluationContext::basic()?;
|
||||
ctx.host = Arc::new(Mutex::new(Box::new(crate::env::host::FakeHost::new())));
|
||||
let mut ctx = basic_evaluation_context()?;
|
||||
ctx.host = Arc::new(Mutex::new(Box::new(nu_engine::FakeHost::new())));
|
||||
|
||||
let mut expected = IndexMap::new();
|
||||
expected.insert(
|
||||
@ -448,8 +457,8 @@ mod tests {
|
||||
#[test]
|
||||
fn syncs_path_if_new_path_entry_in_session_is_not_in_configuration_file(
|
||||
) -> Result<(), ShellError> {
|
||||
let mut ctx = EvaluationContext::basic()?;
|
||||
ctx.host = Arc::new(Mutex::new(Box::new(crate::env::host::FakeHost::new())));
|
||||
let mut ctx = basic_evaluation_context()?;
|
||||
ctx.host = Arc::new(Mutex::new(Box::new(nu_engine::FakeHost::new())));
|
||||
|
||||
let expected = std::env::join_paths(vec![
|
||||
PathBuf::from("/Users/andresrobalino/.volta/bin"),
|
||||
@ -535,8 +544,8 @@ mod tests {
|
||||
#[test]
|
||||
fn nu_paths_have_higher_priority_and_new_paths_get_appended_to_the_end(
|
||||
) -> Result<(), ShellError> {
|
||||
let mut ctx = EvaluationContext::basic()?;
|
||||
ctx.host = Arc::new(Mutex::new(Box::new(crate::env::host::FakeHost::new())));
|
||||
let mut ctx = basic_evaluation_context()?;
|
||||
ctx.host = Arc::new(Mutex::new(Box::new(nu_engine::FakeHost::new())));
|
||||
|
||||
let expected = std::env::join_paths(vec![
|
||||
PathBuf::from("/Users/andresrobalino/.volta/bin"),
|
||||
|
@ -1,493 +0,0 @@
|
||||
use nu_errors::ShellError;
|
||||
use nu_parser::ParserScope;
|
||||
use nu_protocol::hir::ClassifiedBlock;
|
||||
use nu_protocol::{
|
||||
Primitive, ReturnSuccess, ShellTypeName, Signature, SyntaxShape, UntaggedValue, Value,
|
||||
};
|
||||
use nu_source::{AnchorLocation, TaggedItem};
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
use num_bigint::BigInt;
|
||||
|
||||
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, Let, Nth,
|
||||
StrCollect, WholeStreamCommand, Wrap,
|
||||
};
|
||||
use crate::evaluation_context::EvaluationContext;
|
||||
use nu_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 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(Let {}),
|
||||
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, &ctx)?;
|
||||
|
||||
println!("{:#?}", block);
|
||||
|
||||
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 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(Let {}),
|
||||
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, &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 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(Let {}),
|
||||
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, &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: &EvaluationContext) -> Result<ClassifiedBlock, ShellError> {
|
||||
//FIXME: do we still need this?
|
||||
let line = if let Some(line) = line.strip_suffix('\n') {
|
||||
line
|
||||
} else {
|
||||
line
|
||||
};
|
||||
|
||||
let (lite_result, err) = nu_parser::lex(&line, 0);
|
||||
if let Some(err) = err {
|
||||
return Err(err.into());
|
||||
}
|
||||
let (lite_result, err) = nu_parser::group(lite_result);
|
||||
if let Some(err) = err {
|
||||
return Err(err.into());
|
||||
}
|
||||
|
||||
// TODO ensure the command whose examples we're testing is actually in the pipeline
|
||||
let (block, err) = nu_parser::classify_block(&lite_result, &ctx.scope);
|
||||
Ok(ClassifiedBlock { block, failed: err })
|
||||
}
|
||||
|
||||
async fn evaluate_block(
|
||||
block: ClassifiedBlock,
|
||||
ctx: &mut EvaluationContext,
|
||||
) -> Result<Vec<Value>, ShellError> {
|
||||
let input_stream = InputStream::empty();
|
||||
let env = ctx.get_env();
|
||||
|
||||
ctx.scope.enter_scope();
|
||||
ctx.scope.add_env(env);
|
||||
|
||||
let result = run_block(&block.block, ctx, input_stream).await;
|
||||
|
||||
ctx.scope.exit_scope();
|
||||
|
||||
let result = result?.drain_vec().await;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
// 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) -> Result<OutputStream, ShellError> {
|
||||
let name_tag = args.call_info.name_tag.clone();
|
||||
|
||||
let (
|
||||
Arguments {
|
||||
path: mocked_path,
|
||||
open: open_mock,
|
||||
},
|
||||
_input,
|
||||
) = args.process().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) -> Result<OutputStream, ShellError> {
|
||||
let name_tag = args.call_info.name_tag.clone();
|
||||
let (MockEchoArgs { rest }, input) = args.process().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) -> 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>;
|
||||
|
||||
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(
|
||||
rl: &mut rustyline::Editor<crate::shell::Helper>,
|
||||
) -> Result<(), nu_errors::ShellError> {
|
||||
let filename = keybinding_path()?;
|
||||
let filename = nu_data::keybinding::keybinding_path()?;
|
||||
let contents = std::fs::read_to_string(filename);
|
||||
|
||||
// Silently fail if there is no file there
|
||||
|
@ -14,45 +14,23 @@ extern crate quickcheck;
|
||||
extern crate quickcheck_macros;
|
||||
|
||||
mod cli;
|
||||
mod commands;
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
mod completion;
|
||||
mod deserializer;
|
||||
mod documentation;
|
||||
mod env;
|
||||
mod evaluate;
|
||||
mod evaluation_context;
|
||||
mod format;
|
||||
mod futures;
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
mod git;
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
mod keybinding;
|
||||
mod path;
|
||||
mod plugin;
|
||||
pub mod script;
|
||||
mod line_editor;
|
||||
mod shell;
|
||||
pub mod types;
|
||||
pub mod utils;
|
||||
|
||||
#[cfg(test)]
|
||||
mod examples;
|
||||
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
pub use crate::cli::cli;
|
||||
|
||||
pub use crate::cli::{parse_and_eval, register_plugins, run_script_file};
|
||||
pub use crate::commands::classified::block::run_block;
|
||||
pub use crate::commands::command::{
|
||||
whole_stream_command, CommandArgs, EvaluatedWholeStreamCommandArgs, Example, WholeStreamCommand,
|
||||
};
|
||||
|
||||
pub use crate::commands::default_context::create_default_context;
|
||||
pub use crate::commands::help::get_help;
|
||||
pub use crate::env::environment_syncer::EnvironmentSyncer;
|
||||
pub use crate::env::host::BasicHost;
|
||||
pub use crate::evaluation_context::EvaluationContext;
|
||||
pub use crate::prelude::ToOutputStream;
|
||||
pub use nu_command::commands::default_context::create_default_context;
|
||||
pub use nu_data::config;
|
||||
pub use nu_data::dict::TaggedListBuilder;
|
||||
pub use nu_data::primitive;
|
||||
|
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)
|
||||
);
|
||||
});
|
||||
|
||||
nu_stream::InputStream::from_stream(objects.boxed())
|
||||
} else {
|
||||
$expr
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! trace_out_stream {
|
||||
(target: $target:tt, $desc:tt = $expr:expr) => {{
|
||||
@ -68,45 +46,19 @@ macro_rules! trace_out_stream {
|
||||
}};
|
||||
}
|
||||
|
||||
pub(crate) use nu_protocol::{errln, out, outln, row};
|
||||
use nu_source::HasFallibleSpan;
|
||||
|
||||
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::evaluate::scope::Scope;
|
||||
|
||||
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 bigdecimal::BigDecimal;
|
||||
pub(crate) use futures::stream::BoxStream;
|
||||
pub(crate) use futures::{Stream, StreamExt};
|
||||
pub(crate) use nu_engine::Host;
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) use nu_errors::ShellError;
|
||||
pub(crate) use nu_parser::ParserScope;
|
||||
pub(crate) use nu_source::{
|
||||
b, AnchorLocation, DebugDocBuilder, PrettyDebug, PrettyDebugWithSource, Span, SpannedItem, Tag,
|
||||
TaggedItem, Text,
|
||||
};
|
||||
pub(crate) use nu_stream::{InputStream, InterruptibleStream, OutputStream};
|
||||
#[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 num_bigint::BigInt;
|
||||
pub(crate) use num_traits::cast::ToPrimitive;
|
||||
pub(crate) use serde::Deserialize;
|
||||
pub(crate) use std::collections::VecDeque;
|
||||
pub(crate) use std::future::Future;
|
||||
pub(crate) use std::sync::atomic::{AtomicBool, Ordering};
|
||||
pub(crate) use std::sync::Arc;
|
||||
|
||||
pub(crate) use async_trait::async_trait;
|
||||
pub(crate) use indexmap::{indexmap, IndexMap};
|
||||
pub(crate) use itertools::Itertools;
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) use std::sync::atomic::Ordering;
|
||||
|
||||
#[allow(clippy::clippy::wrong_self_convention)]
|
||||
pub trait FromInputStream {
|
||||
fn from_input_stream(self) -> OutputStream;
|
||||
}
|
||||
@ -122,26 +74,7 @@ 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(),
|
||||
},
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::clippy::wrong_self_convention)]
|
||||
pub trait ToOutputStream {
|
||||
fn to_output_stream(self) -> OutputStream;
|
||||
}
|
||||
@ -157,16 +90,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")]
|
||||
pub(crate) mod completer;
|
||||
pub(crate) mod filesystem_shell;
|
||||
pub(crate) mod help_shell;
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
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")]
|
||||
pub(crate) use helper::Helper;
|
||||
|
@ -4,7 +4,7 @@ use crate::completion::matchers;
|
||||
use crate::completion::matchers::Matcher;
|
||||
use crate::completion::path::{PathCompleter, PathSuggestion};
|
||||
use crate::completion::{self, Completer, Suggestion};
|
||||
use crate::evaluation_context::EvaluationContext;
|
||||
use nu_engine::EvaluationContext;
|
||||
use nu_parser::ParserScope;
|
||||
use nu_source::Tag;
|
||||
|
||||
|
@ -1,12 +1,8 @@
|
||||
use std::borrow::Cow::{self, Owned};
|
||||
|
||||
use nu_source::{Tag, Tagged};
|
||||
|
||||
use crate::completion;
|
||||
use crate::evaluation_context::EvaluationContext;
|
||||
use crate::shell::completer::NuCompleter;
|
||||
use crate::shell::painter::Painter;
|
||||
use crate::shell::palette::DefaultPalette;
|
||||
use nu_engine::{DefaultPalette, EvaluationContext, Painter};
|
||||
use nu_source::{Tag, Tagged};
|
||||
use std::borrow::Cow::{self, Owned};
|
||||
|
||||
pub struct Helper {
|
||||
completer: NuCompleter,
|
||||
@ -123,7 +119,7 @@ impl rustyline::validate::Validator for NuValidator {
|
||||
}
|
||||
}
|
||||
|
||||
let (_, err) = nu_parser::group(tokens);
|
||||
let (_, err) = nu_parser::parse_block(tokens);
|
||||
|
||||
if let Some(err) = err {
|
||||
if let nu_errors::ParseErrorReason::Eof { .. } = err.reason() {
|
||||
@ -148,3 +144,51 @@ fn vec_tag<T>(input: Vec<Tagged<T>>) -> Option<Tag> {
|
||||
}
|
||||
|
||||
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,6 +1,8 @@
|
||||
#![allow(dead_code)]
|
||||
use crate::prelude::*;
|
||||
use itertools::{merge_join_by, EitherOrBoth, Itertools};
|
||||
use lazy_static::lazy_static;
|
||||
use log::trace;
|
||||
use nu_engine::Scope;
|
||||
use nu_errors::ShellError;
|
||||
use nu_parser::ParserScope;
|
||||
use nu_protocol::{
|
||||
@ -14,9 +16,6 @@ use nu_source::Span;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::HashMap, hash::Hash};
|
||||
|
||||
use itertools::{merge_join_by, EitherOrBoth, Itertools};
|
||||
use log::trace;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct VarDeclaration {
|
||||
pub name: String,
|
||||
@ -212,7 +211,7 @@ fn get_result_shape_of(
|
||||
l_shape: SyntaxShape,
|
||||
op_expr: &SpannedExpression,
|
||||
r_shape: SyntaxShape,
|
||||
) -> Result<SyntaxShape, ShellError> {
|
||||
) -> SyntaxShape {
|
||||
let op = match op_expr.expr {
|
||||
Expression::Literal(Literal::Operator(op)) => op,
|
||||
_ => unreachable!("Passing anything but the op expr is invalid"),
|
||||
@ -221,7 +220,7 @@ fn get_result_shape_of(
|
||||
//There is some code for that in the evaluator already.
|
||||
//One might reuse it.
|
||||
//For now we ignore this issue
|
||||
Ok(match op {
|
||||
match op {
|
||||
Operator::Equal
|
||||
| Operator::NotEqual
|
||||
| Operator::LessThan
|
||||
@ -258,7 +257,8 @@ fn get_result_shape_of(
|
||||
}
|
||||
}
|
||||
Operator::Modulo => SyntaxShape::Number,
|
||||
})
|
||||
Operator::Pow => SyntaxShape::Number,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_shape_of_expr(expr: &SpannedExpression) -> Option<SyntaxShape> {
|
||||
@ -296,7 +296,7 @@ fn get_shape_of_expr(expr: &SpannedExpression) -> Option<SyntaxShape> {
|
||||
Expression::Boolean(_) => Some(SyntaxShape::String),
|
||||
|
||||
Expression::Path(_) => Some(SyntaxShape::ColumnPath),
|
||||
Expression::FilePath(_) => Some(SyntaxShape::Path),
|
||||
Expression::FilePath(_) => Some(SyntaxShape::FilePath),
|
||||
Expression::Block(_) => Some(SyntaxShape::Block),
|
||||
Expression::ExternalCommand(_) => Some(SyntaxShape::String),
|
||||
Expression::Table(_, _) => Some(SyntaxShape::Table),
|
||||
@ -334,7 +334,7 @@ fn get_result_shape_of_math_expr(
|
||||
//match lhs, rhs
|
||||
match (shapes[0], shapes[1]) {
|
||||
(None, None) | (None, _) | (_, None) => Ok(None),
|
||||
(Some(left), Some(right)) => get_result_shape_of(left, &bin.op, right).map(Some),
|
||||
(Some(left), Some(right)) => Ok(Some(get_result_shape_of(left, &bin.op, right))),
|
||||
}
|
||||
}
|
||||
|
||||
@ -861,7 +861,7 @@ impl VarSyntaxShapeDeductor {
|
||||
}
|
||||
}
|
||||
}
|
||||
Operator::Multiply | Operator::Divide => {
|
||||
Operator::Multiply | Operator::Divide | Operator::Pow => {
|
||||
if let Some(shape) = self.get_shape_of_binary_arg_or_insert_dependency(
|
||||
(var, expr),
|
||||
bin_spanned,
|
||||
|
@ -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]");
|
||||
}
|
@ -1,124 +0,0 @@
|
||||
use nu_test_support::fs::Stub::FileWithContentToBeTrimmed;
|
||||
use nu_test_support::playground::Playground;
|
||||
use nu_test_support::{nu, pipeline};
|
||||
|
||||
#[test]
|
||||
fn regular_columns() {
|
||||
Playground::setup("select_test_1", |dirs, sandbox| {
|
||||
sandbox.with_files(vec![FileWithContentToBeTrimmed(
|
||||
"los_tres_caballeros.csv",
|
||||
r#"
|
||||
first_name,last_name,rusty_at,type
|
||||
Andrés,Robalino,10/11/2013,A
|
||||
Jonathan,Turner,10/12/2013,B
|
||||
Yehuda,Katz,10/11/2013,A
|
||||
"#,
|
||||
)]);
|
||||
|
||||
let actual = nu!(
|
||||
cwd: dirs.test(), pipeline(
|
||||
r#"
|
||||
open los_tres_caballeros.csv
|
||||
| select rusty_at last_name
|
||||
| nth 0
|
||||
| get last_name
|
||||
"#
|
||||
));
|
||||
|
||||
assert_eq!(actual.out, "Robalino");
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complex_nested_columns() {
|
||||
Playground::setup("select_test_2", |dirs, sandbox| {
|
||||
sandbox.with_files(vec![FileWithContentToBeTrimmed(
|
||||
"los_tres_caballeros.json",
|
||||
r#"
|
||||
{
|
||||
"nu": {
|
||||
"committers": [
|
||||
{"name": "Andrés N. Robalino"},
|
||||
{"name": "Jonathan Turner"},
|
||||
{"name": "Yehuda Katz"}
|
||||
],
|
||||
"releases": [
|
||||
{"version": "0.2"}
|
||||
{"version": "0.8"},
|
||||
{"version": "0.9999999"}
|
||||
],
|
||||
"0xATYKARNU": [
|
||||
["Th", "e", " "],
|
||||
["BIG", " ", "UnO"],
|
||||
["punto", "cero"]
|
||||
]
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)]);
|
||||
|
||||
let actual = nu!(
|
||||
cwd: dirs.test(), pipeline(
|
||||
r#"
|
||||
open los_tres_caballeros.json
|
||||
| select nu."0xATYKARNU" nu.committers.name nu.releases.version
|
||||
| where "nu.releases.version" > "0.8"
|
||||
| get "nu.releases.version"
|
||||
"#
|
||||
));
|
||||
|
||||
assert_eq!(actual.out, "0.9999999");
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn allows_if_given_unknown_column_name_is_missing() {
|
||||
Playground::setup("select_test_3", |dirs, sandbox| {
|
||||
sandbox.with_files(vec![FileWithContentToBeTrimmed(
|
||||
"los_tres_caballeros.csv",
|
||||
r#"
|
||||
first_name,last_name,rusty_at,type
|
||||
Andrés,Robalino,10/11/2013,A
|
||||
Jonathan,Turner,10/12/2013,B
|
||||
Yehuda,Katz,10/11/2013,A
|
||||
"#,
|
||||
)]);
|
||||
|
||||
let actual = nu!(
|
||||
cwd: dirs.test(), pipeline(
|
||||
r#"
|
||||
open los_tres_caballeros.csv
|
||||
| select rrusty_at first_name
|
||||
| count
|
||||
"#
|
||||
));
|
||||
|
||||
assert_eq!(actual.out, "3");
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn column_names_with_spaces() {
|
||||
Playground::setup("select_test_4", |dirs, sandbox| {
|
||||
sandbox.with_files(vec![FileWithContentToBeTrimmed(
|
||||
"test_data.csv",
|
||||
r#"
|
||||
first name,last name
|
||||
Jonathan,Turner
|
||||
Jonathan,Arns
|
||||
"#,
|
||||
)]);
|
||||
|
||||
let actual = nu!(
|
||||
cwd: dirs.test(), pipeline(
|
||||
r#"
|
||||
open test_data.csv
|
||||
| select "last name"
|
||||
| to json
|
||||
"#
|
||||
));
|
||||
|
||||
let expected_output = r#"[{"last name":"Turner"},{"last name":"Arns"}]"#;
|
||||
assert_eq!(actual.out, expected_output);
|
||||
})
|
||||
}
|
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.27.1"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
nu-data = { version = "0.27.1", path = "../nu-data" }
|
||||
nu-engine = { version = "0.27.1", path = "../nu-engine" }
|
||||
nu-errors = { version = "0.27.1", path = "../nu-errors" }
|
||||
nu-json = { version = "0.27.1", path = "../nu-json" }
|
||||
nu-parser = { version = "0.27.1", path = "../nu-parser" }
|
||||
nu-plugin = { version = "0.27.1", path = "../nu-plugin" }
|
||||
nu-protocol = { version = "0.27.1", path = "../nu-protocol" }
|
||||
nu-source = { version = "0.27.1", path = "../nu-source" }
|
||||
nu-stream = { version = "0.27.1", path = "../nu-stream" }
|
||||
nu-table = { version = "0.27.1", path = "../nu-table" }
|
||||
nu-test-support = { version = "0.27.1", path = "../nu-test-support" }
|
||||
nu-value-ext = { version = "0.27.1", path = "../nu-value-ext" }
|
||||
|
||||
Inflector = "0.11"
|
||||
ansi_term = "0.12.1"
|
||||
arboard = { version = "1.1.0", optional = true }
|
||||
async-recursion = "0.3.2"
|
||||
async-trait = "0.1.42"
|
||||
base64 = "0.13.0"
|
||||
bigdecimal = { version = "0.2.0", features = ["serde"] }
|
||||
byte-unit = "4.0.9"
|
||||
bytes = "1.0.1"
|
||||
calamine = "0.17.0"
|
||||
chrono = { version = "0.4.19", features = ["serde"] }
|
||||
chrono-tz = "0.5.3"
|
||||
clap = "2.33.3"
|
||||
codespan-reporting = "0.11.0"
|
||||
csv = "1.1.3"
|
||||
ctrlc = { version = "3.1.7", 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.28"
|
||||
filesize = "0.2.0"
|
||||
fs_extra = "1.2.0"
|
||||
futures = { version = "0.3.12", features = ["compat", "io-compat"] }
|
||||
futures-util = "0.3.12"
|
||||
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.1", features = ["serde-1"] }
|
||||
itertools = "0.10.0"
|
||||
lazy_static = "1.*"
|
||||
log = "0.4.14"
|
||||
meval = "0.2.0"
|
||||
num-bigint = { version = "0.3.1", features = ["serde"] }
|
||||
num-format = { version = "0.4.0", features = ["with-num-bigint"] }
|
||||
num-traits = "0.2.14"
|
||||
parking_lot = "0.11.1"
|
||||
pin-utils = "0.1.0"
|
||||
pretty-hex = "0.2.1"
|
||||
ptree = { version = "0.3.1", optional = true }
|
||||
query_interface = "0.3.5"
|
||||
quick-xml = "0.21.0"
|
||||
rand = "0.7.3"
|
||||
rayon = "1.5.0"
|
||||
regex = "1.4.3"
|
||||
roxmltree = "0.14.0"
|
||||
rust-embed = "5.9.0"
|
||||
rustyline = { version = "7.1.0", optional = true }
|
||||
serde = { version = "1.0.123", features = ["derive"] }
|
||||
serde_bytes = "0.11.5"
|
||||
serde_ini = "0.2.0"
|
||||
serde_json = "1.0.61"
|
||||
serde_urlencoded = "0.7.0"
|
||||
serde_yaml = "0.8.16"
|
||||
sha2 = "0.9.3"
|
||||
shellexpand = "2.1.0"
|
||||
strip-ansi-escapes = "0.1.0"
|
||||
sxd-document = "0.3.2"
|
||||
sxd-xpath = "0.4.2"
|
||||
tempfile = "3.2.0"
|
||||
term = { version = "0.7.0", optional = true }
|
||||
term_size = "0.3.2"
|
||||
termcolor = "1.1.2"
|
||||
titlecase = "1.1.0"
|
||||
toml = "0.5.8"
|
||||
trash = { version = "1.3.0", optional = true }
|
||||
unicode-segmentation = "1.7.1"
|
||||
url = "2.2.0"
|
||||
uuid_crate = { package = "uuid", version = "0.8.2", features = ["v4"], optional = true }
|
||||
which = { version = "4.0.2", optional = true }
|
||||
zip = { version = "0.5.9", optional = true }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
umask = "1.0.0"
|
||||
users = "0.11.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 = "1.0.3"
|
||||
quickcheck_macros = "1.0.0"
|
||||
|
||||
[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()
|
||||
}
|
@ -7,7 +7,7 @@ mod to_delimited_data;
|
||||
pub(crate) mod ansi;
|
||||
pub(crate) mod append;
|
||||
pub(crate) mod args;
|
||||
pub(crate) mod autoenv;
|
||||
pub mod autoenv;
|
||||
pub(crate) mod autoenv_trust;
|
||||
pub(crate) mod autoenv_untrust;
|
||||
pub(crate) mod autoview;
|
||||
@ -20,7 +20,7 @@ pub(crate) mod chart;
|
||||
pub(crate) mod classified;
|
||||
#[cfg(feature = "clipboard-cli")]
|
||||
pub(crate) mod clip;
|
||||
pub(crate) mod command;
|
||||
pub mod command;
|
||||
pub(crate) mod compact;
|
||||
pub(crate) mod config;
|
||||
pub(crate) mod constants;
|
||||
@ -30,7 +30,7 @@ pub(crate) mod date;
|
||||
pub(crate) mod debug;
|
||||
pub(crate) mod def;
|
||||
pub(crate) mod default;
|
||||
pub(crate) mod default_context;
|
||||
pub mod default_context;
|
||||
pub(crate) mod describe;
|
||||
pub(crate) mod do_;
|
||||
pub(crate) mod drop;
|
||||
@ -115,6 +115,7 @@ pub(crate) mod split_by;
|
||||
pub(crate) mod str_;
|
||||
pub(crate) mod table;
|
||||
pub(crate) mod tags;
|
||||
pub(crate) mod termsize;
|
||||
pub(crate) mod to;
|
||||
pub(crate) mod to_csv;
|
||||
pub(crate) mod to_html;
|
||||
@ -136,9 +137,6 @@ pub(crate) mod wrap;
|
||||
|
||||
pub(crate) use autoview::Autoview;
|
||||
pub(crate) use cd::Cd;
|
||||
pub(crate) use command::{
|
||||
whole_stream_command, Command, Example, UnevaluatedCallInfo, WholeStreamCommand,
|
||||
};
|
||||
|
||||
pub(crate) use ansi::Ansi;
|
||||
pub(crate) use append::Command as Append;
|
||||
@ -200,7 +198,7 @@ pub(crate) use from_xlsx::FromXLSX;
|
||||
pub(crate) use from_xml::FromXML;
|
||||
pub(crate) use from_yaml::FromYAML;
|
||||
pub(crate) use from_yaml::FromYML;
|
||||
pub(crate) use get::Get;
|
||||
pub(crate) use get::Command as Get;
|
||||
pub(crate) use group_by::Command as GroupBy;
|
||||
pub(crate) use group_by_date::GroupByDate;
|
||||
pub(crate) use hash_::{Hash, HashBase64};
|
||||
@ -248,7 +246,7 @@ pub(crate) use reverse::Reverse;
|
||||
pub(crate) use rm::Remove;
|
||||
pub(crate) use run_external::RunExternalCommand;
|
||||
pub(crate) use save::Save;
|
||||
pub(crate) use select::Select;
|
||||
pub(crate) use select::Command as Select;
|
||||
pub(crate) use seq::Seq;
|
||||
pub(crate) use seq_dates::SeqDates;
|
||||
pub(crate) use shells::Shells;
|
||||
@ -263,16 +261,17 @@ pub(crate) use split_by::SplitBy;
|
||||
pub(crate) use str_::{
|
||||
Str, StrCamelCase, StrCapitalize, StrCollect, StrContains, StrDowncase, StrEndsWith,
|
||||
StrFindReplace, StrFrom, StrIndexOf, StrKebabCase, StrLPad, StrLength, StrPascalCase, StrRPad,
|
||||
StrReverse, StrScreamingSnakeCase, StrSet, StrSnakeCase, StrStartsWith, StrSubstring,
|
||||
StrToDatetime, StrToDecimal, StrToInteger, StrTrim, StrTrimLeft, StrTrimRight, StrUpcase,
|
||||
StrReverse, StrScreamingSnakeCase, StrSnakeCase, StrStartsWith, StrSubstring, StrToDatetime,
|
||||
StrToDecimal, StrToInteger, StrTrim, StrTrimLeft, StrTrimRight, StrUpcase,
|
||||
};
|
||||
pub(crate) use table::Table;
|
||||
pub(crate) use tags::Tags;
|
||||
pub(crate) use termsize::TermSize;
|
||||
pub(crate) use to::To;
|
||||
pub(crate) use to_csv::ToCSV;
|
||||
pub(crate) use to_html::ToHTML;
|
||||
pub(crate) use to_json::ToJSON;
|
||||
pub(crate) use to_md::ToMarkdown;
|
||||
pub(crate) use to_md::Command as ToMarkdown;
|
||||
pub(crate) use to_toml::ToTOML;
|
||||
pub(crate) use to_tsv::ToTSV;
|
||||
pub(crate) use to_url::ToURL;
|
||||
@ -290,8 +289,8 @@ pub(crate) use wrap::Wrap;
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::commands::whole_stream_command;
|
||||
use crate::examples::{test_anchors, test_examples};
|
||||
use nu_engine::{whole_stream_command, Command};
|
||||
use nu_errors::ShellError;
|
||||
|
||||
fn full_tests() -> Vec<Command> {
|
||||
@ -302,6 +301,37 @@ mod tests {
|
||||
whole_stream_command(Move),
|
||||
whole_stream_command(Update),
|
||||
whole_stream_command(Empty),
|
||||
// whole_stream_command(Select),
|
||||
// whole_stream_command(Get),
|
||||
// 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),
|
||||
whole_stream_command(ToMarkdown),
|
||||
]
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use ansi_term::Color;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
@ -9,7 +9,7 @@ pub struct Ansi;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct AnsiArgs {
|
||||
color: Value,
|
||||
code: Value,
|
||||
escape: Option<Tagged<String>>,
|
||||
osc: Option<Tagged<String>>,
|
||||
}
|
||||
@ -23,18 +23,18 @@ impl WholeStreamCommand for Ansi {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("ansi")
|
||||
.optional(
|
||||
"color",
|
||||
"code",
|
||||
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(
|
||||
"escape", // \x1b
|
||||
"escape", // \x1b[
|
||||
SyntaxShape::Any,
|
||||
"escape sequence without the escape character(s)",
|
||||
Some('e'),
|
||||
)
|
||||
.named(
|
||||
"osc",
|
||||
"osc", // \x1b]
|
||||
SyntaxShape::Any,
|
||||
"operating system command (ocs) escape sequence without the escape character(s)",
|
||||
Some('o'),
|
||||
@ -119,7 +119,7 @@ Format: #
|
||||
}
|
||||
|
||||
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let (AnsiArgs { color, escape, osc }, _) = args.process().await?;
|
||||
let (AnsiArgs { code, escape, osc }, _) = args.process().await?;
|
||||
|
||||
if let Some(e) = escape {
|
||||
let esc_vec: Vec<char> = e.item.chars().collect();
|
||||
@ -145,6 +145,7 @@ Format: #
|
||||
o.tag(),
|
||||
));
|
||||
}
|
||||
|
||||
//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
|
||||
let output = format!("\x1b]{};", o.item);
|
||||
@ -153,25 +154,24 @@ Format: #
|
||||
)));
|
||||
}
|
||||
|
||||
let color_string = color.as_string()?;
|
||||
let ansi_code = str_to_ansi_color(color_string);
|
||||
let code_string = code.as_string()?;
|
||||
let ansi_code = str_to_ansi(code_string);
|
||||
|
||||
if let Some(output) = ansi_code {
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::string(output).into_value(color.tag()),
|
||||
UntaggedValue::string(output).into_value(code.tag()),
|
||||
)))
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"Unknown color",
|
||||
"unknown color",
|
||||
color.tag(),
|
||||
"Unknown ansi code",
|
||||
"unknown ansi code",
|
||||
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() {
|
||||
"g" | "green" => Some(Color::Green.prefix().to_string()),
|
||||
"gb" | "green_bold" => Some(Color::Green.bold().prefix().to_string()),
|
||||
@ -222,6 +222,57 @@ pub fn str_to_ansi_color(s: String) -> Option<String> {
|
||||
"wd" | "white_dimmed" => Some(Color::White.dimmed().prefix().to_string()),
|
||||
"wr" | "white_reverse" => Some(Color::White.reverse().prefix().to_string()),
|
||||
"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,
|
||||
}
|
||||
}
|
||||
@ -235,6 +286,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Ansi {})?)
|
||||
test_examples(Ansi {})
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
|
@ -1,12 +1,12 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
pub struct Autoenv;
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Default)]
|
||||
@ -20,11 +20,12 @@ impl Trusted {
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn file_is_trusted(nu_env_file: &PathBuf, content: &[u8]) -> Result<bool, ShellError> {
|
||||
pub fn file_is_trusted(nu_env_file: &Path, content: &[u8]) -> Result<bool, ShellError> {
|
||||
let contentdigest = Sha256::digest(&content).as_slice().to_vec();
|
||||
let nufile = std::fs::canonicalize(nu_env_file)?;
|
||||
|
||||
let trusted = read_trusted()?;
|
||||
|
||||
Ok(trusted.files.get(&nufile.to_string_lossy().to_string()) == Some(&contentdigest))
|
||||
}
|
||||
|
||||
@ -63,8 +64,7 @@ The file can contain several optional sections:
|
||||
}
|
||||
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::string(crate::commands::help::get_help(&Autoenv, &args.scope))
|
||||
.into_value(Tag::unknown()),
|
||||
UntaggedValue::string(get_help(&Autoenv, &args.scope)).into_value(Tag::unknown()),
|
||||
)))
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::autoenv::read_trusted;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::SyntaxShape;
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
|
@ -1,6 +1,6 @@
|
||||
use super::autoenv::Trusted;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::SyntaxShape;
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
|
@ -1,8 +1,8 @@
|
||||
use crate::commands::autoview::options::{ConfigExtensions, NuConfig as AutoViewConfiguration};
|
||||
use crate::commands::{UnevaluatedCallInfo, WholeStreamCommand};
|
||||
use crate::prelude::*;
|
||||
use crate::primitive::get_color_config;
|
||||
use nu_data::value::format_leaf;
|
||||
use nu_engine::{UnevaluatedCallInfo, WholeStreamCommand};
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::hir::{self, Expression, ExternalRedirection, Literal, SpannedExpression};
|
||||
use nu_protocol::{Primitive, Signature, UntaggedValue, Value};
|
||||
@ -134,30 +134,7 @@ pub async fn autoview(context: RunnableContext) -> Result<OutputStream, ShellErr
|
||||
out!("{}", s);
|
||||
}
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Line(ref 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).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)),
|
||||
value: UntaggedValue::Primitive(Primitive::FilePath(s)),
|
||||
..
|
||||
} => {
|
||||
out!("{}", s.display());
|
||||
@ -196,6 +173,13 @@ pub async fn autoview(context: RunnableContext) -> Result<OutputStream, ShellErr
|
||||
let output = format_leaf(&x).plain_string(100_000);
|
||||
out!("{}", output);
|
||||
}
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Filesize(_)),
|
||||
..
|
||||
} => {
|
||||
let output = format_leaf(&x).plain_string(100_000);
|
||||
out!("{}", output);
|
||||
}
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Date(d)),
|
||||
..
|
||||
@ -332,6 +316,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Command {})?)
|
||||
test_examples(Command {})
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
use crate::commands::classified::block::run_block;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
#[cfg(feature = "rich-benchmark")]
|
||||
use heim::cpu::time;
|
||||
// #[cfg(feature = "rich-benchmark")]
|
||||
// use heim::cpu::time;
|
||||
use nu_engine::run_block;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
hir::{Block, CapturedBlock, ClassifiedCommand, Group, InternalCommand, Pipeline},
|
||||
@ -70,7 +70,7 @@ impl WholeStreamCommand for Benchmark {
|
||||
|
||||
async fn benchmark(raw_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = raw_args.call_info.args.span;
|
||||
let mut context = EvaluationContext::from_raw(&raw_args);
|
||||
let mut context = EvaluationContext::from_args(&raw_args);
|
||||
let scope = raw_args.scope.clone();
|
||||
let (BenchmarkArgs { block, passthrough }, input) = raw_args.process().await?;
|
||||
|
||||
@ -81,22 +81,22 @@ async fn benchmark(raw_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
let start_time = Instant::now();
|
||||
|
||||
#[cfg(feature = "rich-benchmark")]
|
||||
let start = time().await;
|
||||
// #[cfg(feature = "rich-benchmark")]
|
||||
// let start = time().await;
|
||||
|
||||
context.scope.enter_scope();
|
||||
let result = run_block(&block.block, &context, input).await;
|
||||
context.scope.exit_scope();
|
||||
let output = result?.into_vec().await;
|
||||
|
||||
#[cfg(feature = "rich-benchmark")]
|
||||
let end = time().await;
|
||||
// #[cfg(feature = "rich-benchmark")]
|
||||
// let end = time().await;
|
||||
|
||||
let end_time = Instant::now();
|
||||
context.clear_errors();
|
||||
|
||||
// return basic runtime
|
||||
#[cfg(not(feature = "rich-benchmark"))]
|
||||
//#[cfg(not(feature = "rich-benchmark"))]
|
||||
{
|
||||
let mut indexmap = IndexMap::with_capacity(1);
|
||||
|
||||
@ -105,28 +105,28 @@ async fn benchmark(raw_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
benchmark_output(indexmap, output, passthrough, &tag, &mut context).await
|
||||
}
|
||||
// return advanced stats
|
||||
#[cfg(feature = "rich-benchmark")]
|
||||
if let (Ok(start), Ok(end)) = (start, end) {
|
||||
let mut indexmap = IndexMap::with_capacity(4);
|
||||
// #[cfg(feature = "rich-benchmark")]
|
||||
// if let (Ok(start), Ok(end)) = (start, end) {
|
||||
// let mut indexmap = IndexMap::with_capacity(4);
|
||||
|
||||
let real_time = into_big_int(end_time - start_time);
|
||||
indexmap.insert("real time".to_string(), real_time);
|
||||
// let real_time = into_big_int(end_time - start_time);
|
||||
// indexmap.insert("real time".to_string(), real_time);
|
||||
|
||||
let user_time = into_big_int(end.user() - start.user());
|
||||
indexmap.insert("user time".to_string(), user_time);
|
||||
// let user_time = into_big_int(end.user() - start.user());
|
||||
// indexmap.insert("user time".to_string(), user_time);
|
||||
|
||||
let system_time = into_big_int(end.system() - start.system());
|
||||
indexmap.insert("system time".to_string(), system_time);
|
||||
// let system_time = into_big_int(end.system() - start.system());
|
||||
// indexmap.insert("system time".to_string(), system_time);
|
||||
|
||||
let idle_time = into_big_int(end.idle() - start.idle());
|
||||
indexmap.insert("idle time".to_string(), idle_time);
|
||||
// let idle_time = into_big_int(end.idle() - start.idle());
|
||||
// indexmap.insert("idle time".to_string(), idle_time);
|
||||
|
||||
benchmark_output(indexmap, output, passthrough, &tag, &mut context).await
|
||||
} else {
|
||||
Err(ShellError::untagged_runtime_error(
|
||||
"Could not retrieve CPU time",
|
||||
))
|
||||
}
|
||||
// benchmark_output(indexmap, output, passthrough, &tag, &mut context).await
|
||||
// } else {
|
||||
// Err(ShellError::untagged_runtime_error(
|
||||
// "Could not retrieve CPU time",
|
||||
// ))
|
||||
// }
|
||||
}
|
||||
|
||||
async fn benchmark_output<T, Output>(
|
@ -1,8 +1,8 @@
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use nu_data::value::format_leaf;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
|
||||
#[derive(Deserialize)]
|
@ -1,7 +1,7 @@
|
||||
use crate::commands::{command::EvaluatedWholeStreamCommandArgs, WholeStreamCommand};
|
||||
use crate::prelude::*;
|
||||
use chrono::{Datelike, Local, NaiveDate};
|
||||
use indexmap::IndexMap;
|
||||
use nu_engine::{EvaluatedWholeStreamCommandArgs, WholeStreamCommand};
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Dictionary, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
|
||||
@ -337,6 +337,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Cal {})?)
|
||||
test_examples(Cal {})
|
||||
}
|
||||
}
|
@ -1,16 +1,9 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use nu_engine::shell::CdArgs;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
use nu_source::Tagged;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CdArgs {
|
||||
pub(crate) path: Option<Tagged<PathBuf>>,
|
||||
}
|
||||
|
||||
pub struct Cd;
|
||||
|
||||
@ -23,7 +16,7 @@ impl WholeStreamCommand for Cd {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("cd").optional(
|
||||
"directory",
|
||||
SyntaxShape::Path,
|
||||
SyntaxShape::FilePath,
|
||||
"the directory to change to",
|
||||
)
|
||||
}
|
||||
@ -74,6 +67,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Cd {})?)
|
||||
test_examples(Cd {})
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
@ -19,7 +19,7 @@ impl WholeStreamCommand for Char {
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("ansi")
|
||||
Signature::build("char")
|
||||
.required(
|
||||
"character",
|
||||
SyntaxShape::Any,
|
||||
@ -130,24 +130,6 @@ fn str_to_character(s: &str) -> Option<String> {
|
||||
"snowy" | "snow" => 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,
|
||||
}
|
||||
}
|
||||
@ -161,6 +143,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Char {})?)
|
||||
test_examples(Char {})
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||
|
||||
@ -28,8 +28,7 @@ impl WholeStreamCommand for Chart {
|
||||
}
|
||||
|
||||
Ok(OutputStream::one(Ok(ReturnSuccess::Value(
|
||||
UntaggedValue::string(crate::commands::help::get_help(&Chart, &args.scope))
|
||||
.into_value(Tag::unknown()),
|
||||
UntaggedValue::string(get_help(&Chart, &args.scope)).into_value(Tag::unknown()),
|
||||
))))
|
||||
}
|
||||
}
|
||||
@ -43,6 +42,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Chart {})?)
|
||||
test_examples(Chart {})
|
||||
}
|
||||
}
|
@ -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::prelude::*;
|
||||
use nu_engine::evaluate_baseline_expr;
|
||||
use nu_engine::{MaybeTextCodec, StringOrBinary};
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::io::Write;
|
||||
@ -18,6 +18,7 @@ use nu_protocol::hir::Expression;
|
||||
use nu_protocol::hir::{ExternalCommand, ExternalRedirection};
|
||||
use nu_protocol::{Primitive, ShellTypeName, UntaggedValue, Value};
|
||||
use nu_source::Tag;
|
||||
use nu_stream::trace_stream;
|
||||
|
||||
pub(crate) async fn run_external_command(
|
||||
command: ExternalCommand,
|
||||
@ -95,7 +96,7 @@ async fn run_with_stdin(
|
||||
|
||||
#[cfg(feature = "dirs")]
|
||||
{
|
||||
home_dir = dirs::home_dir;
|
||||
home_dir = dirs_next::home_dir;
|
||||
}
|
||||
#[cfg(not(feature = "dirs"))]
|
||||
{
|
||||
@ -221,8 +222,7 @@ fn spawn(
|
||||
for value in block_on_stream(input) {
|
||||
match &value.value {
|
||||
UntaggedValue::Primitive(Primitive::Nothing) => continue,
|
||||
UntaggedValue::Primitive(Primitive::String(s))
|
||||
| UntaggedValue::Primitive(Primitive::Line(s)) => {
|
||||
UntaggedValue::Primitive(Primitive::String(s)) => {
|
||||
if stdin_write.write(s.as_bytes()).is_err() {
|
||||
// Other side has closed, so exit
|
||||
return Ok(());
|
||||
@ -464,7 +464,7 @@ pub fn did_find_command(#[allow(unused)] name: &str) -> bool {
|
||||
let cmd_builtins = [
|
||||
"assoc", "break", "color", "copy", "date", "del", "dir", "dpath", "echo", "erase",
|
||||
"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)
|
||||
@ -533,15 +533,16 @@ mod tests {
|
||||
add_double_quotes, argument_is_quoted, escape_double_quotes, expand_tilde, remove_quotes,
|
||||
};
|
||||
#[cfg(feature = "which")]
|
||||
use super::{run_external_command, EvaluationContext, InputStream};
|
||||
use super::{run_external_command, InputStream};
|
||||
|
||||
#[cfg(feature = "which")]
|
||||
use futures::executor::block_on;
|
||||
#[cfg(feature = "which")]
|
||||
use nu_engine::basic_evaluation_context;
|
||||
#[cfg(feature = "which")]
|
||||
use nu_errors::ShellError;
|
||||
#[cfg(feature = "which")]
|
||||
use nu_test_support::commands::ExternalBuilder;
|
||||
|
||||
// async fn read(mut stream: OutputStream) -> Option<Value> {
|
||||
// match stream.try_next().await {
|
||||
// Ok(val) => {
|
||||
@ -562,7 +563,7 @@ mod tests {
|
||||
|
||||
let input = InputStream::empty();
|
||||
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(cmd, &mut ctx, input, ExternalRedirection::Stdout)
|
||||
@ -576,7 +577,7 @@ mod tests {
|
||||
// async fn failure_run() -> Result<(), ShellError> {
|
||||
// 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)
|
||||
// .await?
|
||||
// .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 nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::Signature;
|
||||
use std::process::Command;
|
@ -1,6 +1,6 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use futures::stream::StreamExt;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, Value};
|
||||
|
||||
@ -101,6 +101,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Clip {})?)
|
||||
test_examples(Clip {})
|
||||
}
|
||||
}
|
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,7 +1,7 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use futures::future;
|
||||
use futures::stream::StreamExt;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
@ -81,6 +81,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Compact {})?)
|
||||
test_examples(Compact {})
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||
|
@ -1,8 +1,9 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use crate::{CommandArgs, OutputStream};
|
||||
use nu_engine::CommandArgs;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||
use nu_stream::OutputStream;
|
||||
|
||||
pub struct Command;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
|
||||
use nu_source::Tagged;
|
||||
@ -21,7 +21,7 @@ impl WholeStreamCommand for SubCommand {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("config load").required(
|
||||
"load",
|
||||
SyntaxShape::Path,
|
||||
SyntaxShape::FilePath,
|
||||
"Path to load the config from",
|
||||
)
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue};
|
||||
|
||||
@ -36,6 +36,6 @@ pub async fn path(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let path = config::default_path()?;
|
||||
|
||||
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,5 +1,5 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
|
||||
use nu_source::Tagged;
|
@ -1,5 +1,5 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
@ -1,6 +1,6 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use futures::stream::StreamExt;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, UntaggedValue, Value};
|
||||
|
||||
@ -81,6 +81,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Count {})?)
|
||||
test_examples(Count {})
|
||||
}
|
||||
}
|
@ -1,19 +1,10 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
use nu_source::Tagged;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub struct Cpy;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CopyArgs {
|
||||
pub src: Tagged<PathBuf>,
|
||||
pub dst: Tagged<PathBuf>,
|
||||
pub recursive: Tagged<bool>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl WholeStreamCommand for Cpy {
|
||||
fn name(&self) -> &str {
|
||||
@ -22,8 +13,8 @@ impl WholeStreamCommand for Cpy {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("cp")
|
||||
.required("src", SyntaxShape::Pattern, "the place to copy from")
|
||||
.required("dst", SyntaxShape::Path, "the place to copy to")
|
||||
.required("src", SyntaxShape::GlobPattern, "the place to copy from")
|
||||
.required("dst", SyntaxShape::FilePath, "the place to copy to")
|
||||
.switch(
|
||||
"recursive",
|
||||
"copy recursively through subdirectories",
|
||||
@ -67,6 +58,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Cpy {})?)
|
||||
test_examples(Cpy {})
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||
|
||||
@ -21,8 +21,7 @@ impl WholeStreamCommand for Command {
|
||||
|
||||
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
Ok(OutputStream::one(ReturnSuccess::value(
|
||||
UntaggedValue::string(crate::commands::help::get_help(&Command, &args.scope))
|
||||
.into_value(Tag::unknown()),
|
||||
UntaggedValue::string(get_help(&Command, &args.scope)).into_value(Tag::unknown()),
|
||||
)))
|
||||
}
|
||||
}
|
||||
@ -36,6 +35,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Command {})?)
|
||||
test_examples(Command {})
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
Dictionary, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||
@ -104,6 +104,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Date {})?)
|
||||
test_examples(Date {})
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use chrono_tz::TZ_VARIANTS;
|
||||
use indexmap::IndexMap;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Dictionary, ReturnSuccess, Signature, UntaggedValue};
|
||||
|
||||
@ -70,6 +70,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Date {})?)
|
||||
test_examples(Date {})
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use chrono::{DateTime, Local};
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, UntaggedValue};
|
||||
|
||||
@ -45,6 +45,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Date {})?)
|
||||
test_examples(Date {})
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use chrono::{Datelike, Timelike};
|
||||
use indexmap::IndexMap;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Dictionary, Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
|
||||
|
||||
@ -100,6 +100,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Date {})?)
|
||||
test_examples(Date {})
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
use crate::commands::date::parser::{datetime_in_timezone, ParseErrorKind};
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
@ -105,6 +105,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Date {})?)
|
||||
test_examples(Date {})
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ use chrono::{DateTime, Utc};
|
||||
use nu_errors::ShellError;
|
||||
|
||||
use crate::commands::date::utils::date_to_value;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_protocol::Signature;
|
||||
|
||||
pub struct Date;
|
||||
@ -50,6 +50,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Date {})?)
|
||||
test_examples(Date {})
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||
|
||||
@ -53,6 +53,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Debug {})?)
|
||||
test_examples(Debug {})
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{hir::CapturedBlock, Signature, SyntaxShape, Value};
|
@ -1,5 +1,5 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
@ -80,6 +80,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Default {})?)
|
||||
test_examples(Default {})
|
||||
}
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
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 = EvaluationContext::basic()?;
|
||||
let context = basic_evaluation_context()?;
|
||||
|
||||
{
|
||||
use crate::commands::*;
|
||||
@ -89,7 +91,6 @@ pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Bo
|
||||
whole_stream_command(StrFindReplace),
|
||||
whole_stream_command(StrFrom),
|
||||
whole_stream_command(StrSubstring),
|
||||
whole_stream_command(StrSet),
|
||||
whole_stream_command(StrToDatetime),
|
||||
whole_stream_command(StrContains),
|
||||
whole_stream_command(StrIndexOf),
|
||||
@ -236,6 +237,7 @@ pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Bo
|
||||
whole_stream_command(UrlQuery),
|
||||
whole_stream_command(Seq),
|
||||
whole_stream_command(SeqDates),
|
||||
whole_stream_command(TermSize),
|
||||
]);
|
||||
|
||||
#[cfg(feature = "clipboard-cli")]
|
@ -1,5 +1,5 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||
@ -49,6 +49,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Describe {})?)
|
||||
test_examples(Describe {})
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
use crate::commands::classified::block::run_block;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::run_block;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{hir::CapturedBlock, hir::ExternalRedirection, Signature, SyntaxShape, Value};
|
||||
|
||||
@ -55,7 +55,7 @@ impl WholeStreamCommand for Do {
|
||||
async fn do_(raw_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let external_redirection = raw_args.call_info.args.external_redirection;
|
||||
|
||||
let context = EvaluationContext::from_raw(&raw_args);
|
||||
let context = EvaluationContext::from_args(&raw_args);
|
||||
let (
|
||||
DoArgs {
|
||||
ignore_errors,
|
||||
@ -113,6 +113,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Do {})?)
|
||||
test_examples(Do {})
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, SyntaxShape, UntaggedValue};
|
||||
use nu_source::Tagged;
|
||||
@ -86,6 +86,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Drop {})?)
|
||||
test_examples(Drop {})
|
||||
}
|
||||
}
|
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;
|
||||
|
||||
test_examples(Du {})
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
use crate::commands::classified::block::run_block;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::run_block;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
|
||||
use futures::stream::once;
|
||||
use nu_errors::ShellError;
|
||||
@ -111,7 +111,7 @@ pub(crate) fn make_indexed_item(index: usize, item: Value) -> Value {
|
||||
}
|
||||
|
||||
async fn each(raw_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let context = Arc::new(EvaluationContext::from_raw(&raw_args));
|
||||
let context = Arc::new(EvaluationContext::from_args(&raw_args));
|
||||
|
||||
let (each_args, input): (EachArgs, _) = raw_args.process().await?;
|
||||
let block = Arc::new(Box::new(each_args.block));
|
||||
@ -160,6 +160,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Each {})?)
|
||||
test_examples(Each {})
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
use crate::commands::each::process_row;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
hir::CapturedBlock, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||
@ -46,7 +46,7 @@ impl WholeStreamCommand for EachGroup {
|
||||
}
|
||||
|
||||
async fn run(&self, raw_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let context = Arc::new(EvaluationContext::from_raw(&raw_args));
|
||||
let context = Arc::new(EvaluationContext::from_args(&raw_args));
|
||||
let (each_args, input): (EachGroupArgs, _) = raw_args.process().await?;
|
||||
let block = Arc::new(Box::new(each_args.block));
|
||||
|
||||
@ -111,6 +111,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(EachGroup {})?)
|
||||
test_examples(EachGroup {})
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
use crate::commands::each::group::run_block_on_vec;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
//use itertools::Itertools;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{hir::CapturedBlock, Primitive, Signature, SyntaxShape, UntaggedValue};
|
||||
@ -51,7 +51,7 @@ impl WholeStreamCommand for EachWindow {
|
||||
}
|
||||
|
||||
async fn run(&self, raw_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let context = Arc::new(EvaluationContext::from_raw(&raw_args));
|
||||
let context = Arc::new(EvaluationContext::from_args(&raw_args));
|
||||
let (each_args, mut input): (EachWindowArgs, _) = raw_args.process().await?;
|
||||
let block = Arc::new(Box::new(each_args.block));
|
||||
|
||||
@ -100,6 +100,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(EachWindow {})?)
|
||||
test_examples(EachWindow {})
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::hir::Operator;
|
||||
use nu_protocol::{
|
||||
@ -76,6 +76,7 @@ struct RangeIterator {
|
||||
end: Primitive,
|
||||
tag: Tag,
|
||||
is_end_inclusive: bool,
|
||||
moves_up: bool,
|
||||
}
|
||||
|
||||
impl RangeIterator {
|
||||
@ -85,9 +86,15 @@ impl RangeIterator {
|
||||
x => x,
|
||||
};
|
||||
|
||||
let end = match range.to.0.item {
|
||||
Primitive::Nothing => Primitive::Int(u64::MAX.into()),
|
||||
x => x,
|
||||
};
|
||||
|
||||
RangeIterator {
|
||||
moves_up: start <= end,
|
||||
curr: start,
|
||||
end: range.to.0.item,
|
||||
end,
|
||||
tag,
|
||||
is_end_inclusive: matches!(range.to.1, RangeInclusion::Inclusive),
|
||||
}
|
||||
@ -121,7 +128,9 @@ impl Iterator for RangeIterator {
|
||||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
if (ordering == Ordering::Less) || (self.is_end_inclusive && ordering == Ordering::Equal) {
|
||||
if self.moves_up
|
||||
&& (ordering == Ordering::Less || self.is_end_inclusive && ordering == Ordering::Equal)
|
||||
{
|
||||
let output = UntaggedValue::Primitive(self.curr.clone()).into_value(self.tag.clone());
|
||||
|
||||
let next_value = nu_data::value::compute_values(
|
||||
@ -130,6 +139,35 @@ impl Iterator for RangeIterator {
|
||||
&UntaggedValue::int(1),
|
||||
);
|
||||
|
||||
self.curr = match next_value {
|
||||
Ok(result) => match result {
|
||||
UntaggedValue::Primitive(p) => p,
|
||||
_ => {
|
||||
return Some(Err(ShellError::unimplemented(
|
||||
"Internal error: expected a primitive result from increment",
|
||||
)));
|
||||
}
|
||||
},
|
||||
Err((left_type, right_type)) => {
|
||||
return Some(Err(ShellError::coerce_error(
|
||||
left_type.spanned(self.tag.span),
|
||||
right_type.spanned(self.tag.span),
|
||||
)));
|
||||
}
|
||||
};
|
||||
Some(ReturnSuccess::value(output))
|
||||
} else if !self.moves_up
|
||||
&& (ordering == Ordering::Greater
|
||||
|| self.is_end_inclusive && ordering == Ordering::Equal)
|
||||
{
|
||||
let output = UntaggedValue::Primitive(self.curr.clone()).into_value(self.tag.clone());
|
||||
|
||||
let next_value = nu_data::value::compute_values(
|
||||
Operator::Plus,
|
||||
&UntaggedValue::Primitive(self.curr.clone()),
|
||||
&UntaggedValue::int(-1),
|
||||
);
|
||||
|
||||
self.curr = match next_value {
|
||||
Ok(result) => match result {
|
||||
UntaggedValue::Primitive(p) => p,
|
||||
@ -148,7 +186,6 @@ impl Iterator for RangeIterator {
|
||||
};
|
||||
Some(ReturnSuccess::value(output))
|
||||
} else {
|
||||
// TODO: add inclusive/exclusive ranges
|
||||
None
|
||||
}
|
||||
}
|
||||
@ -163,6 +200,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Echo {})?)
|
||||
test_examples(Echo {})
|
||||
}
|
||||
}
|
@ -1,15 +1,15 @@
|
||||
use crate::commands::classified::block::run_block;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::run_block;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
hir::CapturedBlock, ColumnPath, Primitive, ReturnSuccess, Signature, SyntaxShape,
|
||||
UntaggedValue, Value,
|
||||
};
|
||||
use nu_source::Tagged;
|
||||
use nu_value_ext::{as_string, ValueExt};
|
||||
|
||||
use crate::utils::arguments::arguments;
|
||||
use futures::stream::once;
|
||||
use nu_value_ext::{as_string, ValueExt};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Arguments {
|
||||
@ -84,9 +84,10 @@ impl WholeStreamCommand for Command {
|
||||
async fn is_empty(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
let name_tag = Arc::new(args.call_info.name_tag.clone());
|
||||
let context = Arc::new(EvaluationContext::from_raw(&args));
|
||||
let (Arguments { rest }, input) = args.process().await?;
|
||||
let (columns, default_block): (Vec<ColumnPath>, Option<Box<CapturedBlock>>) = arguments(rest)?;
|
||||
let context = Arc::new(EvaluationContext::from_args(&args));
|
||||
let (Arguments { mut rest }, input) = args.process().await?;
|
||||
let (columns, default_block): (Vec<ColumnPath>, Option<Box<CapturedBlock>>) =
|
||||
arguments(&mut rest)?;
|
||||
let default_block = Arc::new(default_block);
|
||||
|
||||
if input.is_empty() {
|
||||
@ -130,37 +131,6 @@ async fn is_empty(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
.to_output_stream())
|
||||
}
|
||||
|
||||
fn arguments(
|
||||
rest: Vec<Value>,
|
||||
) -> Result<(Vec<ColumnPath>, Option<Box<CapturedBlock>>), ShellError> {
|
||||
let mut rest = rest;
|
||||
let mut columns = vec![];
|
||||
let mut default = None;
|
||||
|
||||
let last_argument = rest.pop();
|
||||
|
||||
match last_argument {
|
||||
Some(Value {
|
||||
value: UntaggedValue::Block(call),
|
||||
..
|
||||
}) => default = Some(call),
|
||||
Some(other) => {
|
||||
let Tagged { item: path, .. } = other.as_column_path()?;
|
||||
|
||||
columns = vec![path];
|
||||
}
|
||||
None => {}
|
||||
};
|
||||
|
||||
for argument in rest {
|
||||
let Tagged { item: path, .. } = argument.as_column_path()?;
|
||||
|
||||
columns.push(path);
|
||||
}
|
||||
|
||||
Ok((columns, default))
|
||||
}
|
||||
|
||||
async fn process_row(
|
||||
context: Arc<EvaluationContext>,
|
||||
input: Value,
|
@ -1,6 +1,6 @@
|
||||
use crate::commands::UnevaluatedCallInfo;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::UnevaluatedCallInfo;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::hir::ExternalRedirection;
|
||||
use nu_protocol::{
|
||||
@ -27,7 +27,7 @@ impl WholeStreamCommand for Enter {
|
||||
Signature::build("enter")
|
||||
.required(
|
||||
"location",
|
||||
SyntaxShape::Path,
|
||||
SyntaxShape::FilePath,
|
||||
"the location to create a new shell from",
|
||||
)
|
||||
.named(
|
||||
@ -189,6 +189,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Enter {})?)
|
||||
test_examples(Enter {})
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
|
||||
use nu_source::Tagged;
|
||||
@ -93,6 +93,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Every {})?)
|
||||
test_examples(Every {})
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
use nu_source::Tagged;
|
||||
@ -21,8 +21,11 @@ impl WholeStreamCommand for Exec {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("exec")
|
||||
.required("command", SyntaxShape::Path, "the command to execute")
|
||||
.rest(SyntaxShape::Pattern, "any additional arguments for command")
|
||||
.required("command", SyntaxShape::FilePath, "the command to execute")
|
||||
.rest(
|
||||
SyntaxShape::GlobPattern,
|
||||
"any additional arguments for command",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
@ -1,4 +1,3 @@
|
||||
use crate::commands::command::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{CommandAction, ReturnSuccess, Signature};
|
||||
@ -60,6 +59,6 @@ mod tests {
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
Ok(test_examples(Exit {})?)
|
||||
test_examples(Exit {})
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user